visualfries 0.1.10120 → 0.3.2

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 (133) hide show
  1. package/README.md +97 -0
  2. package/bin/visualfries.js +1570 -0
  3. package/dist/DIContainer.d.ts +2 -1
  4. package/dist/DIContainer.js +16 -5
  5. package/dist/SceneBuilder.svelte.d.ts +70 -1
  6. package/dist/SceneBuilder.svelte.js +96 -29
  7. package/dist/agent/audioMixer.d.ts +34 -0
  8. package/dist/agent/audioMixer.js +308 -0
  9. package/dist/agent/broll.d.ts +35 -0
  10. package/dist/agent/broll.js +226 -0
  11. package/dist/agent/capabilities.d.ts +34 -0
  12. package/dist/agent/capabilities.js +246 -0
  13. package/dist/agent/captionScene.d.ts +23 -0
  14. package/dist/agent/captionScene.js +204 -0
  15. package/dist/agent/catalog.d.ts +24 -0
  16. package/dist/agent/catalog.js +67 -0
  17. package/dist/agent/cueFiles.d.ts +54 -0
  18. package/dist/agent/cueFiles.js +219 -0
  19. package/dist/agent/cuePresets.d.ts +7 -0
  20. package/dist/agent/cuePresets.js +50 -0
  21. package/dist/agent/deterministicMedia.d.ts +61 -0
  22. package/dist/agent/deterministicMedia.js +303 -0
  23. package/dist/agent/index.d.ts +18 -0
  24. package/dist/agent/index.js +18 -0
  25. package/dist/agent/inspectScene.d.ts +36 -0
  26. package/dist/agent/inspectScene.js +139 -0
  27. package/dist/agent/localRender.d.ts +82 -0
  28. package/dist/agent/localRender.js +702 -0
  29. package/dist/agent/overlays.d.ts +40 -0
  30. package/dist/agent/overlays.js +325 -0
  31. package/dist/agent/productionPlan.d.ts +131 -0
  32. package/dist/agent/productionPlan.js +322 -0
  33. package/dist/agent/renderPlan.d.ts +27 -0
  34. package/dist/agent/renderPlan.js +68 -0
  35. package/dist/agent/renderRanges.d.ts +24 -0
  36. package/dist/agent/renderRanges.js +73 -0
  37. package/dist/agent/runtimeSupport.d.ts +19 -0
  38. package/dist/agent/runtimeSupport.js +192 -0
  39. package/dist/agent/streamingEncoder.d.ts +31 -0
  40. package/dist/agent/streamingEncoder.js +208 -0
  41. package/dist/agent/transcripts.d.ts +29 -0
  42. package/dist/agent/transcripts.js +146 -0
  43. package/dist/agent/transitions.d.ts +20 -0
  44. package/dist/agent/transitions.js +169 -0
  45. package/dist/animations/PixiAnimationTarget.d.ts +29 -0
  46. package/dist/animations/PixiAnimationTarget.js +63 -0
  47. package/dist/animations/builders/LineHighlighterAnimationBuilder.js +20 -3
  48. package/dist/animations/builders/WordHighlighterAnimationBuilder.js +15 -2
  49. package/dist/browser/browserExport.d.ts +73 -0
  50. package/dist/browser/browserExport.js +180 -0
  51. package/dist/browser/glTransitions.d.ts +37 -0
  52. package/dist/browser/glTransitions.js +261 -0
  53. package/dist/browser/index.d.ts +3 -0
  54. package/dist/browser/index.js +3 -0
  55. package/dist/browser/mediaDecode.d.ts +31 -0
  56. package/dist/browser/mediaDecode.js +152 -0
  57. package/dist/builders/PixiComponentBuilder.d.ts +6 -0
  58. package/dist/builders/PixiComponentBuilder.js +12 -0
  59. package/dist/builders/_ComponentState.svelte.d.ts +7 -5
  60. package/dist/builders/_ComponentState.svelte.js +29 -15
  61. package/dist/builders/html/StyleBuilder.js +9 -8
  62. package/dist/builders/html/TextComponentHtmlBuilder.js +4 -2
  63. package/dist/builders/html/processors/AppearanceStyleProcessor.js +1 -1
  64. package/dist/builders/html/processors/TextAppearanceStyleProcessor.js +7 -0
  65. package/dist/builders/html/processors/TextEffectsStyleProcessor.js +32 -13
  66. package/dist/commands/ReplaceSourceOnTimeCommand.js +9 -1
  67. package/dist/commands/SeekCommand.js +19 -6
  68. package/dist/components/AnimatedGIF.d.ts +3 -0
  69. package/dist/components/AnimatedGIF.js +28 -1
  70. package/dist/components/Component.svelte.d.ts +5 -5
  71. package/dist/components/Component.svelte.js +29 -13
  72. package/dist/components/ComponentContext.svelte.js +68 -23
  73. package/dist/components/hooks/AnimationHook.js +1 -1
  74. package/dist/components/hooks/CanvasFillHook.d.ts +12 -0
  75. package/dist/components/hooks/CanvasFillHook.js +75 -0
  76. package/dist/components/hooks/DeterministicMediaFrameHook.js +3 -0
  77. package/dist/components/hooks/HtmlTextHook.js +11 -3
  78. package/dist/components/hooks/HtmlToCanvasHook.js +8 -25
  79. package/dist/components/hooks/MediaHook.js +172 -47
  80. package/dist/components/hooks/MediaSeekingHook.js +138 -88
  81. package/dist/components/hooks/PixiGifHook.js +4 -4
  82. package/dist/components/hooks/PixiSplitScreenDisplayObjectHook.js +73 -6
  83. package/dist/components/hooks/PixiVideoTextureHook.js +10 -4
  84. package/dist/components/hooks/PixiVisualTransformHook.d.ts +16 -0
  85. package/dist/components/hooks/PixiVisualTransformHook.js +102 -0
  86. package/dist/components/hooks/SubtitlesHook.js +48 -24
  87. package/dist/components/hooks/VerifyMediaHook.js +2 -2
  88. package/dist/directors/ComponentDirector.d.ts +1 -0
  89. package/dist/directors/ComponentDirector.js +41 -8
  90. package/dist/fonts/fontDiscovery.js +12 -1
  91. package/dist/layers/Layer.svelte.d.ts +54 -0
  92. package/dist/layers/Layer.svelte.js +2 -25
  93. package/dist/managers/AppManager.svelte.js +8 -5
  94. package/dist/managers/ComponentsManager.svelte.d.ts +7 -7
  95. package/dist/managers/ComponentsManager.svelte.js +29 -15
  96. package/dist/managers/DeterministicMediaManager.js +38 -3
  97. package/dist/managers/EventManager.js +3 -1
  98. package/dist/managers/LayersManager.svelte.d.ts +54 -0
  99. package/dist/managers/RenderManager.d.ts +5 -0
  100. package/dist/managers/RenderManager.js +67 -21
  101. package/dist/managers/StateManager.svelte.d.ts +56 -0
  102. package/dist/managers/StateManager.svelte.js +60 -58
  103. package/dist/managers/SubtitlesManager.svelte.js +1 -3
  104. package/dist/managers/TimeManager.svelte.d.ts +4 -0
  105. package/dist/managers/TimeManager.svelte.js +23 -7
  106. package/dist/schemas/runtime/deterministic.js +5 -1
  107. package/dist/schemas/runtime/types.d.ts +36 -15
  108. package/dist/schemas/scene/components.d.ts +126 -0
  109. package/dist/schemas/scene/components.js +11 -0
  110. package/dist/schemas/scene/core.d.ts +109 -10
  111. package/dist/schemas/scene/core.js +1 -1
  112. package/dist/utils/mediaWindow.d.ts +13 -0
  113. package/dist/utils/mediaWindow.js +25 -0
  114. package/dist/utils/svgGenerator.js +1 -1
  115. package/dist/utils/timelineWindow.d.ts +2 -0
  116. package/dist/utils/timelineWindow.js +7 -0
  117. package/dist/utils/utils.js +2 -4
  118. package/docs/AGENT_PATTERNS.md +243 -0
  119. package/docs/AGENT_WORKFLOW.md +364 -0
  120. package/docs/AUTHORING_BEST_PRACTICES.md +188 -0
  121. package/docs/AUTHORING_SYSTEM_AUDIT.md +98 -0
  122. package/docs/BROWSER_EXPORT_SPIKE.md +55 -0
  123. package/docs/DETERMINISTIC_RENDERER.md +83 -0
  124. package/docs/NEXT_RELEASE.md +28 -0
  125. package/docs/PROPOSED_VISUALFRIES_SKILL.md +68 -0
  126. package/docs/examples/agent-cues.json +49 -0
  127. package/docs/examples/agent-transcript.json +23 -0
  128. package/docs/examples/agent-transcript.srt +7 -0
  129. package/docs/examples/agent-transcript.vtt +7 -0
  130. package/docs/examples/image-animation.json +87 -0
  131. package/docs/examples/native-text-metric-badge.json +109 -0
  132. package/package.json +133 -100
  133. package/skills/visualfries/SKILL.md +328 -0
@@ -0,0 +1,364 @@
1
+ # VisualFries Agent Workflow
2
+
3
+ This document defines the agent-facing contract for VisualFries.
4
+
5
+ Read [Authoring Best Practices](AUTHORING_BEST_PRACTICES.md) before authoring. It defines the
6
+ native semantic component policy, runtime support matrix, effect/compositing limits, and required
7
+ entry/settled/exit/reseek frame QA. Validation and inspection are structural gates, not rendering
8
+ proof.
9
+
10
+ ## Goal
11
+
12
+ Make VisualFries usable by agents without requiring the ContentFries UI:
13
+
14
+ 1. create render-ready scene JSON,
15
+ 2. add captions from transcripts,
16
+ 3. validate and inspect scenes,
17
+ 4. render fast QA previews through the CLI browser adapter,
18
+ 5. hand final VIDEO/GIF scenes to the local deterministic renderer path.
19
+
20
+ ## CLI
21
+
22
+ ```bash
23
+ visualfries validate <scene.json> [--json]
24
+ visualfries inspect <scene.json> [--json] [--screenshots --output <dir>]
25
+ visualfries init <dir> [--video <video> --transcript <file>]
26
+ visualfries caption-scene --video <video> --transcript <file> --output <scene.json>
27
+ visualfries preset-cues --duration <seconds> --output <cues.json>
28
+ visualfries validate-cues <cues.json> [--duration <seconds>] [--json]
29
+ visualfries apply-cues <scene.json> --cues <cues.json> --output <scene.json>
30
+ visualfries qa <scene.json> --output <dir>
31
+ visualfries compose --video <video> --transcript <file> --output <out.mp4>
32
+ visualfries produce <production-plan.json> --output <out.mp4> --scene-output <scene.json> --qa-output <dir>
33
+ visualfries render <scene.json> --output <out.mp4|frames-dir> [--frames-only]
34
+ visualfries catalog [--json]
35
+ visualfries doctor [--json]
36
+ ```
37
+
38
+ Use `produce` for authored edits that need more than captions plus generic cues. A production plan groups the edit into named beats and supports source trims, automatic video freeze-frame holds, native TEXT editorial overlays, exact multi-track audio, transitions, and QA frames. Visible typography compiles to native TEXT by default. `renderAs: "SVG"` is an explicit compatibility fallback for a documented native limitation. The command emits ordinary VisualFries scene JSON, renders at timeline event boundaries, then checks the finished audio lead-in.
39
+
40
+ ```json
41
+ {
42
+ "version": 1,
43
+ "id": "proof-hook",
44
+ "settings": { "width": 1080, "height": 1920, "duration": 6, "fps": 30 },
45
+ "beats": [
46
+ {
47
+ "id": "reaction",
48
+ "start": 0,
49
+ "end": 3,
50
+ "media": [
51
+ { "id": "reaction", "url": "./reaction.mp4", "start": 0, "end": 3, "freezeAt": 1.8 }
52
+ ],
53
+ "overlays": [{ "text": "NOT DEAD.", "start": 1.8, "end": 3, "style": "verdict-slam" }]
54
+ }
55
+ ],
56
+ "audio": [{ "id": "voice", "url": "./voice.wav", "startAt": 0, "volume": 1 }],
57
+ "transitions": [{ "time": 3, "style": "focus-pull" }],
58
+ "qa": { "framesAt": [0.1, 1.9, 3.1], "maxLeadingSilence": 0.1, "requiredText": ["NOT DEAD."] }
59
+ }
60
+ ```
61
+
62
+ ```bash
63
+ visualfries produce ./production-plan.json \
64
+ --scene-output ./scene.json \
65
+ --qa-output ./qa \
66
+ --output ./final.mp4
67
+ ```
68
+
69
+ `render` uses a controlled Vite browser page, Playwright, and `ffmpeg` for static scenes and fast previews. It never requires opening ContentFries UI.
70
+
71
+ Important render contract:
72
+
73
+ - `--render-mode final` is the default.
74
+ - Final scenes with `VIDEO` or `GIF` components require the local deterministic renderer. Native browser media seek is not trusted for final output because it can create stale, duplicated, or shifted frames.
75
+ - Use `--render-mode preview` for quick QA frames or rough local checks.
76
+ - `--allow-browser-media-final` exists only as an escape hatch for experiments. Do not use it for shipped output.
77
+ - In final mode, the CLI predecodes active `VIDEO`/`GIF` ranges to exact frame images and injects a deterministic media provider into the render page.
78
+
79
+ Useful render options:
80
+
81
+ - `--frames-only` renders a PNG frame sequence for QA instead of MP4.
82
+ - `--render-mode preview` permits the browser preview path for VIDEO/GIF scenes.
83
+ - `--engine browser-preview` or `--engine deterministic-local` can force renderer planning when debugging.
84
+ - `--from-frame <n>` and `--to-frame <n>` render a partial range for fast checks.
85
+ - Full contiguous renders use the browser-side `renderFrameRange()` path, avoiding one Playwright round trip per frame.
86
+ - `--stream-encode` pipes rendered frames directly into local `ffmpeg` with `image2pipe`. Prefer it for final contiguous MP4 renders once QA frames look right.
87
+ - `--skip-duplicates` asks VisualFries deterministic dirty checking to reuse unchanged frames when possible.
88
+ - `--fps <number>` overrides scene FPS.
89
+ - `--audio <path|none>` overrides automatic audio mapping from the local scene audio mix.
90
+ - Without `--audio`, final contiguous renders build a local mixed audio track from active VIDEO/AUDIO components, `audioTracks`, and `settings.audio`.
91
+ - `VISUALFRIES_NODE_MODULES=/path/to/node_modules` lets agents point the CLI at an existing Playwright install.
92
+ - `doctor --json` checks ffmpeg, Vite, Svelte Vite plugin, Playwright, Chromium, and temp directory resolution before an agent starts a render.
93
+ - `catalog --json` lists supported caption presets, cue presets, overlay styles, b-roll motions, transitions, transcript formats, and CLI commands.
94
+ - `validate-cues --json` checks cue file shape, known styles/motions/transitions, and timing before an agent applies cues.
95
+ - `qa` writes `inspect.json`, `screenshots.json`, and sampled `frames/` into one QA directory.
96
+
97
+ Use `init` to create a self-contained agent working directory:
98
+
99
+ ```bash
100
+ visualfries init ./video-package \
101
+ --video ./input.mp4 \
102
+ --transcript ./transcript.srt \
103
+ --preset hidden-engine-center \
104
+ --cue-preset hidden-engine-dynamic
105
+ ```
106
+
107
+ It creates `scene.json`, `cues.json`, `assets/`, `qa/frames/`, `qa/inspect.json`, `notes.md`, and transcript examples. `cues.json` is generated from the selected cue preset and can be edited before compose/render.
108
+
109
+ Use `compose` when an agent should prepare the scene and, for now, produce a preview MP4 in one command:
110
+
111
+ ```bash
112
+ visualfries compose \
113
+ --video ./input.mp4 \
114
+ --transcript ./transcript.srt \
115
+ --cue-preset hidden-engine-dynamic \
116
+ --cues ./cues.json \
117
+ --scene-output ./scene.json \
118
+ --qa-output ./qa/frames \
119
+ --render-mode preview \
120
+ --output ./out.mp4
121
+ ```
122
+
123
+ `compose` runs the same underlying pipeline as the step-by-step workflow:
124
+
125
+ ```text
126
+ caption-scene -> optional cue preset -> optional cue file -> inspect -> optional QA screenshots -> render
127
+ ```
128
+
129
+ Use `apply-cues` when an agent has already planned the visual timeline:
130
+
131
+ ```bash
132
+ visualfries preset-cues --duration 45 \
133
+ --preset hidden-engine-dynamic \
134
+ --output ./cues.json
135
+
136
+ visualfries apply-cues ./scene.json \
137
+ --cues ./cues.json \
138
+ --output ./scene.with-cues.json
139
+ ```
140
+
141
+ Cue files can contain `broll`, `overlays`, and `transitions` arrays:
142
+
143
+ ```json
144
+ {
145
+ "broll": [
146
+ { "url": "./assets/profile.mp4", "start": 2, "end": 5, "type": "VIDEO" },
147
+ { "url": "./assets/chart.png", "start": 5, "end": 7, "type": "IMAGE", "motion": "slow-zoom-in" }
148
+ ],
149
+ "overlays": [
150
+ { "text": "LOVE THIS 😍", "start": 0.4, "end": 1.1, "style": "hook-punch" },
151
+ { "text": "NECK 🤯", "start": 1.1, "end": 1.7, "style": "shock-word" }
152
+ ],
153
+ "transitions": [
154
+ { "time": 2, "style": "dip-to-black" },
155
+ { "time": 5, "style": "swipe-left", "color": "#04483D" }
156
+ ]
157
+ }
158
+ ```
159
+
160
+ Relative b-roll URLs are resolved relative to the cue file path, so an agent package can keep cues and assets together.
161
+
162
+ `preset-cues` creates a valid starter cue file. It is not meant to replace creative judgment; agents should replace placeholder overlay text and add b-roll paths before the final render.
163
+
164
+ ## Node API
165
+
166
+ Use the agent-only subpath for automations and CLIs:
167
+
168
+ ```ts
169
+ import { createCaptionScene, inspectScene, normalizeTranscript } from 'visualfries/agent';
170
+ ```
171
+
172
+ The root `visualfries` export includes the full library surface. Agents should use `visualfries/agent` for captioning and inspection because it avoids browser/Svelte runtime imports.
173
+
174
+ Renderer planning is also agent-safe:
175
+
176
+ ```ts
177
+ import { resolveAgentRenderPlan, requiresDeterministicRender } from 'visualfries/agent';
178
+
179
+ const plan = resolveAgentRenderPlan(scene, { mode: 'final' });
180
+
181
+ if (requiresDeterministicRender(scene)) {
182
+ // Final output needs local deterministic media predecode, not browser video seek.
183
+ }
184
+ ```
185
+
186
+ For short-form overlays:
187
+
188
+ ```ts
189
+ import {
190
+ addAgentBrollSequence,
191
+ addAgentTextOverlays,
192
+ addAgentTransitions
193
+ } from 'visualfries/agent';
194
+
195
+ const sceneWithOverlays = addAgentTextOverlays({
196
+ scene,
197
+ overlays: [
198
+ { text: 'LOVE THIS 😍', start: 0.4, end: 1.1, style: 'pop-label' },
199
+ { text: 'NECK 🤯', start: 1.1, end: 1.7, style: 'shock-word' }
200
+ ]
201
+ });
202
+
203
+ const sceneWithBroll = addAgentBrollSequence({
204
+ scene,
205
+ cues: [
206
+ { url: './broll/profile.mp4', start: 2.0, end: 5.0, type: 'VIDEO' },
207
+ { url: './broll/chart.png', start: 5.0, end: 7.0, type: 'IMAGE', motion: 'slow-zoom-in' }
208
+ ]
209
+ });
210
+
211
+ const sceneWithTransitions = addAgentTransitions({
212
+ scene,
213
+ transitions: [
214
+ { time: 2.0, style: 'dip-to-black' },
215
+ { time: 5.0, style: 'swipe-left', color: '#04483D' }
216
+ ]
217
+ });
218
+ ```
219
+
220
+ ### `caption-scene`
221
+
222
+ Creates a vertical 9:16 scene with:
223
+
224
+ - full-frame video component,
225
+ - subtitle component,
226
+ - scene asset registry,
227
+ - `settings.subtitles.data` populated from transcript JSON.
228
+
229
+ Example:
230
+
231
+ ```bash
232
+ visualfries caption-scene \
233
+ --video ./input.mp4 \
234
+ --transcript ./transcript.json \
235
+ --preset hidden-engine-center \
236
+ --output ./scene.json
237
+ ```
238
+
239
+ Accepted transcript shapes:
240
+
241
+ Plain subtitle files:
242
+
243
+ ```bash
244
+ visualfries caption-scene \
245
+ --video ./input.mp4 \
246
+ --transcript ./captions.srt \
247
+ --preset hidden-engine-center \
248
+ --output ./scene.json
249
+ ```
250
+
251
+ Supported subtitle file formats:
252
+
253
+ - `.srt`
254
+ - `.vtt`
255
+
256
+ Structured JSON:
257
+
258
+ ```json
259
+ {
260
+ "segments": [
261
+ {
262
+ "text": "The best content asset is not always a post.",
263
+ "start": 0,
264
+ "end": 2.4,
265
+ "words": [{ "text": "The", "start": 0, "end": 0.12 }]
266
+ }
267
+ ]
268
+ }
269
+ ```
270
+
271
+ ```json
272
+ {
273
+ "words": [
274
+ { "text": "The", "start": 0, "end": 0.12 },
275
+ { "text": "best", "start": 0.12, "end": 0.35 }
276
+ ]
277
+ }
278
+ ```
279
+
280
+ ## Presets
281
+
282
+ Initial caption presets:
283
+
284
+ - `reels-center`
285
+ - `reels-lower`
286
+ - `podcast-clean`
287
+ - `hidden-engine-center`
288
+
289
+ Initial agent overlay styles:
290
+
291
+ - `pop-label` for quick reaction labels above/below captions.
292
+ - `shock-word` for large emphatic keyword reveals.
293
+ - `soft-card` for calmer proof/context callouts.
294
+ - `hook-punch` for the first loud hook label.
295
+ - `proof-pill` for compact proof/credibility beats.
296
+ - `metric-badge` for big numbers and business proof.
297
+ - `danger-crossout` for wrong-path / negative beats.
298
+ - `cta-card` for final choice/question cards.
299
+
300
+ Initial agent b-roll helper:
301
+
302
+ - `addAgentBrollSequence` for timed portrait video/image/GIF cues below captions and overlays.
303
+ - Image cues default to subtle `slow-zoom-in`; use `motion: 'none' | 'slow-zoom-in' | 'slow-zoom-out' | 'drift-up'`.
304
+
305
+ Initial agent transition helper:
306
+
307
+ - `addAgentTransitions` for fast full-frame transition covers at exact beat times.
308
+ - Transition helper covers use animated native SHAPE rectangles.
309
+ - Supported styles: `dip-to-black`, `flash`, `swipe-left`, `swipe-up`.
310
+
311
+ Overlay rules:
312
+
313
+ - Keep the center caption lane free unless the overlay replaces captions for that moment.
314
+ - Use one overlay idea per beat. Split “LOVE THIS” and “NECK” into separate timed cues.
315
+ - Prefer 0.4-1.4 second overlay durations. Longer overlays start feeling like static slides.
316
+ - Render 1-3 QA frames before MP4 encode when a new overlay style is used.
317
+
318
+ See [AGENT_PATTERNS.md](AGENT_PATTERNS.md) for repeatable caption, overlay, b-roll, and QA patterns.
319
+
320
+ ## Quality Gates
321
+
322
+ Before a scene is accepted:
323
+
324
+ ```bash
325
+ visualfries validate scene.json
326
+ visualfries inspect scene.json --json
327
+ visualfries inspect scene.json --screenshots --samples 3 --output ./qa/frames --json
328
+ ```
329
+
330
+ `inspect` checks schema validity, timeline bounds, missing assets, and subtitle data anchors. With `--screenshots`, it also renders sampled QA frames and returns their paths in the JSON report.
331
+
332
+ Before publishing a rendered video:
333
+
334
+ ```bash
335
+ visualfries inspect scene.json --screenshots --samples 3 --output ./qa-frames --json
336
+ visualfries render scene.json --output ./out.mp4
337
+ ffprobe -v error -show_entries stream=codec_type,width,height -of json ./out.mp4
338
+ ```
339
+
340
+ For static-heavy scenes, proof screenshots, and overlay sections, the faster render path is:
341
+
342
+ ```bash
343
+ visualfries render scene.json --output ./out.mp4 --skip-duplicates
344
+ ```
345
+
346
+ Do not use `--skip-duplicates` blindly on complex video-heavy scenes until QA frames look correct.
347
+
348
+ ## Complete Agent Production Path
349
+
350
+ VisualFries uses these layers for complete agent-driven production:
351
+
352
+ 1. CLI scene creation and validation. Done.
353
+ 2. Caption scene generator. Done.
354
+ 3. Renderer adapter: `visualfries render scene.json --output out.mp4`. Done for local browser + ffmpeg rendering.
355
+ 4. Agent text overlay cues. Done for initial pop/shock/card styles.
356
+ 5. Screenshot inspect: `visualfries inspect scene.json --screenshots`. Done.
357
+ 6. Agent project scaffold: `visualfries init <dir>`. Done.
358
+ 7. Pattern registry for transitions and b-roll layouts. Initial b-roll sequence helper, image motion, transition helper, and cookbook done.
359
+ 8. Cue-file CLI application for b-roll/overlays/transitions. Done.
360
+ 9. Starter cue presets: `visualfries preset-cues`. Done for `hidden-engine-dynamic` and `captioned-clean`.
361
+ 10. One-command agent compose workflow: `visualfries compose`. Done.
362
+ 11. Skill/cookbook examples for common agent jobs.
363
+
364
+ The current implementation supports caption-scene creation, validation, inspection, QA frame rendering, MP4 rendering, b-roll cues, text overlays, simple transition cues, cue-file application from the CLI, starter cue presets, and one-command compose.
@@ -0,0 +1,188 @@
1
+ # VisualFries Authoring Best Practices
2
+
3
+ VisualFries is an authoring system, not only a schema. A scene is correct only when its semantic components survive validation, runtime evaluation, frame QA, and final rendering.
4
+
5
+ ## Default workflow
6
+
7
+ ```text
8
+ inspect inputs and runtime
9
+ -> choose native semantic components
10
+ -> author scene
11
+ -> validate + inspect structure
12
+ -> frame-QA entry, settled, and exit states
13
+ -> reseek the same frames
14
+ -> render with the deterministic final path
15
+ ```
16
+
17
+ Validation proves shape. `inspect` proves structural references and timing. Neither proves that a renderer evaluates an animation or effect.
18
+
19
+ ## Component decision tree
20
+
21
+ 1. Is the visible content typography?
22
+ - Use `TEXT` for headings, metrics, labels, badges, cards, verdicts, CTAs, and other editable words.
23
+ - Use `SUBTITLES` when typography follows transcript timing.
24
+ 2. Is it a photo, screenshot, logo, illustration, or supplied bitmap/vector asset?
25
+ - Use `IMAGE` (`GIF` for animated image assets).
26
+ 3. Is it moving footage or sound?
27
+ - Use `VIDEO` or `AUDIO`.
28
+ 4. Is it independent geometry, decoration, progress, a mask-like layout element, or a transition cover?
29
+ - Use `SHAPE`.
30
+ 5. Does typography require a treatment that native `TEXT` cannot render?
31
+ - Rasterization is an explicit fallback. Record the missing native capability and frame-QA the result. Do not rasterize typography merely for convenience.
32
+
33
+ ## Native TEXT is mandatory by default
34
+
35
+ Use one `TEXT` component for a normal metric badge such as `881 VIEWS`. It owns its text, background, radius, alignment, outline, shadow, and animation.
36
+
37
+ Good:
38
+
39
+ ```json
40
+ {
41
+ "id": "views-badge",
42
+ "type": "TEXT",
43
+ "text": "881 VIEWS",
44
+ "timeline": { "startAt": 0.2, "endAt": 2.8 },
45
+ "order": 10,
46
+ "appearance": {
47
+ "x": 90,
48
+ "y": 150,
49
+ "width": 420,
50
+ "height": 132,
51
+ "horizontalAlign": "center",
52
+ "verticalAlign": "center",
53
+ "background": {
54
+ "enabled": true,
55
+ "color": "#F5D547",
56
+ "target": "wrapper",
57
+ "radius": 24
58
+ },
59
+ "text": {
60
+ "fontFamily": "Montserrat",
61
+ "fontSize": { "value": 72, "unit": "px" },
62
+ "fontWeight": "900",
63
+ "color": "#101820",
64
+ "textAlign": "center",
65
+ "outline": { "enabled": true, "color": "#FFFFFF", "size": 2 },
66
+ "shadow": {
67
+ "enabled": true,
68
+ "color": "#000000",
69
+ "blur": 12,
70
+ "offsetX": 0,
71
+ "offsetY": 4,
72
+ "opacity": 0.55
73
+ }
74
+ }
75
+ }
76
+ }
77
+ ```
78
+
79
+ Bad:
80
+
81
+ - `881 VIEWS.png` as a full-card `IMAGE`.
82
+ - A rectangle `SHAPE` whose only purpose is to sit behind ordinary `TEXT`.
83
+ - SVG typography generated by a production plan without an explicit native limitation.
84
+ - Assuming schema-valid `clipColor`, dashed outline, or a generic blur must render.
85
+
86
+ A separate `SHAPE` is justified when geometry needs independent timing, motion, progress behavior, or decoration. It is not the default badge background.
87
+
88
+ Directly authored transition geometry is `SHAPE`. `addAgentTransitions` now emits a full-frame animated rectangle rather than the former empty-TEXT compatibility cover.
89
+
90
+ Complete example: [`examples/native-text-metric-badge.json`](examples/native-text-metric-badge.json).
91
+
92
+ ## TEXT rendering and compositing
93
+
94
+ `TEXT` uses a wrapper plus an inner text element.
95
+
96
+ - `appearance.background.target: "wrapper"` fills the fixed component box. Use this for badges/cards and for gradient text on a background.
97
+ - `appearance.background.target: "element"` hugs the glyph block and receives legacy `0.22em` padding only when explicit padding is absent.
98
+ - `appearance.text.padding` accepts a non-negative pixel number or `{ top, right, bottom, left }`.
99
+ - `appearance.background.radius` is in pixels.
100
+ - `appearance.text.color` accepts solid colors or gradients. Gradient glyphs use CSS background clipping.
101
+ - `appearance.background.color` accepts solid colors or gradients.
102
+ - Avoid gradient glyphs plus an element-target background: both compete for the inner element's CSS background. Use a wrapper background.
103
+ - Structured outline uses pixel width. Only solid outline is rendered; `dashed`, `dotted`, and `dashArray` remain validation-only.
104
+ - Structured shadow renders color, opacity, x/y offsets, and blur. Legacy named shadow presets remain separate behavior.
105
+ - Wrapper-background TEXT animations target the wrapper, so background and glyph enter together.
106
+ - Plain `TEXT` can target `words`, `lines`, or `chars` through SplitText animations. Transcript-timed active-word behavior belongs on `SUBTITLES`; plain TEXT has no typed word-timing authoring field.
107
+ - `activeWord` and `activeLine` support color/background/weight/scale. `highlightColors` cycles solid colors by active index. If both modes are enabled, `activeWord` wins and validation reports the conflict.
108
+ - Gradient entries in `highlightColors` are diagnosed as unsupported.
109
+ - `clipColor` has no defined runtime semantics. Runtime-aware validation warns before permissive nested parsing can strip it; strict mode rejects it.
110
+
111
+ Browser preview keeps TEXT as HTML above the Pixi canvas. Server/final rendering rasterizes TEXT into Pixi. Risky cross-type stacking and CSS effects require final-render frame QA because preview and final compositing can differ.
112
+
113
+ ## Animation contract
114
+
115
+ Runtime-confirmed component animation support:
116
+
117
+ | Component | Animation status | Notes |
118
+ | ------------------- | --------------------- | -------------------------------------------------------------------------------------------- |
119
+ | `TEXT` | Supported | Element or wrapper target; words/lines/chars available. |
120
+ | `SUBTITLES` | Supported with limits | Cue timing works; advanced `out` anchors need visual QA. |
121
+ | `IMAGE` | Supported | Shared Pixi target: relative x/y offsets, opacity, degree rotation, uniform and axis scales. |
122
+ | `VIDEO` | Supported transforms | Same Pixi contract; playback-rate/loop parity remains limited. |
123
+ | `GIF` | Supported transforms | Same Pixi contract; native/final GIF timing parity remains limited. |
124
+ | `SHAPE` | Supported | Regular and progress shapes use a stable outer Pixi target. |
125
+ | `COLOR`, `GRADIENT` | Supported | Canvas fill rendered into Pixi, then the shared transform target. |
126
+ | `AUDIO` | Not applicable | AUDIO has no visual animation target. |
127
+
128
+ For Pixi visuals, animation `x` and `y` are translation offsets relative to authored placement. Pivot/transform origin is fixed at the component center and is not author-configurable. This matches TEXT translation semantics and keeps swipe/drift helpers coherent.
129
+
130
+ Animation rules:
131
+
132
+ - `component.timeline.startAt` offsets the component timeline.
133
+ - Animation-entry `startAt` is relative to component start.
134
+ - `enabled: false` entries do not run.
135
+ - Prefer frame-index-derived times (`frame / fps`) for deterministic QA.
136
+ - For each animation, inspect pre-entry, first-active/mid-entry, settled, and exit frames.
137
+ - Seek forward, backward, and back to the same frame. Same frame must reproduce the same transform/pixels.
138
+ - Destroy/rebuild tests matter; teardown must revert and kill GSAP timelines.
139
+ - SplitText selectors (`words`, `lines`, `chars`, CSS selectors) are TEXT-only. Runtime-aware validation warns (or errors in strict mode) instead of treating Pixi root fallback as support.
140
+ - Animation `setup` steps and `alignTween: "end"|"center"` are not production-safe yet.
141
+
142
+ Complete IMAGE example: [`examples/image-animation.json`](examples/image-animation.json).
143
+
144
+ ## Effects and renderer truth
145
+
146
+ Confirmed:
147
+
148
+ - TEXT: structured shadow and solid outline.
149
+ - IMAGE/VIDEO: `layoutSplit` and `fillBackgroundBlur` through the Pixi split-screen path.
150
+ - SHAPE: basic canvas/Pixi geometry and progress shapes.
151
+
152
+ Validation-only or incomplete:
153
+
154
+ - Generic `blur`, `colorAdjustment`, and `rotationRandomizer` are not generally attached to renderers.
155
+ - SHAPE rectangle `cornerRadius` and gradient fill require explicit rendered verification; do not treat schema acceptance as support.
156
+ - Agent transition helpers emit native animated SHAPE rectangles.
157
+ - Same-layer component stacking uses `component.order` (higher order renders later/on top after synchronization). Higher layer order renders above lower layer order in final Pixi composition.
158
+
159
+ ## QA checklist
160
+
161
+ ```bash
162
+ visualfries doctor --json
163
+ visualfries catalog --component TEXT --capabilities --json
164
+ visualfries validate scene.json --strict-runtime-support
165
+ visualfries inspect scene.json --json
166
+ visualfries explain scene.json --component views-badge --frame 12 --json
167
+ visualfries parity scene.json --frames 5,12,35 --output qa/parity --json
168
+
169
+ # Render explicit frame windows around authored events.
170
+ visualfries render scene.json --frames-only --from-frame 5 --to-frame 20 --output qa/entry
171
+ visualfries render scene.json --frames-only --from-frame 35 --to-frame 36 --output qa/settled
172
+
173
+ # Final VIDEO/GIF scenes use deterministic-local rendering.
174
+ visualfries render scene.json --stream-encode --output out.mp4
175
+ ```
176
+
177
+ Uniform three-frame sampling can miss a late or short entrance. Production plans should declare exact `qa.framesAt`; raw scenes should render explicit frame ranges.
178
+
179
+ `parity` captures actual client composition and final server composition, records SHA-256 plus raw and semantic ffmpeg SSIM, evaluates optional class/ROI thresholds from `--rois`, and renders every requested frame forward then backward. It also writes 4× amplified diff rows and a contact sheet. Add `--strict` for CI. The torture-scene baseline passes with zero runtime/resource errors; raw GIF/video decoder noise remains visible and is reported separately from semantic mismatch.
180
+
181
+ ## Known open limitations
182
+
183
+ - Visual transform origin is fixed center for Pixi targets; TEXT uses CSS transform ownership. No authorable cross-renderer origin exists.
184
+ - Browser HTML TEXT versus final Pixi TEXT can produce cross-type stacking differences.
185
+ - `clipColor`, gradient highlight palettes, dashed/dotted outline, generic effects, and animation setup steps are unsupported.
186
+ - Native GIF timing and VIDEO/GIF playback controls are not yet preview/final parity guarantees.
187
+ - `componentCenter` and advanced out/align anchors have timing limitations.
188
+ - Radial GRADIENT shape/position currently uses a centered max-radius fallback.
@@ -0,0 +1,98 @@
1
+ # VisualFries Authoring System Audit
2
+
3
+ Date: 2026-07-12
4
+
5
+ Scope: schema/runtime truth, semantic component selection, visual animation, TEXT compositing, agent diagnostics, preview/final parity, and real frame QA. The current repo is authoritative. The browser/WebGL/MediaBunny worktree was evidence only; browser export was not blindly ported.
6
+
7
+ ## Findings, evidence, disposition
8
+
9
+ | Severity | Finding | Evidence | Disposition |
10
+ | -------- | ------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
11
+ | Critical | Schema accepted animation data for every component although construction attached `AnimationHook` only to TEXT/SUBTITLES/IMAGE. | Base component schema versus `ComponentDirector`; browser regression from the Funeral short. | Fixed for every visual type through a shared Pixi wrapper target; AUDIO remains explicitly nonvisual. Registry/director synchronization tests prevent silent drift. |
12
+ | Critical | COLOR and GRADIENT validated but had no render hook. | `ComponentDirector` returned bare components. | Fixed with canvas fills, Pixi texture/display construction, shared animation target, tests, and frame-QA scene coverage. |
13
+ | High | IMAGE x/y bridge used absolute-center semantics that contradicted TEXT and authored drift/swipe helpers. | `PixiAnimationTarget`, b-roll helpers, transition helpers. | Fixed: all Pixi x/y are placement-relative offsets around a fixed-center outer wrapper. Migration note added. |
14
+ | High | Unsupported runtime fields could validate silently. | Base animation catchalls, permissive nested TEXT parsing, effect schemas. | Fixed materially: capability registry, default warnings, strict runtime-support gate, property/selector/effect/text conflict diagnostics, and pre-parse clipColor detection. Unknown string presets still need deeper static resolution. |
15
+ | High | Production-plan visible typography defaulted to raster/SVG. | Overlay schema/compiler. | Fixed: native TEXT is default; SVG remains explicit documented fallback. |
16
+ | High | Transition helpers used empty TEXT as full-frame geometry. | Agent transition helper and regressions. | Fixed: helpers now emit animated native SHAPE rectangles. |
17
+ | High | Browser HTML TEXT and final Pixi-rasterized TEXT do not share one stacking representation. | `DomManager`, `HtmlTextHook`, `HtmlToCanvasHook`. | Calibrated parity now passes for supported stacking in the torture scene. Arbitrary HTML/Pixi cross-layer interleaving remains an explicit architectural limitation. |
18
+ | Critical | Generated browser harness replaced EventEmitter3 with a shim that discarded listener context, breaking Pixi WebGL prerender and texture updates. | Browser stacks at `BatchRenderer.onPrerender` (`_flushId`) and `Texture.onBaseTextureUpdated` (`noFrame`). | Fixed with a context/once/removal-compatible shim and regression. Browser IMAGE/VIDEO/GIF/SHAPE/COLOR/GRADIENT now render with zero runtime errors. |
19
+ | High | Client seek returned before its asynchronous render and newly attached animation timelines settled. | `TimelineManager.seek`, `RenderManager` queue, sparse browser captures. | Fixed: both renderer paths now render, re-seek after lazy construction, render again, and the harness performs an initialized seek barrier. |
20
+ | High | Preview and final used different hard-coded canvas backgrounds and ignored scene background. | `AppManager` renderer options. | Fixed: both paths use the solid scene background contract; gradient scene backgrounds still require a GRADIENT component. |
21
+ | Medium | Unconfigured system fonts were treated as Google Fonts, creating CORS failures and nondeterministic fallback noise. | Font discovery and SVG text generation. | Fixed: remote font loading is explicit; unconfigured Arial/system families stay local. |
22
+ | Medium | TEXT padding, active scale, and highlight palette fields were absent/ignored. | TEXT schema/builders/highlighter builders. | Fixed: px padding, active word/line scale, solid palette cycling, reset coverage, and deterministic active-word precedence. |
23
+ | Medium | Active-line reset restored background styling instead of glyph color. | `LineHighlighterAnimationBuilder`. | Fixed and asserted explicitly. |
24
+ | Medium | `clipColor` was silently stripped by permissive nested parsing and had no defined semantics. | Runtime/schema search plus parse behavior. | Not invented. Warned by default, rejected by strict gate, documented as open semantic design. |
25
+ | Medium | `visible: false` became true in component state. | Truthy fallback in `_ComponentState`. | Fixed with nullish default and shared wrapper visibility enforcement. |
26
+ | Medium | Same-layer order, component teardown, structured shadow/outline, wrapper transform ownership, and radius units had confirmed defects. | Prior audit source/render tests. | Fixed in the current uncommitted audit set with regression coverage. |
27
+ | High | Scene teardown destroyed Pixi before async component hooks completed, while manager listeners could not be removed by identity. | `SceneBuilder.destroy`, `ComponentsManager.destroy`, `EventManager.on`, `RenderManager`. | Fixed: component/media teardown is awaited before Pixi/DOM destruction; registered callback identities are detached and covered by lifecycle regressions. |
28
+
29
+ ## Runtime truth
30
+
31
+ - TEXT/SUBTITLES: HTML animation target; TEXT selectors include container, words, lines, chars, and CSS.
32
+ - IMAGE/VIDEO/GIF/SHAPE/COLOR/GRADIENT: stable outer Pixi target with relative x/y, opacity, degree rotation, scale, scaleX, and scaleY. Pixi selectors support container only.
33
+ - AUDIO: no visual target and no visual animation claim.
34
+ - Visual timing is component-relative; disabled global/list entries do not evaluate; destroy reverts/kills timelines.
35
+ - Pixi transform origin is fixed component center and not authorable.
36
+ - COLOR supports CSS-color canvas fill including alpha. GRADIENT supports linear/radial canvas fills; radial shape/position currently falls back to centered max radius.
37
+
38
+ ## TEXT/compositing truth
39
+
40
+ - Paint/style merge order is component background, glyph fill/gradient, then text effects. Active highlight background is a separate element behind split glyphs.
41
+ - Wrapper-target background is preferred for badges/cards and required when both background and glyph are gradients.
42
+ - Element-target gradient background plus gradient glyph fill is diagnosed because both use `background-image` on the inner element.
43
+ - Pixel padding is authorable through `appearance.text.padding`; absent element-target padding keeps the prior `0.22em` fallback.
44
+ - Active word/line scale and solid `highlightColors` work. Active word takes precedence if both modes are enabled. Gradient highlight palettes remain unsupported.
45
+ - Structured solid outline and structured shadow work. Dashed/dotted outline and generic effects remain unsupported/incomplete.
46
+
47
+ ## Agent contract
48
+
49
+ ```bash
50
+ visualfries catalog --component TEXT --capabilities --json
51
+ visualfries validate scene.json # compatible load + explicit warnings
52
+ visualfries validate scene.json --strict-runtime-support
53
+ visualfries inspect scene.json --json
54
+ visualfries explain scene.json --component <id> --frame <n> --json
55
+ ```
56
+
57
+ `explain` seeks the actual browser runtime and reads the chosen HTML/Pixi target; it does not approximate easing in a separate static evaluator.
58
+
59
+ ## Verification state
60
+
61
+ - `pnpm exec vitest run`: 64/64 files, 439/439 tests passed.
62
+ - `pnpm run check`: 0 errors; 8 pre-existing docs/accessibility/CSS warnings.
63
+ - `pnpm run build`: passed; `pnpm run package` and standalone `pnpm exec publint` passed.
64
+ - A local runtime-truth torture scene passed strict runtime validation with 0 issues across 9 visual components. Generated QA inputs and outputs are intentionally not committed.
65
+ - Real deterministic final render: 46 frames; frames 0, 9, 18, 30, and 45 visually reviewed.
66
+ - Sparse forward/back/reseek `[18, 30, 18]`: repeated frame 18 matched exactly at SHA-256 `5e30d8dd44ed7cd9ee7ecca8dd6f48dcbf8a48adfd4ac11b47d0eb3d1645636b`.
67
+ - Runtime `explain` at SHAPE frame 18 returned the actual Pixi target and computed x/y/opacity/rotation/scales.
68
+ - Browser/final parity is green on frames 0, 9, 18, 30, and 45. Raw whole-frame SSIM is `0.926262–0.999791`; semantic SSIM is `0.967344–0.999804`. Same-Pixi settled ROIs are `0.995803–1.0` raw, TEXT/SUBTITLES are `0.997588–0.999813`, and zero browser/final runtime or resource errors were recorded.
69
+ - Forward/reverse order `[0,9,18,30,45,45,30,18,9,0]` is stable. Frames 9/18/30/45 are byte-exact in both paths; final frame 0 repeats at SSIM `0.999791` because SVG text rasterization differs by at most three luma levels.
70
+ - A local contact sheet and parity manifest were reviewed across preview, final, and amplified-difference outputs; generated files are intentionally not committed.
71
+ - `git diff --check`: clean. No commit, push, merge, publish, or global-skill modification occurred.
72
+
73
+ ## Open limitations
74
+
75
+ 1. Browser HTML typography is always above the shared Pixi canvas. Arbitrary TEXT/Pixi cross-layer interleaving can still differ from final ordering; the supported torture composition keeps typography above Pixi visuals.
76
+ 2. Native GIF and deterministic ffmpeg decoding differ in palette dithering. Raw GIF ROI reaches `0.539`; 2px semantic SSIM is `0.977`, confirming matching structure/color fields without pretending pixels are identical.
77
+ 3. Native browser VIDEO and predecoded final VIDEO use different decode/color paths; current ROI semantic SSIM is `0.939–0.998`. Exact media-frame identity needs a future PTS contract for half-frame starts.
78
+ 4. Plain absolute local paths now load, but relative paths are still resolved from process cwd rather than the scene file directory, and assetId-only component sources still need runtime hydration from the asset registry.
79
+ 5. Final frame-0 SVG text reseek is visually stable (`0.999791`) but not byte-exact. Other sampled forward/back reseeks are exact.
80
+ 6. Transform origin is not authorable across visual renderers.
81
+ 7. `clipColor` semantics, gradient highlight palettes, generic effects, dashed/dotted outline, and animation setup steps remain unsupported.
82
+ 8. Unknown system animation preset names are still resolved at construction time rather than fully diagnosed statically.
83
+ 9. Advanced animation center/end anchors and active-line transcript timing remain limited.
84
+ 10. Radial gradient shape/position fields use a centered fallback.
85
+ 11. Browser export remains a separate next phase; the MediaBunny spike was not promoted without the higher-priority runtime-truth/parity gates.
86
+
87
+ ## Honest readiness score
88
+
89
+ | Dimension | Score | Reason |
90
+ | --- | ---: | --- |
91
+ | Creative speed | 8.3/10 | Semantic helpers, native transitions, and capability discovery remove substantial source-reading. |
92
+ | Runtime trust | 8.2/10 | Strict runtime gate and construction-synchronized registry close the largest silent-success gaps. Unknown preset resolution remains. |
93
+ | Editability | 8.7/10 | Native TEXT defaults, padding/highlighting, SHAPE transitions, and raw JSON output preserve authorability. |
94
+ | Determinism | 8.2/10 | Shared targets and frames 9/18/30/45 reseek exactly; frame-0 SVG text is visually stable rather than byte-exact, and native media timing caveats remain. |
95
+ | Debugging | 8.0/10 | Runtime-backed explain plus stable capability IDs are useful; deeper preset/effect state could improve. |
96
+ | Agent ergonomics | 8.1/10 | Catalog, strict validate, inspect, explain, docs, examples, and release notes form a coherent loop. |
97
+ | Preview/final parity | 8.2/10 | Zero missing visuals/errors; semantic whole-frame and all class ROIs pass. Cross-layer HTML/Pixi ordering and decoder-level pixel differences remain. |
98
+ | Production readiness | 8.0/10 | Agent-visible runtime truth plus green supported-path parity clears the 8/10 bar. Relative/assetId media hydration and arbitrary mixed stacking still block 9/10. |