egaki 0.6.0 → 0.7.1

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