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,538 @@
1
+ /**
2
+ * Vite plugin for the video framework.
3
+ *
4
+ * Discovers MDX files in the project root and serves each as a page route.
5
+ * The default entry (video.mdx or index.mdx) is served at /; others at
6
+ * /<relative-path-without-extension>. Auto-injects spiceflow + react plugins.
7
+ *
8
+ * Usage in vite.config.ts:
9
+ * import { video } from 'egaki/vite'
10
+ * export default defineConfig({ plugins: [video()] })
11
+ * // or with explicit default entry:
12
+ * export default defineConfig({ plugins: [video({ entry: './video.mdx' })] })
13
+ */
14
+ import path from 'node:path';
15
+ import fs from 'node:fs';
16
+ import { createRequire } from 'node:module';
17
+ import { fileURLToPath } from 'node:url';
18
+ import { spiceflowPlugin } from 'spiceflow/vite';
19
+ import react from '@vitejs/plugin-react';
20
+ import tailwindcss from '@tailwindcss/vite';
21
+ import { mdxParse } from 'safe-mdx/parse';
22
+ import { collectServerImportSources } from "./server-mdx.js";
23
+ import { parseFrontmatter } from "./mdx-parse.js";
24
+ // Resolve the package src/ directory from this file's location.
25
+ // Used for resolve.alias so the RSC module runner can resolve relative
26
+ // imports from app.tsx (same pattern as egaki/vite).
27
+ const __srcDir = fileURLToPath(new URL('.', import.meta.url));
28
+ const APP_SRC_PATH = path.join(__srcDir, 'app.tsx');
29
+ const VIRTUAL_APP = 'virtual:egaki-app';
30
+ const RESOLVED_APP = '\0' + VIRTUAL_APP;
31
+ const VIRTUAL_MDX = 'virtual:egaki-mdx';
32
+ const RESOLVED_MDX = '\0' + VIRTUAL_MDX;
33
+ const VIRTUAL_MODULES = 'virtual:egaki-modules';
34
+ const RESOLVED_MODULES = '\0' + VIRTUAL_MODULES;
35
+ const PKG_NAME = 'egaki';
36
+ /** Resolve a relative MDX import source against the project root,
37
+ * probing common extensions. Returns the absolute path or undefined. */
38
+ function resolveSourceToFile(root, source) {
39
+ const base = path.resolve(root, source);
40
+ for (const ext of ['', '.tsx', '.ts', '.jsx', '.js', '.mdx', '.md']) {
41
+ const candidate = base + ext;
42
+ if (fs.existsSync(candidate) && fs.statSync(candidate).isFile()) {
43
+ return candidate.replace(/\\/g, '/');
44
+ }
45
+ }
46
+ return undefined;
47
+ }
48
+ /**
49
+ * Extract raw source text ranges per section directly from the mdast.
50
+ * Works with heading nodes' positions to capture the FULL raw heading
51
+ * text including props like `duration=3s` and `transition=20` that
52
+ * `splitIntoSections` strips during parsing. Each section spans from
53
+ * its heading's start offset to the next heading's start (or EOF).
54
+ */
55
+ function sectionRawTexts(source, mdast) {
56
+ // Collect the start offsets of each heading node
57
+ const headingStarts = [];
58
+ for (const node of mdast.children) {
59
+ if (node.type === 'heading' && node.position?.start?.offset != null) {
60
+ headingStarts.push(node.position.start.offset);
61
+ }
62
+ }
63
+ // Slice source between consecutive headings, trimming trailing whitespace
64
+ // so boundary changes (adding/removing a following section) don't cause
65
+ // false positives on the preceding section.
66
+ return headingStarts.map((start, i) => {
67
+ const end = i + 1 < headingStarts.length ? headingStarts[i + 1] : source.length;
68
+ return source.slice(start, end).trimEnd();
69
+ });
70
+ }
71
+ /**
72
+ * Compare old and new MDX sources section-by-section. Returns the index
73
+ * of the first added or edited section, or null if nothing changed (or
74
+ * only deletions occurred, which we skip per design).
75
+ */
76
+ export function findChangedSectionIndex(oldSource, newSource) {
77
+ try {
78
+ const oldTexts = sectionRawTexts(oldSource, mdxParse(oldSource));
79
+ const newTexts = sectionRawTexts(newSource, mdxParse(newSource));
80
+ const maxLen = Math.max(oldTexts.length, newTexts.length);
81
+ for (let i = 0; i < maxLen; i++) {
82
+ if (i >= oldTexts.length)
83
+ return i; // new section added
84
+ if (i >= newTexts.length)
85
+ return null; // section deleted, skip
86
+ if (oldTexts[i] !== newTexts[i]) {
87
+ // Distinguish edit from deletion: if the next old section matches
88
+ // the current new section, a section was deleted (shifted down).
89
+ // Look ahead to detect deletions at any position, not just the tail.
90
+ if (newTexts.length < oldTexts.length && oldTexts[i + 1] === newTexts[i]) {
91
+ return null; // deletion, skip
92
+ }
93
+ return i; // content changed
94
+ }
95
+ }
96
+ return null; // no scene-level change (frontmatter/preamble only)
97
+ }
98
+ catch {
99
+ return null; // parse error, don't seek
100
+ }
101
+ }
102
+ /** Discover .mdx files in the project root directory (non-recursive).
103
+ * Only root-level files become entries to avoid import resolution issues
104
+ * with nested paths. Returns a map of routePath → absolutePath. */
105
+ function discoverMdxEntries(root) {
106
+ const entries = new Map();
107
+ if (!fs.existsSync(root))
108
+ return entries;
109
+ for (const entry of fs.readdirSync(root, { withFileTypes: true })) {
110
+ if (entry.isDirectory())
111
+ continue;
112
+ if (!/\.mdx$/.test(entry.name))
113
+ continue;
114
+ const fullPath = path.join(root, entry.name);
115
+ const routePath = entry.name.replace(/\.mdx$/, '');
116
+ entries.set(routePath, fullPath.replace(/\\/g, '/'));
117
+ }
118
+ return entries;
119
+ }
120
+ /** Pick the default entry route from discovered entries.
121
+ * Priority: explicit option > video.mdx > index.mdx > first alphabetically. */
122
+ function resolveDefaultRoute(entries, explicitEntry, root) {
123
+ if (explicitEntry && root) {
124
+ const absEntry = path.isAbsolute(explicitEntry)
125
+ ? explicitEntry.replace(/\\/g, '/')
126
+ : path.resolve(root, explicitEntry).replace(/\\/g, '/');
127
+ for (const [route, absPath] of entries) {
128
+ if (absPath === absEntry)
129
+ return route;
130
+ }
131
+ }
132
+ if (entries.has('video'))
133
+ return 'video';
134
+ if (entries.has('index'))
135
+ return 'index';
136
+ // First alphabetically
137
+ const sorted = [...entries.keys()].sort();
138
+ return sorted[0] ?? 'video';
139
+ }
140
+ export function video(options) {
141
+ let root;
142
+ /** All discovered MDX entry files: routePath → absolutePath */
143
+ let mdxEntries = new Map();
144
+ /** Route path of the default entry (served at /) */
145
+ let defaultRoute = '';
146
+ /** Whether the user's project has `motion` (framer-motion) installed. */
147
+ let hasMotion = false;
148
+ /** Cached previous MDX sources for section-level diff detection, keyed by abs path. */
149
+ const previousMdxSources = new Map();
150
+ /** Set of absolute paths of all entry MDX files for quick lookup. */
151
+ let entryPathSet = new Set();
152
+ /** Is this file referenced inside a <Server> block of any entry MDX?
153
+ * Parsed on demand (no cache — file changes are rare and parsing is
154
+ * milliseconds). Used to decide which edits need an rsc:update. */
155
+ const isServerImportedFile = (file) => {
156
+ try {
157
+ for (const absPath of entryPathSet) {
158
+ const sources = collectServerImportSources(mdxParse(fs.readFileSync(absPath, 'utf-8')));
159
+ if (sources.some((source) => resolveSourceToFile(root, source) === file))
160
+ return true;
161
+ }
162
+ return false;
163
+ }
164
+ catch {
165
+ return false;
166
+ }
167
+ };
168
+ const videoPlugin = {
169
+ name: 'egaki:core',
170
+ configResolved(config) {
171
+ root = config.root;
172
+ // Discover all MDX entries in the project root.
173
+ mdxEntries = discoverMdxEntries(root);
174
+ // If explicit entry is provided but not found, create a minimal entry
175
+ // in the map (will error below if file doesn't exist).
176
+ if (options?.entry) {
177
+ const absEntry = (path.isAbsolute(options.entry)
178
+ ? options.entry
179
+ : path.resolve(root, options.entry)).replace(/\\/g, '/');
180
+ if (!fs.existsSync(absEntry)) {
181
+ throw new Error(`[egaki] entry file not found: ${absEntry}\n` +
182
+ `Set entry to a path relative to the vite root.`);
183
+ }
184
+ // Ensure explicit entry is in the map
185
+ const relPath = path.relative(root, absEntry).replace(/\\/g, '/');
186
+ const routePath = relPath.replace(/\.mdx$/, '');
187
+ mdxEntries.set(routePath, absEntry);
188
+ }
189
+ if (mdxEntries.size === 0) {
190
+ throw new Error(`[egaki] no .mdx files found in ${root}\n` +
191
+ `Create a video.mdx file or set entry explicitly.`);
192
+ }
193
+ defaultRoute = resolveDefaultRoute(mdxEntries, options?.entry, root);
194
+ entryPathSet = new Set(mdxEntries.values());
195
+ // Seed previous sources for section-level diff detection.
196
+ for (const [, absPath] of mdxEntries) {
197
+ try {
198
+ previousMdxSources.set(absPath, fs.readFileSync(absPath, 'utf-8'));
199
+ }
200
+ catch { /* ignore read errors */ }
201
+ }
202
+ // Auto-generate egaki-env.d.ts so MDX LSP knows about built-in
203
+ // components via the global MDXProvidedComponents type. Same
204
+ // pattern Vite uses for vite-env.d.ts.
205
+ const envDtsPath = path.join(root, 'egaki-env.d.ts');
206
+ const envDtsContent = 'import \'egaki/mdx-components\'\n';
207
+ try {
208
+ const existing = fs.existsSync(envDtsPath) ? fs.readFileSync(envDtsPath, 'utf-8') : '';
209
+ if (existing !== envDtsContent) {
210
+ fs.writeFileSync(envDtsPath, envDtsContent);
211
+ }
212
+ }
213
+ catch {
214
+ // Non-fatal: LSP autocomplete just won't work
215
+ }
216
+ // Detect if the user has `motion` (framer-motion) installed.
217
+ // When present, we inject timing patches so motion.div animations
218
+ // sync with Remotion's frame-based rendering.
219
+ try {
220
+ createRequire(root + '/').resolve('motion-dom');
221
+ hasMotion = true;
222
+ }
223
+ catch {
224
+ hasMotion = false;
225
+ }
226
+ },
227
+ resolveId(id) {
228
+ if (id === VIRTUAL_APP)
229
+ return RESOLVED_APP;
230
+ if (id === VIRTUAL_MDX)
231
+ return RESOLVED_MDX;
232
+ if (id === VIRTUAL_MODULES)
233
+ return RESOLVED_MODULES;
234
+ },
235
+ load(id) {
236
+ if (id === RESOLVED_MDX) {
237
+ // Import all entry MDX files as raw strings (?raw for HMR tracking).
238
+ // Export an entries map so app.tsx can serve each at its route.
239
+ const defaultAbsPath = mdxEntries.get(defaultRoute);
240
+ // Parse frontmatter from the default entry for composition dimensions.
241
+ let fm;
242
+ try {
243
+ const mdxContent = fs.readFileSync(defaultAbsPath, 'utf-8');
244
+ fm = parseFrontmatter(mdxParse(mdxContent));
245
+ }
246
+ catch (e) {
247
+ console.error('[egaki] frontmatter parse error:', e);
248
+ fm = { fps: 30, bpm: 120, width: 1920, height: 1080, scale: 1 };
249
+ }
250
+ const folderName = path.basename(root);
251
+ const imports = [];
252
+ const entriesObj = [];
253
+ const pathsObj = [];
254
+ let i = 0;
255
+ for (const [routePath, absPath] of mdxEntries) {
256
+ const varName = `__entry${i++}`;
257
+ imports.push(`import ${varName} from ${JSON.stringify(absPath + '?raw')}`);
258
+ entriesObj.push(` ${JSON.stringify(routePath)}: ${varName}`);
259
+ pathsObj.push(` ${JSON.stringify(routePath)}: ${JSON.stringify(absPath)}`);
260
+ }
261
+ return [
262
+ ...imports,
263
+ `export const entries = {`,
264
+ entriesObj.join(',\n'),
265
+ `}`,
266
+ `export const entryPaths = {`,
267
+ pathsObj.join(',\n'),
268
+ `}`,
269
+ `export const defaultRoute = ${JSON.stringify(defaultRoute)}`,
270
+ `export const projectRoot = ${JSON.stringify(root.replace(/\\/g, '/'))}`,
271
+ `export const compositionWidth = ${fm.width}`,
272
+ `export const compositionHeight = ${fm.height}`,
273
+ `export const folderName = ${JSON.stringify(folderName)}`,
274
+ // Backward compat: default export is the default entry source
275
+ `export default entries[${JSON.stringify(defaultRoute)}]`,
276
+ `export const entryPath = entryPaths[${JSON.stringify(defaultRoute)}]`,
277
+ ].join('\n');
278
+ }
279
+ if (id === RESOLVED_MODULES) {
280
+ // Build an eager module map for all user files in the project
281
+ // root. Each file is imported statically so modules are available
282
+ // synchronously — no async resolution, no loading state.
283
+ //
284
+ // This map is only imported by the client (and ssr) — the rsc env
285
+ // resolves <Server> slot modules via dynamic imports in app.tsx.
286
+ // *.server.{ts,tsx} files are excluded: that postfix is the hard
287
+ // "never bundle to the browser" guarantee for files with API keys
288
+ // or node-only imports.
289
+ const imports = [];
290
+ const entries = [];
291
+ let i = 0;
292
+ const walkDir = (dir) => {
293
+ if (!fs.existsSync(dir))
294
+ return;
295
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
296
+ if (entry.name === 'node_modules' || entry.name === 'dist' || entry.name === 'e2e' || entry.name === 'test-results' || entry.name.startsWith('.'))
297
+ continue;
298
+ const fullPath = path.join(dir, entry.name);
299
+ if (entry.isDirectory()) {
300
+ walkDir(fullPath);
301
+ }
302
+ else if (/\.(tsx?|jsx?|mdx?)$/.test(entry.name) && !/\.(test|spec|config)\./.test(entry.name)) {
303
+ // Entry MDX files are NOT skipped: they may be imported as
304
+ // partials by other MDX files (e.g. `import Intro from './intro.mdx'`).
305
+ // Self-import is a user error and harmless (safe-mdx handles it).
306
+ if (/\.server\.[jt]sx?$/.test(entry.name))
307
+ continue;
308
+ const isMdx = /\.mdx?$/.test(entry.name);
309
+ const relPath = './' + path.relative(root, fullPath).replace(/\\/g, '/');
310
+ const absPath = fullPath.replace(/\\/g, '/');
311
+ const varName = `__mod${i++}`;
312
+ if (isMdx) {
313
+ // MDX/MD files loaded as raw strings for client rendering
314
+ imports.push(`import ${varName} from ${JSON.stringify(absPath + '?raw')}`);
315
+ entries.push(` ${JSON.stringify(relPath)}: { default: ${varName} }`);
316
+ }
317
+ else {
318
+ imports.push(`import * as ${varName} from ${JSON.stringify(absPath)}`);
319
+ entries.push(` ${JSON.stringify(relPath)}: ${varName}`);
320
+ }
321
+ }
322
+ }
323
+ };
324
+ walkDir(root);
325
+ // No self-accept here: mdx-client.tsx accepts updates of this
326
+ // module via import.meta.hot.accept('virtual:egaki-modules', cb).
327
+ // When a user file changes, HMR propagates through this module to
328
+ // that boundary, re-executing this module with fresh imports and
329
+ // handing the new map to the callback. Self-accepting here would
330
+ // make THIS module the boundary and the importer callback would
331
+ // never fire.
332
+ // When motion is installed, import motion-timing.ts as a
333
+ // side-effect so JSAnimation patches run before any user component.
334
+ // resolve.dedupe (set in configEnvironment) ensures motion-dom
335
+ // resolves to the same instance that motion/react uses.
336
+ const motionTimingPath = path.join(__srcDir, 'motion-timing.ts').replace(/\\/g, '/');
337
+ const motionImport = hasMotion ? [`import ${JSON.stringify(motionTimingPath)}`] : [];
338
+ return [
339
+ ...motionImport,
340
+ ...imports,
341
+ `export const eagerModules = {`,
342
+ entries.join(',\n'),
343
+ `}`,
344
+ ].join('\n');
345
+ }
346
+ if (id === RESOLVED_APP) {
347
+ // Spiceflow entry: import the framework's app from its absolute
348
+ // source path so the RSC module runner resolves relative imports
349
+ // (./mdx-parse.ts etc.) from the correct filesystem directory.
350
+ return [
351
+ `import { app } from ${JSON.stringify(APP_SRC_PATH)}`,
352
+ `export { app }`,
353
+ ].join('\n');
354
+ }
355
+ },
356
+ // HMR for file changes in the project.
357
+ //
358
+ // Entry MDX: the source string flows server → client through the RSC
359
+ // flight payload, so invalidate the virtual modules in all envs and
360
+ // send rsc:update to re-fetch the flight.
361
+ //
362
+ // User .tsx/.ts/.mdx/.css files: handled in the client module graph
363
+ // (Fast Refresh for components, dep-accept in mdx-client.tsx for the
364
+ // rest) AND via rsc:update, because <Server> slots are rendered in the
365
+ // rsc env from the same files — the flight refetch delivers fresh
366
+ // slots. On rsc/ssr envs we invalidate the changed modules manually
367
+ // and return [] to suppress default HMR, which would trigger an SSR
368
+ // "program reload" → full page reload.
369
+ //
370
+ // File create/delete: the generated module list changed and no accept
371
+ // chain exists for new files, so invalidate everything + full reload.
372
+ hotUpdate(ctx) {
373
+ const normalizedFile = ctx.file.replace(/\\/g, '/');
374
+ const isEntryMdx = entryPathSet.has(normalizedFile);
375
+ const isImportedMdx = /\.mdx?$/.test(ctx.file)
376
+ && !isEntryMdx
377
+ && !ctx.file.includes('node_modules')
378
+ && ctx.file.startsWith(root);
379
+ const isUserFile = /\.[jt]sx?$/.test(ctx.file)
380
+ && !ctx.file.includes('node_modules')
381
+ && ctx.file.startsWith(root);
382
+ const isCss = /\.css$/.test(ctx.file)
383
+ && !ctx.file.includes('node_modules')
384
+ && ctx.file.startsWith(root);
385
+ if (!isEntryMdx && !isImportedMdx && !isUserFile && !isCss)
386
+ return;
387
+ const invalidateVirtual = (ids) => {
388
+ for (const env of Object.values(ctx.server.environments)) {
389
+ for (const resolvedId of ids) {
390
+ const mod = env.moduleGraph.getModuleById(resolvedId);
391
+ if (mod) {
392
+ env.moduleGraph.invalidateModule(mod);
393
+ }
394
+ }
395
+ }
396
+ };
397
+ // Create/delete: regenerate module list and entry map, full reload.
398
+ if (ctx.type !== 'update') {
399
+ // Re-discover entries in case a new MDX file was added or removed.
400
+ mdxEntries = discoverMdxEntries(root);
401
+ if (options?.entry) {
402
+ const absEntry = (path.isAbsolute(options.entry)
403
+ ? options.entry
404
+ : path.resolve(root, options.entry)).replace(/\\/g, '/');
405
+ const relPath = path.relative(root, absEntry).replace(/\\/g, '/');
406
+ mdxEntries.set(relPath.replace(/\.mdx$/, ''), absEntry);
407
+ }
408
+ defaultRoute = resolveDefaultRoute(mdxEntries, options?.entry, root);
409
+ const nextEntryPathSet = new Set(mdxEntries.values());
410
+ // Sync previousMdxSources: seed new entries, prune removed ones.
411
+ for (const file of previousMdxSources.keys()) {
412
+ if (!nextEntryPathSet.has(file))
413
+ previousMdxSources.delete(file);
414
+ }
415
+ for (const file of nextEntryPathSet) {
416
+ if (!previousMdxSources.has(file)) {
417
+ try {
418
+ previousMdxSources.set(file, fs.readFileSync(file, 'utf-8'));
419
+ }
420
+ catch { /* file may be mid-write */ }
421
+ }
422
+ }
423
+ entryPathSet = nextEntryPathSet;
424
+ invalidateVirtual([RESOLVED_APP, RESOLVED_MDX, RESOLVED_MODULES]);
425
+ if (this.environment.name === 'client') {
426
+ ctx.server.environments.client?.hot.send({ type: 'full-reload' });
427
+ }
428
+ return [];
429
+ }
430
+ if (isEntryMdx) {
431
+ invalidateVirtual([RESOLVED_APP, RESOLVED_MDX]);
432
+ if (this.environment.name === 'client') {
433
+ // Section-level diff detection for the changed entry.
434
+ const newMdxSource = fs.readFileSync(normalizedFile, 'utf-8');
435
+ const prevSource = previousMdxSources.get(normalizedFile);
436
+ const changedSection = prevSource != null
437
+ ? findChangedSectionIndex(prevSource, newMdxSource)
438
+ : null;
439
+ previousMdxSources.set(normalizedFile, newMdxSource);
440
+ ctx.server.environments.client?.hot.send({
441
+ type: 'custom',
442
+ event: 'rsc:update',
443
+ data: { file: ctx.file },
444
+ });
445
+ if (changedSection != null) {
446
+ ctx.server.environments.client?.hot.send({
447
+ type: 'custom',
448
+ event: 'egaki:scene-changed',
449
+ data: { sectionIndex: changedSection, file: normalizedFile },
450
+ });
451
+ }
452
+ }
453
+ return [];
454
+ }
455
+ // User file / imported MDX / CSS updates.
456
+ // Client env: let default HMR run (Fast Refresh for components,
457
+ // dep-accept propagation through virtual:egaki-modules for the rest).
458
+ if (this.environment.name === 'client') {
459
+ return;
460
+ }
461
+ // rsc/ssr envs: keep graphs fresh for the next render, but suppress
462
+ // default HMR (would cause a full program reload).
463
+ invalidateVirtual([RESOLVED_APP, RESOLVED_MODULES]);
464
+ for (const mod of ctx.modules) {
465
+ this.environment.moduleGraph.invalidateModule(mod);
466
+ }
467
+ // Edits to files referenced inside <Server> (or *.server.* postfix)
468
+ // send rsc:update: <Server> slots render in the rsc env, so the
469
+ // flight must be refetched for fresh slot content. Sent from the
470
+ // rsc branch AFTER invalidation so the browser's refetch cannot
471
+ // race a stale rsc module graph. The refetch remounts the client
472
+ // tree (spiceflow payload swap resets the Player to frame 0), so it
473
+ // must NOT fire for regular files — those are covered by
474
+ // client-graph HMR which preserves player state.
475
+ if (this.environment.name === 'rsc') {
476
+ const file = ctx.file.replace(/\\/g, '/');
477
+ if (/\.server\.[jt]sx?$/.test(file) || isServerImportedFile(file)) {
478
+ ctx.server.environments.client?.hot.send({
479
+ type: 'custom',
480
+ event: 'rsc:update',
481
+ data: { file: ctx.file },
482
+ });
483
+ }
484
+ }
485
+ return [];
486
+ },
487
+ };
488
+ // Keep the video package inside the RSC/SSR transform pipeline
489
+ const rscPackagePlugin = {
490
+ name: 'egaki:rsc-package',
491
+ configEnvironment(name, config) {
492
+ // noExternal: keep package in transform pipeline for all environments
493
+ config.resolve ??= {};
494
+ const existing = config.resolve.noExternal;
495
+ if (existing === true)
496
+ return;
497
+ const arr = Array.isArray(existing) ? existing : existing ? [existing] : [];
498
+ arr.push(new RegExp(`^${PKG_NAME}`));
499
+ arr.push(/^tweakpane/);
500
+ config.resolve.noExternal = arr;
501
+ // Deduplicate motion packages so egaki's motion-timing virtual module
502
+ // patches the same JSAnimation class that motion/react uses. Without
503
+ // this, Vite can resolve motion-dom to different instances and
504
+ // prototype patches won't affect the user's animations.
505
+ // Always applied (not gated by hasMotion) because configEnvironment
506
+ // runs before configResolved where hasMotion is set. Harmless when
507
+ // motion isn't installed — dedupe on missing packages is a no-op.
508
+ config.resolve.dedupe = mergeUnique(config.resolve.dedupe, ['motion', 'motion-dom', 'motion-utils']);
509
+ if (name === 'client') {
510
+ config.optimizeDeps ??= {};
511
+ config.optimizeDeps.exclude = mergeUnique(config.optimizeDeps.exclude, [PKG_NAME]);
512
+ config.optimizeDeps.include = mergeUnique(config.optimizeDeps.include, [
513
+ `${PKG_NAME} > spiceflow > @vitejs/plugin-rsc/vendor/react-server-dom/client.browser`,
514
+ `${PKG_NAME} > remotion`,
515
+ `${PKG_NAME} > @remotion/player`,
516
+ `${PKG_NAME} > safe-mdx`,
517
+ ]);
518
+ }
519
+ if (name === 'rsc' || name === 'ssr') {
520
+ config.optimizeDeps ??= {};
521
+ config.optimizeDeps.exclude = mergeUnique(config.optimizeDeps.exclude, ['spiceflow']);
522
+ }
523
+ },
524
+ };
525
+ return [
526
+ videoPlugin,
527
+ rscPackagePlugin,
528
+ tailwindcss(),
529
+ spiceflowPlugin({ entry: VIRTUAL_APP }),
530
+ react(),
531
+ ];
532
+ }
533
+ function mergeUnique(existing, items) {
534
+ const set = new Set(existing ?? []);
535
+ for (const item of items)
536
+ set.add(item);
537
+ return [...set];
538
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * WaveGradientShader — animated noise-driven gradient with wave distortion.
3
+ *
4
+ * Port of Framer's GradientWave shader module for Remotion/egaki.
5
+ * Original source:
6
+ * https://framerusercontent.com/modules/qbISo04IgXwHvt1f08Bw/PqHx9uwswPwEixzYIrpZ/GradientWave.js
7
+ *
8
+ * A 4-color gradient is warped through seed-dependent noise rotation and
9
+ * wave distortion. The seed controls flow directions, harmonic frequencies,
10
+ * and phase offsets, so each seed produces a visually distinct pattern.
11
+ * Two layers (rotated at seed-derived angles) are blended with a vertical
12
+ * smoothstep, producing a rich organic gradient that evolves over time.
13
+ */
14
+ import type { CSSProperties } from 'react';
15
+ export interface WaveGradientShaderProps {
16
+ /** Color palette for the gradient (max 4). Hex strings like "#FF3624". */
17
+ colors?: string[];
18
+ /** Seed for noise and flow variation. Different seeds = different patterns. */
19
+ seed?: number;
20
+ /** Animation speed multiplier. 0 = frozen, 1.5 = default, 3 = fast. */
21
+ waveSpeed?: number;
22
+ /** Horizontal wave frequency. Controls how many waves fit across the X axis. */
23
+ waveFreqX?: number;
24
+ /** Vertical wave frequency. Controls how many waves fit across the Y axis. */
25
+ waveFreqY?: number;
26
+ /** Wave propagation angle in degrees. Rotates the entire wave pattern. */
27
+ waveAngle?: number;
28
+ /** Wave distortion amplitude. Higher = more extreme warping. */
29
+ waveAmplitude?: number;
30
+ /** Smoothstep mask softness. Controls how sharply wave edges blend. */
31
+ maskSoftness?: number;
32
+ /** Mix amount between rotated noise and wave warp. 0 = pure rotation, 1 = pure wave. */
33
+ blendAmount?: number;
34
+ style?: CSSProperties;
35
+ }
36
+ /**
37
+ * Property controls matching the original Framer GradientWave module.
38
+ * Ranges, defaults, and step sizes are preserved from the original.
39
+ */
40
+ export declare const WaveGradientShader: React.FC<WaveGradientShaderProps>;
41
+ //# sourceMappingURL=wave-gradient-shader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wave-gradient-shader.d.ts","sourceRoot":"","sources":["../../src/vite/wave-gradient-shader.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAO1C,MAAM,WAAW,uBAAuB;IACtC,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IACjB,+EAA+E;IAC/E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gFAAgF;IAChF,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gEAAgE;IAChE,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,uEAAuE;IACvE,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,wFAAwF;IACxF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,aAAa,CAAA;CACtB;AAyID;;;GAGG;AACH,eAAO,MAAM,kBAAkB,EAoEzB,KAAK,CAAC,EAAE,CAAC,uBAAuB,CAAC,CAAA"}