frameyard 0.2.0 → 0.4.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.
- package/CHANGELOG.md +102 -0
- package/GLOSSARY.md +58 -2
- package/README.md +185 -95
- package/dist/bindings.d.ts +42 -0
- package/dist/bindings.d.ts.map +1 -0
- package/dist/bindings.js +144 -0
- package/dist/bindings.js.map +1 -0
- package/dist/cli.js +37 -14
- package/dist/cli.js.map +1 -1
- package/dist/contracts.d.ts +73 -47
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +14 -159
- package/dist/contracts.js.map +1 -1
- package/dist/errors.d.ts +15 -4
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +8 -0
- package/dist/errors.js.map +1 -1
- package/dist/html/index.d.ts +5 -0
- package/dist/html/index.d.ts.map +1 -0
- package/dist/html/index.js +3 -0
- package/dist/html/index.js.map +1 -0
- package/dist/html/parse.d.ts +30 -0
- package/dist/html/parse.d.ts.map +1 -0
- package/dist/html/parse.js +80 -0
- package/dist/html/parse.js.map +1 -0
- package/dist/html/validate.d.ts +14 -0
- package/dist/html/validate.d.ts.map +1 -0
- package/dist/html/validate.js +931 -0
- package/dist/html/validate.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/preview/main.d.ts +12 -3
- package/dist/preview/main.d.ts.map +1 -1
- package/dist/preview/main.js +208 -85
- package/dist/preview/main.js.map +1 -1
- package/dist/project.d.ts +2 -0
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +4 -0
- package/dist/project.js.map +1 -1
- package/dist/renderer/audio.d.ts +5 -1
- package/dist/renderer/audio.d.ts.map +1 -1
- package/dist/renderer/audio.js +4 -0
- package/dist/renderer/audio.js.map +1 -1
- package/dist/renderer/browser.d.ts +12 -1
- package/dist/renderer/browser.d.ts.map +1 -1
- package/dist/renderer/browser.js +69 -11
- package/dist/renderer/browser.js.map +1 -1
- package/dist/renderer/index.d.ts +30 -5
- package/dist/renderer/index.d.ts.map +1 -1
- package/dist/renderer/index.js +204 -26
- package/dist/renderer/index.js.map +1 -1
- package/dist/runtime/bindings.d.ts +11 -0
- package/dist/runtime/bindings.d.ts.map +1 -0
- package/dist/runtime/bindings.js +164 -0
- package/dist/runtime/bindings.js.map +1 -0
- package/dist/runtime/diagnostics.d.ts +4 -0
- package/dist/runtime/diagnostics.d.ts.map +1 -0
- package/dist/runtime/diagnostics.js +107 -0
- package/dist/runtime/diagnostics.js.map +1 -0
- package/dist/runtime/host.d.ts +12 -0
- package/dist/runtime/host.d.ts.map +1 -0
- package/dist/runtime/host.js +701 -0
- package/dist/runtime/host.js.map +1 -0
- package/dist/runtime/index.d.ts +0 -26
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +0 -286
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/media.d.ts +16 -0
- package/dist/runtime/media.d.ts.map +1 -0
- package/dist/runtime/media.js +307 -0
- package/dist/runtime/media.js.map +1 -0
- package/dist/scaffold.d.ts.map +1 -1
- package/dist/scaffold.js +169 -78
- package/dist/scaffold.js.map +1 -1
- package/dist/server/composition-html.d.ts +20 -0
- package/dist/server/composition-html.d.ts.map +1 -0
- package/dist/server/composition-html.js +45 -0
- package/dist/server/composition-html.js.map +1 -0
- package/dist/server/preview-html.d.ts.map +1 -1
- package/dist/server/preview-html.js +19 -14
- package/dist/server/preview-html.js.map +1 -1
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +94 -6
- package/dist/server/server.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/adr/0001-keep-composition-authoring-web-native.md +2 -0
- package/docs/adr/0003-render-browser-frames-offline.md +2 -0
- package/docs/adr/0005-keep-parallel-rendering-opt-in-and-frame-ordered.md +3 -0
- package/docs/adr/0006-seek-embedded-media-from-the-frame-clock.md +11 -0
- package/docs/adr/0007-make-html-documents-the-composition-unit.md +31 -0
- package/docs/migration-0.4.md +279 -0
- package/docs/v0.1-design.md +82 -57
- package/examples/demo/README.md +7 -3
- package/examples/demo/compositions/demo.controller.js +120 -0
- package/examples/demo/compositions/demo.html +253 -0
- package/examples/demo/video.config.js +1 -1
- package/package.json +9 -3
- package/skills/frameyard/README.md +4 -0
- package/skills/frameyard/SKILL.md +41 -11
- package/skills/frameyard/references/audio-assets.md +25 -14
- package/skills/frameyard/references/bindings.md +73 -0
- package/skills/frameyard/references/common-mistakes.md +59 -0
- package/skills/frameyard/references/controllers.md +126 -0
- package/skills/frameyard/references/deterministic-authoring.md +160 -41
- package/skills/frameyard/references/diagnostics.md +90 -0
- package/skills/frameyard/references/failure-recovery.md +38 -12
- package/skills/frameyard/references/json-results.md +43 -8
- package/skills/frameyard/references/subtitles-karaoke.md +10 -18
- package/examples/demo/compositions/demo.js +0 -206
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import { FrameyardError } from "../errors.js";
|
|
2
|
+
import { frameToSeconds } from "./clock.js";
|
|
3
|
+
const MEDIA_TIMEOUT_MS = 30_000;
|
|
4
|
+
const TIME_EPSILON = 0.0005;
|
|
5
|
+
const preparedMedia = new WeakMap();
|
|
6
|
+
const preparedStates = new Set();
|
|
7
|
+
const pendingPreparation = new WeakMap();
|
|
8
|
+
const VIDEO_MIME_TYPES = {
|
|
9
|
+
".mov": "video/quicktime",
|
|
10
|
+
".mp4": "video/mp4",
|
|
11
|
+
".m4v": "video/mp4",
|
|
12
|
+
".ogv": "video/ogg",
|
|
13
|
+
".webm": "video/webm",
|
|
14
|
+
};
|
|
15
|
+
function mediaSource(video) {
|
|
16
|
+
const direct = video.getAttribute("src");
|
|
17
|
+
if (direct !== null && direct.trim().length > 0) {
|
|
18
|
+
return direct.trim();
|
|
19
|
+
}
|
|
20
|
+
const source = video.querySelector("source[src]");
|
|
21
|
+
const nested = source?.getAttribute("src");
|
|
22
|
+
if (nested !== null && nested !== undefined && nested.trim().length > 0) {
|
|
23
|
+
return nested.trim();
|
|
24
|
+
}
|
|
25
|
+
return "";
|
|
26
|
+
}
|
|
27
|
+
/** Converts a composition-relative media reference to a normalized project path. */
|
|
28
|
+
export function normalizeMediaSource(raw) {
|
|
29
|
+
if (raw.length === 0) {
|
|
30
|
+
throw new FrameyardError("MEDIA_INVALID", "An embedded video must have a non-empty src attribute.");
|
|
31
|
+
}
|
|
32
|
+
if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(raw) || raw.startsWith("//") || raw.startsWith("\\")) {
|
|
33
|
+
throw new FrameyardError("MEDIA_INVALID", `Embedded video source must be a local project-relative file, not "${raw}".`);
|
|
34
|
+
}
|
|
35
|
+
let pathValue = raw.split(/[?#]/, 1)[0] ?? "";
|
|
36
|
+
pathValue = pathValue.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
37
|
+
if (pathValue.startsWith("./")) {
|
|
38
|
+
pathValue = pathValue.slice(2);
|
|
39
|
+
}
|
|
40
|
+
if (pathValue.length === 0 || pathValue.split("/").includes("..") || pathValue.includes("\0")) {
|
|
41
|
+
throw new FrameyardError("MEDIA_INVALID", `Embedded video source must stay inside the project, not "${raw}".`);
|
|
42
|
+
}
|
|
43
|
+
let decoded;
|
|
44
|
+
try {
|
|
45
|
+
decoded = decodeURIComponent(pathValue);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
throw new FrameyardError("MEDIA_INVALID", `Embedded video source is not a valid URL path: "${raw}".`);
|
|
49
|
+
}
|
|
50
|
+
if (decoded.length === 0 || decoded.split("/").includes("..") || decoded.includes("\0")) {
|
|
51
|
+
throw new FrameyardError("MEDIA_INVALID", `Embedded video source must stay inside the project, not "${raw}".`);
|
|
52
|
+
}
|
|
53
|
+
return decoded;
|
|
54
|
+
}
|
|
55
|
+
function videoUrl(pathValue) {
|
|
56
|
+
return new URL(`/${pathValue}`, window.location.origin);
|
|
57
|
+
}
|
|
58
|
+
function waitForEvent(video, event, message, code = "MEDIA_INVALID") {
|
|
59
|
+
return new Promise((resolve, reject) => {
|
|
60
|
+
let timer;
|
|
61
|
+
function finish() {
|
|
62
|
+
video.removeEventListener(event, onEvent);
|
|
63
|
+
video.removeEventListener("error", onError);
|
|
64
|
+
clearTimeout(timer);
|
|
65
|
+
}
|
|
66
|
+
function onEvent() {
|
|
67
|
+
finish();
|
|
68
|
+
resolve();
|
|
69
|
+
}
|
|
70
|
+
function onError() {
|
|
71
|
+
finish();
|
|
72
|
+
reject(new FrameyardError(code, `${message}${video.error?.message ? `: ${video.error.message}` : ""}`));
|
|
73
|
+
}
|
|
74
|
+
timer = setTimeout(() => {
|
|
75
|
+
finish();
|
|
76
|
+
reject(new FrameyardError(code, `${message} Timed out after ${MEDIA_TIMEOUT_MS / 1000}s.`));
|
|
77
|
+
}, MEDIA_TIMEOUT_MS);
|
|
78
|
+
video.addEventListener(event, onEvent, { once: true });
|
|
79
|
+
video.addEventListener("error", onError, { once: true });
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
async function prepareVideo(video, owner) {
|
|
83
|
+
const raw = mediaSource(video);
|
|
84
|
+
const source = normalizeMediaSource(raw);
|
|
85
|
+
const spec = mediaSpec(video);
|
|
86
|
+
const existing = preparedMedia.get(video);
|
|
87
|
+
if (existing && existing.owner === owner && existing.source === source) {
|
|
88
|
+
return existing;
|
|
89
|
+
}
|
|
90
|
+
if (existing) {
|
|
91
|
+
preparedMedia.delete(video);
|
|
92
|
+
preparedStates.delete(existing);
|
|
93
|
+
URL.revokeObjectURL(existing.objectUrl);
|
|
94
|
+
}
|
|
95
|
+
let response;
|
|
96
|
+
try {
|
|
97
|
+
response = await fetch(videoUrl(source), { cache: "no-store" });
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
throw new FrameyardError("ASSET_NOT_FOUND", `Could not load embedded video asset "${source}".`, {
|
|
101
|
+
cause: error,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
if (!response.ok) {
|
|
105
|
+
throw new FrameyardError("ASSET_NOT_FOUND", `Could not load embedded video asset "${source}" (HTTP ${response.status}).`);
|
|
106
|
+
}
|
|
107
|
+
const blob = await response.blob();
|
|
108
|
+
if (blob.size === 0) {
|
|
109
|
+
throw new FrameyardError("MEDIA_INVALID", `Embedded video asset "${source}" is empty.`);
|
|
110
|
+
}
|
|
111
|
+
const extension = source.slice(source.lastIndexOf(".")).toLowerCase();
|
|
112
|
+
const type = blob.type || VIDEO_MIME_TYPES[extension] || "video/webm";
|
|
113
|
+
const videoBlob = blob.type === type ? blob : blob.slice(0, blob.size, type);
|
|
114
|
+
const objectUrl = URL.createObjectURL(videoBlob);
|
|
115
|
+
const authorMuted = video.muted;
|
|
116
|
+
for (const nested of Array.from(video.querySelectorAll("source"))) {
|
|
117
|
+
nested.remove();
|
|
118
|
+
}
|
|
119
|
+
const loaded = waitForEvent(video, "loadeddata", `Embedded video asset "${source}" could not be decoded.`);
|
|
120
|
+
video.preload = "auto";
|
|
121
|
+
video.playsInline = true;
|
|
122
|
+
video.pause();
|
|
123
|
+
video.muted = true;
|
|
124
|
+
video.src = objectUrl;
|
|
125
|
+
video.load();
|
|
126
|
+
try {
|
|
127
|
+
await loaded;
|
|
128
|
+
if (!Number.isFinite(video.duration) || video.duration <= 0 || video.seekable.length === 0) {
|
|
129
|
+
throw new FrameyardError("MEDIA_INVALID", `Embedded video asset "${source}" is not seekable.`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
URL.revokeObjectURL(objectUrl);
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
const state = { element: video, owner, source, objectUrl, spec, authorMuted };
|
|
137
|
+
preparedMedia.set(video, state);
|
|
138
|
+
preparedStates.add(state);
|
|
139
|
+
return state;
|
|
140
|
+
}
|
|
141
|
+
async function prepareOrGet(video, owner) {
|
|
142
|
+
const ready = preparedMedia.get(video);
|
|
143
|
+
if (ready && ready.owner === owner) {
|
|
144
|
+
return ready;
|
|
145
|
+
}
|
|
146
|
+
const pending = pendingPreparation.get(video);
|
|
147
|
+
if (pending) {
|
|
148
|
+
return pending;
|
|
149
|
+
}
|
|
150
|
+
const preparation = prepareVideo(video, owner);
|
|
151
|
+
pendingPreparation.set(video, preparation);
|
|
152
|
+
try {
|
|
153
|
+
return await preparation;
|
|
154
|
+
}
|
|
155
|
+
finally {
|
|
156
|
+
pendingPreparation.delete(video);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/** Loads every embedded video into memory before frame production begins. */
|
|
160
|
+
export async function prepareMedia(container) {
|
|
161
|
+
const videos = Array.from(container.querySelectorAll("video"));
|
|
162
|
+
await Promise.all(videos.map((video) => prepareOrGet(video, container)));
|
|
163
|
+
}
|
|
164
|
+
function integerAttribute(element, name, fallback) {
|
|
165
|
+
const raw = element.getAttribute(name);
|
|
166
|
+
if (raw === null || raw.trim().length === 0) {
|
|
167
|
+
return fallback;
|
|
168
|
+
}
|
|
169
|
+
const value = Number(raw);
|
|
170
|
+
if (!Number.isInteger(value) || value < 0) {
|
|
171
|
+
throw new FrameyardError("MEDIA_INVALID", `Embedded video ${name} must be a non-negative integer.`);
|
|
172
|
+
}
|
|
173
|
+
return value;
|
|
174
|
+
}
|
|
175
|
+
function secondsAttribute(element, name, fallback, allowZero) {
|
|
176
|
+
const raw = element.getAttribute(name);
|
|
177
|
+
if (raw === null || raw.trim().length === 0) {
|
|
178
|
+
return fallback;
|
|
179
|
+
}
|
|
180
|
+
const value = Number(raw);
|
|
181
|
+
if (!Number.isFinite(value) || value < 0 || (!allowZero && value === 0)) {
|
|
182
|
+
throw new FrameyardError("MEDIA_INVALID", `Embedded video ${name} must be ${allowZero ? "a non-negative" : "a positive"} number of seconds.`);
|
|
183
|
+
}
|
|
184
|
+
return value;
|
|
185
|
+
}
|
|
186
|
+
function volumeAttribute(element) {
|
|
187
|
+
const raw = element.getAttribute("data-fy-volume");
|
|
188
|
+
if (raw === null || raw.trim().length === 0) {
|
|
189
|
+
return Math.max(0, Math.min(1, element.volume));
|
|
190
|
+
}
|
|
191
|
+
const value = Number(raw);
|
|
192
|
+
if (!Number.isFinite(value) || value < 0 || value > 1) {
|
|
193
|
+
throw new FrameyardError("MEDIA_INVALID", "Embedded video data-fy-volume must be between 0 and 1.");
|
|
194
|
+
}
|
|
195
|
+
return value;
|
|
196
|
+
}
|
|
197
|
+
function mediaSpec(element) {
|
|
198
|
+
const startFrame = integerAttribute(element, "data-fy-start", 0);
|
|
199
|
+
const trimStart = secondsAttribute(element, "data-fy-trim", 0, true);
|
|
200
|
+
const durationRaw = element.getAttribute("data-fy-duration");
|
|
201
|
+
const trimDuration = durationRaw === null || durationRaw.trim().length === 0
|
|
202
|
+
? undefined
|
|
203
|
+
: secondsAttribute(element, "data-fy-duration", 0, false);
|
|
204
|
+
const spec = {
|
|
205
|
+
startFrame,
|
|
206
|
+
trimStart,
|
|
207
|
+
volume: volumeAttribute(element),
|
|
208
|
+
};
|
|
209
|
+
if (trimDuration !== undefined) {
|
|
210
|
+
spec.trimDuration = trimDuration;
|
|
211
|
+
}
|
|
212
|
+
return spec;
|
|
213
|
+
}
|
|
214
|
+
function seekTarget(video, spec, frame, fps) {
|
|
215
|
+
const localSeconds = frameToSeconds(frame, fps) - spec.startFrame / fps;
|
|
216
|
+
const usedSeconds = spec.trimDuration === undefined
|
|
217
|
+
? Math.max(0, localSeconds)
|
|
218
|
+
: Math.min(spec.trimDuration, Math.max(0, localSeconds));
|
|
219
|
+
const target = spec.trimStart + usedSeconds;
|
|
220
|
+
const duration = Number.isFinite(video.duration) ? Math.max(0, video.duration) : target;
|
|
221
|
+
return Math.min(target, Math.max(0, duration - TIME_EPSILON));
|
|
222
|
+
}
|
|
223
|
+
async function seekVideo(video, frame, fps) {
|
|
224
|
+
const state = preparedMedia.get(video);
|
|
225
|
+
if (!state) {
|
|
226
|
+
throw new FrameyardError("MEDIA_INVALID", "Embedded video elements must be created in mount(); videos added during update() cannot be prepared without network access.");
|
|
227
|
+
}
|
|
228
|
+
if (!video.paused) {
|
|
229
|
+
video.pause();
|
|
230
|
+
}
|
|
231
|
+
if (video.readyState < HTMLMediaElement.HAVE_CURRENT_DATA) {
|
|
232
|
+
await waitForEvent(video, "loadeddata", "Embedded video is not ready for frame production.");
|
|
233
|
+
}
|
|
234
|
+
const target = seekTarget(video, state.spec, frame, fps);
|
|
235
|
+
if (video.seeking) {
|
|
236
|
+
await waitForEvent(video, "seeked", "Embedded video could not finish an earlier seek.", "MEDIA_SEEK_FAILED");
|
|
237
|
+
}
|
|
238
|
+
if (!video.seeking && Math.abs(video.currentTime - target) < TIME_EPSILON) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
const seeked = waitForEvent(video, "seeked", "Embedded video could not seek to the requested frame.", "MEDIA_SEEK_FAILED");
|
|
242
|
+
try {
|
|
243
|
+
video.currentTime = target;
|
|
244
|
+
}
|
|
245
|
+
catch (error) {
|
|
246
|
+
throw new FrameyardError("MEDIA_SEEK_FAILED", `Embedded video could not seek to ${target.toFixed(3)}s: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
247
|
+
}
|
|
248
|
+
await seeked;
|
|
249
|
+
}
|
|
250
|
+
async function nextPaint() {
|
|
251
|
+
await new Promise((resolve) => {
|
|
252
|
+
requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Seeks every embedded video to the requested composition frame and waits for
|
|
257
|
+
* the browser to present the result. This is the asynchronous half of a seek;
|
|
258
|
+
* composition update() stays synchronous.
|
|
259
|
+
*/
|
|
260
|
+
export async function settleMedia(container, frame, fps) {
|
|
261
|
+
const videos = Array.from(container.querySelectorAll("video"));
|
|
262
|
+
if (videos.length === 0) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
await Promise.all(videos.map((video) => seekVideo(video, frame, fps)));
|
|
266
|
+
await nextPaint();
|
|
267
|
+
}
|
|
268
|
+
/** Describes the audio contributed by unmuted embedded videos for preview and FFmpeg. */
|
|
269
|
+
export function describeMediaAudio(container) {
|
|
270
|
+
const clips = [];
|
|
271
|
+
for (const video of Array.from(container.querySelectorAll("video"))) {
|
|
272
|
+
const state = preparedMedia.get(video);
|
|
273
|
+
if (!state || state.authorMuted || video.getAttribute("data-fy-audio") === "off") {
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
const spec = state.spec;
|
|
277
|
+
if (spec.volume === 0) {
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
const clip = {
|
|
281
|
+
src: state.source,
|
|
282
|
+
startFrame: spec.startFrame,
|
|
283
|
+
trimStart: spec.trimStart,
|
|
284
|
+
volume: spec.volume,
|
|
285
|
+
};
|
|
286
|
+
if (spec.trimDuration !== undefined) {
|
|
287
|
+
clip.trimDuration = spec.trimDuration;
|
|
288
|
+
}
|
|
289
|
+
clips.push(Object.freeze(clip));
|
|
290
|
+
}
|
|
291
|
+
return Object.freeze(clips);
|
|
292
|
+
}
|
|
293
|
+
/** Releases object URLs and media resources owned by the runtime. */
|
|
294
|
+
export function releaseMedia(container) {
|
|
295
|
+
for (const state of Array.from(preparedStates)) {
|
|
296
|
+
if (state.owner !== container) {
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
preparedStates.delete(state);
|
|
300
|
+
preparedMedia.delete(state.element);
|
|
301
|
+
state.element.pause();
|
|
302
|
+
URL.revokeObjectURL(state.objectUrl);
|
|
303
|
+
state.element.removeAttribute("src");
|
|
304
|
+
state.element.load();
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
//# sourceMappingURL=media.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media.js","sourceRoot":"","sources":["../../src/runtime/media.ts"],"names":[],"mappings":"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"}
|
package/dist/scaffold.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAyPA,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAmBzE;AAED,eAAO,MAAM,aAAa,UAKzB,CAAC"}
|
package/dist/scaffold.js
CHANGED
|
@@ -5,22 +5,100 @@ This project produces deterministic, parameterized video with Frameyard. Follow
|
|
|
5
5
|
|
|
6
6
|
## Project layout
|
|
7
7
|
|
|
8
|
-
- \`video.config.js\` explicitly maps composition IDs to
|
|
9
|
-
- \`
|
|
10
|
-
- \`
|
|
11
|
-
- \`props/\` contains JSON props, merged shallowly over \`defaultProps\` and deep-frozen.
|
|
8
|
+
- \`video.config.js\` explicitly maps composition IDs to \`.html\` composition documents. There is no directory scanning; a new composition is invisible until it is listed.
|
|
9
|
+
- \`compositions/\` contains HTML/CSS compositions. An optional controller lives beside the document as a \`.controller.js\` module; import \`frameyard/runtime\` for \`random("stable:key")\` and other browser APIs.
|
|
10
|
+
- \`props/\` contains JSON props, merged shallowly over the composition's \`data-fy="props"\` defaults and deep-frozen.
|
|
12
11
|
- \`assets/\` (create it when needed) contains audio, images, fonts, and generated assets.
|
|
12
|
+
- \`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).
|
|
13
|
+
|
|
14
|
+
\`width\`, \`height\`, \`fps\`, and \`duration-in-frames\` are fixed on \`<fy-composition>\`. Do not derive them from props.
|
|
15
|
+
|
|
16
|
+
## Composition skeleton
|
|
17
|
+
|
|
18
|
+
\`\`\`html
|
|
19
|
+
<!doctype html>
|
|
20
|
+
<html>
|
|
21
|
+
<head>
|
|
22
|
+
<meta charset="utf-8">
|
|
23
|
+
<script type="application/json" data-fy="props">{ "title": "Hello" }</script>
|
|
24
|
+
</head>
|
|
25
|
+
<body>
|
|
26
|
+
<fy-composition width="1280" height="720" fps="30" duration-in-frames="150">
|
|
27
|
+
<h1 data-fy-text="title"></h1>
|
|
28
|
+
</fy-composition>
|
|
29
|
+
</body>
|
|
30
|
+
</html>
|
|
31
|
+
\`\`\`
|
|
32
|
+
|
|
33
|
+
## Bindings
|
|
34
|
+
|
|
35
|
+
- \`data-fy-text="path"\` sets text content.
|
|
36
|
+
- \`data-fy-attr-src="path"\` (and other \`data-fy-attr-*\` names) sets an attribute.
|
|
37
|
+
- \`data-fy-class-active="path"\` toggles a class.
|
|
38
|
+
- \`data-fy-if="path"\` removes the element when the value is false.
|
|
39
|
+
- \`<template data-fy-repeat="items">\` clones its content for each item; use \`item\` and \`index\`, and style stagger with \`--fy-index\`.
|
|
40
|
+
- Paths are dot-separated (\`user.name\`, \`items.0.label\`). Missing paths warn and resolve to an empty value.
|
|
41
|
+
- Primitive top-level props are also available as \`--fy-prop-<name>\` CSS custom properties.
|
|
42
|
+
|
|
43
|
+
## Animation
|
|
44
|
+
|
|
45
|
+
- CSS \`@keyframes\` and Web Animations API animations are paused and seeked from the frame clock.
|
|
46
|
+
- \`data-fy-anim-start\`, \`data-fy-anim-duration\`, and \`data-fy-anim-easing\` schedule one animation per element in composition frames. The CSS \`animation\` shorthand supplies keyframes and fill mode.
|
|
47
|
+
- Frame-state variables are set on \`:root\`: \`--fy-frame\`, \`--fy-time\`, \`--fy-progress\`, \`--fy-fps\`, \`--fy-duration\`, and \`--fy-duration-frames\`.
|
|
48
|
+
- Use \`--fy-progress\` for progress bars and \`--fy-frame\`/\`--fy-time\` in \`calc()\` for simple computed motion.
|
|
49
|
+
- CSS transitions are not deterministic; do not use them.
|
|
50
|
+
|
|
51
|
+
## Controller
|
|
52
|
+
|
|
53
|
+
Exactly one optional controller is allowed, inline or external:
|
|
54
|
+
|
|
55
|
+
\`\`\`html
|
|
56
|
+
<script type="text/fy-controller">
|
|
57
|
+
export default {
|
|
58
|
+
mount({ root, props }) {},
|
|
59
|
+
update({ frame, props, root }) {},
|
|
60
|
+
};
|
|
61
|
+
</script>
|
|
62
|
+
\`\`\`
|
|
63
|
+
|
|
64
|
+
\`\`\`html
|
|
65
|
+
<script type="text/fy-controller" src="./hello.controller.js"></script>
|
|
66
|
+
\`\`\`
|
|
67
|
+
|
|
68
|
+
- \`mount\` may be asynchronous; \`update\` and \`validateProps\` are synchronous and seek-safe; \`dispose\` releases resources.
|
|
69
|
+
- Use inline for small, single-use controllers; extract to an external module for Canvas 2D, WebGL, karaoke, reuse, tests, or a large controller.
|
|
70
|
+
- A controller may be validation-only and export just \`validateProps(props)\`.
|
|
71
|
+
- The controller is the only executable code. Other scripts and \`on*\` handlers are rejected.
|
|
72
|
+
- Controller-created DOM is not re-bound; declarative bindings apply once before \`mount\`.
|
|
73
|
+
|
|
74
|
+
## Determinism rules
|
|
13
75
|
|
|
14
|
-
|
|
76
|
+
- A frame may depend only on its integer \`frame\`, immutable \`props\`, and assets loaded before frame production.
|
|
77
|
+
- 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.
|
|
78
|
+
- Use \`random("stable:key")\` from \`frameyard/runtime\` for randomness.
|
|
79
|
+
- Load remote data, fonts, and images before frame production. Network requests are blocked during capture; a \`fetch()\` from \`update()\` is a bug.
|
|
80
|
+
- Redraw Canvas 2D and WebGL from the current frame. Production pins software WebGL for reproducible pixels.
|
|
81
|
+
- Embedded video and audio use local project files and \`data-fy-start\` (frames), \`data-fy-trim\` (seconds), optional \`data-fy-duration\` (seconds), and \`data-fy-volume\` (0-1). Let the runtime seek video; do not call \`play()\`, \`pause()\`, or set \`currentTime\` in \`update()\`.
|
|
82
|
+
- Media and transcript \`src\` values resolve from the project root. The controller \`src\` and ordinary HTML asset URLs resolve relative to the composition document.
|
|
83
|
+
|
|
84
|
+
## Audio and transcripts
|
|
85
|
+
|
|
86
|
+
- Audio clips are \`<audio>\` elements placed by composition frames and trimmed by seconds. Frameyard does not time-stretch audio or change composition duration to fit it.
|
|
87
|
+
- An unmuted embedded video contributes its audio track to the same mix; use \`muted\` or \`data-fy-audio="off"\` for a visual-only video.
|
|
88
|
+
- Declare required transcripts with \`<fy-transcript src="assets/voice.transcript.json" words></fy-transcript>\`.
|
|
89
|
+
- 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 a controller.
|
|
90
|
+
- Do not overwrite or regenerate generated assets without explicit approval.
|
|
91
|
+
- \`words\` requires measured word timings; never interpolate segment timings.
|
|
92
|
+
- Commit \`frameyard.assets.json\` when present; do not edit hashes or manifest entries by hand.
|
|
15
93
|
|
|
16
94
|
## Agent workflow
|
|
17
95
|
|
|
18
|
-
1. Read \`video.config.js\`, the composition
|
|
19
|
-
2. Author the composition
|
|
20
|
-
3. Validate every frame: \`npx frameyard check <id> --json\`. Use \`--props <file>\` to validate a specific props file.
|
|
96
|
+
1. Read \`video.config.js\`, the composition HTML, the optional controller, and the props file before changing behavior.
|
|
97
|
+
2. Author the composition with native HTML, CSS, SVG, Canvas 2D, WebGL, embedded video, and an optional controller. Do not add a bundling step.
|
|
98
|
+
3. Validate every frame: \`npx frameyard check <id> --json\`. Static validation runs before Chromium and reports stable diagnostic codes with source locations. Use \`--props <file>\` to validate a specific props file.
|
|
21
99
|
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.
|
|
100
|
+
5. Render: \`npx frameyard render <id> --props <file> --out <file.mp4> [--concurrency <n>] --json\`.
|
|
101
|
+
6. Report the composition, controller, props, validation result, diagnostics, 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
102
|
|
|
25
103
|
## Commands
|
|
26
104
|
|
|
@@ -34,27 +112,9 @@ npx frameyard render hello --props props/hello.json --out hello.mp4 --json
|
|
|
34
112
|
|
|
35
113
|
- Use \`--json\` for non-interactive commands. Parse stdout as the structured result; treat stderr as progress and diagnostics.
|
|
36
114
|
- Use \`--project <dir>\` when running outside the project root.
|
|
115
|
+
- Use \`--concurrency <n>\` for faster local rendering when useful; the default is \`1\` and the maximum is \`16\`. It changes capture scheduling only, not composition behavior or output frame order.
|
|
37
116
|
- \`still\` and \`render\` replace existing outputs only with \`--overwrite\`. Generated assets are replaced only with \`--force\`, and only with user approval.
|
|
38
117
|
|
|
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
118
|
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
119
|
|
|
60
120
|
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.
|
|
@@ -63,6 +123,8 @@ const PROJECT_README = `# My Frameyard project
|
|
|
63
123
|
|
|
64
124
|
Coding agents should read \`AGENTS.md\` for the project rules and the check, still, and render workflow.
|
|
65
125
|
|
|
126
|
+
The composition is a plain HTML document at \`compositions/hello.html\`. Its metadata, default props, markup, CSS animation, and bindings live in that one file.
|
|
127
|
+
|
|
66
128
|
Start the preview:
|
|
67
129
|
|
|
68
130
|
\`\`\`sh
|
|
@@ -87,58 +149,87 @@ npm run still -- hello --frame 42 --out hello-42.png
|
|
|
87
149
|
\`\`\`
|
|
88
150
|
`;
|
|
89
151
|
const SCAFFOLD_TEMPLATES = {
|
|
90
|
-
"video.config.js": `export default {\n compositions: {\n hello: "./compositions/hello.
|
|
152
|
+
"video.config.js": `export default {\n compositions: {\n hello: "./compositions/hello.html",\n },\n};\n`,
|
|
91
153
|
"props/hello.json": `${JSON.stringify({ title: "Hello, Frameyard", accent: "#b8f36b" }, null, 2)}\n`,
|
|
92
154
|
"AGENTS.md": AGENTS_GUIDE,
|
|
93
155
|
"README.md": PROJECT_README,
|
|
94
|
-
"compositions/hello.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
156
|
+
"compositions/hello.html": `<!doctype html>
|
|
157
|
+
<html>
|
|
158
|
+
<head>
|
|
159
|
+
<meta charset="utf-8">
|
|
160
|
+
<script type="application/json" data-fy="props">
|
|
161
|
+
{ "title": "Hello, Frameyard", "accent": "#b8f36b" }
|
|
162
|
+
</script>
|
|
163
|
+
<style>
|
|
164
|
+
@keyframes fade-up {
|
|
165
|
+
from { opacity: 0; transform: translateY(28px); }
|
|
166
|
+
to { opacity: 1; transform: translateY(0); }
|
|
167
|
+
}
|
|
168
|
+
@keyframes drift {
|
|
169
|
+
from { transform: translate(-120px, -80px); }
|
|
170
|
+
to { transform: translate(120px, 80px); }
|
|
171
|
+
}
|
|
172
|
+
#hello {
|
|
173
|
+
position: relative;
|
|
174
|
+
width: 100%;
|
|
175
|
+
height: 100%;
|
|
176
|
+
display: grid;
|
|
177
|
+
place-items: center;
|
|
178
|
+
overflow: hidden;
|
|
179
|
+
background: #0b0d10;
|
|
180
|
+
color: #e8edf3;
|
|
181
|
+
font-family: Inter, system-ui, sans-serif;
|
|
182
|
+
}
|
|
183
|
+
#hello h1 {
|
|
184
|
+
position: relative;
|
|
185
|
+
margin: 0;
|
|
186
|
+
font-size: 96px;
|
|
187
|
+
letter-spacing: -0.04em;
|
|
188
|
+
opacity: 0;
|
|
189
|
+
animation: fade-up 1s cubic-bezier(0.215, 0.61, 0.355, 1) both;
|
|
190
|
+
}
|
|
191
|
+
#hello p {
|
|
192
|
+
position: relative;
|
|
193
|
+
margin: 18px 0 0;
|
|
194
|
+
color: #8a97a6;
|
|
195
|
+
font-size: 26px;
|
|
196
|
+
}
|
|
197
|
+
#glow {
|
|
198
|
+
position: absolute;
|
|
199
|
+
left: 50%;
|
|
200
|
+
top: 50%;
|
|
201
|
+
width: 520px;
|
|
202
|
+
height: 520px;
|
|
203
|
+
margin: -260px 0 0 -260px;
|
|
204
|
+
border-radius: 50%;
|
|
205
|
+
background: var(--fy-prop-accent);
|
|
206
|
+
filter: blur(120px);
|
|
207
|
+
opacity: 0.16;
|
|
208
|
+
animation: drift 12s ease-in-out infinite alternate;
|
|
209
|
+
}
|
|
210
|
+
#sweep {
|
|
211
|
+
position: absolute;
|
|
212
|
+
left: 0;
|
|
213
|
+
bottom: 0;
|
|
214
|
+
width: calc(var(--fy-progress) * 100%);
|
|
215
|
+
height: 4px;
|
|
216
|
+
background: var(--fy-prop-accent);
|
|
217
|
+
}
|
|
218
|
+
</style>
|
|
219
|
+
</head>
|
|
220
|
+
<body>
|
|
221
|
+
<fy-composition width="1280" height="720" fps="30" duration-in-frames="150">
|
|
222
|
+
<div id="hello">
|
|
223
|
+
<div id="glow"></div>
|
|
224
|
+
<div style="position: relative; text-align: center">
|
|
225
|
+
<h1 id="title" data-fy-text="title" data-fy-anim-start="0" data-fy-anim-duration="24"></h1>
|
|
226
|
+
<p>Deterministic video, authored on the web.</p>
|
|
227
|
+
</div>
|
|
228
|
+
<div id="sweep"></div>
|
|
229
|
+
</div>
|
|
230
|
+
</fy-composition>
|
|
231
|
+
</body>
|
|
232
|
+
</html>
|
|
142
233
|
`,
|
|
143
234
|
};
|
|
144
235
|
// Keep the generated package name valid for npm and pnpm.
|
package/dist/scaffold.js.map
CHANGED
|
@@ -1 +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
|
|
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6CAsHwB,OAAO,kFAAkF,OAAO;CAC5I,CAAC;AAEF,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BtB,CAAC;AAEF,MAAM,kBAAkB,GAA2B;IACjD,iBAAiB,EAAE,0FAA0F;IAC7G,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,yBAAyB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6E5B;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"}
|