egaki 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (280) hide show
  1. package/CHANGELOG.md +188 -0
  2. package/dist/cli/cache-utils.d.ts +33 -0
  3. package/dist/cli/cache-utils.d.ts.map +1 -0
  4. package/dist/cli/cache-utils.js +157 -0
  5. package/dist/cli/cached-generate.d.ts +105 -0
  6. package/dist/cli/cached-generate.d.ts.map +1 -0
  7. package/dist/cli/cached-generate.js +208 -0
  8. package/dist/cli/cached-generate.test.d.ts +11 -0
  9. package/dist/cli/cached-generate.test.d.ts.map +1 -0
  10. package/dist/cli/cached-generate.test.js +431 -0
  11. package/dist/cli/cartesia-provider.d.ts +16 -0
  12. package/dist/cli/cartesia-provider.d.ts.map +1 -0
  13. package/dist/cli/cartesia-provider.js +184 -0
  14. package/dist/cli/chatgpt-auth.d.ts.map +1 -0
  15. package/dist/cli/cli.d.ts +4 -0
  16. package/dist/cli/cli.d.ts.map +1 -0
  17. package/dist/cli/cli.js +1329 -0
  18. package/dist/cli/clone-generate.d.ts +26 -0
  19. package/dist/cli/clone-generate.d.ts.map +1 -0
  20. package/dist/cli/clone-generate.js +148 -0
  21. package/dist/{credentials.d.ts → cli/credentials.d.ts} +11 -2
  22. package/dist/cli/credentials.d.ts.map +1 -0
  23. package/dist/{credentials.js → cli/credentials.js} +88 -5
  24. package/dist/cli/elevenlabs-speech-provider.d.ts +26 -0
  25. package/dist/cli/elevenlabs-speech-provider.d.ts.map +1 -0
  26. package/dist/cli/elevenlabs-speech-provider.js +199 -0
  27. package/dist/cli/generate.d.ts +140 -0
  28. package/dist/cli/generate.d.ts.map +1 -0
  29. package/dist/cli/generate.js +604 -0
  30. package/dist/cli/generate.test.d.ts +2 -0
  31. package/dist/cli/generate.test.d.ts.map +1 -0
  32. package/dist/cli/generate.test.js +131 -0
  33. package/dist/cli/login.d.ts.map +1 -0
  34. package/dist/{login.js → cli/login.js} +45 -4
  35. package/dist/cli/main.d.ts +3 -0
  36. package/dist/cli/main.d.ts.map +1 -0
  37. package/dist/cli/main.js +7 -0
  38. package/dist/cli/model-catalog.d.ts +141 -0
  39. package/dist/cli/model-catalog.d.ts.map +1 -0
  40. package/dist/cli/model-catalog.js +2135 -0
  41. package/dist/{models.d.ts → cli/models.d.ts} +16 -9
  42. package/dist/cli/models.d.ts.map +1 -0
  43. package/dist/cli/models.js +313 -0
  44. package/dist/cli/open-browser.d.ts.map +1 -0
  45. package/dist/cli/openai-speech-provider.d.ts +3 -0
  46. package/dist/cli/openai-speech-provider.d.ts.map +1 -0
  47. package/dist/cli/openai-speech-provider.js +28 -0
  48. package/dist/cli/separation-generate.d.ts +34 -0
  49. package/dist/cli/separation-generate.d.ts.map +1 -0
  50. package/dist/cli/separation-generate.js +117 -0
  51. package/dist/cli/speech-catalog.d.ts +35 -0
  52. package/dist/cli/speech-catalog.d.ts.map +1 -0
  53. package/dist/cli/speech-catalog.js +195 -0
  54. package/dist/cli/speech-generate.d.ts +86 -0
  55. package/dist/cli/speech-generate.d.ts.map +1 -0
  56. package/dist/cli/speech-generate.js +156 -0
  57. package/dist/cli/speech-models.d.ts +8 -0
  58. package/dist/cli/speech-models.d.ts.map +1 -0
  59. package/dist/cli/speech-models.js +109 -0
  60. package/dist/cli/speech-provider.test.d.ts +2 -0
  61. package/dist/cli/speech-provider.test.d.ts.map +1 -0
  62. package/dist/cli/speech-provider.test.js +197 -0
  63. package/dist/cli/subscription.d.ts.map +1 -0
  64. package/dist/cli/transcription-catalog.d.ts +35 -0
  65. package/dist/cli/transcription-catalog.d.ts.map +1 -0
  66. package/dist/cli/transcription-catalog.js +192 -0
  67. package/dist/cli/transcription-generate.d.ts +62 -0
  68. package/dist/cli/transcription-generate.d.ts.map +1 -0
  69. package/dist/cli/transcription-generate.js +144 -0
  70. package/dist/cli/transcription-models.d.ts +9 -0
  71. package/dist/cli/transcription-models.d.ts.map +1 -0
  72. package/dist/cli/transcription-models.js +100 -0
  73. package/dist/cli/transcription-providers.d.ts +22 -0
  74. package/dist/cli/transcription-providers.d.ts.map +1 -0
  75. package/dist/cli/transcription-providers.js +290 -0
  76. package/dist/cli/video-model-catalog.d.ts +2 -0
  77. package/dist/cli/video-model-catalog.d.ts.map +1 -0
  78. package/dist/cli/video-model-catalog.js +5 -0
  79. package/dist/cli/xai-auth.d.ts +29 -0
  80. package/dist/cli/xai-auth.d.ts.map +1 -0
  81. package/dist/cli/xai-auth.js +325 -0
  82. package/dist/vite/angled-screen.d.ts +57 -0
  83. package/dist/vite/angled-screen.d.ts.map +1 -0
  84. package/dist/vite/angled-screen.js +115 -0
  85. package/dist/vite/app.d.ts +51 -0
  86. package/dist/vite/app.d.ts.map +1 -0
  87. package/dist/vite/app.js +150 -0
  88. package/dist/vite/bands-shader.d.ts +47 -0
  89. package/dist/vite/bands-shader.d.ts.map +1 -0
  90. package/dist/vite/bands-shader.js +267 -0
  91. package/dist/vite/code-block.d.ts +107 -0
  92. package/dist/vite/code-block.d.ts.map +1 -0
  93. package/dist/vite/code-block.js +641 -0
  94. package/dist/vite/components.d.ts +36 -0
  95. package/dist/vite/components.d.ts.map +1 -0
  96. package/dist/vite/components.js +113 -0
  97. package/dist/vite/dispersion-rings-shader.d.ts +44 -0
  98. package/dist/vite/dispersion-rings-shader.d.ts.map +1 -0
  99. package/dist/vite/dispersion-rings-shader.js +282 -0
  100. package/dist/vite/easing-curves.d.ts +129 -0
  101. package/dist/vite/easing-curves.d.ts.map +1 -0
  102. package/dist/vite/easing-curves.js +584 -0
  103. package/dist/vite/easing-curves.test.d.ts +2 -0
  104. package/dist/vite/easing-curves.test.d.ts.map +1 -0
  105. package/dist/vite/easing-curves.test.js +200 -0
  106. package/dist/vite/generated-media-client.d.ts +35 -0
  107. package/dist/vite/generated-media-client.d.ts.map +1 -0
  108. package/dist/vite/generated-media-client.js +76 -0
  109. package/dist/vite/keyframes.d.ts +129 -0
  110. package/dist/vite/keyframes.d.ts.map +1 -0
  111. package/dist/vite/keyframes.js +194 -0
  112. package/dist/vite/layout-editor.d.ts +45 -0
  113. package/dist/vite/layout-editor.d.ts.map +1 -0
  114. package/dist/vite/layout-editor.js +587 -0
  115. package/dist/vite/layout-transition.d.ts +136 -0
  116. package/dist/vite/layout-transition.d.ts.map +1 -0
  117. package/dist/vite/layout-transition.js +581 -0
  118. package/dist/vite/liquid-gradient-shader.d.ts +62 -0
  119. package/dist/vite/liquid-gradient-shader.d.ts.map +1 -0
  120. package/dist/vite/liquid-gradient-shader.js +413 -0
  121. package/dist/vite/mdx-client.d.ts +15 -0
  122. package/dist/vite/mdx-client.d.ts.map +1 -0
  123. package/dist/vite/mdx-client.js +265 -0
  124. package/dist/vite/mdx-parse.d.ts +102 -0
  125. package/dist/vite/mdx-parse.d.ts.map +1 -0
  126. package/dist/vite/mdx-parse.js +251 -0
  127. package/dist/vite/mdx-provided-components.d.ts +18 -0
  128. package/dist/vite/mdx-provided-components.d.ts.map +1 -0
  129. package/dist/vite/mdx-provided-components.js +14 -0
  130. package/dist/vite/mdx-video.d.ts +327 -0
  131. package/dist/vite/mdx-video.d.ts.map +1 -0
  132. package/dist/vite/mdx-video.js +596 -0
  133. package/dist/vite/mdx-video.test.d.ts +9 -0
  134. package/dist/vite/mdx-video.test.d.ts.map +1 -0
  135. package/dist/vite/mdx-video.test.js +1945 -0
  136. package/dist/vite/media-components.d.ts +45 -0
  137. package/dist/vite/media-components.d.ts.map +1 -0
  138. package/dist/vite/media-components.js +355 -0
  139. package/dist/vite/media-duration-store.d.ts +66 -0
  140. package/dist/vite/media-duration-store.d.ts.map +1 -0
  141. package/dist/vite/media-duration-store.js +204 -0
  142. package/dist/vite/player-page.d.ts +35 -0
  143. package/dist/vite/player-page.d.ts.map +1 -0
  144. package/dist/vite/player-page.js +720 -0
  145. package/dist/vite/render-client.d.ts +18 -0
  146. package/dist/vite/render-client.d.ts.map +1 -0
  147. package/dist/vite/render-client.js +67 -0
  148. package/dist/vite/sdk.d.ts +221 -0
  149. package/dist/vite/sdk.d.ts.map +1 -0
  150. package/dist/vite/sdk.js +355 -0
  151. package/dist/vite/server-components.d.ts +55 -0
  152. package/dist/vite/server-components.d.ts.map +1 -0
  153. package/dist/vite/server-components.js +156 -0
  154. package/dist/vite/server-mdx.d.ts +74 -0
  155. package/dist/vite/server-mdx.d.ts.map +1 -0
  156. package/dist/vite/server-mdx.js +259 -0
  157. package/dist/vite/shader-renderer.d.ts +48 -0
  158. package/dist/vite/shader-renderer.d.ts.map +1 -0
  159. package/dist/vite/shader-renderer.js +411 -0
  160. package/dist/vite/store-hooks.d.ts +12 -0
  161. package/dist/vite/store-hooks.d.ts.map +1 -0
  162. package/dist/vite/store-hooks.js +93 -0
  163. package/dist/vite/store.d.ts +75 -0
  164. package/dist/vite/store.d.ts.map +1 -0
  165. package/dist/vite/store.js +52 -0
  166. package/dist/vite/store.test.d.ts +6 -0
  167. package/dist/vite/store.test.d.ts.map +1 -0
  168. package/dist/vite/store.test.js +172 -0
  169. package/dist/vite/tweakpane-hook.d.ts +94 -0
  170. package/dist/vite/tweakpane-hook.d.ts.map +1 -0
  171. package/dist/vite/tweakpane-hook.js +450 -0
  172. package/dist/vite/vite-plugin.d.ts +28 -0
  173. package/dist/vite/vite-plugin.d.ts.map +1 -0
  174. package/dist/vite/vite-plugin.js +538 -0
  175. package/dist/vite/wave-gradient-shader.d.ts +41 -0
  176. package/dist/vite/wave-gradient-shader.d.ts.map +1 -0
  177. package/dist/vite/wave-gradient-shader.js +207 -0
  178. package/package.json +103 -25
  179. package/skills/egaki/SKILL.md +162 -1
  180. package/src/cli/cache-utils.ts +169 -0
  181. package/src/cli/cached-generate.test.ts +531 -0
  182. package/src/cli/cached-generate.ts +348 -0
  183. package/src/cli/cartesia-provider.ts +249 -0
  184. package/src/cli/cli.ts +1818 -0
  185. package/src/cli/clone-generate.ts +202 -0
  186. package/src/{credentials.ts → cli/credentials.ts} +90 -7
  187. package/src/cli/elevenlabs-speech-provider.ts +243 -0
  188. package/src/cli/generate.test.ts +166 -0
  189. package/src/cli/generate.ts +912 -0
  190. package/src/{login.ts → cli/login.ts} +48 -3
  191. package/src/cli/main.ts +8 -0
  192. package/src/cli/model-catalog.ts +2336 -0
  193. package/src/cli/models.ts +408 -0
  194. package/src/cli/openai-speech-provider.ts +34 -0
  195. package/src/cli/separation-generate.ts +187 -0
  196. package/src/cli/speech-catalog.ts +253 -0
  197. package/src/cli/speech-generate.ts +275 -0
  198. package/src/cli/speech-models.ts +146 -0
  199. package/src/cli/speech-provider.test.ts +226 -0
  200. package/src/cli/transcription-catalog.ts +250 -0
  201. package/src/cli/transcription-generate.ts +214 -0
  202. package/src/cli/transcription-models.ts +136 -0
  203. package/src/cli/transcription-providers.ts +427 -0
  204. package/src/cli/video-model-catalog.ts +14 -0
  205. package/src/cli/xai-auth.ts +396 -0
  206. package/src/vite/angled-screen.tsx +214 -0
  207. package/src/vite/app.tsx +197 -0
  208. package/src/vite/bands-shader.tsx +319 -0
  209. package/src/vite/code-block.tsx +939 -0
  210. package/src/vite/components.tsx +278 -0
  211. package/src/vite/dispersion-rings-shader.tsx +331 -0
  212. package/src/vite/easing-curves.test.ts +232 -0
  213. package/src/vite/easing-curves.ts +743 -0
  214. package/src/vite/generated-media-client.tsx +121 -0
  215. package/src/vite/keyframes.tsx +347 -0
  216. package/src/vite/layout-editor.tsx +709 -0
  217. package/src/vite/layout-transition.tsx +706 -0
  218. package/src/vite/liquid-gradient-shader.tsx +474 -0
  219. package/src/vite/mdx-client.tsx +420 -0
  220. package/src/vite/mdx-parse.ts +343 -0
  221. package/src/vite/mdx-provided-components.ts +19 -0
  222. package/src/vite/mdx-video.test.tsx +2219 -0
  223. package/src/vite/mdx-video.tsx +976 -0
  224. package/src/vite/media-components.tsx +473 -0
  225. package/src/vite/media-duration-store.ts +225 -0
  226. package/src/vite/motion-timing.ts +194 -0
  227. package/src/vite/player-page.tsx +1107 -0
  228. package/src/vite/render-client.ts +84 -0
  229. package/src/vite/sdk.ts +598 -0
  230. package/src/vite/server-components.tsx +241 -0
  231. package/src/vite/server-mdx.ts +285 -0
  232. package/src/vite/shader-renderer.tsx +535 -0
  233. package/src/vite/store-hooks.ts +117 -0
  234. package/src/vite/store.test.ts +202 -0
  235. package/src/vite/store.ts +115 -0
  236. package/src/vite/styles.css +21 -0
  237. package/src/vite/tweakpane-hook.tsx +593 -0
  238. package/src/vite/virtual-modules.d.ts +30 -0
  239. package/src/vite/vite-plugin.ts +584 -0
  240. package/src/vite/wave-gradient-shader.tsx +253 -0
  241. package/README.md +0 -266
  242. package/dist/antigravity-auth.d.ts +0 -15
  243. package/dist/antigravity-auth.d.ts.map +0 -1
  244. package/dist/antigravity-auth.js +0 -544
  245. package/dist/antigravity-image.d.ts +0 -11
  246. package/dist/antigravity-image.d.ts.map +0 -1
  247. package/dist/antigravity-image.js +0 -285
  248. package/dist/chatgpt-auth.d.ts.map +0 -1
  249. package/dist/cli.d.ts +0 -3
  250. package/dist/cli.d.ts.map +0 -1
  251. package/dist/cli.js +0 -968
  252. package/dist/credentials.d.ts.map +0 -1
  253. package/dist/gateway-model-candidates.generated.d.ts +0 -11
  254. package/dist/gateway-model-candidates.generated.d.ts.map +0 -1
  255. package/dist/gateway-model-candidates.generated.js +0 -64
  256. package/dist/login.d.ts.map +0 -1
  257. package/dist/model-catalog.d.ts +0 -42
  258. package/dist/model-catalog.d.ts.map +0 -1
  259. package/dist/model-catalog.js +0 -1001
  260. package/dist/models.d.ts.map +0 -1
  261. package/dist/models.js +0 -246
  262. package/dist/open-browser.d.ts.map +0 -1
  263. package/dist/subscription.d.ts.map +0 -1
  264. package/dist/video-model-catalog.d.ts +0 -52
  265. package/dist/video-model-catalog.d.ts.map +0 -1
  266. package/dist/video-model-catalog.js +0 -306
  267. package/src/cli.ts +0 -1378
  268. package/src/model-catalog.ts +0 -1077
  269. package/src/models.ts +0 -309
  270. package/src/video-model-catalog.ts +0 -363
  271. /package/dist/{chatgpt-auth.d.ts → cli/chatgpt-auth.d.ts} +0 -0
  272. /package/dist/{chatgpt-auth.js → cli/chatgpt-auth.js} +0 -0
  273. /package/dist/{login.d.ts → cli/login.d.ts} +0 -0
  274. /package/dist/{open-browser.d.ts → cli/open-browser.d.ts} +0 -0
  275. /package/dist/{open-browser.js → cli/open-browser.js} +0 -0
  276. /package/dist/{subscription.d.ts → cli/subscription.d.ts} +0 -0
  277. /package/dist/{subscription.js → cli/subscription.js} +0 -0
  278. /package/src/{chatgpt-auth.ts → cli/chatgpt-auth.ts} +0 -0
  279. /package/src/{open-browser.ts → cli/open-browser.ts} +0 -0
  280. /package/src/{subscription.ts → cli/subscription.ts} +0 -0
@@ -0,0 +1,278 @@
1
+ 'use client'
2
+
3
+ /**
4
+ * Visual text effect components for egaki video.
5
+ *
6
+ * Must be 'use client' because they use Remotion hooks (useCurrentFrame,
7
+ * useVideoConfig, spring, interpolate) which only work inside the Player
8
+ * render context on the client.
9
+ */
10
+
11
+ import {
12
+ AbsoluteFill,
13
+ interpolate,
14
+ spring,
15
+ useCurrentFrame,
16
+ useVideoConfig,
17
+ } from 'remotion'
18
+
19
+
20
+ // ---------------------------------------------------------------------------
21
+ // Shared constants
22
+ // ---------------------------------------------------------------------------
23
+
24
+ const FONT_SANS =
25
+ '-apple-system, BlinkMacSystemFont, "SF Pro Display", "Segoe UI", sans-serif'
26
+
27
+ // ---------------------------------------------------------------------------
28
+ // BlurReveal — text fades in from blurred to sharp
29
+ // ---------------------------------------------------------------------------
30
+
31
+ export interface BlurRevealProps {
32
+ text: string
33
+ blur?: number
34
+ fontSize?: number
35
+ color?: string
36
+ fontWeight?: number
37
+ /** Duration of the reveal in frames (defaults to 60% of composition) */
38
+ revealFrames?: number
39
+ }
40
+
41
+ export function BlurReveal({
42
+ text,
43
+ blur = 20,
44
+ fontSize = 96,
45
+ color = '#fafafa',
46
+ fontWeight = 700,
47
+ revealFrames,
48
+ }: BlurRevealProps) {
49
+ const frame = useCurrentFrame()
50
+ const { durationInFrames } = useVideoConfig()
51
+ const dur = revealFrames ?? durationInFrames * 0.6
52
+
53
+ const opacity = interpolate(frame, [0, dur], [0, 1], {
54
+ extrapolateRight: 'clamp',
55
+ })
56
+ const blurAmount = interpolate(frame, [0, dur], [blur, 0], {
57
+ extrapolateRight: 'clamp',
58
+ })
59
+
60
+ return (
61
+ <AbsoluteFill
62
+ style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}
63
+ >
64
+ <span
65
+ style={{
66
+ opacity,
67
+ filter: `blur(${blurAmount}px)`,
68
+ fontSize,
69
+ fontWeight,
70
+ color,
71
+ letterSpacing: '-0.04em',
72
+ fontFamily: FONT_SANS,
73
+ }}
74
+ >
75
+ {text}
76
+ </span>
77
+ </AbsoluteFill>
78
+ )
79
+ }
80
+
81
+ // ---------------------------------------------------------------------------
82
+ // MaskedSlideReveal — words slide up from behind a mask
83
+ // ---------------------------------------------------------------------------
84
+
85
+ export interface MaskedSlideRevealProps {
86
+ text: string
87
+ staggerDelay?: number
88
+ fontSize?: number
89
+ color?: string
90
+ fontWeight?: number
91
+ }
92
+
93
+ export function MaskedSlideReveal({
94
+ text,
95
+ staggerDelay = 3,
96
+ fontSize = 56,
97
+ color = '#fafafa',
98
+ fontWeight = 600,
99
+ }: MaskedSlideRevealProps) {
100
+ const frame = useCurrentFrame()
101
+ const { fps } = useVideoConfig()
102
+ const words = text.split(' ')
103
+
104
+ return (
105
+ <AbsoluteFill
106
+ style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}
107
+ >
108
+ <span
109
+ style={{
110
+ fontSize,
111
+ fontWeight,
112
+ color,
113
+ letterSpacing: '-0.03em',
114
+ fontFamily: FONT_SANS,
115
+ }}
116
+ >
117
+ {words.map((word, i) => {
118
+ const t = spring({
119
+ frame: frame - i * staggerDelay,
120
+ fps,
121
+ config: { damping: 14 },
122
+ })
123
+ return (
124
+ <span
125
+ key={i}
126
+ style={{
127
+ display: 'inline-block',
128
+ overflow: 'hidden',
129
+ verticalAlign: 'bottom',
130
+ lineHeight: 1.1,
131
+ marginRight: '0.25em',
132
+ }}
133
+ >
134
+ <span
135
+ style={{
136
+ display: 'inline-block',
137
+ transform: `translateY(${(1 - t) * 100}%)`,
138
+ }}
139
+ >
140
+ {word}
141
+ </span>
142
+ </span>
143
+ )
144
+ })}
145
+ </span>
146
+ </AbsoluteFill>
147
+ )
148
+ }
149
+
150
+ // ---------------------------------------------------------------------------
151
+ // StaggeredFadeUp
152
+ // ---------------------------------------------------------------------------
153
+
154
+ export interface StaggeredFadeUpProps {
155
+ text: string
156
+ staggerDelay?: number
157
+ distance?: number
158
+ fontSize?: number
159
+ color?: string
160
+ fontWeight?: number
161
+ }
162
+
163
+ export function StaggeredFadeUp({
164
+ text,
165
+ staggerDelay = 4,
166
+ distance = 24,
167
+ fontSize = 48,
168
+ color = '#a1a1aa',
169
+ fontWeight = 400,
170
+ }: StaggeredFadeUpProps) {
171
+ const frame = useCurrentFrame()
172
+ const words = text.split(' ')
173
+
174
+ return (
175
+ <AbsoluteFill
176
+ style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}
177
+ >
178
+ <span
179
+ style={{
180
+ fontSize,
181
+ fontWeight,
182
+ color,
183
+ letterSpacing: '-0.02em',
184
+ fontFamily: FONT_SANS,
185
+ }}
186
+ >
187
+ {words.map((word, i) => {
188
+ const local = frame - i * staggerDelay
189
+ const opacity = interpolate(local, [0, 14], [0, 1], {
190
+ extrapolateLeft: 'clamp',
191
+ extrapolateRight: 'clamp',
192
+ })
193
+ const y = interpolate(local, [0, 14], [distance, 0], {
194
+ extrapolateLeft: 'clamp',
195
+ extrapolateRight: 'clamp',
196
+ })
197
+ return (
198
+ <span
199
+ key={i}
200
+ style={{
201
+ display: 'inline-block',
202
+ marginRight: '0.25em',
203
+ opacity,
204
+ transform: `translateY(${y}px)`,
205
+ }}
206
+ >
207
+ {word}
208
+ </span>
209
+ )
210
+ })}
211
+ </span>
212
+ </AbsoluteFill>
213
+ )
214
+ }
215
+
216
+ // ---------------------------------------------------------------------------
217
+ // ShimmerSweep — light sweep across text
218
+ // ---------------------------------------------------------------------------
219
+
220
+ export interface ShimmerSweepProps {
221
+ text: string
222
+ baseColor?: string
223
+ shineColor?: string
224
+ fontSize?: number
225
+ fontWeight?: number
226
+ }
227
+
228
+ export function ShimmerSweep({
229
+ text,
230
+ baseColor = '#52525b',
231
+ shineColor = '#fafafa',
232
+ fontSize = 72,
233
+ fontWeight = 700,
234
+ }: ShimmerSweepProps) {
235
+ const frame = useCurrentFrame()
236
+ const { durationInFrames } = useVideoConfig()
237
+
238
+ const position = interpolate(
239
+ frame,
240
+ [0, durationInFrames * 0.75],
241
+ [200, -100],
242
+ { extrapolateLeft: 'clamp', extrapolateRight: 'clamp' },
243
+ )
244
+
245
+ const textStyle: React.CSSProperties = {
246
+ fontSize,
247
+ fontWeight,
248
+ letterSpacing: '-0.04em',
249
+ fontFamily: FONT_SANS,
250
+ margin: 0,
251
+ lineHeight: 1,
252
+ }
253
+
254
+ return (
255
+ <AbsoluteFill
256
+ style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}
257
+ >
258
+ <div style={{ position: 'relative', display: 'inline-block' }}>
259
+ <span style={{ ...textStyle, color: baseColor }}>{text}</span>
260
+ <span
261
+ style={{
262
+ ...textStyle,
263
+ position: 'absolute',
264
+ inset: 0,
265
+ color: 'transparent',
266
+ backgroundClip: 'text',
267
+ WebkitBackgroundClip: 'text',
268
+ backgroundImage: `linear-gradient(110deg, transparent 30%, ${shineColor} 50%, transparent 70%)`,
269
+ backgroundSize: '200% 100%',
270
+ backgroundPosition: `${position}% 50%`,
271
+ }}
272
+ >
273
+ {text}
274
+ </span>
275
+ </div>
276
+ </AbsoluteFill>
277
+ )
278
+ }
@@ -0,0 +1,331 @@
1
+ 'use client'
2
+
3
+ /**
4
+ * DispersionRingsShader — chromatic dispersion through concentric ring lenses.
5
+ *
6
+ * Port of Framer's DispersionRings shader module for Remotion/egaki.
7
+ * Original source:
8
+ * https://framerusercontent.com/modules/VMKsfJdfTvRVeIoDd5X9/fXq10iSPqH2cgEWzpK4N/DispersionRings.js
9
+ *
10
+ * An animated gradient of user-defined colors is distorted through concentric
11
+ * ring-shaped lenses radiating from the center. Each ring splits light into
12
+ * RGB channels at its edges (chromatic dispersion), producing rainbow fringing
13
+ * similar to light passing through concentric prisms. 8-sample temporal
14
+ * anti-aliasing with per-sample spectral weighting gives the effect a soft,
15
+ * photographic quality.
16
+ */
17
+
18
+ import type { CSSProperties } from 'react'
19
+ import { defineShader } from './shader-renderer.tsx'
20
+
21
+ // ---------------------------------------------------------------------------
22
+ // Props
23
+ // ---------------------------------------------------------------------------
24
+
25
+ export interface DispersionRingsShaderProps {
26
+ /** Color palette for the gradient (max 8). Hex strings like "#91FFCC". */
27
+ colors?: string[]
28
+ /** Seed for gradient flow directions and frequencies. Different seeds = different patterns. */
29
+ seed?: number
30
+ /** Animation speed multiplier. 0 = frozen, 0.5 = default, 2 = fast. */
31
+ speed?: number
32
+ /** Wavy spatial jitter per sample. 0 = clean, higher = dreamy/melting distortion. */
33
+ ephemeralAmp?: number
34
+ /** UV scale before the ring grid. Higher = more zoomed in, fewer visible rings. */
35
+ lensScale?: number
36
+ /** Spacing between concentric rings. Smaller = tighter rings. */
37
+ ringSpacing?: number
38
+ /** Radius of each ring lens. Controls magnification area vs flat area. */
39
+ ringRadius?: number
40
+ /** How strongly the ring lens warps UVs. Higher = more magnification. */
41
+ ringWarpStrength?: number
42
+ /** How much R and B channels diverge from G at ring edges. 0 = none, 1 = maximum. */
43
+ ringDispersion?: number
44
+ /** Extra rainbow tint multiplier at ring edges. Pushes edge colors toward prismatic look. */
45
+ edgeDisp?: number
46
+ style?: CSSProperties
47
+ }
48
+
49
+ // ---------------------------------------------------------------------------
50
+ // Fragment shader body
51
+ // ---------------------------------------------------------------------------
52
+
53
+ /**
54
+ * Raw GLSL fragment body from DispersionRings.js.
55
+ * The defineShader engine prepends #version, precision, v_uv, fragColor,
56
+ * uniform declarations, and built-in uniforms automatically.
57
+ *
58
+ * Algorithm overview:
59
+ * 1. Gradient flow: seed-derived sin/cos waves create an organic color field
60
+ * 2. Ring lens: distance from center is divided into repeating ring cells;
61
+ * each ring has a spherical lens that warps UVs (magnification at center,
62
+ * edge factor at rim)
63
+ * 3. Chromatic dispersion: lens applied 3x per sample (R, G, B) with different
64
+ * index-of-refraction offsets, splitting color channels at ring edges
65
+ * 4. 8-sample TAA: per-pixel random offset + spectral tint weights, averaged
66
+ */
67
+ const FRAGMENT_SOURCE = `
68
+ const int SAMPLES = 8;
69
+ const float EPHEMERAL_DRIP = 1.0;
70
+
71
+ // === PCG hash - https://www.jcgt.org/published/0009/03/02/
72
+ uvec3 hash3(uvec3 v) {
73
+ v = v * 1664525u + 1013904223u;
74
+ v.x += v.y * v.z;
75
+ v.y += v.z * v.x;
76
+ v.z += v.x * v.y;
77
+ v ^= v >> 16u;
78
+ v.x += v.y * v.z;
79
+ v.y += v.z * v.x;
80
+ v.z += v.x * v.y;
81
+ return v;
82
+ }
83
+
84
+ uvec3 seed;
85
+ vec3 random3f() {
86
+ seed = hash3(seed);
87
+ return vec3(seed) / float(-1u);
88
+ }
89
+
90
+ vec3 seedRandom(float seedVal) {
91
+ uvec3 s = uvec3(
92
+ floatBitsToUint(seedVal),
93
+ floatBitsToUint(seedVal * 1.5 + 7.31),
94
+ floatBitsToUint(seedVal * 2.7 + 13.37)
95
+ );
96
+ s = hash3(s);
97
+ return vec3(s) / float(0xFFFFFFFFu);
98
+ }
99
+
100
+ // === PALETTE SAMPLING ===
101
+ vec3 getColor(int idx) {
102
+ if (u_colors_length < 1) return vec3(0.0);
103
+ int safeIdx = clamp(idx, 0, u_colors_length - 1);
104
+ return u_colors[safeIdx].rgb;
105
+ }
106
+
107
+ vec3 paletteN(float t, int count) {
108
+ if (count < 1) return vec3(0.0);
109
+ if (count < 2) return getColor(0);
110
+ t = clamp(t, 0.0, 1.0) * float(count - 1);
111
+ int idx = min(int(floor(t)), count - 2);
112
+ float localT = fract(t);
113
+ localT = localT * localT * (3.0 - 2.0 * localT);
114
+ return mix(getColor(idx), getColor(idx + 1), localT);
115
+ }
116
+
117
+ // === Gradient Flow ===
118
+ float getGradientT(vec2 uv, float t, vec2 dir1, vec2 dir2, vec3 freqs, vec2 dir3) {
119
+ vec2 suv = uv * 1.;
120
+
121
+ float flow = dot(suv, dir1) + sin(dot(suv, dir2) * freqs.x + t) * 0.3 + t * 0.2;
122
+ float flow2 = dot(suv, dir2.yx) + cos(dot(suv, dir1.yx) * freqs.y - t * 0.8) * 0.25;
123
+
124
+ float gradT = sin(flow * 1.5) * 0.5 + 0.5;
125
+ gradT += cos(flow2 * 1.2) * 1.3;
126
+ gradT += sin(dot(suv, dir3) * freqs.z + t * 3.5) * 1.2;
127
+
128
+ return smoothstep(0.0, 4.12, gradT);
129
+ }
130
+
131
+ // === RING LENS ===
132
+ void applyRingLens(vec2 pp, vec2 fragCoord, vec2 r, float iorOffset, out vec2 warpedUV, out float edgeFactor) {
133
+ float radiusSq = u_ringRadius * u_ringRadius;
134
+
135
+ vec2 lensUV = (fragCoord - vec2(r.x * 0.5, 0.0)) / r.y * u_lensScale;
136
+ float dist = length(lensUV);
137
+
138
+ float fw = fwidth(dist / u_ringSpacing) * u_ringSpacing;
139
+
140
+ float ringDist = mod(dist, u_ringSpacing) / u_ringSpacing;
141
+ float ringShifted = ringDist - 0.5;
142
+ float localR = ringShifted * 2.0;
143
+
144
+ float sp = radiusSq - localR * localR;
145
+
146
+ float edgeSdf = abs(localR) - u_ringRadius;
147
+ float edgeAA = smoothstep(fw, -fw, edgeSdf);
148
+
149
+ float lensAmount = smoothstep(0., 0.3, sp);
150
+ edgeFactor = (1.0 - smoothstep(0.0, radiusSq, sp)) * lensAmount * edgeAA;
151
+
152
+ vec2 dir = lensUV / max(dist, 0.001);
153
+
154
+ warpedUV = pp;
155
+ if (sp > 0.0) {
156
+ float lens = sqrt(sp) / max(u_ringRadius, 0.001);
157
+ float baseWarp = mix(1.0, u_ringWarpStrength, lens);
158
+ float warpAmount = baseWarp * (1.0 + iorOffset);
159
+ float ringCenter = (floor(dist / u_ringSpacing) + 0.5) * u_ringSpacing;
160
+ vec2 offset = pp - dir * ringCenter;
161
+ warpedUV = dir * ringCenter + offset * warpAmount;
162
+ }
163
+ }
164
+
165
+ void main() {
166
+ vec2 fragCoord = v_uv * u_resolution;
167
+ seed = uvec3(uvec2(fragCoord), uint(fract(u_time) * 1000.0));
168
+
169
+ vec2 r = u_resolution;
170
+ vec2 p = (fragCoord * 2.0 - r) / r.y;
171
+ float t = u_time * u_speed;
172
+
173
+ int colorCount = u_colors_length;
174
+
175
+ // Early out: no colors -> black
176
+ if (colorCount < 1) {
177
+ fragColor = vec4(0.0, 0.0, 0.0, 1.0);
178
+ return;
179
+ }
180
+
181
+ // Seed-based flow directions (precomputed once)
182
+ vec3 seedOff1 = seedRandom(u_seed);
183
+ vec3 seedOff2 = seedRandom(u_seed + 100.0);
184
+
185
+ float angle1 = seedOff1.x * 6.28;
186
+ float angle2 = seedOff1.y * 6.28;
187
+ vec2 dir1 = vec2(cos(angle1), sin(angle1));
188
+ vec2 dir2 = vec2(cos(angle2), sin(angle2));
189
+ vec2 dir3 = dir1 + dir2;
190
+ vec3 freqs = vec3(
191
+ 1.0 + seedOff1.z * 2.0,
192
+ 1.0 + seedOff2.x * 1.5,
193
+ 1.5 + seedOff2.y * 2.0
194
+ );
195
+
196
+ float dice = random3f().x;
197
+
198
+ vec3 ringIorOffsets = vec3(-1.0, 0.0, 1.0) * u_ringDispersion;
199
+
200
+ vec3 col = vec3(0.0);
201
+
202
+ for (int i = 0; i < SAMPLES; i++) {
203
+ float ephemeral = (float(i) + dice) / float(SAMPLES);
204
+ float sqEph = ephemeral * ephemeral;
205
+
206
+ vec2 pt = p;
207
+ pt.x += u_ephemeralAmp * sqEph * sin(p.y * 2.0 + t);
208
+ pt.y += u_ephemeralAmp * sqEph * cos(p.x * 1.5 - t) * 0.5;
209
+ pt.y -= (1.0 - exp(-EPHEMERAL_DRIP * sqEph)) * abs(pt.y) * sign(pt.y) * 0.3;
210
+
211
+ vec3 tint = smoothstep(1.0, 0.0, abs(3.0 * ephemeral - vec3(1.0, 1.5, 2.0)));
212
+
213
+ vec3 gradTs = vec3(0.0);
214
+ vec3 edgeFactors = vec3(0.0);
215
+
216
+ for (int c = 0; c < 3; c++) {
217
+ vec2 pp = pt * u_lensScale;
218
+ vec2 warpedUV;
219
+ float edgeFactor;
220
+ applyRingLens(pp, fragCoord, r, ringIorOffsets[c], warpedUV, edgeFactor);
221
+
222
+ vec2 gradUV = warpedUV / u_lensScale;
223
+ gradTs[c] = getGradientT(gradUV, t * 0.8, dir1, dir2, freqs, dir3);
224
+ edgeFactors[c] = edgeFactor;
225
+ }
226
+
227
+ vec3 convergentColor = paletteN(gradTs.g, colorCount);
228
+ float edgeMix = max(max(edgeFactors.r, edgeFactors.g), edgeFactors.b);
229
+
230
+ vec3 dispersedColor = vec3(
231
+ paletteN(gradTs.r, colorCount).r,
232
+ convergentColor.g,
233
+ paletteN(gradTs.b, colorCount).b
234
+ );
235
+
236
+ vec3 finalColor = mix(convergentColor, dispersedColor, edgeMix * 2.0);
237
+
238
+ vec3 rainbow = (gradTs - gradTs.g) * 3.0;
239
+ finalColor += rainbow * edgeMix * u_edgeDisp;
240
+
241
+ col += tint * finalColor * (3.0 / float(SAMPLES));
242
+ }
243
+
244
+ fragColor = vec4(col, 1.0);
245
+ }
246
+ `
247
+
248
+ // ---------------------------------------------------------------------------
249
+ // Component
250
+ // ---------------------------------------------------------------------------
251
+
252
+ /**
253
+ * Property controls matching the original Framer DispersionRings module.
254
+ * Ranges, defaults, and step sizes are preserved from the original.
255
+ */
256
+ export const DispersionRingsShader = defineShader({
257
+ title: 'DispersionRingsShader',
258
+ fragment: FRAGMENT_SOURCE,
259
+ propertyControls: {
260
+ colors: {
261
+ type: 'array',
262
+ control: { type: 'color' },
263
+ maxCount: 8,
264
+ maxVisible: 4,
265
+ defaultValue: ['#91FFCC', '#FFB938', '#FF4242'],
266
+ },
267
+ seed: {
268
+ type: 'number',
269
+ defaultValue: 47,
270
+ min: 0,
271
+ max: 1000,
272
+ step: 1,
273
+ },
274
+ speed: {
275
+ type: 'number',
276
+ defaultValue: 0.5,
277
+ min: 0,
278
+ max: 2,
279
+ step: 0.01,
280
+ },
281
+ ephemeralAmp: {
282
+ type: 'number',
283
+ defaultValue: 0.12,
284
+ min: 0,
285
+ max: 0.5,
286
+ step: 0.01,
287
+ },
288
+ lensScale: {
289
+ type: 'number',
290
+ defaultValue: 10,
291
+ min: 0.1,
292
+ max: 10,
293
+ step: 0.1,
294
+ },
295
+ ringSpacing: {
296
+ type: 'number',
297
+ defaultValue: 1.5,
298
+ min: 0.1,
299
+ max: 5,
300
+ step: 0.1,
301
+ },
302
+ ringRadius: {
303
+ type: 'number',
304
+ defaultValue: 1,
305
+ min: 0.1,
306
+ max: 2,
307
+ step: 0.01,
308
+ },
309
+ ringWarpStrength: {
310
+ type: 'number',
311
+ defaultValue: 4,
312
+ min: 0,
313
+ max: 5,
314
+ step: 0.1,
315
+ },
316
+ ringDispersion: {
317
+ type: 'number',
318
+ defaultValue: 0.4,
319
+ min: 0,
320
+ max: 1,
321
+ step: 0.01,
322
+ },
323
+ edgeDisp: {
324
+ type: 'number',
325
+ defaultValue: 1.3,
326
+ min: 0,
327
+ max: 5,
328
+ step: 0.1,
329
+ },
330
+ },
331
+ }) as React.FC<DispersionRingsShaderProps>