frameyard 0.8.0 → 0.9.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 (285) hide show
  1. package/CHANGELOG.md +110 -14
  2. package/GLOSSARY.md +112 -2
  3. package/README.md +302 -265
  4. package/dist/assets/integrations.d.ts +8 -4
  5. package/dist/assets/integrations.d.ts.map +1 -1
  6. package/dist/assets/integrations.js +8 -4
  7. package/dist/assets/integrations.js.map +1 -1
  8. package/dist/assets/provenance.d.ts +2 -2
  9. package/dist/assets/provenance.d.ts.map +1 -1
  10. package/dist/assets/provenance.js +5 -3
  11. package/dist/assets/provenance.js.map +1 -1
  12. package/dist/assets/tts-supertonic.d.ts +28 -0
  13. package/dist/assets/tts-supertonic.d.ts.map +1 -0
  14. package/dist/assets/tts-supertonic.js +156 -0
  15. package/dist/assets/tts-supertonic.js.map +1 -0
  16. package/dist/assets/tts.d.ts +18 -6
  17. package/dist/assets/tts.d.ts.map +1 -1
  18. package/dist/assets/tts.js +219 -97
  19. package/dist/assets/tts.js.map +1 -1
  20. package/dist/cli.js +1685 -93
  21. package/dist/cli.js.map +1 -1
  22. package/dist/composition/format.d.ts +1 -1
  23. package/dist/composition/format.d.ts.map +1 -1
  24. package/dist/composition/format.js +1 -1
  25. package/dist/composition/format.js.map +1 -1
  26. package/dist/context.d.ts +82 -0
  27. package/dist/context.d.ts.map +1 -0
  28. package/dist/context.js +277 -0
  29. package/dist/context.js.map +1 -0
  30. package/dist/contracts.d.ts +25 -0
  31. package/dist/contracts.d.ts.map +1 -1
  32. package/dist/contracts.js.map +1 -1
  33. package/dist/doctor.d.ts +14 -1
  34. package/dist/doctor.d.ts.map +1 -1
  35. package/dist/doctor.js +166 -7
  36. package/dist/doctor.js.map +1 -1
  37. package/dist/errors.d.ts +1 -1
  38. package/dist/errors.d.ts.map +1 -1
  39. package/dist/errors.js.map +1 -1
  40. package/dist/fonts/add.d.ts +41 -0
  41. package/dist/fonts/add.d.ts.map +1 -0
  42. package/dist/fonts/add.js +259 -0
  43. package/dist/fonts/add.js.map +1 -0
  44. package/dist/fonts/binary.d.ts +4 -0
  45. package/dist/fonts/binary.d.ts.map +1 -0
  46. package/dist/fonts/binary.js +21 -0
  47. package/dist/fonts/binary.js.map +1 -0
  48. package/dist/fonts/css.d.ts +4 -0
  49. package/dist/fonts/css.d.ts.map +1 -0
  50. package/dist/fonts/css.js +50 -0
  51. package/dist/fonts/css.js.map +1 -0
  52. package/dist/fonts/fontsource.d.ts +107 -0
  53. package/dist/fonts/fontsource.d.ts.map +1 -0
  54. package/dist/fonts/fontsource.js +565 -0
  55. package/dist/fonts/fontsource.js.map +1 -0
  56. package/dist/fonts/index.d.ts +11 -0
  57. package/dist/fonts/index.d.ts.map +1 -0
  58. package/dist/fonts/index.js +11 -0
  59. package/dist/fonts/index.js.map +1 -0
  60. package/dist/fonts/install.d.ts +24 -0
  61. package/dist/fonts/install.d.ts.map +1 -0
  62. package/dist/fonts/install.js +145 -0
  63. package/dist/fonts/install.js.map +1 -0
  64. package/dist/fonts/manifest.d.ts +21 -0
  65. package/dist/fonts/manifest.d.ts.map +1 -0
  66. package/dist/fonts/manifest.js +96 -0
  67. package/dist/fonts/manifest.js.map +1 -0
  68. package/dist/fonts/options.d.ts +9 -0
  69. package/dist/fonts/options.d.ts.map +1 -0
  70. package/dist/fonts/options.js +66 -0
  71. package/dist/fonts/options.js.map +1 -0
  72. package/dist/fonts/schema.d.ts +4 -0
  73. package/dist/fonts/schema.d.ts.map +1 -0
  74. package/dist/fonts/schema.js +316 -0
  75. package/dist/fonts/schema.js.map +1 -0
  76. package/dist/fonts/summary.d.ts +16 -0
  77. package/dist/fonts/summary.d.ts.map +1 -0
  78. package/dist/fonts/summary.js +22 -0
  79. package/dist/fonts/summary.js.map +1 -0
  80. package/dist/fonts/types.d.ts +56 -0
  81. package/dist/fonts/types.d.ts.map +1 -0
  82. package/dist/fonts/types.js +8 -0
  83. package/dist/fonts/types.js.map +1 -0
  84. package/dist/fonts/verify.d.ts +33 -0
  85. package/dist/fonts/verify.d.ts.map +1 -0
  86. package/dist/fonts/verify.js +200 -0
  87. package/dist/fonts/verify.js.map +1 -0
  88. package/dist/html/validate.d.ts.map +1 -1
  89. package/dist/html/validate.js +59 -0
  90. package/dist/html/validate.js.map +1 -1
  91. package/dist/index.d.ts +3 -3
  92. package/dist/index.d.ts.map +1 -1
  93. package/dist/index.js +1 -1
  94. package/dist/index.js.map +1 -1
  95. package/dist/inspect.d.ts +61 -0
  96. package/dist/inspect.d.ts.map +1 -0
  97. package/dist/inspect.js +325 -0
  98. package/dist/inspect.js.map +1 -0
  99. package/dist/lint.d.ts +63 -0
  100. package/dist/lint.d.ts.map +1 -0
  101. package/dist/lint.js +265 -0
  102. package/dist/lint.js.map +1 -0
  103. package/dist/policy.d.ts +69 -0
  104. package/dist/policy.d.ts.map +1 -0
  105. package/dist/policy.js +361 -0
  106. package/dist/policy.js.map +1 -0
  107. package/dist/preview/timeline-data.d.ts +17 -69
  108. package/dist/preview/timeline-data.d.ts.map +1 -1
  109. package/dist/preview/timeline-host.d.ts.map +1 -1
  110. package/dist/preview/timeline-host.js +70 -45
  111. package/dist/preview/timeline-host.js.map +1 -1
  112. package/dist/preview/timeline-main.d.ts.map +1 -1
  113. package/dist/preview/timeline-main.js +47 -4
  114. package/dist/preview/timeline-main.js.map +1 -1
  115. package/dist/project.d.ts +10 -3
  116. package/dist/project.d.ts.map +1 -1
  117. package/dist/project.js +20 -17
  118. package/dist/project.js.map +1 -1
  119. package/dist/renderer/ffmpeg.d.ts +42 -2
  120. package/dist/renderer/ffmpeg.d.ts.map +1 -1
  121. package/dist/renderer/ffmpeg.js +254 -22
  122. package/dist/renderer/ffmpeg.js.map +1 -1
  123. package/dist/renderer/index.js +1 -1
  124. package/dist/renderer/index.js.map +1 -1
  125. package/dist/renderer/keyframe-expressions.d.ts +39 -0
  126. package/dist/renderer/keyframe-expressions.d.ts.map +1 -0
  127. package/dist/renderer/keyframe-expressions.js +180 -0
  128. package/dist/renderer/keyframe-expressions.js.map +1 -0
  129. package/dist/renderer/timeline.d.ts +2 -0
  130. package/dist/renderer/timeline.d.ts.map +1 -1
  131. package/dist/renderer/timeline.js +89 -116
  132. package/dist/renderer/timeline.js.map +1 -1
  133. package/dist/runtime/host.d.ts.map +1 -1
  134. package/dist/runtime/host.js +4 -0
  135. package/dist/runtime/host.js.map +1 -1
  136. package/dist/scaffold.d.ts +3 -0
  137. package/dist/scaffold.d.ts.map +1 -1
  138. package/dist/scaffold.js +48 -320
  139. package/dist/scaffold.js.map +1 -1
  140. package/dist/server/composition-html.d.ts +2 -0
  141. package/dist/server/composition-html.d.ts.map +1 -1
  142. package/dist/server/composition-html.js +7 -0
  143. package/dist/server/composition-html.js.map +1 -1
  144. package/dist/server/server.d.ts.map +1 -1
  145. package/dist/server/server.js +31 -1
  146. package/dist/server/server.js.map +1 -1
  147. package/dist/server/timeline-preview-data.d.ts.map +1 -1
  148. package/dist/server/timeline-preview-data.js +12 -34
  149. package/dist/server/timeline-preview-data.js.map +1 -1
  150. package/dist/server/timeline-preview-html.d.ts.map +1 -1
  151. package/dist/server/timeline-preview-html.js +18 -2
  152. package/dist/server/timeline-preview-html.js.map +1 -1
  153. package/dist/templates.d.ts +16 -0
  154. package/dist/templates.d.ts.map +1 -0
  155. package/dist/templates.js +186 -0
  156. package/dist/templates.js.map +1 -0
  157. package/dist/timeline/easing.d.ts +36 -0
  158. package/dist/timeline/easing.d.ts.map +1 -0
  159. package/dist/timeline/easing.js +225 -0
  160. package/dist/timeline/easing.js.map +1 -0
  161. package/dist/timeline/keyframes.d.ts +23 -0
  162. package/dist/timeline/keyframes.d.ts.map +1 -0
  163. package/dist/timeline/keyframes.js +95 -0
  164. package/dist/timeline/keyframes.js.map +1 -0
  165. package/dist/timeline/plan.d.ts +6 -12
  166. package/dist/timeline/plan.d.ts.map +1 -1
  167. package/dist/timeline/plan.js +17 -30
  168. package/dist/timeline/plan.js.map +1 -1
  169. package/dist/timeline/resolve.d.ts +12 -0
  170. package/dist/timeline/resolve.d.ts.map +1 -1
  171. package/dist/timeline/resolve.js +105 -9
  172. package/dist/timeline/resolve.js.map +1 -1
  173. package/dist/timeline/scene.d.ts +126 -0
  174. package/dist/timeline/scene.d.ts.map +1 -0
  175. package/dist/timeline/scene.js +109 -0
  176. package/dist/timeline/scene.js.map +1 -0
  177. package/dist/timeline/schema.d.ts +31 -0
  178. package/dist/timeline/schema.d.ts.map +1 -1
  179. package/dist/timeline/schema.js +240 -9
  180. package/dist/timeline/schema.js.map +1 -1
  181. package/dist/timeline/transitions.d.ts +21 -0
  182. package/dist/timeline/transitions.d.ts.map +1 -0
  183. package/dist/timeline/transitions.js +23 -0
  184. package/dist/timeline/transitions.js.map +1 -0
  185. package/dist/version.d.ts +1 -1
  186. package/dist/version.js +1 -1
  187. package/docs/adr/0007-make-html-documents-the-composition-unit.md +1 -1
  188. package/docs/adr/0010-make-timelines-the-render-unit.md +3 -2
  189. package/docs/adr/0014-compose-timeline-clips-with-css-blend-modes.md +2 -1
  190. package/docs/adr/0015-inherit-composition-format-from-the-project.md +2 -2
  191. package/docs/adr/0016-author-compositions-as-html-fragments.md +1 -1
  192. package/docs/adr/0018-animate-timeline-clips-with-keyframes.md +35 -0
  193. package/docs/adr/0019-make-same-track-overlap-the-transition-window.md +36 -0
  194. package/docs/adr/0020-crossfade-audio-clips-on-audio-tracks.md +27 -0
  195. package/docs/adr/0021-project-timeline-scenes-once.md +32 -0
  196. package/docs/adr/0022-gate-heavy-operations-with-a-workspace-resource-policy.md +35 -0
  197. package/docs/adr/0023-pin-fonts-as-project-assets.md +98 -0
  198. package/docs/migration-0.4.md +2 -2
  199. package/docs/preview-testing.md +19 -6
  200. package/docs/{v0.1-design.md → v0.x-design.md} +55 -30
  201. package/examples/blend/README.md +3 -3
  202. package/examples/demo/README.md +2 -2
  203. package/examples/intro/README.md +71 -0
  204. package/examples/intro/assets/fonts/figtree/LICENSE.txt +93 -0
  205. package/examples/intro/assets/fonts/figtree/figtree-latin-wght-normal.woff2 +0 -0
  206. package/examples/intro/assets/fonts/instrument-serif/LICENSE.txt +93 -0
  207. package/examples/intro/assets/fonts/instrument-serif/instrument-serif-latin-400-italic.woff2 +0 -0
  208. package/examples/intro/assets/fonts/space-mono/LICENSE.txt +93 -0
  209. package/examples/intro/assets/fonts/space-mono/space-mono-latin-400-normal.woff2 +0 -0
  210. package/examples/intro/assets/fonts/space-mono/space-mono-latin-700-normal.woff2 +0 -0
  211. package/examples/intro/assets/grain.png +0 -0
  212. package/examples/intro/assets/score.ogg +0 -0
  213. package/examples/intro/compositions/brand.html +412 -0
  214. package/examples/intro/compositions/chrome.controller.js +63 -0
  215. package/examples/intro/compositions/chrome.html +256 -0
  216. package/examples/intro/compositions/lattice.controller.js +148 -0
  217. package/examples/intro/compositions/lattice.html +308 -0
  218. package/examples/intro/compositions/opening.html +504 -0
  219. package/examples/intro/compositions/studio.html +930 -0
  220. package/examples/intro/compositions/theme.css +218 -0
  221. package/examples/intro/fy.config.js +13 -0
  222. package/examples/intro/fy.fonts.json +100 -0
  223. package/examples/intro/scripts/make-grain.mjs +79 -0
  224. package/examples/intro/scripts/make-score.mjs +702 -0
  225. package/examples/intro/timelines/intro.timeline.json +60 -0
  226. package/examples/keyframes/README.md +76 -0
  227. package/examples/keyframes/compositions/backdrop.html +60 -0
  228. package/examples/keyframes/compositions/card.html +99 -0
  229. package/examples/keyframes/fy.config.js +10 -0
  230. package/examples/keyframes/timelines/keyframes.timeline.json +60 -0
  231. package/examples/nested/README.md +112 -0
  232. package/examples/nested/assets/pulse.wav +0 -0
  233. package/examples/nested/compositions/backdrop.html +84 -0
  234. package/examples/nested/compositions/card.html +275 -0
  235. package/examples/nested/compositions/overlay.html +307 -0
  236. package/examples/nested/fy.config.js +13 -0
  237. package/examples/nested/scripts/make-pulse.sh +20 -0
  238. package/examples/nested/timelines/chapter-a.timeline.json +39 -0
  239. package/examples/nested/timelines/chapter-b.timeline.json +39 -0
  240. package/examples/nested/timelines/nested-reel.timeline.json +52 -0
  241. package/examples/static/README.md +2 -2
  242. package/examples/transitions/README.md +128 -0
  243. package/examples/transitions/assets/alpha.wav +0 -0
  244. package/examples/transitions/assets/beta.wav +0 -0
  245. package/examples/transitions/assets/gamma.wav +0 -0
  246. package/examples/transitions/compositions/alpha.html +56 -0
  247. package/examples/transitions/compositions/beta.html +56 -0
  248. package/examples/transitions/compositions/gamma.html +56 -0
  249. package/examples/transitions/fy.config.js +12 -0
  250. package/examples/transitions/timelines/audio-crossfade.timeline.json +44 -0
  251. package/examples/transitions/timelines/transitions.timeline.json +31 -0
  252. package/examples/video/README.md +4 -4
  253. package/examples/webgl/README.md +1 -1
  254. package/package.json +12 -5
  255. package/scaffolds/init/AGENTS.md +131 -0
  256. package/scaffolds/init/README.md +56 -0
  257. package/scaffolds/init/compositions/hello.html +79 -0
  258. package/scaffolds/init/fy.config.js +9 -0
  259. package/scaffolds/init/gitignore.template +1 -0
  260. package/scaffolds/init/package.json +11 -0
  261. package/scaffolds/init/props/hello.json +4 -0
  262. package/scaffolds/init/props/main.json +6 -0
  263. package/scaffolds/init/timelines/main.timeline.json +20 -0
  264. package/scaffolds/local-models/LOCAL-MODELS.md +77 -0
  265. package/scaffolds/local-models/fy.policy.json +5 -0
  266. package/scaffolds/local-models/opencode/opencode.jsonc +17 -0
  267. package/scaffolds/local-models/pi/APPEND_SYSTEM.md +21 -0
  268. package/scaffolds/local-models/pi/sandbox.json +15 -0
  269. package/scaffolds/local-models/pi/settings.json +15 -0
  270. package/skills/frameyard/README.md +1 -0
  271. package/skills/frameyard/SKILL.md +59 -61
  272. package/skills/frameyard/references/audio-assets.md +32 -3
  273. package/skills/frameyard/references/common-mistakes.md +53 -2
  274. package/skills/frameyard/references/deterministic-authoring.md +10 -3
  275. package/skills/frameyard/references/diagnostics.md +31 -1
  276. package/skills/frameyard/references/failure-recovery.md +32 -6
  277. package/skills/frameyard/references/fonts.md +132 -0
  278. package/skills/frameyard/references/json-results.md +119 -6
  279. package/skills/frameyard/references/quick-reference.md +222 -0
  280. package/skills/frameyard/references/timelines.md +97 -7
  281. /package/examples/blend/{video.config.js → fy.config.js} +0 -0
  282. /package/examples/demo/{video.config.js → fy.config.js} +0 -0
  283. /package/examples/static/{video.config.js → fy.config.js} +0 -0
  284. /package/examples/video/{video.config.js → fy.config.js} +0 -0
  285. /package/examples/webgl/{video.config.js → fy.config.js} +0 -0
package/CHANGELOG.md CHANGED
@@ -8,6 +8,113 @@ Frameyard uses `0.x` versions until the composition, configuration, CLI,
8
8
  JSON-result, transcript, and skill contracts stabilize. Before `1.0.0`, a
9
9
  contract change may ship in a minor release and is called out explicitly below.
10
10
 
11
+ ## [Unreleased]
12
+
13
+ ## [0.9.0] - 2026-11-06
14
+
15
+ ### Added
16
+
17
+ - `fy.fonts.json` records vendored font families, files, licenses, and
18
+ SHA-256 values. `frameyard font search` filters the Fontsource catalog, and
19
+ `font add <id>` pins a Fontsource `npmVersion`, vendors its WOFF2 files and
20
+ license, and supports variable `wght` or explicit static weights. `font add
21
+ --file` copies a local WOFF2/WOFF/TTF/OTF font, `font add --url` vendors an
22
+ HTTPS source with an optional SHA-256, and `font list`/`verify`/`remove`
23
+ manage the manifest. The server injects the generated `@font-face` sheet into
24
+ every composition, the host fails with `FONT_LOAD_FAILED` when a used face
25
+ does not load, and static validation warns with `FONT_REMOTE` for remote font
26
+ URLs. See
27
+ `docs/adr/0023-pin-fonts-as-project-assets.md`.
28
+ - `fy.policy.json` is a workspace resource policy discovered from the
29
+ working directory upward. It gates `tts`, `transcribe`, and `render`, caps
30
+ `still`, denies `--force`/`--overwrite`, and supports the `shared-cpu`
31
+ profile. `FRAMEYARD_POLICY` overrides the file. See
32
+ `docs/adr/0022-gate-heavy-operations-with-a-workspace-resource-policy.md`.
33
+ - `frameyard lint <id>` runs static validation, timeline resolution, scene and
34
+ keyframe projection for every frame, a controller determinism scan, and media
35
+ metadata probing without Chromium. It is the edit-loop gate; `check` remains
36
+ the full gate.
37
+ - `frameyard context --json` prints a compact project digest with resolved
38
+ composition metadata, prop keys and types, timeline clip summaries, unique
39
+ assets, diagnostics, the active policy, and next commands.
40
+ - `frameyard inspect <image> --json` reports dimensions, alpha coverage, blank
41
+ detection, background and dominant colors, a content bounding box, a coarse
42
+ luminance grid, and edge density. `frameyard compare <a> <b> --json` reports
43
+ pixel and 3×3 region differences and exits 1 when the images differ.
44
+ - `frameyard add --list` and `frameyard add <composition|timeline> <id>
45
+ --template <name>` write `static-poster`, `title-card`, `lower-third`, or
46
+ `slideshow` entries and print the exact `fy.config.js` registration
47
+ snippet. `add local-models` and `init --local-models` install the optional
48
+ policy, OpenCode permissions, and Pi settings. `add` never edits the config
49
+ and never overwrites an existing entry. The skill adds a compact quick
50
+ reference for limited-context hosts.
51
+ - `init` templates now live under `scaffolds/init/`; `src/scaffold.ts` reads
52
+ them and renders the project-name and version placeholders.
53
+ - `pnpm eval:local` runs an opt-in local-model authoring eval against a
54
+ llama.cpp router. It covers eight tasks, feeds `quick-reference.md` into the
55
+ system prompt, repairs lint failures, and reports first-pass status, turns,
56
+ tokens, wall time, sampled server CPU/RSS/GPU, and optional budgets. It never
57
+ renders and stays outside `pnpm check`.
58
+ - `tts`, `transcribe`, and `render` accept `--dry-run`, which validates inputs
59
+ and returns `plan`, `commandLine`, `prerequisites`, and `blockers` without
60
+ writing outputs, loading a model, launching Chromium, or encoding.
61
+ `--profile shared-cpu` caps timeline workers at 2 and composition concurrency
62
+ at 1; `--low-priority` lowers process priority without the caps.
63
+ - `doctor` reports the active resource policy and basic CPU, load, and memory
64
+ resources. Local-model host setup is opt-in through
65
+ `scaffolds/local-models/`, which contains the `authoring` policy, OpenCode
66
+ permissions, and Pi settings; the repository does not enable it by default.
67
+ - `tts --engine supertonic` synthesizes 31-language speech through
68
+ `sherpa-onnx-offline-tts` and the Supertonic 3 model archive. It normalizes
69
+ the engine output to the frozen 24 kHz mono WAV contract, records the seven
70
+ model files in the provenance manifest, and adds `doctor --sherpa-onnx-tts`
71
+ and `doctor --model-dir` inspection. The default engine remains `qwen`.
72
+ - Timeline clips on one video track may dissolve across their overlap through a
73
+ timeline-level `transitions` array. The window is `to.start .. from.end`; the
74
+ incoming clip composites above the outgoing clip with `opacity × eased
75
+ progress`, contributed audio crossfades with equal power, and preview draws a
76
+ read-only band. Undeclared overlap stays an error. See
77
+ `docs/adr/0019-make-same-track-overlap-the-transition-window.md` and
78
+ `examples/transitions/`.
79
+ - Audio clips on an audio track may crossfade through the same `transitions`
80
+ array with `kind: "crossfade"`. The kind/track matrix is explicit: `dissolve`
81
+ is video-only, `crossfade` is audio-only. See
82
+ `docs/adr/0020-crossfade-audio-clips-on-audio-tracks.md` and the
83
+ `audio-crossfade` timeline in `examples/transitions/`.
84
+ - Timeline clips animate `x`, `y`, `scale`, `rotation`, and `opacity` with
85
+ clip-local `keyframes`, CSS easing, preview markers, and FFmpeg expressions.
86
+ Animated opacity composes through blend modes. See
87
+ `docs/adr/0018-animate-timeline-clips-with-keyframes.md` and
88
+ `examples/keyframes/`.
89
+
90
+ ### Changed
91
+
92
+ - `frameyard init` without a directory prompts for a project name (default
93
+ `my-video`) on an interactive terminal and creates a directory with that
94
+ name. Non-interactive and `--json` runs use `my-video` without prompting.
95
+ Pass a directory to scaffold into an explicit path or the current directory.
96
+ - The project configuration file is `fy.config.js` (previously
97
+ `video.config.js`), the assets manifest is `fy.assets.json` (previously
98
+ `frameyard.assets.json`), and the workspace resource policy is
99
+ `fy.policy.json` (previously `frameyard.policy.json`). Rename existing files
100
+ in place; the loaders read only the new names. `FRAMEYARD_POLICY` keeps
101
+ its name.
102
+
103
+ ### Fixed
104
+
105
+ - Timeline preview layers pin `color-scheme: light` on the embedded document
106
+ root. A composition that declared a dark scheme could paint an opaque canvas
107
+ base and hide every layer beneath it, so a timeline with a transparent
108
+ overlay composition appeared to show only the overlay.
109
+ - Rotated timeline clips keep their full corners. Keyed rotation uses a
110
+ segment-stable diagonal bound; static rotation uses its exact rotated
111
+ bounding box.
112
+ - Animated-opacity masks use a 2×2 FFmpeg source instead of 1×1. FFmpeg 6
113
+ rejects a 1×1 `yuv420p` frame, which broke keyframe, transition, and example
114
+ renders on Ubuntu 24.04 runners.
115
+
116
+ [0.9.0]: https://github.com/vladiantio/frameyard/compare/v0.8.0...v0.9.0
117
+
11
118
  ## [0.8.0] - 2026-11-03
12
119
 
13
120
  ### Changed
@@ -61,12 +168,9 @@ contract change may ship in a minor release and is called out explicitly below.
61
168
  applies `mix-blend-mode` and stacks layers by track; production uses an
62
169
  alpha-aware FFmpeg composite. Nested timelines blend as flattened groups.
63
170
  See ADR 0014 and `examples/blend/`.
64
- - `examples/static/` demonstrates a timeless composition rendered to PNG and
65
- reused as a timeline image.
66
- - `examples/blend/compositions/backdrop.html` demonstrates an inherited
67
- composition format.
68
- - Static composition validation, host, CLI, timeline, preview, and example
69
- coverage.
171
+ - Static composition validation, host, CLI, timeline, and preview coverage.
172
+
173
+ [0.8.0]: https://github.com/vladiantio/frameyard/compare/v0.7.0...v0.8.0
70
174
 
71
175
  ## [0.7.0] - 2026-11-02
72
176
 
@@ -111,7 +215,6 @@ contract change may ship in a minor release and is called out explicitly below.
111
215
  layer iframes reach the preview transport, while text entry does not step
112
216
  frames across iframe boundaries.
113
217
 
114
- [0.8.0]: https://github.com/vladiantio/frameyard/compare/v0.7.0...v0.8.0
115
218
  [0.7.0]: https://github.com/vladiantio/frameyard/compare/v0.6.0...v0.7.0
116
219
 
117
220
  ## [0.6.0] - 2026-11-01
@@ -142,8 +245,6 @@ contract change may ship in a minor release and is called out explicitly below.
142
245
  `timelines` map. `project.json` publishes `format` and `timelines`.
143
246
  - Timeline-first `init` scaffold with a composition clip, timeline override
144
247
  props, and `main` commands.
145
- - The video example adds WebM and MP4 timelines that place video clips under a
146
- transparent HTML overlay.
147
248
  - Official skill reference for timelines, clips, tracks, nested timelines,
148
249
  props overrides, commands, preview, and determinism.
149
250
  - Timeline config, schema, resolution, planning, rendering, preview, and
@@ -173,11 +274,6 @@ contract change may ship in a minor release and is called out explicitly below.
173
274
 
174
275
  ### Added
175
276
 
176
- - `examples/webgl/` demonstrates a frame-seeked WebGL shader driven by an
177
- external controller.
178
- - `examples/video/` demonstrates two-pass embedded video with the same
179
- composition rendered from WebM and MP4 sources, plus a script that
180
- regenerates both clips with FFmpeg.
181
277
  - `test/examples.test.ts` captures a still from every bundled example.
182
278
  - `pnpm compare-stills <a.png> <b.png>` reports an exact decoded-pixel diff and
183
279
  exits nonzero on any difference, for checking determinism at the capture
package/GLOSSARY.md CHANGED
@@ -151,17 +151,79 @@ How a clip source's natural frame is fitted into the project frame or an explici
151
151
  _Avoid_: Resize mode, object-fit
152
152
 
153
153
  **Clip transform**:
154
- The static size, position, rotation, and opacity applied to a visual clip. Size is either an explicit `width`/`height` box or a `scale` multiplier.
154
+ The size, position, rotation, and opacity applied to a visual clip. Size is either an explicit `width`/`height` box or a `scale` multiplier. Static transform values and keyframe tracks are separate; a keyed channel cannot also be a static scalar.
155
155
  _Avoid_: Effect, animation
156
156
 
157
+ **Clip keyframes**:
158
+ A per-channel animation on a visual clip's presentation: `x`, `y`, `scale`, `rotation`, or `opacity`. Keys use clip-local integer frames and hold before the first and after the last key.
159
+ _Avoid_: CSS keyframes, composition animation
160
+
161
+ **Keyframe**:
162
+ One `{ frame, value, easing? }` entry in a clip keyframe track. `frame` is clip-local; `easing` applies to the interval after it.
163
+ _Avoid_: Marker, cue
164
+
165
+ **Keyframe track**:
166
+ The ordered keyframes for one presentation channel. Keys are strictly increasing and stay within the clip's `0..duration` range.
167
+ _Avoid_: Animation curve, property lane
168
+
169
+ **Easing**:
170
+ A CSS timing function that shapes the interval between two timeline keyframes. Preview evaluates it exactly; production approximates it in the FFmpeg filter graph.
171
+ _Avoid_: Interpolation, curve
172
+
157
173
  **Blend mode**:
158
174
  The static CSS `mix-blend-mode` a visual clip applies against the accumulated backdrop of all lower layers and the timeline background. It respects the clip's source alpha and is not animated.
159
175
  _Avoid_: Filter, effect, composite mode
160
176
 
177
+ **Transition**:
178
+ A declared handoff between two clips on one track, written as `{ from, to, kind, easing? }` in the timeline's `transitions` array. `dissolve` is a visual fade on a video track; `crossfade` is an audio gain ramp on an audio track. The clips overlap; an overlap without a declared transition is still an error.
179
+ _Avoid_: Overlap
180
+
181
+ **Crossfade**:
182
+ The audio-track transition kind. It ramps the outgoing audio clip down and the incoming clip up with equal power and changes no pixels.
183
+ _Avoid_: Dissolve, fade
184
+
185
+ **Transition window**:
186
+ The overlap `to.start .. from.end` where both clips are active. During a dissolve the incoming clip composites above the outgoing clip with `opacity × eased progress`, evaluated at absolute timeline frames.
187
+ _Avoid_: Handle, overlap region
188
+
189
+ **Transition role**:
190
+ The side a clip takes in a transition: `out` for the clip being replaced, `in` for the clip replacing it.
191
+ _Avoid_: Transition direction, fade side
192
+
193
+ **Equal-power crossfade**:
194
+ The audio gain curve inside either transition kind: the outgoing clip ramps as `sqrt(1 - t)` and the incoming clip as `sqrt(t)` after easing, keeping perceived loudness steady.
195
+ _Avoid_: Linear fade
196
+
161
197
  **Nested timeline**:
162
198
  A timeline used as a clip source inside another timeline.
163
199
  _Avoid_: Compound composition
164
200
 
201
+ ### Fonts
202
+
203
+ **Font manifest**:
204
+ The versioned `fy.fonts.json` file that records vendored font families, their CSS family names, providers, licenses, and file hashes. It is the source of truth for the generated `@font-face` sheet.
205
+ _Avoid_: Font config, font cache
206
+
207
+ **Font provider**:
208
+ The acquisition source recorded for a font family: `local` for a user-supplied file, `fontsource` for a pinned Fontsource download, or `url` for an explicit HTTPS source.
209
+ _Avoid_: Font catalog, font CDN
210
+
211
+ **Font family entry**:
212
+ One manifest entry keyed by a stable id. It contains the CSS family name, provider metadata, license, optional variable axes, and one or more font files.
213
+ _Avoid_: Font face, font package
214
+
215
+ **Font face**:
216
+ One file entry inside a family: a subset, style, weight or weight range, format, optional unicode range, SHA-256, and byte size.
217
+ _Avoid_: Font variant, font weight
218
+
219
+ **Font subset**:
220
+ A provider-defined slice of a family's glyph coverage, such as `latin` or `latin-ext`. Subsets are recorded per face and may carry a CSS `unicode-range`.
221
+ _Avoid_: Language, charset
222
+
223
+ **Variable font**:
224
+ A font file that carries a continuous range for one or more axes instead of separate static weights. Frameyard records the axes and emits a CSS weight range; the first version installs the `wght` axis only.
225
+ _Avoid_: Dynamic font, multiple weight font
226
+
165
227
  ### Deterministic execution
166
228
 
167
229
  **Frame**:
@@ -172,6 +234,10 @@ _Avoid_: Timestamp, animation tick
172
234
  A clip whose timeline range contains the current timeline frame.
173
235
  _Avoid_: Visible clip
174
236
 
237
+ **Timeline scene**:
238
+ The ordered active clips and their presentation at one timeline frame or over one render range, including transition roles and composite order. It is the timeline-level arrangement, not a composition.
239
+ _Avoid_: Timeline composition, frame snapshot
240
+
175
241
  **Clip capture**:
176
242
  The pixel frames a composition produces for a timeline clip before the timeline compositor combines layers.
177
243
  _Avoid_: Screenshot, render
@@ -312,6 +378,46 @@ _Avoid_: Frame export, image sequence
312
378
  The guarantee that, for the same timeline or composition revision, props, assets, and frame under a pinned runtime/browser environment, the visual state is identical. It does not imply identical encoded bytes, even on the same machine; encoded output depends on the encoder and its runtime.
313
379
  _Avoid_: Bit-for-bit encoding equality
314
380
 
381
+ ### Resource policy
382
+
383
+ **Resource policy**:
384
+ A workspace-local `fy.policy.json` declaration of which CLI operations are allowed and which resource limits apply. It is discovered from the working directory upward, independent of `fy.config.js`, and can only tighten its tier.
385
+ _Avoid_: Project config, agent runtime
386
+
387
+ **Policy tier**:
388
+ One of `light`, `authoring`, or `full`. A tier fixes the allowed heavy operations, the still-frame cap (1, 4, or the library cap of 32), and overwrite permission. `FRAMEYARD_POLICY` replaces the policy file for a human override.
389
+ _Avoid_: Permission mode, sandbox
390
+
391
+ **Resource profile**:
392
+ A named set of runtime caps and priority settings for a shared machine. `shared-cpu` caps timeline workers at two, composition concurrency at one, and lowers process priority.
393
+ _Avoid_: Encoder preset, render mode
394
+
395
+ **Lint**:
396
+ A Node-only validation pass that resolves a composition or timeline, projects every timeline scene and keyframe channel, scans controller source for wall-clock and randomness calls, and probes media metadata without launching Chromium. Lint is not a substitute for `check`.
397
+ _Avoid_: Static check, fast render
398
+
399
+ **Dry run**:
400
+ A heavy command mode that validates inputs and returns a plan, handoff command, prerequisites, and blockers without writing outputs, loading a model, launching Chromium, or encoding.
401
+ _Avoid_: Preview, partial render
402
+
403
+ ### Inspection and templates
404
+
405
+ **Project context**:
406
+ A compact, read-only digest of a project's format, composition metadata, prop types, timeline clips, assets, installed fonts, diagnostics, active policy, and next commands.
407
+ _Avoid_: Project dump, repo summary
408
+
409
+ **Image inspection**:
410
+ Text facts extracted from a decoded still: dimensions, alpha coverage, blank detection, background and dominant colors, content bounding box, luminance grid, and edge density.
411
+ _Avoid_: Visual review, AI vision
412
+
413
+ **Image comparison**:
414
+ A pixel and region diff between two decoded images. It reports differing pixels, channel deltas, a bounding box, and a 3×3 region breakdown.
415
+ _Avoid_: Pixel hash, visual diff
416
+
417
+ **Project template**:
418
+ A known-good composition or timeline entry that `add` writes while printing the explicit `fy.config.js` registration snippet.
419
+ _Avoid_: Generator, project scaffold
420
+
315
421
  ### Agent operation
316
422
 
317
423
  **Agent-assisted authoring and operation**:
@@ -333,9 +439,13 @@ A versioned, project-local record of generated assets, their content hashes, and
333
439
  _Avoid_: Render cache
334
440
 
335
441
  **Speech synthesis** (TTS):
336
- The local production of a spoken audio asset from text using a named speaker.
442
+ The local production of a spoken audio asset from text using a named speaker or numeric speaker id.
337
443
  _Avoid_: Voice generation, voice cloning, voice design
338
444
 
445
+ **Speech engine**:
446
+ A local executable that turns text into a speech asset. Frameyard supports qwentts.cpp CustomVoice and sherpa-onnx Supertonic 3.
447
+ _Avoid_: TTS provider, cloud voice
448
+
339
449
  **Transcription**:
340
450
  The local production of timed text from source audio or video.
341
451
  _Avoid_: Subtitle rendering