frameyard 0.0.0-stage → 0.2.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 (131) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/GLOSSARY.md +145 -0
  3. package/LICENSE +21 -0
  4. package/README.md +311 -2
  5. package/dist/assets/executable.d.ts +16 -0
  6. package/dist/assets/executable.d.ts.map +1 -0
  7. package/dist/assets/executable.js +59 -0
  8. package/dist/assets/executable.js.map +1 -0
  9. package/dist/assets/files.d.ts +4 -0
  10. package/dist/assets/files.d.ts.map +1 -0
  11. package/dist/assets/files.js +30 -0
  12. package/dist/assets/files.js.map +1 -0
  13. package/dist/assets/integrations.d.ts +15 -0
  14. package/dist/assets/integrations.d.ts.map +1 -0
  15. package/dist/assets/integrations.js +15 -0
  16. package/dist/assets/integrations.js.map +1 -0
  17. package/dist/assets/process.d.ts +29 -0
  18. package/dist/assets/process.d.ts.map +1 -0
  19. package/dist/assets/process.js +97 -0
  20. package/dist/assets/process.js.map +1 -0
  21. package/dist/assets/provenance.d.ts +77 -0
  22. package/dist/assets/provenance.d.ts.map +1 -0
  23. package/dist/assets/provenance.js +302 -0
  24. package/dist/assets/provenance.js.map +1 -0
  25. package/dist/assets/transcribe.d.ts +38 -0
  26. package/dist/assets/transcribe.d.ts.map +1 -0
  27. package/dist/assets/transcribe.js +357 -0
  28. package/dist/assets/transcribe.js.map +1 -0
  29. package/dist/assets/tts.d.ts +29 -0
  30. package/dist/assets/tts.d.ts.map +1 -0
  31. package/dist/assets/tts.js +180 -0
  32. package/dist/assets/tts.js.map +1 -0
  33. package/dist/cli.d.ts +3 -0
  34. package/dist/cli.d.ts.map +1 -0
  35. package/dist/cli.js +795 -0
  36. package/dist/cli.js.map +1 -0
  37. package/dist/contracts.d.ts +106 -0
  38. package/dist/contracts.d.ts.map +1 -0
  39. package/dist/contracts.js +297 -0
  40. package/dist/contracts.js.map +1 -0
  41. package/dist/doctor.d.ts +56 -0
  42. package/dist/doctor.d.ts.map +1 -0
  43. package/dist/doctor.js +476 -0
  44. package/dist/doctor.js.map +1 -0
  45. package/dist/errors.d.ts +10 -0
  46. package/dist/errors.d.ts.map +1 -0
  47. package/dist/errors.js +18 -0
  48. package/dist/errors.js.map +1 -0
  49. package/dist/index.d.ts +8 -0
  50. package/dist/index.d.ts.map +1 -0
  51. package/dist/index.js +5 -0
  52. package/dist/index.js.map +1 -0
  53. package/dist/preview/main.d.ts +19 -0
  54. package/dist/preview/main.d.ts.map +1 -0
  55. package/dist/preview/main.js +480 -0
  56. package/dist/preview/main.js.map +1 -0
  57. package/dist/project.d.ts +16 -0
  58. package/dist/project.d.ts.map +1 -0
  59. package/dist/project.js +88 -0
  60. package/dist/project.js.map +1 -0
  61. package/dist/renderer/audio.d.ts +31 -0
  62. package/dist/renderer/audio.d.ts.map +1 -0
  63. package/dist/renderer/audio.js +88 -0
  64. package/dist/renderer/audio.js.map +1 -0
  65. package/dist/renderer/browser.d.ts +22 -0
  66. package/dist/renderer/browser.d.ts.map +1 -0
  67. package/dist/renderer/browser.js +175 -0
  68. package/dist/renderer/browser.js.map +1 -0
  69. package/dist/renderer/ffmpeg.d.ts +58 -0
  70. package/dist/renderer/ffmpeg.d.ts.map +1 -0
  71. package/dist/renderer/ffmpeg.js +268 -0
  72. package/dist/renderer/ffmpeg.js.map +1 -0
  73. package/dist/renderer/index.d.ts +72 -0
  74. package/dist/renderer/index.d.ts.map +1 -0
  75. package/dist/renderer/index.js +281 -0
  76. package/dist/renderer/index.js.map +1 -0
  77. package/dist/renderer/transcripts.d.ts +30 -0
  78. package/dist/renderer/transcripts.d.ts.map +1 -0
  79. package/dist/renderer/transcripts.js +86 -0
  80. package/dist/renderer/transcripts.js.map +1 -0
  81. package/dist/runtime/clock.d.ts +5 -0
  82. package/dist/runtime/clock.d.ts.map +1 -0
  83. package/dist/runtime/clock.js +16 -0
  84. package/dist/runtime/clock.js.map +1 -0
  85. package/dist/runtime/index.d.ts +29 -0
  86. package/dist/runtime/index.d.ts.map +1 -0
  87. package/dist/runtime/index.js +289 -0
  88. package/dist/runtime/index.js.map +1 -0
  89. package/dist/runtime/random.d.ts +8 -0
  90. package/dist/runtime/random.d.ts.map +1 -0
  91. package/dist/runtime/random.js +21 -0
  92. package/dist/runtime/random.js.map +1 -0
  93. package/dist/scaffold.d.ts +3 -0
  94. package/dist/scaffold.d.ts.map +1 -0
  95. package/dist/scaffold.js +176 -0
  96. package/dist/scaffold.js.map +1 -0
  97. package/dist/server/preview-html.d.ts +2 -0
  98. package/dist/server/preview-html.d.ts.map +1 -0
  99. package/dist/server/preview-html.js +229 -0
  100. package/dist/server/preview-html.js.map +1 -0
  101. package/dist/server/server.d.ts +17 -0
  102. package/dist/server/server.d.ts.map +1 -0
  103. package/dist/server/server.js +237 -0
  104. package/dist/server/server.js.map +1 -0
  105. package/dist/transcript.d.ts +44 -0
  106. package/dist/transcript.d.ts.map +1 -0
  107. package/dist/transcript.js +130 -0
  108. package/dist/transcript.js.map +1 -0
  109. package/dist/version.d.ts +2 -0
  110. package/dist/version.d.ts.map +1 -0
  111. package/dist/version.js +2 -0
  112. package/dist/version.js.map +1 -0
  113. package/docs/adr/0001-keep-composition-authoring-web-native.md +3 -0
  114. package/docs/adr/0002-make-frame-and-props-the-only-animation-state.md +3 -0
  115. package/docs/adr/0003-render-browser-frames-offline.md +3 -0
  116. package/docs/adr/0004-produce-local-ai-assets-outside-rendering.md +3 -0
  117. package/docs/v0.1-design.md +238 -0
  118. package/examples/demo/README.md +24 -0
  119. package/examples/demo/assets/chime.wav +0 -0
  120. package/examples/demo/compositions/demo.js +206 -0
  121. package/examples/demo/props/demo.json +5 -0
  122. package/examples/demo/video.config.js +5 -0
  123. package/package.json +73 -3
  124. package/skills/frameyard/README.md +35 -0
  125. package/skills/frameyard/SKILL.md +60 -0
  126. package/skills/frameyard/references/audio-assets.md +86 -0
  127. package/skills/frameyard/references/deterministic-authoring.md +107 -0
  128. package/skills/frameyard/references/failure-recovery.md +57 -0
  129. package/skills/frameyard/references/json-results.md +203 -0
  130. package/skills/frameyard/references/subtitles-karaoke.md +95 -0
  131. package/skills/frameyard/scripts/frameyard.mjs +60 -0
@@ -0,0 +1,289 @@
1
+ import { normalizeComposition, resolveAudioClips, resolveProps, resolveTranscriptClips, } from "../contracts.js";
2
+ import { FrameyardError, isFrameyardError } from "../errors.js";
3
+ import { frameToMilliseconds } from "./clock.js";
4
+ export { frameToMilliseconds, frameToSeconds } from "./clock.js";
5
+ export { random } from "./random.js";
6
+ function isThenable(value) {
7
+ return ((typeof value === "object" || typeof value === "function") &&
8
+ value !== null &&
9
+ typeof value.then === "function");
10
+ }
11
+ function wrapCompositionError(phase, frame, error) {
12
+ if (isFrameyardError(error)) {
13
+ return error;
14
+ }
15
+ const location = frame === null ? "" : ` at frame ${frame}`;
16
+ return new FrameyardError("COMPOSITION_ERROR", `Composition ${phase}() failed${location}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
17
+ }
18
+ function seekAnimations(container, frame, fps, onTransition) {
19
+ if (typeof container.getAnimations !== "function") {
20
+ return;
21
+ }
22
+ const time = frameToMilliseconds(frame, fps);
23
+ let sawTransition = false;
24
+ for (const animation of container.getAnimations({ subtree: true })) {
25
+ if (typeof CSSTransition !== "undefined" && animation instanceof CSSTransition) {
26
+ sawTransition = true;
27
+ }
28
+ try {
29
+ animation.pause();
30
+ animation.currentTime = time;
31
+ }
32
+ catch (error) {
33
+ throw new FrameyardError("COMPOSITION_ERROR", `A CSS or Web Animation could not be seeked to frame ${frame}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
34
+ }
35
+ }
36
+ if (sawTransition) {
37
+ onTransition?.();
38
+ }
39
+ }
40
+ function installDiagnosticsClock() {
41
+ const warnings = new Set();
42
+ const originalRandom = Math.random;
43
+ const originalDateNow = Date.now;
44
+ const originalSetTimeout = window.setTimeout;
45
+ const originalSetInterval = window.setInterval;
46
+ const originalRaf = window.requestAnimationFrame;
47
+ const perf = performance;
48
+ const originalPerfNow = perf.now;
49
+ let perfPatched = false;
50
+ Math.random = () => {
51
+ warnings.add("Math.random()");
52
+ return originalRandom();
53
+ };
54
+ Date.now = () => {
55
+ warnings.add("Date.now()");
56
+ return originalDateNow();
57
+ };
58
+ window.setTimeout = ((handler, timeout, ...args) => {
59
+ warnings.add("setTimeout()");
60
+ return originalSetTimeout(handler, timeout, ...args);
61
+ });
62
+ window.setInterval = ((handler, timeout, ...args) => {
63
+ warnings.add("setInterval()");
64
+ return originalSetInterval(handler, timeout, ...args);
65
+ });
66
+ window.requestAnimationFrame = ((callback) => {
67
+ warnings.add("requestAnimationFrame()");
68
+ return originalRaf(callback);
69
+ });
70
+ try {
71
+ perf.now = () => {
72
+ warnings.add("performance.now()");
73
+ return originalPerfNow();
74
+ };
75
+ perfPatched = true;
76
+ }
77
+ catch {
78
+ // Some engines make performance.now non-writable; skip that signal.
79
+ }
80
+ return {
81
+ warnings,
82
+ restore() {
83
+ Math.random = originalRandom;
84
+ Date.now = originalDateNow;
85
+ window.setTimeout = originalSetTimeout;
86
+ window.setInterval = originalSetInterval;
87
+ window.requestAnimationFrame = originalRaf;
88
+ if (perfPatched) {
89
+ perf.now = originalPerfNow;
90
+ }
91
+ },
92
+ };
93
+ }
94
+ function diagnosticsMessage(scope, frame, warning) {
95
+ const location = frame === null ? "" : ` at frame ${frame}`;
96
+ switch (warning) {
97
+ case "Math.random()":
98
+ return `${scope}${location} used Math.random(); use random("stable:key") for deterministic values.`;
99
+ case "Date.now()":
100
+ case "performance.now()":
101
+ return `${scope}${location} read ${warning}; derive time from the frame and frame rate.`;
102
+ default:
103
+ return `${scope}${location} used ${warning}; drive animation from update({ frame }).`;
104
+ }
105
+ }
106
+ function withDiagnosticsSync(scope, frame, diagnostics, callback) {
107
+ if (!diagnostics) {
108
+ return callback();
109
+ }
110
+ const clock = installDiagnosticsClock();
111
+ try {
112
+ return callback();
113
+ }
114
+ finally {
115
+ clock.restore();
116
+ for (const warning of clock.warnings) {
117
+ try {
118
+ diagnostics(diagnosticsMessage(scope, frame, warning));
119
+ }
120
+ catch {
121
+ // Diagnostics must never affect composition execution.
122
+ }
123
+ }
124
+ }
125
+ }
126
+ async function withDiagnosticsAsync(scope, diagnostics, callback) {
127
+ if (!diagnostics) {
128
+ return callback();
129
+ }
130
+ const clock = installDiagnosticsClock();
131
+ try {
132
+ return await callback();
133
+ }
134
+ finally {
135
+ clock.restore();
136
+ for (const warning of clock.warnings) {
137
+ try {
138
+ diagnostics(diagnosticsMessage(scope, null, warning));
139
+ }
140
+ catch {
141
+ // Diagnostics must never affect composition execution.
142
+ }
143
+ }
144
+ }
145
+ }
146
+ async function disposeAfterFailure(composition) {
147
+ try {
148
+ const result = composition.dispose?.();
149
+ if (isThenable(result)) {
150
+ await result;
151
+ }
152
+ }
153
+ catch {
154
+ // Cleanup after a failed mount or first update must not mask the failure.
155
+ }
156
+ }
157
+ async function waitForMountedAssets(container) {
158
+ await document.fonts.ready;
159
+ const images = Array.from(container.querySelectorAll("img"));
160
+ await Promise.all(images.map(async (image) => {
161
+ if (!image.currentSrc && !image.src) {
162
+ return;
163
+ }
164
+ try {
165
+ await image.decode();
166
+ }
167
+ catch (error) {
168
+ throw new FrameyardError("ASSET_NOT_FOUND", `Could not load image asset "${image.currentSrc || image.src}".`, {
169
+ cause: error,
170
+ });
171
+ }
172
+ }));
173
+ }
174
+ /** Imports a composition module through the preview server and normalizes its default export. */
175
+ export async function loadCompositionModule(url) {
176
+ let module;
177
+ try {
178
+ module = (await import(/* @vite-ignore */ url));
179
+ }
180
+ catch (error) {
181
+ throw new FrameyardError("COMPOSITION_INVALID", `Could not load composition module ${url}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
182
+ }
183
+ if (module.default === undefined) {
184
+ throw new FrameyardError("COMPOSITION_INVALID", `Composition module ${url} has no default export.`);
185
+ }
186
+ return normalizeComposition(module.default);
187
+ }
188
+ /**
189
+ * Mounts a composition and returns a seekable runtime. Mounting and asset
190
+ * loading complete before this promise resolves; every subsequent seek is
191
+ * synchronous and independent of previously visited frames.
192
+ */
193
+ export async function createCompositionRuntime(options) {
194
+ const composition = normalizeComposition(options.composition);
195
+ const props = resolveProps(composition, options.props);
196
+ const audioClips = resolveAudioClips(composition, props);
197
+ const transcriptClips = resolveTranscriptClips(composition, props);
198
+ const { container } = options;
199
+ const diagnostics = options.diagnostics;
200
+ let warnedTransition = false;
201
+ const warnTransition = () => {
202
+ if (!diagnostics || warnedTransition) {
203
+ return;
204
+ }
205
+ warnedTransition = true;
206
+ try {
207
+ diagnostics("Composition uses CSS transitions; derive visual styles from frame and props in update() instead.");
208
+ }
209
+ catch {
210
+ // Diagnostics must never affect composition execution.
211
+ }
212
+ };
213
+ container.replaceChildren();
214
+ try {
215
+ await withDiagnosticsAsync("Composition mount()", diagnostics, () => composition.mount({ container, props }));
216
+ }
217
+ catch (error) {
218
+ await disposeAfterFailure(composition);
219
+ container.replaceChildren();
220
+ throw wrapCompositionError("mount", null, error);
221
+ }
222
+ try {
223
+ await waitForMountedAssets(container);
224
+ }
225
+ catch (error) {
226
+ await disposeAfterFailure(composition);
227
+ container.replaceChildren();
228
+ throw error;
229
+ }
230
+ let frame = 0;
231
+ let disposed = false;
232
+ function seek(targetFrame) {
233
+ if (disposed) {
234
+ throw new FrameyardError("COMPOSITION_ERROR", "Cannot seek a disposed composition runtime.");
235
+ }
236
+ if (!Number.isInteger(targetFrame) || targetFrame < 0 || targetFrame >= composition.durationInFrames) {
237
+ throw new FrameyardError("FRAME_OUT_OF_RANGE", `Frame ${targetFrame} is outside the valid range 0..${composition.durationInFrames - 1}.`);
238
+ }
239
+ try {
240
+ const result = withDiagnosticsSync("Composition update()", targetFrame, diagnostics, () => composition.update({ frame: targetFrame, props }));
241
+ if (isThenable(result)) {
242
+ throw new FrameyardError("COMPOSITION_UPDATE_ASYNC", `Composition update() must be synchronous, but it returned a promise at frame ${targetFrame}.`);
243
+ }
244
+ seekAnimations(container, targetFrame, composition.fps, warnTransition);
245
+ }
246
+ catch (error) {
247
+ throw wrapCompositionError("update", targetFrame, error);
248
+ }
249
+ frame = targetFrame;
250
+ }
251
+ try {
252
+ seek(0);
253
+ }
254
+ catch (error) {
255
+ await disposeAfterFailure(composition);
256
+ container.replaceChildren();
257
+ throw error;
258
+ }
259
+ return Object.freeze({
260
+ composition,
261
+ props,
262
+ audioClips,
263
+ transcriptClips,
264
+ get frame() {
265
+ return frame;
266
+ },
267
+ seek,
268
+ async dispose() {
269
+ if (disposed) {
270
+ return;
271
+ }
272
+ disposed = true;
273
+ try {
274
+ if (composition.dispose) {
275
+ const result = composition.dispose();
276
+ if (isThenable(result)) {
277
+ await result;
278
+ }
279
+ }
280
+ }
281
+ catch (error) {
282
+ container.replaceChildren();
283
+ throw wrapCompositionError("dispose", null, error);
284
+ }
285
+ container.replaceChildren();
286
+ },
287
+ });
288
+ }
289
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Returns a deterministic value in [0, 1) derived only from the supplied key.
3
+ *
4
+ * The calculation is stateless: call order and previous frames cannot affect
5
+ * the result. Use stable, descriptive keys such as `random("star:17:y")`.
6
+ */
7
+ export declare function random(key: string): number;
8
+ //# sourceMappingURL=random.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"random.d.ts","sourceRoot":"","sources":["../../src/runtime/random.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAgB1C"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Returns a deterministic value in [0, 1) derived only from the supplied key.
3
+ *
4
+ * The calculation is stateless: call order and previous frames cannot affect
5
+ * the result. Use stable, descriptive keys such as `random("star:17:y")`.
6
+ */
7
+ export function random(key) {
8
+ let hash = 0x811c9dc5;
9
+ for (let index = 0; index < key.length; index += 1) {
10
+ hash ^= key.charCodeAt(index);
11
+ hash = Math.imul(hash, 0x01000193);
12
+ }
13
+ // MurmurHash3's 32-bit finalizer spreads adjacent keys across the range.
14
+ hash ^= hash >>> 16;
15
+ hash = Math.imul(hash, 0x7feb352d);
16
+ hash ^= hash >>> 15;
17
+ hash = Math.imul(hash, 0x846ca68b);
18
+ hash ^= hash >>> 16;
19
+ return (hash >>> 0) / 0x1_0000_0000;
20
+ }
21
+ //# sourceMappingURL=random.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"random.js","sourceRoot":"","sources":["../../src/runtime/random.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,UAAU,MAAM,CAAC,GAAW;IAChC,IAAI,IAAI,GAAG,UAAU,CAAC;IAEtB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,GAAG,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACnD,IAAI,IAAI,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAC9B,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IACrC,CAAC;IAED,yEAAyE;IACzE,IAAI,IAAI,IAAI,KAAK,EAAE,CAAC;IACpB,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IACnC,IAAI,IAAI,IAAI,KAAK,EAAE,CAAC;IACpB,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IACnC,IAAI,IAAI,IAAI,KAAK,EAAE,CAAC;IAEpB,OAAO,CAAC,IAAI,KAAK,CAAC,CAAC,GAAG,aAAa,CAAC;AACtC,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function scaffoldFiles(projectName: string): Record<string, string>;
2
+ export declare const SCAFFOLD_NEXT: string[];
3
+ //# sourceMappingURL=scaffold.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AA8JA,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAmBzE;AAED,eAAO,MAAM,aAAa,UAKzB,CAAC"}
@@ -0,0 +1,176 @@
1
+ import { VERSION } from "./version.js";
2
+ const AGENTS_GUIDE = `# AGENTS.md
3
+
4
+ This project produces deterministic, parameterized video with Frameyard. Follow this guide when editing or rendering it.
5
+
6
+ ## Project layout
7
+
8
+ - \`video.config.js\` explicitly maps composition IDs to entry modules. There is no directory scanning; a new composition is invisible until it is listed.
9
+ - \`package.json\` pins the CLI version in \`dev\`, \`check\`, \`render\`, and \`still\` scripts. Run \`dev\` with \`npm run dev\` or \`pnpm dev\`; for the others, pass the composition id: \`npm run check -- hello\` (npm) or \`pnpm check hello\` (pnpm).
10
+ - \`compositions/\` contains native JavaScript ES modules. Import bare \`frameyard\` and \`frameyard/runtime\`; the preview server supplies the import map.
11
+ - \`props/\` contains JSON props, merged shallowly over \`defaultProps\` and deep-frozen.
12
+ - \`assets/\` (create it when needed) contains audio, images, fonts, and generated assets.
13
+
14
+ \`width\`, \`height\`, \`fps\`, and \`durationInFrames\` are fixed composition metadata. Do not derive them from props.
15
+
16
+ ## Agent workflow
17
+
18
+ 1. Read \`video.config.js\`, the composition source, and the props file before changing behavior.
19
+ 2. Author the composition or props with native HTML, CSS, SVG, Canvas 2D, and JavaScript. Do not add a bundling step.
20
+ 3. Validate every frame: \`npx frameyard check <id> --json\`. Use \`--props <file>\` to validate a specific props file.
21
+ 4. Inspect a representative frame: \`npx frameyard still <id> --frame <n> --out <file.png> --json\`, then view the PNG when the host supports images. State explicitly when visual inspection is not possible.
22
+ 5. Render: \`npx frameyard render <id> --props <file> --out <file.mp4> --json\`.
23
+ 6. Report the composition, props, validation result, still path and inspection status, video path, and any failure. Never claim success when \`check\` fails, a still is missing, or a render exits nonzero.
24
+
25
+ ## Commands
26
+
27
+ \`\`\`sh
28
+ npx frameyard dev
29
+ npx frameyard doctor --json
30
+ npx frameyard check hello --json
31
+ npx frameyard still hello --frame 42 --out hello-42.png --json
32
+ npx frameyard render hello --props props/hello.json --out hello.mp4 --json
33
+ \`\`\`
34
+
35
+ - Use \`--json\` for non-interactive commands. Parse stdout as the structured result; treat stderr as progress and diagnostics.
36
+ - Use \`--project <dir>\` when running outside the project root.
37
+ - \`still\` and \`render\` replace existing outputs only with \`--overwrite\`. Generated assets are replaced only with \`--force\`, and only with user approval.
38
+
39
+ ## Determinism rules
40
+
41
+ - A frame may depend only on its integer \`frame\`, immutable \`props\`, and assets loaded before frame production.
42
+ - \`mount()\` may await loading work. \`update({ frame, props })\` is synchronous and seek-safe. \`dispose()\` releases resources.
43
+ - Keep mutable state in module-scope variables, not on \`this\`.
44
+ - Use \`random("stable:key")\` from \`frameyard/runtime\` for randomness.
45
+ - Never use \`Math.random()\`, \`Date.now()\`, \`performance.now()\`, timers, independent \`requestAnimationFrame()\` loops, CSS transitions, or state left from a previously visited frame as animation inputs.
46
+ - CSS \`@keyframes\` and the Web Animations API are valid; the runtime seeks them.
47
+ - Load remote data, fonts, and images during \`mount()\` or before the first frame. Network requests are blocked during capture; a \`fetch()\` from \`update()\` is a bug.
48
+ - Redraw Canvas 2D from the current frame.
49
+
50
+ ## Audio and transcripts
51
+
52
+ - Audio clips are placed by composition frames and trimmed by seconds. Frameyard does not time-stretch audio or change composition duration to fit it.
53
+ - Produce speech with \`npx frameyard tts\` and transcripts with \`npx frameyard transcribe\`; never call \`qwen-tts\` or \`whisper-cli\` directly, and never run inference inside \`mount()\` or \`update()\`.
54
+ - Do not overwrite or regenerate generated assets without explicit approval.
55
+ - \`words: true\` requires measured word timings; never interpolate segment timings.
56
+ - Commit \`frameyard.assets.json\` when present; do not edit hashes or manifest entries by hand.
57
+
58
+ The official \`frameyard\` agent skill contains the full host-neutral contract. Install it with \`npx skills add vladiantio/frameyard\` or see the \`skills/frameyard/\` directory in the \`frameyard\` npm package. This file is the project-local summary.
59
+
60
+ This project was scaffolded with frameyard ${VERSION}. \`npx frameyard\` resolves the latest published version; run \`npx frameyard@${VERSION}\` when you need the CLI version that scaffolded the project.
61
+ `;
62
+ const PROJECT_README = `# My Frameyard project
63
+
64
+ Coding agents should read \`AGENTS.md\` for the project rules and the check, still, and render workflow.
65
+
66
+ Start the preview:
67
+
68
+ \`\`\`sh
69
+ npx frameyard dev
70
+ \`\`\`
71
+
72
+ Validate and render:
73
+
74
+ \`\`\`sh
75
+ npx frameyard doctor
76
+ npx frameyard check hello
77
+ npx frameyard render hello --props props/hello.json --out hello.mp4
78
+ \`\`\`
79
+
80
+ Or run the pinned scripts from \`package.json\`:
81
+
82
+ \`\`\`sh
83
+ npm run dev
84
+ npm run check -- hello
85
+ npm run render -- hello --props props/hello.json --out hello.mp4
86
+ npm run still -- hello --frame 42 --out hello-42.png
87
+ \`\`\`
88
+ `;
89
+ const SCAFFOLD_TEMPLATES = {
90
+ "video.config.js": `export default {\n compositions: {\n hello: "./compositions/hello.js",\n },\n};\n`,
91
+ "props/hello.json": `${JSON.stringify({ title: "Hello, Frameyard", accent: "#b8f36b" }, null, 2)}\n`,
92
+ "AGENTS.md": AGENTS_GUIDE,
93
+ "README.md": PROJECT_README,
94
+ "compositions/hello.js": `import { defineComposition } from "frameyard";
95
+
96
+ let title;
97
+ let sweep;
98
+ let glow;
99
+
100
+ export default defineComposition({
101
+ width: 1280,
102
+ height: 720,
103
+ fps: 30,
104
+ durationInFrames: 150,
105
+ defaultProps: { title: "Hello, Frameyard", accent: "#b8f36b" },
106
+ validateProps(props) {
107
+ const errors = [];
108
+ if (typeof props.title !== "string") errors.push("title must be a string");
109
+ if (typeof props.accent !== "string") errors.push("accent must be a string");
110
+ return errors;
111
+ },
112
+ mount({ container, props }) {
113
+ container.style.setProperty("--accent", props.accent);
114
+ container.innerHTML =
115
+ '<style>' +
116
+ '#hello { position: relative; width: 100%; height: 100%; display: grid; place-items: center; overflow: hidden; background: #0b0d10; color: #e8edf3; font-family: Inter, system-ui, sans-serif; }' +
117
+ '#hello h1 { position: relative; margin: 0; font-size: 96px; letter-spacing: -0.04em; }' +
118
+ '#hello p { position: relative; margin: 18px 0 0; color: #8a97a6; font-size: 26px; }' +
119
+ '#glow { position: absolute; width: 520px; height: 520px; border-radius: 50%; background: var(--accent); filter: blur(120px); opacity: 0.16; }' +
120
+ '#sweep { position: absolute; left: 0; bottom: 0; width: 0%; height: 4px; background: var(--accent); }' +
121
+ '</style>' +
122
+ '<div id="hello"><div id="glow"></div><div style="position: relative; text-align: center"><h1 id="title"></h1><p>Deterministic video, authored on the web.</p></div><div id="sweep"></div></div>';
123
+ title = container.querySelector("#title");
124
+ sweep = container.querySelector("#sweep");
125
+ glow = container.querySelector("#glow");
126
+ },
127
+ update({ frame, props }) {
128
+ title.textContent = props.title;
129
+ const intro = Math.min(1, frame / 24);
130
+ title.style.opacity = String(intro);
131
+ title.style.transform = "translateY(" + (1 - intro) * 28 + "px)";
132
+ glow.style.transform =
133
+ "translate(" + Math.sin(frame / 26) * 120 + "px," + Math.cos(frame / 34) * 80 + "px)";
134
+ sweep.style.width = (frame / 149) * 100 + "%";
135
+ },
136
+ dispose() {
137
+ title = undefined;
138
+ sweep = undefined;
139
+ glow = undefined;
140
+ },
141
+ });
142
+ `,
143
+ };
144
+ // Keep the generated package name valid for npm and pnpm.
145
+ function packageName(projectName) {
146
+ const normalized = projectName
147
+ .toLowerCase()
148
+ .replace(/[^a-z0-9._-]+/g, "-")
149
+ .replace(/^[._-]+|[._-]+$/g, "")
150
+ .slice(0, 214)
151
+ .replace(/[._-]+$/g, "");
152
+ return normalized === "" ? "frameyard-project" : normalized;
153
+ }
154
+ export function scaffoldFiles(projectName) {
155
+ return {
156
+ "package.json": `${JSON.stringify({
157
+ name: packageName(projectName),
158
+ private: true,
159
+ type: "module",
160
+ scripts: {
161
+ dev: `npx --yes frameyard@${VERSION} dev`,
162
+ check: `npx --yes frameyard@${VERSION} check`,
163
+ render: `npx --yes frameyard@${VERSION} render`,
164
+ still: `npx --yes frameyard@${VERSION} still`,
165
+ },
166
+ }, null, 2)}\n`,
167
+ ...SCAFFOLD_TEMPLATES,
168
+ };
169
+ }
170
+ export const SCAFFOLD_NEXT = [
171
+ "npx frameyard doctor",
172
+ "npx frameyard dev",
173
+ "npx frameyard check hello",
174
+ "npx frameyard render hello --out hello.mp4",
175
+ ];
176
+ //# sourceMappingURL=scaffold.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6CA0DwB,OAAO,kFAAkF,OAAO;CAC5I,CAAC;AAEF,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BtB,CAAC;AAEF,MAAM,kBAAkB,GAA2B;IACjD,iBAAiB,EAAE,wFAAwF;IAC3G,kBAAkB,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI;IACpG,WAAW,EAAE,YAAY;IACzB,WAAW,EAAE,cAAc;IAC3B,uBAAuB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgD1B;CACA,CAAC;AAEF,0DAA0D;AAC1D,SAAS,WAAW,CAAC,WAAmB;IACtC,MAAM,UAAU,GAAG,WAAW;SAC3B,WAAW,EAAE;SACb,OAAO,CAAC,gBAAgB,EAAE,GAAG,CAAC;SAC9B,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;SAC/B,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;SACb,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC3B,OAAO,UAAU,KAAK,EAAE,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,UAAU,CAAC;AAC9D,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,WAAmB;IAC/C,OAAO;QACL,cAAc,EAAE,GAAG,IAAI,CAAC,SAAS,CAC/B;YACE,IAAI,EAAE,WAAW,CAAC,WAAW,CAAC;YAC9B,OAAO,EAAE,IAAI;YACb,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE;gBACP,GAAG,EAAE,uBAAuB,OAAO,MAAM;gBACzC,KAAK,EAAE,uBAAuB,OAAO,QAAQ;gBAC7C,MAAM,EAAE,uBAAuB,OAAO,SAAS;gBAC/C,KAAK,EAAE,uBAAuB,OAAO,QAAQ;aAC9C;SACF,EACD,IAAI,EACJ,CAAC,CACF,IAAI;QACL,GAAG,kBAAkB;KACtB,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,sBAAsB;IACtB,mBAAmB;IACnB,2BAA2B;IAC3B,4CAA4C;CAC7C,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function renderPreviewHtml(): string;
2
+ //# sourceMappingURL=preview-html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview-html.d.ts","sourceRoot":"","sources":["../../src/server/preview-html.ts"],"names":[],"mappings":"AAWA,wBAAgB,iBAAiB,IAAI,MAAM,CA6N1C"}