Skip to content

Commit ccab6cc

Browse files
committed
add Code
1 parent ec04041 commit ccab6cc

5 files changed

Lines changed: 1066 additions & 28 deletions

File tree

package-lock.json

Lines changed: 12 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,13 @@
3232
"@types/opentype.js": "^1.3.4",
3333
"mathjax-full": "^3.2.1",
3434
"opentype.js": "^1.3.4",
35+
"prismjs": "^1.30.0",
3536
"puppeteer": "^24.1.1",
36-
"react": "^19.2.0",
37-
"react-dom": "^19.2.0",
38-
"react-router-dom": "^6.28.0",
39-
"three": "^0.166.1"
40-
},
37+
"react": "^19.2.0",
38+
"react-dom": "^19.2.0",
39+
"react-router-dom": "^6.28.0",
40+
"three": "^0.166.1"
41+
},
4142
"devDependencies": {
4243
"@eslint/js": "^9.39.1",
4344
"@types/node": "^24.10.1",

project/project.tsx

Lines changed: 187 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { useAnimation, useVariable } from "../src/lib/animation"
2-
import { DrawText } from "../src/lib/animation/effect/draw-text"
32
import { BEZIER_SMOOTH } from "../src/lib/animation/functions"
43
import { Clip } from "../src/lib/clip"
54
import { seconds } from "../src/lib/frame"
65
import { FillFrame } from "../src/lib/layout/fill-frame"
6+
import { Code } from "../src/lib/misc/code"
77
import { Project, type ProjectSettings } from "../src/lib/project"
88
import { TimeLine } from "../src/lib/timeline"
99

@@ -14,29 +14,195 @@ export const PROJECT_SETTINGS: ProjectSettings = {
1414
fps: 60,
1515
}
1616

17-
const HelloScene = () => {
18-
const progress = useVariable(0)
19-
const color = useVariable("#FFFFFF")
17+
const CODE_STEPS = [
18+
{
19+
language: "ts" as const,
20+
code: `type User = { id: string; first: string; last: string }
2021
21-
useAnimation(async (context) => {
22-
await context.parallel([
23-
context.move(progress).to(1, seconds(3), BEZIER_SMOOTH),
24-
context.move(color).to("#75a9bd", seconds(3), BEZIER_SMOOTH),
22+
export const fetchUser = async (id: string) => {
23+
const res = await fetch(\`/api/users/\${id}\`)
24+
return res.json()
25+
}`,
26+
},
27+
{
28+
language: "ts" as const,
29+
code: `type User = { id: string; first: string; last: string }
30+
31+
export const fetchUser = async (id: string): Promise<User> => {
32+
const res = await fetch(\`/api/users/\${id}\`)
33+
if (!res.ok) {
34+
throw new Error("request failed")
35+
}
36+
return res.json()
37+
}`,
38+
},
39+
{
40+
language: "ts" as const,
41+
code: `type User = { id: string; first: string; last: string }
42+
43+
export const fetchUser = async (id: string): Promise<User> => {
44+
const res = await fetch(\`/api/users/\${id}\`)
45+
if (!res.ok) {
46+
throw new Error("request failed")
47+
}
48+
const user = await res.json() as User
49+
return user
50+
}`,
51+
},
52+
{
53+
language: "ts" as const,
54+
code: `type User = { id: string; first: string; last: string; fullName: string }
55+
56+
export const fetchUser = async (id: string): Promise<User> => {
57+
const res = await fetch(\`/api/users/\${id}\`)
58+
if (!res.ok) {
59+
throw new Error("request failed")
60+
}
61+
const user = await res.json() as Omit<User, "fullName">
62+
const fullName = \`\${user.first} \${user.last}\`
63+
return { ...user, fullName }
64+
}`,
65+
},
66+
]
67+
68+
const CodeScene = () => {
69+
const codeStep = useVariable(0)
70+
const focusStep = useVariable(0)
71+
const panelOpacity = useVariable(0)
72+
const panelOffset = useVariable(50)
73+
74+
useAnimation(async (ctx) => {
75+
await ctx.parallel([
76+
ctx.move(panelOpacity).to(1, seconds(0.7), BEZIER_SMOOTH),
77+
ctx.move(panelOffset).to(0, seconds(0.7), BEZIER_SMOOTH),
78+
])
79+
80+
await ctx.sleep(seconds(0.2))
81+
82+
await ctx.parallel([
83+
ctx.move(codeStep).to(1, seconds(1.7), BEZIER_SMOOTH),
84+
ctx.move(focusStep).to(1, seconds(1.7), BEZIER_SMOOTH),
85+
])
86+
87+
await ctx.sleep(seconds(0.3))
88+
89+
await ctx.parallel([
90+
ctx.move(codeStep).to(2, seconds(1.8), BEZIER_SMOOTH),
91+
ctx.move(focusStep).to(2, seconds(1.8), BEZIER_SMOOTH),
92+
])
93+
94+
await ctx.sleep(seconds(0.3))
95+
96+
await ctx.parallel([
97+
ctx.move(codeStep).to(3, seconds(2.0), BEZIER_SMOOTH),
98+
ctx.move(focusStep).to(3, seconds(2.0), BEZIER_SMOOTH),
99+
])
100+
101+
await ctx.sleep(seconds(0.6))
102+
103+
await ctx.parallel([
104+
ctx.move(panelOpacity).to(0, seconds(0.8), BEZIER_SMOOTH),
105+
ctx.move(panelOffset).to(-30, seconds(0.8), BEZIER_SMOOTH),
25106
])
26-
await context.sleep(seconds(1))
27-
await context.move(progress).to(0, seconds(3), BEZIER_SMOOTH)
28107
}, [])
29108

30109
return (
31-
<FillFrame style={{ alignItems: "center", justifyContent: "center" }}>
32-
<DrawText
33-
text="Hello, world!"
34-
fontUrl="assets/NotoSerifCJKJP-Medium.ttf"
35-
strokeWidth={2}
36-
progress={progress}
37-
strokeColor={color.use()}
38-
fillColor={color.use()}
39-
/>
110+
<FillFrame
111+
style={{
112+
alignItems: "center",
113+
justifyContent: "center",
114+
background:
115+
"radial-gradient(circle at 20% 20%, rgba(56,189,248,0.12), transparent 45%), radial-gradient(circle at 80% 80%, rgba(14,165,233,0.08), transparent 40%), #020617",
116+
}}
117+
>
118+
<div
119+
style={{
120+
width: 1480,
121+
maxWidth: "92%",
122+
padding: 22,
123+
borderRadius: 18,
124+
background: "linear-gradient(180deg, rgba(15,23,42,0.94), rgba(2,6,23,0.94))",
125+
border: "1px solid rgba(56,189,248,0.28)",
126+
boxShadow: "0 28px 70px rgba(2,6,23,0.65)",
127+
transform: `translateY(${panelOffset.use()}px)`,
128+
opacity: panelOpacity.use(),
129+
}}
130+
>
131+
<div
132+
style={{
133+
marginBottom: 14,
134+
color: "#bae6fd",
135+
fontSize: 22,
136+
fontWeight: 700,
137+
letterSpacing: "0.02em",
138+
fontFamily: "'Fira Sans', 'Noto Sans JP', sans-serif",
139+
}}
140+
>
141+
Code Step Demo
142+
</div>
143+
144+
<Code
145+
steps={CODE_STEPS}
146+
step={codeStep}
147+
fontSize={30}
148+
lineHeight={1.55}
149+
padding={18}
150+
theme={{
151+
base: "#dbeafe",
152+
keyword: "#7dd3fc",
153+
type: "#fca5a5",
154+
string: "#86efac",
155+
number: "#fbbf24",
156+
comment: "#94a3b8",
157+
builtin: "#c4b5fd",
158+
punctuation: "#cbd5e1",
159+
}}
160+
highlightTracks={[
161+
{
162+
id: "main-focus",
163+
step: focusStep,
164+
steps: [
165+
{
166+
codeStep: 0,
167+
match: "await fetch(`/api/users/${id}`)",
168+
padding: { x: 14, y: 5 },
169+
radius: 12,
170+
strokeWidth: 3,
171+
color: "#22d3ee",
172+
fillColor: "rgba(34,211,238,0.12)",
173+
},
174+
{
175+
codeStep: 1,
176+
match: "if (!res.ok) {\n throw new Error(\"request failed\")\n }",
177+
padding: { x: 14, y: 5 },
178+
radius: 12,
179+
strokeWidth: 3,
180+
color: "#f59e0b",
181+
fillColor: "rgba(245,158,11,0.12)",
182+
},
183+
{
184+
codeStep: 2,
185+
match: "const user = await res.json() as User",
186+
padding: { x: 14, y: 5 },
187+
radius: 12,
188+
strokeWidth: 3,
189+
color: "#a78bfa",
190+
fillColor: "rgba(167,139,250,0.14)",
191+
},
192+
{
193+
codeStep: 3,
194+
match: "return { ...user, fullName }",
195+
padding: { x: 14, y: 5 },
196+
radius: 12,
197+
strokeWidth: 3,
198+
color: "#34d399",
199+
fillColor: "rgba(52,211,153,0.14)",
200+
},
201+
],
202+
},
203+
]}
204+
/>
205+
</div>
40206
</FillFrame>
41207
)
42208
}
@@ -45,8 +211,8 @@ export const PROJECT = () => {
45211
return (
46212
<Project>
47213
<TimeLine>
48-
<Clip label="Hello">
49-
<HelloScene />
214+
<Clip label="Code Demo">
215+
<CodeScene />
50216
</Clip>
51217
</TimeLine>
52218
</Project>

0 commit comments

Comments
 (0)