Skip to content

Commit 315264f

Browse files
authored
Merge pull request #6 from UndefinedCreations/new_homepage
New homepage
2 parents d7d3383 + 4f357c1 commit 315264f

31 files changed

+1629
-15
lines changed

app/(home)/akari/page.tsx

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
"use client"
2+
3+
import React, { useState, useEffect } from "react"
4+
import { motion } from "framer-motion"
5+
import { CodeBlock } from "fumadocs-ui/components/codeblock"
6+
import { DynamicCodeBlock } from "fumadocs-ui/components/dynamic-codeblock"
7+
import Image from "next/image"
8+
import VideoPlayer from "@/app/components/hsl-video"
9+
10+
export default function HomePage() {
11+
return (
12+
<main className="p-4 pt-0 flex min-h-screen relative flex-col bg-neutral-900 text-center overflow-hidden">
13+
<motion.header initial={{opacity: 0}} animate={{opacity: 1}} transition={{duration: 1}} className="container outline-2 rounded-b-xl outline-neutral-700 bg-gradient-to-r from-rose-400 transaprent to-blue-500 mx-auto relative overflow-hidden h-100 w-screen py-4 items-center justify-center flex flex-col">
14+
<VideoPlayer
15+
className="w-full h-full blur-sm z-0 absolute inset-0 object-cover opacity-75"
16+
controls={false} loop muted playsInline autoPlay src={"https://bamblingen.no/api/v1/files/video?v=20250927-b47fc640b07187e5"}
17+
/>
18+
<div className="z-1 w-full h-full inset-0 absolute flex flex-col items-center justify-center ">
19+
<Amazing delay={0} />
20+
</div>
21+
</motion.header>
22+
23+
<motion.div
24+
className="absolute top-120 left-1/2 -translate-1/2 rounded-xl p-0 h-auto max-w-4xl mx-auto shadow-md text-left"
25+
initial={{ translateY: 0, opacity: 0 }}
26+
animate={{ translateY: -50, opacity: 1 }}
27+
transition={{ delay: 1, duration: 1, ease: "anticipate" }}
28+
>
29+
<TypingCodeBlock
30+
text={`StellarCommand("message")
31+
.addAliases("msg", "tell")
32+
.addOnlinePlayersArgument("target")
33+
.addStringArgument("message", StringType.PHRASE)
34+
.addExecution<Player> {
35+
val target = getArgument<Player>("target")
36+
val message = getArgument<String>("message")
37+
target.sendMessage(message)
38+
}`}
39+
speed={10}
40+
/>
41+
</motion.div>
42+
</main>
43+
)
44+
}
45+
46+
// Title animation
47+
function Amazing({ delay }: { delay: number }) {
48+
return (
49+
<React.Fragment>
50+
<motion.div
51+
initial={{ scale: 2, opacity: 0, letterSpacing: "64px" }}
52+
animate={{ scale: 1, opacity: 1, letterSpacing: "8px" }}
53+
transition={{ duration: 1, delay, ease: "anticipate" }}
54+
className="font-black text-shadow-title text-white text-9xl"
55+
>
56+
<Image className="mb-2" alt="akari" unoptimized width={320} height={100} src={"/logos/akari.svg"} ></Image>
57+
</motion.div>
58+
<motion.div
59+
initial={{ scale: 2, opacity: 0, }}
60+
animate={{ scale: 1, opacity: 1, }}
61+
transition={{ duration: 1, delay: 0.5, ease: "anticipate" }}
62+
className="font-black text-white text-9xl"
63+
>
64+
<p className="text-white bg-neutral-900 px-4 py-1 rounded-lg border border-neutral-600 text-2xl font-semibold text-shadow-title">In-game cinematics, no mods</p>
65+
</motion.div>
66+
</React.Fragment>
67+
)
68+
}
69+
70+
// Typewriter effect, but using fumadocs-ui's CodeBlock for formatting
71+
function TypingCodeBlock({ text, speed = 50 }: { text: string; speed?: number }) {
72+
const [displayed, setDisplayed] = useState("")
73+
74+
useEffect(() => {
75+
let i = 0
76+
const interval = setInterval(() => {
77+
if (i < text.length) {
78+
setDisplayed((prev) => prev + text[i])
79+
i++
80+
} else {
81+
clearInterval(interval)
82+
}
83+
}, speed)
84+
return () => clearInterval(interval)
85+
}, [text, speed])
86+
87+
return <DynamicCodeBlock
88+
lang="Kotlin"
89+
code={displayed}
90+
options={{ theme: "dracula-soft" }}
91+
/>
92+
}

app/(home)/layout.tsx

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,22 @@
11
import type { ReactNode } from 'react';
22
import { HomeLayout } from 'fumadocs-ui/layouts/home';
33
import { baseOptions } from '@/app/layout.config';
4+
import Link from 'next/link';
5+
import { BsDiscord } from 'react-icons/bs';
6+
import BasicFooter from '../components/layout/basic-footer';
7+
import { Navbar } from 'fumadocs-ui/layouts/home/navbar';
8+
import { SearchDialog } from 'fumadocs-ui/components/dialog/search';
49

510
export default function Layout({ children }: { children: ReactNode }) {
6-
return <HomeLayout {...baseOptions}>{children}</HomeLayout>;
11+
return <div>
12+
<HomeLayout
13+
{...baseOptions}
14+
themeSwitch={{enabled: false}}
15+
>
16+
<div className='min-h-screen inline'>
17+
{children}
18+
</div>
19+
<BasicFooter />
20+
</HomeLayout>
21+
</div>;
722
}

app/(home)/lynx/page.tsx

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
"use client"
2+
3+
import React, { useState, useEffect, useRef } from "react"
4+
import { motion } from "framer-motion"
5+
import { CodeBlock } from "fumadocs-ui/components/codeblock"
6+
import { DynamicCodeBlock } from "fumadocs-ui/components/dynamic-codeblock"
7+
import Image from "next/image"
8+
import { TypeTable } from "fumadocs-ui/components/type-table"
9+
import { Book, Check, Circle, Clock, Cross, File, GitBranch, Github, LucideGitPullRequest, Plus, Share, X } from "lucide-react"
10+
import Link from "next/link"
11+
import { SiKotlin } from "react-icons/si"
12+
import { IoLibrary } from "react-icons/io5"
13+
import { BiSolidError } from "react-icons/bi"
14+
import { MdList } from "react-icons/md"
15+
import ParallaxLogo from "./parallax"
16+
import { SplitMB } from "@/app/components/Split-media-body"
17+
import TypingCodeBlock from "@/app/components/typing-code-block"
18+
import LatestVersion from "@/app/components/latest-version"
19+
import { RiGitRepositoryLine } from "react-icons/ri"
20+
21+
type CodeExample = {
22+
code: string,
23+
title: string,
24+
}
25+
26+
const examples: CodeExample[] = [
27+
{
28+
"title": "Spawn NPC",
29+
"code": "location.spawnNPC(\n name = \"FakePlayer\",\n skin = Skin(texture, signature)\n).onClick {\n sender.sendMessage(clickType.name)\n}.setScale(10.0)"
30+
},
31+
{
32+
"title": "Nick Player",
33+
"code": "player.setName(newName)\nplayer.setSkin(Skin(texture, signature))"
34+
},
35+
{
36+
"title": "Sidebar/Scoreboard",
37+
"code": "sidebar(\"Survival\") {\n addEmptyLine()\n addUpdatablePlayerLine { \"${ChatColor.AQUA}${it.name}\" }\n addUpdatablePlayerTimerLine(20) { \"${ChatColor.RED}Kills : ${ChatColor.GRAY}${it.getStatistic(Statistic.PLAYER_KILLS)}\" }\n addUpdatablePlayerTimerLine(20) { \"${ChatColor.DARK_PURPLE}Deaths : ${ChatColor.GRAY}${it.getStatistic(Statistic.DEATHS)}\" }\n addUpdatablePlayerTimerLine(20) { \"${ChatColor.DARK_AQUA}Ping : ${ChatColor.GRAY}${it.ping}\" }\n addEmptyLine()\n addUpdatablePlayerTimerLine(20) { \"${ChatColor.AQUA}Rank : ${ChatColor.GRAY}OWNER\" }\n addUpdatableTimerLine(20) { \"${ChatColor.AQUA}Online : ${ChatColor.GRAY}${Bukkit.getOnlinePlayers().size}\" }\n addEmptyLine()\n}"
38+
},
39+
{
40+
"title": "Scheduler",
41+
"code": "delay(20) {\n Bukkit.broadcastMessage(\"Hello World!!\")\n}"
42+
}
43+
]
44+
45+
46+
export default function LynxPage() {
47+
48+
const [codeExample, setCodeExample] = useState<CodeExample | null>(null)
49+
50+
useEffect(() => {
51+
setCodeExample(examples[Math.floor(Math.random() * examples.length)])
52+
}, [])
53+
54+
return (
55+
<main className="p-4 pt-0 flex min-h-screen relative flex-col bg-neutral-900 text-center overflow-hidden">
56+
<motion.header initial={{opacity: 0}} animate={{opacity: 1}} transition={{duration: 1}} className="container outline-2 rounded-b-xl outline-neutral-700 bg-gradient-to-r from-blue-900 to-violet-700 mx-auto relative overflow-hidden h-100 w-full py-4 items-center justify-center flex flex-col">
57+
<div className="z-0 absolute inset-0 w-full opacity-50 skew-5 scale-150 bg-dotted-black"></div>
58+
<div className="z-0 absolute inset-0 w-full bg-gradient-to-r opacity-75 from-blue-500 via-transparent to-violet-500"></div>
59+
<div className="z-1 w-full h-full inset-0 absolute flex flex-col items-center justify-center ">
60+
<Amazing delay={0} />
61+
</div>
62+
</motion.header>
63+
64+
<motion.div
65+
className="rounded-xl p-0 h-auto max-w-4xl mx-auto shadow-md text-left"
66+
initial={{ translateY: -75, opacity: 0 }}
67+
animate={{ translateY: -75, opacity: 1 }}
68+
transition={{ delay: 1, duration: 1, ease: "anticipate" }}
69+
>
70+
{codeExample && <h2 className="text-xl bg-neutral-800/75 border-2 border-b-0 border-neutral-800/25 backdrop-blur-3xl mb-0 rounded-none rounded-t-md px-4 py-1 w-fit">{codeExample?.title}</h2>}
71+
{codeExample && <TypingCodeBlock
72+
text={codeExample?.code || ""}
73+
onComplete={()=>{}}
74+
speed={5}
75+
className={"rounded-tl-none rounded-b-2xl border-neutral-800/25"}
76+
/>}
77+
</motion.div>
78+
79+
<section className="mt-0 w-full relative container flex flex-row items-center justify-center mx-auto gap-4 md:gap-8">
80+
<Link href={"/docs/lynx/latest"} className="hover:underline flex flex-row gap-2 text-xl items-center" ><Book /> Documentation</Link>
81+
<Link href={"https://github.com/UndefinedCreations/Lynx"} className="hover:underline flex flex-row gap-2 text-xl items-center" ><Github /> Github</Link>
82+
<Link href={"https://repo.undefinedcreations.com/#/releases/com/undefined/lynx"} className="hover:underline flex flex-row gap-2 text-xl items-center" ><RiGitRepositoryLine /> Repository</Link>
83+
</section>
84+
85+
<section className="mt-6 w-full relative container flex flex-row items-center justify-center mx-auto gap-2">
86+
<LatestVersion groupId="com.undefined" artifactId="lynx" />
87+
<LatestVersion groupId="com.undefined" artifactId="lynx" type="version" />
88+
</section>
89+
90+
91+
<Divider />
92+
<section className="mb-32 h-fit">
93+
<SplitMB
94+
media={{type: "image", src:"https://cdn.undefinedcreations.com/undefinedcreations/website/group-photo.png"}}
95+
title="Spawn NPCs"
96+
description="You can spawn player specific NPCs. You can use this to create mirrored NPC skins, make the npc look at the player, or simply hide unimportant ones from other players."
97+
direction="right"
98+
// link={{label: "See Example", href: "/docs/lynx/latest/modules/display/examples/custom-gui"}}
99+
/>
100+
</section>
101+
<section className="mb-32 h-fit">
102+
<SplitMB
103+
media={{type: "image", src:"https://cdn.undefinedcreations.com/undefinedcreations/website/idk_what_this_is.gif"}}
104+
title="Edit players names"
105+
description="You can even nick players with protocols to make client specific changes. Imagine giving different names to teammates in a minigame or a friend prefix."
106+
direction="left"
107+
classNames={{media: "object-center scale-125"}}
108+
// link={{label: "See Example", href: "/docs/lynx/latest/modules/display/examples/custom-gui"}}
109+
/>
110+
</section>
111+
<section className="mb-32 h-fit">
112+
<SplitMB
113+
media={{type: "image", src:"https://cdn.undefinedcreations.com/undefinedcreations/website/sidebar.png"}}
114+
title="Client-side sidebar"
115+
description="Easy to create with no flickering and a scoreboard per player Due to its smart client-side implementation this sidebar will only be rendered on the client as the server only handles delivering its content."
116+
direction="right"
117+
classNames={{media: "object-right scale-100"}}
118+
/>
119+
</section>
120+
<section className="mb-32">
121+
<SplitMB
122+
media={{type: "image", src:"https://cdn.undefinedcreations.com/lynx/display/cusotm-gui-example.gif"}}
123+
title="Easily create complex & performant features"
124+
description="In this example Lynx leverages NMS and Packet Display Entities to create, player-specific GUIs without using Spigot's performance-heavy API, saving server resources."
125+
direction="left"
126+
classNames={{media: "object-contain max-w-fit rounded-md mx-auto flex items-center justify-center"}}
127+
link={{label: "See Example", href: "/docs/lynx/latest/modules/display/examples/custom-gui"}}
128+
/>
129+
</section>
130+
131+
<Divider />
132+
133+
134+
</main>
135+
)
136+
}
137+
138+
function Divider () {
139+
return (
140+
<div className="container mx-auto w-full my-24 h-0.5 bg-gradient-to-r to-transparent via-neutral-700 from-transparent" />
141+
)
142+
}
143+
144+
// Title animation
145+
function Amazing({ delay }: { delay: number }) {
146+
return (
147+
<React.Fragment>
148+
<motion.div
149+
initial={{ scale: 2, opacity: 0, letterSpacing: "64px" }}
150+
animate={{ scale: 1, opacity: 1, letterSpacing: ["4px"] }}
151+
transition={{ duration: 1, delay, ease: "anticipate" }}
152+
className="font-black text-shadow-title text-white text-6xl md:7xl lg:text-8xl xl:text-9xl"
153+
>
154+
<p className="flex flex-row items-center"><Image src={"/logos/lynx.svg"} className="scale-100 size-20 lg:size-48" quality={100} width={256} height={256} alt="stellar-logo" />Lynx</p>
155+
</motion.div>
156+
<motion.div
157+
initial={{ scale: 2, opacity: 0, }}
158+
animate={{ scale: 1, opacity: 1, }}
159+
transition={{ duration: 1, delay: 0.5, ease: "anticipate" }}
160+
className="font-black text-white text-9xl"
161+
>
162+
<p className="text-white mb-16 px-4 py-1 rounded-lg text-lg md:text-xl lg:text-2xl font-semibold text-shadow-title">General Purpose API for future servers</p>
163+
</motion.div>
164+
</React.Fragment>
165+
)
166+
}

app/(home)/lynx/parallax.tsx

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"use client"
2+
3+
import { motion, useScroll, useTransform, useSpring } from "framer-motion"
4+
import Image from "next/image"
5+
6+
export default function ParallaxLogo() {
7+
const { scrollY } = useScroll()
8+
9+
// Create a mapped value based on scroll
10+
const rawY = useTransform(scrollY, [0, 1000], [0, -200])
11+
const rawScale = useTransform(scrollY, [0, 1000], [0.5, 0.6])
12+
const rawBlur = useTransform(scrollY, [0, 1000], [0.5, 1])
13+
14+
// Apply a spring for smooth "follow" motion
15+
const y = useSpring(rawY, { stiffness: 50, damping: 20, mass: 0.8 })
16+
const scale = useSpring(rawScale, { stiffness: 50, damping: 20, mass: 0.8 })
17+
const blur = useSpring(rawBlur, { stiffness: 50, damping: 20, mass: 0.8 })
18+
19+
return (
20+
<motion.div
21+
className="fixed -top-1/4 right-1/3 w-full h-screen overflow-hidden pointer-events-none"
22+
style={{ y, scale, x: y, filter:(`blur(${blur.get()}px)`) }}
23+
>
24+
<Image
25+
src="/logos/stellar.png"
26+
alt="stellar-logo"
27+
width={1920}
28+
height={800}
29+
quality={50}
30+
priority
31+
className="w-full h-full object-contain opacity-25 blur-2xl saturate-500"
32+
/>
33+
</motion.div>
34+
)
35+
}

0 commit comments

Comments
 (0)