frameyard 0.7.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.
- package/CHANGELOG.md +164 -7
- package/GLOSSARY.md +152 -18
- package/README.md +328 -285
- package/dist/assets/integrations.d.ts +8 -4
- package/dist/assets/integrations.d.ts.map +1 -1
- package/dist/assets/integrations.js +8 -4
- package/dist/assets/integrations.js.map +1 -1
- package/dist/assets/provenance.d.ts +2 -2
- package/dist/assets/provenance.d.ts.map +1 -1
- package/dist/assets/provenance.js +5 -3
- package/dist/assets/provenance.js.map +1 -1
- package/dist/assets/tts-supertonic.d.ts +28 -0
- package/dist/assets/tts-supertonic.d.ts.map +1 -0
- package/dist/assets/tts-supertonic.js +156 -0
- package/dist/assets/tts-supertonic.js.map +1 -0
- package/dist/assets/tts.d.ts +18 -6
- package/dist/assets/tts.d.ts.map +1 -1
- package/dist/assets/tts.js +219 -97
- package/dist/assets/tts.js.map +1 -1
- package/dist/cli.js +1705 -106
- package/dist/cli.js.map +1 -1
- package/dist/composition/descriptor.d.ts +17 -3
- package/dist/composition/descriptor.d.ts.map +1 -1
- package/dist/composition/descriptor.js +51 -28
- package/dist/composition/descriptor.js.map +1 -1
- package/dist/composition/format.d.ts +12 -0
- package/dist/composition/format.d.ts.map +1 -0
- package/dist/composition/format.js +28 -0
- package/dist/composition/format.js.map +1 -0
- package/dist/composition/index.d.ts +2 -1
- package/dist/composition/index.d.ts.map +1 -1
- package/dist/composition/index.js +1 -0
- package/dist/composition/index.js.map +1 -1
- package/dist/context.d.ts +82 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +277 -0
- package/dist/context.js.map +1 -0
- package/dist/contracts.d.ts +80 -6
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +3 -0
- package/dist/contracts.js.map +1 -1
- package/dist/doctor.d.ts +14 -1
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +166 -7
- package/dist/doctor.js.map +1 -1
- package/dist/errors.d.ts +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/fonts/add.d.ts +41 -0
- package/dist/fonts/add.d.ts.map +1 -0
- package/dist/fonts/add.js +259 -0
- package/dist/fonts/add.js.map +1 -0
- package/dist/fonts/binary.d.ts +4 -0
- package/dist/fonts/binary.d.ts.map +1 -0
- package/dist/fonts/binary.js +21 -0
- package/dist/fonts/binary.js.map +1 -0
- package/dist/fonts/css.d.ts +4 -0
- package/dist/fonts/css.d.ts.map +1 -0
- package/dist/fonts/css.js +50 -0
- package/dist/fonts/css.js.map +1 -0
- package/dist/fonts/fontsource.d.ts +107 -0
- package/dist/fonts/fontsource.d.ts.map +1 -0
- package/dist/fonts/fontsource.js +565 -0
- package/dist/fonts/fontsource.js.map +1 -0
- package/dist/fonts/index.d.ts +11 -0
- package/dist/fonts/index.d.ts.map +1 -0
- package/dist/fonts/index.js +11 -0
- package/dist/fonts/index.js.map +1 -0
- package/dist/fonts/install.d.ts +24 -0
- package/dist/fonts/install.d.ts.map +1 -0
- package/dist/fonts/install.js +145 -0
- package/dist/fonts/install.js.map +1 -0
- package/dist/fonts/manifest.d.ts +21 -0
- package/dist/fonts/manifest.d.ts.map +1 -0
- package/dist/fonts/manifest.js +96 -0
- package/dist/fonts/manifest.js.map +1 -0
- package/dist/fonts/options.d.ts +9 -0
- package/dist/fonts/options.d.ts.map +1 -0
- package/dist/fonts/options.js +66 -0
- package/dist/fonts/options.js.map +1 -0
- package/dist/fonts/schema.d.ts +4 -0
- package/dist/fonts/schema.d.ts.map +1 -0
- package/dist/fonts/schema.js +316 -0
- package/dist/fonts/schema.js.map +1 -0
- package/dist/fonts/summary.d.ts +16 -0
- package/dist/fonts/summary.d.ts.map +1 -0
- package/dist/fonts/summary.js +22 -0
- package/dist/fonts/summary.js.map +1 -0
- package/dist/fonts/types.d.ts +56 -0
- package/dist/fonts/types.d.ts.map +1 -0
- package/dist/fonts/types.js +8 -0
- package/dist/fonts/types.js.map +1 -0
- package/dist/fonts/verify.d.ts +33 -0
- package/dist/fonts/verify.d.ts.map +1 -0
- package/dist/fonts/verify.js +200 -0
- package/dist/fonts/verify.js.map +1 -0
- package/dist/html/document-adapter.d.ts +3 -3
- package/dist/html/document-adapter.d.ts.map +1 -1
- package/dist/html/document-adapter.js +1 -1
- package/dist/html/document-adapter.js.map +1 -1
- package/dist/html/index.d.ts +1 -1
- package/dist/html/index.d.ts.map +1 -1
- package/dist/html/parse.d.ts +10 -2
- package/dist/html/parse.d.ts.map +1 -1
- package/dist/html/parse.js +14 -5
- package/dist/html/parse.js.map +1 -1
- package/dist/html/validate.d.ts +12 -1
- package/dist/html/validate.d.ts.map +1 -1
- package/dist/html/validate.js +292 -61
- package/dist/html/validate.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/inspect.d.ts +61 -0
- package/dist/inspect.d.ts.map +1 -0
- package/dist/inspect.js +325 -0
- package/dist/inspect.js.map +1 -0
- package/dist/lint.d.ts +63 -0
- package/dist/lint.d.ts.map +1 -0
- package/dist/lint.js +265 -0
- package/dist/lint.js.map +1 -0
- package/dist/policy.d.ts +69 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +361 -0
- package/dist/policy.js.map +1 -0
- package/dist/preview/main.d.ts +2 -2
- package/dist/preview/main.d.ts.map +1 -1
- package/dist/preview/main.js +35 -14
- package/dist/preview/main.js.map +1 -1
- package/dist/preview/timeline-data.d.ts +17 -65
- package/dist/preview/timeline-data.d.ts.map +1 -1
- package/dist/preview/timeline-host.d.ts.map +1 -1
- package/dist/preview/timeline-host.js +73 -38
- package/dist/preview/timeline-host.js.map +1 -1
- package/dist/preview/timeline-main.d.ts.map +1 -1
- package/dist/preview/timeline-main.js +47 -3
- package/dist/preview/timeline-main.js.map +1 -1
- package/dist/project.d.ts +13 -8
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +20 -17
- package/dist/project.js.map +1 -1
- package/dist/renderer/browser.d.ts +2 -2
- package/dist/renderer/browser.d.ts.map +1 -1
- package/dist/renderer/browser.js +10 -4
- package/dist/renderer/browser.js.map +1 -1
- package/dist/renderer/ffmpeg.d.ts +44 -1
- package/dist/renderer/ffmpeg.d.ts.map +1 -1
- package/dist/renderer/ffmpeg.js +371 -73
- package/dist/renderer/ffmpeg.js.map +1 -1
- package/dist/renderer/index.d.ts +40 -4
- package/dist/renderer/index.d.ts.map +1 -1
- package/dist/renderer/index.js +100 -25
- package/dist/renderer/index.js.map +1 -1
- package/dist/renderer/keyframe-expressions.d.ts +39 -0
- package/dist/renderer/keyframe-expressions.d.ts.map +1 -0
- package/dist/renderer/keyframe-expressions.js +180 -0
- package/dist/renderer/keyframe-expressions.js.map +1 -0
- package/dist/renderer/timeline.d.ts +2 -0
- package/dist/renderer/timeline.d.ts.map +1 -1
- package/dist/renderer/timeline.js +168 -106
- package/dist/renderer/timeline.js.map +1 -1
- package/dist/runtime/host.d.ts.map +1 -1
- package/dist/runtime/host.js +159 -31
- package/dist/runtime/host.js.map +1 -1
- package/dist/scaffold.d.ts +3 -0
- package/dist/scaffold.d.ts.map +1 -1
- package/dist/scaffold.js +48 -317
- package/dist/scaffold.js.map +1 -1
- package/dist/server/composition-html.d.ts +15 -7
- package/dist/server/composition-html.d.ts.map +1 -1
- package/dist/server/composition-html.js +72 -16
- package/dist/server/composition-html.js.map +1 -1
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +56 -6
- package/dist/server/server.js.map +1 -1
- package/dist/server/timeline-preview-data.d.ts.map +1 -1
- package/dist/server/timeline-preview-data.js +12 -23
- package/dist/server/timeline-preview-data.js.map +1 -1
- package/dist/server/timeline-preview-html.d.ts.map +1 -1
- package/dist/server/timeline-preview-html.js +20 -3
- package/dist/server/timeline-preview-html.js.map +1 -1
- package/dist/templates.d.ts +16 -0
- package/dist/templates.d.ts.map +1 -0
- package/dist/templates.js +186 -0
- package/dist/templates.js.map +1 -0
- package/dist/timeline/easing.d.ts +36 -0
- package/dist/timeline/easing.d.ts.map +1 -0
- package/dist/timeline/easing.js +225 -0
- package/dist/timeline/easing.js.map +1 -0
- package/dist/timeline/keyframes.d.ts +23 -0
- package/dist/timeline/keyframes.d.ts.map +1 -0
- package/dist/timeline/keyframes.js +95 -0
- package/dist/timeline/keyframes.js.map +1 -0
- package/dist/timeline/plan.d.ts +6 -12
- package/dist/timeline/plan.d.ts.map +1 -1
- package/dist/timeline/plan.js +17 -30
- package/dist/timeline/plan.js.map +1 -1
- package/dist/timeline/resolve.d.ts +16 -3
- package/dist/timeline/resolve.d.ts.map +1 -1
- package/dist/timeline/resolve.js +119 -13
- package/dist/timeline/resolve.js.map +1 -1
- package/dist/timeline/scene.d.ts +126 -0
- package/dist/timeline/scene.d.ts.map +1 -0
- package/dist/timeline/scene.js +109 -0
- package/dist/timeline/scene.js.map +1 -0
- package/dist/timeline/schema.d.ts +38 -0
- package/dist/timeline/schema.d.ts.map +1 -1
- package/dist/timeline/schema.js +290 -9
- package/dist/timeline/schema.js.map +1 -1
- package/dist/timeline/transitions.d.ts +21 -0
- package/dist/timeline/transitions.d.ts.map +1 -0
- package/dist/timeline/transitions.js +23 -0
- package/dist/timeline/transitions.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/adr/0007-make-html-documents-the-composition-unit.md +2 -2
- package/docs/adr/0008-share-the-composition-document-grammar.md +1 -1
- package/docs/adr/0010-make-timelines-the-render-unit.md +3 -2
- package/docs/adr/0011-compose-timeline-frames-in-a-live-browser-host.md +1 -1
- package/docs/adr/0012-render-timelines-with-segmented-lossless-clip-intermediates.md +1 -1
- package/docs/adr/0014-compose-timeline-clips-with-css-blend-modes.md +38 -0
- package/docs/adr/0015-inherit-composition-format-from-the-project.md +28 -0
- package/docs/adr/0016-author-compositions-as-html-fragments.md +32 -0
- package/docs/adr/0017-render-timeless-compositions-as-stills.md +99 -0
- package/docs/adr/0018-animate-timeline-clips-with-keyframes.md +35 -0
- package/docs/adr/0019-make-same-track-overlap-the-transition-window.md +36 -0
- package/docs/adr/0020-crossfade-audio-clips-on-audio-tracks.md +27 -0
- package/docs/adr/0021-project-timeline-scenes-once.md +32 -0
- package/docs/adr/0022-gate-heavy-operations-with-a-workspace-resource-policy.md +35 -0
- package/docs/adr/0023-pin-fonts-as-project-assets.md +98 -0
- package/docs/migration-0.4.md +5 -3
- package/docs/migration-0.8.md +163 -0
- package/docs/preview-testing.md +23 -3
- package/docs/{v0.1-design.md → v0.x-design.md} +86 -53
- package/examples/blend/README.md +106 -0
- package/examples/blend/assets/ink.mp4 +0 -0
- package/examples/blend/compositions/aurora.html +55 -0
- package/examples/blend/compositions/backdrop.html +74 -0
- package/examples/blend/compositions/labels.html +149 -0
- package/examples/blend/fy.config.js +11 -0
- package/examples/blend/scripts/make-ink.sh +26 -0
- package/examples/blend/timelines/blend.timeline.json +155 -0
- package/examples/demo/README.md +2 -2
- package/examples/demo/compositions/demo.html +243 -251
- package/examples/intro/README.md +71 -0
- package/examples/intro/assets/fonts/figtree/LICENSE.txt +93 -0
- package/examples/intro/assets/fonts/figtree/figtree-latin-wght-normal.woff2 +0 -0
- package/examples/intro/assets/fonts/instrument-serif/LICENSE.txt +93 -0
- package/examples/intro/assets/fonts/instrument-serif/instrument-serif-latin-400-italic.woff2 +0 -0
- package/examples/intro/assets/fonts/space-mono/LICENSE.txt +93 -0
- package/examples/intro/assets/fonts/space-mono/space-mono-latin-400-normal.woff2 +0 -0
- package/examples/intro/assets/fonts/space-mono/space-mono-latin-700-normal.woff2 +0 -0
- package/examples/intro/assets/grain.png +0 -0
- package/examples/intro/assets/score.ogg +0 -0
- package/examples/intro/compositions/brand.html +412 -0
- package/examples/intro/compositions/chrome.controller.js +63 -0
- package/examples/intro/compositions/chrome.html +256 -0
- package/examples/intro/compositions/lattice.controller.js +148 -0
- package/examples/intro/compositions/lattice.html +308 -0
- package/examples/intro/compositions/opening.html +504 -0
- package/examples/intro/compositions/studio.html +930 -0
- package/examples/intro/compositions/theme.css +218 -0
- package/examples/intro/fy.config.js +13 -0
- package/examples/intro/fy.fonts.json +100 -0
- package/examples/intro/scripts/make-grain.mjs +79 -0
- package/examples/intro/scripts/make-score.mjs +702 -0
- package/examples/intro/timelines/intro.timeline.json +60 -0
- package/examples/keyframes/README.md +76 -0
- package/examples/keyframes/compositions/backdrop.html +60 -0
- package/examples/keyframes/compositions/card.html +99 -0
- package/examples/keyframes/fy.config.js +10 -0
- package/examples/keyframes/timelines/keyframes.timeline.json +60 -0
- package/examples/nested/README.md +112 -0
- package/examples/nested/assets/pulse.wav +0 -0
- package/examples/nested/compositions/backdrop.html +84 -0
- package/examples/nested/compositions/card.html +275 -0
- package/examples/nested/compositions/overlay.html +307 -0
- package/examples/nested/fy.config.js +13 -0
- package/examples/nested/scripts/make-pulse.sh +20 -0
- package/examples/nested/timelines/chapter-a.timeline.json +39 -0
- package/examples/nested/timelines/chapter-b.timeline.json +39 -0
- package/examples/nested/timelines/nested-reel.timeline.json +52 -0
- package/examples/static/README.md +17 -0
- package/examples/static/compositions/still.html +37 -0
- package/examples/static/fy.config.js +9 -0
- package/examples/static/timelines/still.timeline.json +13 -0
- package/examples/transitions/README.md +128 -0
- package/examples/transitions/assets/alpha.wav +0 -0
- package/examples/transitions/assets/beta.wav +0 -0
- package/examples/transitions/assets/gamma.wav +0 -0
- package/examples/transitions/compositions/alpha.html +56 -0
- package/examples/transitions/compositions/beta.html +56 -0
- package/examples/transitions/compositions/gamma.html +56 -0
- package/examples/transitions/fy.config.js +12 -0
- package/examples/transitions/timelines/audio-crossfade.timeline.json +44 -0
- package/examples/transitions/timelines/transitions.timeline.json +31 -0
- package/examples/video/README.md +4 -4
- package/examples/video/compositions/video-mp4.html +349 -357
- package/examples/video/compositions/video-overlay.html +337 -345
- package/examples/video/compositions/video.html +349 -357
- package/examples/webgl/README.md +1 -1
- package/examples/webgl/compositions/webgl.html +205 -213
- package/package.json +13 -5
- package/scaffolds/init/AGENTS.md +131 -0
- package/scaffolds/init/README.md +56 -0
- package/scaffolds/init/compositions/hello.html +79 -0
- package/scaffolds/init/fy.config.js +9 -0
- package/scaffolds/init/gitignore.template +1 -0
- package/scaffolds/init/package.json +11 -0
- package/scaffolds/init/props/hello.json +4 -0
- package/scaffolds/init/props/main.json +6 -0
- package/scaffolds/init/timelines/main.timeline.json +20 -0
- package/scaffolds/local-models/LOCAL-MODELS.md +77 -0
- package/scaffolds/local-models/fy.policy.json +5 -0
- package/scaffolds/local-models/opencode/opencode.jsonc +17 -0
- package/scaffolds/local-models/pi/APPEND_SYSTEM.md +21 -0
- package/scaffolds/local-models/pi/sandbox.json +15 -0
- package/scaffolds/local-models/pi/settings.json +15 -0
- package/skills/frameyard/README.md +1 -0
- package/skills/frameyard/SKILL.md +59 -59
- package/skills/frameyard/references/audio-assets.md +32 -3
- package/skills/frameyard/references/common-mistakes.md +81 -7
- package/skills/frameyard/references/controllers.md +5 -4
- package/skills/frameyard/references/deterministic-authoring.md +49 -37
- package/skills/frameyard/references/diagnostics.md +42 -4
- package/skills/frameyard/references/failure-recovery.md +56 -10
- package/skills/frameyard/references/fonts.md +132 -0
- package/skills/frameyard/references/json-results.md +165 -10
- package/skills/frameyard/references/quick-reference.md +222 -0
- package/skills/frameyard/references/timelines.md +109 -15
- /package/examples/demo/{video.config.js → fy.config.js} +0 -0
- /package/examples/video/{video.config.js → fy.config.js} +0 -0
- /package/examples/webgl/{video.config.js → fy.config.js} +0 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Fonts
|
|
2
|
+
|
|
3
|
+
Frameyard vendors font files into the project. A composition uses a font by its
|
|
4
|
+
CSS family name; the preview server injects the generated `@font-face` sheet
|
|
5
|
+
into every composition before author styles. There is no runtime font CDN
|
|
6
|
+
dependency.
|
|
7
|
+
|
|
8
|
+
## Search Fontsource
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
npx frameyard font search "space grotesk" --subset latin --json
|
|
12
|
+
npx frameyard font search --category sans-serif --variable --limit 10 --json
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Filters are `--category`, `--subset`, `--style`, `--variable`, and `--limit`
|
|
16
|
+
(1–100). Search returns `id`, `family`, `category`, `variable`, `weights`,
|
|
17
|
+
`styles`, `subsets`, `license`, and `type`. Fontsource is the default catalog;
|
|
18
|
+
Google Fonts is covered through Fontsource and does not need a separate API key.
|
|
19
|
+
|
|
20
|
+
## Install a Fontsource family
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
npx frameyard font add space-grotesk --subset latin
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The command fetches the family metadata, pins the Fontsource `npmVersion`,
|
|
27
|
+
downloads only the requested WOFF2 files, downloads the package `LICENSE`, and
|
|
28
|
+
records the exact CDN URL and SHA-256 in `fy.fonts.json`.
|
|
29
|
+
|
|
30
|
+
- A variable family installs the `wght` axis by default. Use multiple
|
|
31
|
+
`--subset` and `--style` values, for example
|
|
32
|
+
`--subset latin,latin-ext --style normal,italic`.
|
|
33
|
+
- `--static` installs static files. `--weight` accepts a comma-separated list,
|
|
34
|
+
for example `--static --weight 400,700`.
|
|
35
|
+
- `--family` overrides the CSS family name when a project needs an alias.
|
|
36
|
+
- Fontsource supplies the license; do not pass `--license` for a Fontsource id.
|
|
37
|
+
- A variable family and a static install of the same family cannot be mixed
|
|
38
|
+
without `--force`, which replaces the family record.
|
|
39
|
+
|
|
40
|
+
`FONT_PROVIDER_UNAVAILABLE` means the Fontsource API or CDN was unreachable.
|
|
41
|
+
`FONT_DOWNLOAD_FAILED` means a response was not a valid WOFF2 file.
|
|
42
|
+
|
|
43
|
+
## Install a local or URL font
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
npx frameyard font add --file ./fonts/SpaceGrotesk.woff2 \
|
|
47
|
+
--family "Space Grotesk" --weight 300-700 --subset latin \
|
|
48
|
+
--license OFL-1.1 --license-file ./fonts/OFL.txt
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`--weight` is a number (`400`) or a variable range (`300-700`). `--style` is
|
|
52
|
+
`normal` or `italic`. `--subset`, `--unicode-range`, `--license`, and
|
|
53
|
+
`--license-file` are optional; a missing license is a warning. The command
|
|
54
|
+
copies the font and license under `assets/fonts/<id>/`, records the SHA-256 and
|
|
55
|
+
byte size, and prints the CSS family to use.
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
npx frameyard font add --url https://example.com/Inter.woff2 \
|
|
59
|
+
--family "Inter" --license OFL-1.1 --license-file ./fonts/OFL.txt \
|
|
60
|
+
--sha256 <hash>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`--url` requires HTTPS; loopback HTTP is allowed for local tests. `--sha256` is
|
|
64
|
+
optional but recommended: the computed hash is always recorded. A URL import
|
|
65
|
+
without `--license`/`--license-file` records `license: { "type": "unknown" }`,
|
|
66
|
+
warns in
|
|
67
|
+
`list`/`verify`/`doctor`, requires the `full` policy, and does not use a shared
|
|
68
|
+
cache. Do not point `--url` at a font whose license you cannot redistribute.
|
|
69
|
+
|
|
70
|
+
Fontsource is the primary catalog. Google Fonts is covered by Fontsource.
|
|
71
|
+
Bunny Fonts is not a vendoring source: its catalog is undocumented, it exposes
|
|
72
|
+
no license metadata, and its files are not frozen. Fontshare is not a provider:
|
|
73
|
+
its Free Font License prohibits redistribution, subsetting, and format
|
|
74
|
+
conversion for most of its catalog. Only OFL-licensed Fontshare files may be
|
|
75
|
+
vendored, through `font add --url`, with their license text and an explicit
|
|
76
|
+
decision by the user.
|
|
77
|
+
|
|
78
|
+
## Manage the manifest
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
npx frameyard font list --json
|
|
82
|
+
npx frameyard font verify --json
|
|
83
|
+
npx frameyard font remove space-grotesk --json
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
`font list` reports installed families, subset/style labels, license, file
|
|
87
|
+
count, bytes, and status. `font verify` checks paths, formats, byte sizes,
|
|
88
|
+
SHA-256 values, license files, and orphaned font directories. `font remove`
|
|
89
|
+
deletes the manifest entry and `assets/fonts/<id>/`; add `--keep-files` to leave
|
|
90
|
+
the binaries in place. `font remove`, `font add --force`, and an unlicensed
|
|
91
|
+
`--url` import require the `full` policy.
|
|
92
|
+
|
|
93
|
+
Adding another subset, style, or weight to the same family merges into the
|
|
94
|
+
existing entry. Adding the same face again fails with `OUTPUT_EXISTS`; pass
|
|
95
|
+
`--force` to replace it. `fy.fonts.json` has `version: 1` and one entry
|
|
96
|
+
per family. Commit it with `assets/fonts/` and the license files.
|
|
97
|
+
|
|
98
|
+
## Use the font
|
|
99
|
+
|
|
100
|
+
```css
|
|
101
|
+
.title {
|
|
102
|
+
font-family: "Space Grotesk", system-ui, sans-serif;
|
|
103
|
+
font-weight: 700;
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The generated sheet uses `font-display: block`. The host waits for
|
|
108
|
+
`document.fonts.ready` after `mount()`, then fails with `FONT_LOAD_FAILED` if a
|
|
109
|
+
used face reports an error instead of silently capturing fallback text.
|
|
110
|
+
`check`, `still`, and `render` verify sizes and hashes before launching
|
|
111
|
+
Chromium; `lint` verifies existence and size. A changed file fails with
|
|
112
|
+
`FONT_HASH_MISMATCH`.
|
|
113
|
+
|
|
114
|
+
## Legacy fonts and remote URLs
|
|
115
|
+
|
|
116
|
+
Existing local `@font-face` rules and `<link rel="stylesheet">` elements keep
|
|
117
|
+
working. A remote font URL in inline CSS, linked local CSS, or a remote
|
|
118
|
+
stylesheet link produces a `FONT_REMOTE` warning. It may work during the loading
|
|
119
|
+
phase, but it is not reproducible and is not covered by the manifest.
|
|
120
|
+
|
|
121
|
+
## Agent workflow
|
|
122
|
+
|
|
123
|
+
1. Search Fontsource with `font search` or choose a local/URL source and verify
|
|
124
|
+
its license.
|
|
125
|
+
2. Install with `font add`, preferring the variable face or the exact static
|
|
126
|
+
weights the composition uses.
|
|
127
|
+
3. Use the returned family name in the composition CSS.
|
|
128
|
+
4. Run `font verify`, `context --json`, `lint`, and `still`.
|
|
129
|
+
5. Inspect the still when typography or line breaks change.
|
|
130
|
+
|
|
131
|
+
Do not download fonts from `update()` or `mount()`. Font acquisition is an
|
|
132
|
+
authoring operation, not frame production.
|
|
@@ -11,7 +11,7 @@ Every non-interactive command supports `--json`. Stdout contains one JSON docume
|
|
|
11
11
|
}
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
Additional fields are command-specific and stable within the 0.
|
|
14
|
+
Additional fields are command-specific and stable within the 0.8 contract. `check`, `still`, and `render` report `elapsedMs`, the wall time of the operation from static validation and preflight through the final frame or publication; CLI argument parsing is excluded.
|
|
15
15
|
|
|
16
16
|
## Error envelope
|
|
17
17
|
|
|
@@ -51,14 +51,117 @@ Additional fields are command-specific and stable within the 0.4 contract. `chec
|
|
|
51
51
|
}
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
Static validation diagnostics include source locations. Runtime diagnostics may include a `frame`. Audio and transcript warnings use `AUDIO_WARNING` and `TRANSCRIPT_WARNING`; controller clock/randomness and CSS transition warnings use `DETERMINISM_WARNING`. See [diagnostics](diagnostics.md) for the code table.
|
|
54
|
+
Static validation diagnostics include source locations. Runtime diagnostics may include a `frame`. Timeline diagnostics add `timeline`, `clip`, `track`, `jsonPath`, and, for keyframe errors, `channel` and the zero-based `keyframe` index; transition diagnostics add `from` and `to`. Audio and transcript warnings use `AUDIO_WARNING` and `TRANSCRIPT_WARNING`; controller clock/randomness and CSS transition warnings use `DETERMINISM_WARNING`. See [diagnostics](diagnostics.md) for the code table.
|
|
55
|
+
|
|
56
|
+
## lint
|
|
57
|
+
|
|
58
|
+
`lint` reports `kind: "composition"` or `kind: "timeline"` and the same diagnostic shape. A timeline result includes `framesProjected`, `segments`, `tracks`, `clips`, and `transitions`; a composition result includes `metadata` and reports `framesProjected: 0` because lint does not seek frames. The result also includes the active `policy` details.
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"ok": true,
|
|
63
|
+
"command": "lint",
|
|
64
|
+
"policy": { "policy": "authoring", "maxStillFrames": 4, "allowOverwrite": false, "source": "env" },
|
|
65
|
+
"kind": "timeline",
|
|
66
|
+
"timeline": "main",
|
|
67
|
+
"entry": "timelines/main.timeline.json",
|
|
68
|
+
"format": { "width": 1920, "height": 1080, "fps": 30 },
|
|
69
|
+
"durationInFrames": 900,
|
|
70
|
+
"framesProjected": 900,
|
|
71
|
+
"segments": 3,
|
|
72
|
+
"diagnostics": [],
|
|
73
|
+
"elapsedMs": 2
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`lint` does not run `validateProps` or composition runtime. A clean lint is not a successful `check`.
|
|
78
|
+
|
|
79
|
+
## context
|
|
80
|
+
|
|
81
|
+
`context` returns a read-only project digest. It includes `root`, `format`, `policy`, `compositions`, `timelines`, `assets`, `fonts`, `next`, and `truncated`. Each composition carries its resolved `metadata`, prop `path`/`type` pairs, controller, and diagnostic counts; each timeline carries duration, tracks, clip summaries, transitions, audio/transcript counts, and diagnostic counts. Each font carries `id`, `family`, `provider`, optional `version`, `variable`, `subsets`, `styles`, `license`, `files`, `bytes`, and `status`. `truncated.fonts` reports a clipped font list.
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"ok": true,
|
|
86
|
+
"command": "context",
|
|
87
|
+
"root": "/path/to/project",
|
|
88
|
+
"format": { "width": 1920, "height": 1080, "fps": 30 },
|
|
89
|
+
"policy": { "policy": "authoring", "profile": "shared-cpu", "maxStillFrames": 4, "allowOverwrite": false, "source": "file" },
|
|
90
|
+
"compositions": [
|
|
91
|
+
{ "id": "main", "entry": "compositions/main.html", "kind": "animated", "metadata": { "width": 1920, "height": 1080, "fps": 30, "durationInFrames": 900 }, "controller": { "kind": "external", "src": "compositions/main.controller.js" }, "props": [{ "path": "title", "type": "string" }], "diagnostics": { "errors": 0, "warnings": 0, "codes": [] } }
|
|
92
|
+
],
|
|
93
|
+
"timelines": [],
|
|
94
|
+
"assets": [],
|
|
95
|
+
"next": ["npx frameyard lint main --json"],
|
|
96
|
+
"truncated": { "clips": false, "assets": false, "props": false }
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## inspect
|
|
101
|
+
|
|
102
|
+
`inspect` decodes the first frame and reports `width`, `height`, `bytes`, `alpha`, `blank`, `background`, `content`, `colors`, `luminanceGrid`, and `edgeDensity`. `alpha.coverage` is the opaque fraction; `content.bbox` is `null` when no pixels differ from the background. It never launches Chromium.
|
|
103
|
+
|
|
104
|
+
## compare
|
|
105
|
+
|
|
106
|
+
`compare` reports `identical`, `differingPixels`, `totalPixels`, `percent`, `maxChannelDelta`, `meanChannelDelta`, `bbox`, and 3×3 `regions`. It exits 1 when the images differ; the JSON body still has `ok: true` and `identical: false`. Different dimensions fail with `IMAGE_INVALID`.
|
|
107
|
+
|
|
108
|
+
## add
|
|
109
|
+
|
|
110
|
+
`add --list` returns `templates` with `name`, `kind`, `description`, and optional `prerequisites`. Adding an entry returns `kind`, `id`, `template`, `entry`, `path`, `register`, `prerequisites`, and `next`. `register` is the exact object to merge into `fy.config.js`; `add` does not edit the config itself.
|
|
111
|
+
|
|
112
|
+
## font
|
|
113
|
+
|
|
114
|
+
`font search` returns `provider: "fontsource"`, the `query`, applied `filters`, `results`, and `truncated`. Each result has `id`, `family`, `category`, `variable`, `weights`, `styles`, `subsets`, `license`, optional `version`, and `type`.
|
|
115
|
+
|
|
116
|
+
`font add` (Fontsource id, `--file`, or `--url`) returns `action: "add"`, a `font` summary (`id`, `family`, `provider`, optional `version`, `variable`, `subsets`, `styles`, `license`, `files`, `bytes`, `status`), the `manifest` path, installed `files`, `warnings`, and `next` commands. Fontsource results identify `provider: "fontsource"` and the pinned `version`; URL results identify `provider: "url"`. `font list` returns `manifest` and a `fonts` array of the same summaries. `font verify` returns `manifest`, `fonts`, `files`, `bytes`, `valid`, and `diagnostics`; errors exit 1, warnings exit 0. `font remove` returns `id`, `family`, `manifest`, `files`, and `keptFiles`.
|
|
117
|
+
|
|
118
|
+
```json
|
|
119
|
+
{
|
|
120
|
+
"ok": true,
|
|
121
|
+
"command": "font",
|
|
122
|
+
"action": "verify",
|
|
123
|
+
"manifest": "/project/fy.fonts.json",
|
|
124
|
+
"fonts": 1,
|
|
125
|
+
"files": 1,
|
|
126
|
+
"bytes": 22288,
|
|
127
|
+
"valid": true,
|
|
128
|
+
"diagnostics": []
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
A present-but-invalid manifest fails with `FONT_MANIFEST_INVALID`; missing files use `FONT_FILE_MISSING`, changed content uses `FONT_HASH_MISMATCH`, and a failed browser load uses `FONT_LOAD_FAILED`. Remote font CSS is a `FONT_REMOTE` warning. Fontsource network or API failures use `FONT_PROVIDER_UNAVAILABLE`; invalid downloaded WOFF2 content uses `FONT_DOWNLOAD_FAILED`; a missing Fontsource family or `font remove` id uses `FONT_NOT_FOUND`.
|
|
133
|
+
|
|
134
|
+
## dry run
|
|
135
|
+
|
|
136
|
+
`tts`, `transcribe`, and `render` accept `--dry-run`. The result has `dryRun: true`, the active `policy`, a command-specific `plan`, a shell-ready `commandLine`, `prerequisites`, `blockers`, and the output path. It does not create the output directory, write the manifest, load a model, launch Chromium, or encode.
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"ok": true,
|
|
141
|
+
"command": "render",
|
|
142
|
+
"dryRun": true,
|
|
143
|
+
"deferred": true,
|
|
144
|
+
"policy": { "policy": "authoring", "maxStillFrames": 4, "allowOverwrite": false, "source": "env" },
|
|
145
|
+
"plan": { "kind": "video", "frames": 900, "segments": 3, "workers": 2, "encoder": "auto", "codec": "h264", "container": "mp4", "probed": false },
|
|
146
|
+
"commandLine": "FRAMEYARD_POLICY=full npx frameyard render main --workers 2 --codec h264 --container mp4",
|
|
147
|
+
"prerequisites": ["assets/voice.wav"],
|
|
148
|
+
"blockers": [],
|
|
149
|
+
"diagnostics": [],
|
|
150
|
+
"output": { "path": "out/main.mp4", "exists": false }
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
An existing output appears in `blockers` with `OUTPUT_EXISTS`; the dry run still exits 0. The handoff command includes `FRAMEYARD_POLICY=full` when the active tier is not `full`. A dry run is not a render; `deferred: true` means the heavy operation was not executed and the `commandLine` is the handoff.
|
|
55
155
|
|
|
56
156
|
## check
|
|
57
157
|
|
|
158
|
+
Animated composition results report `kind: "animated"`. `metadata` reports the resolved format, combining declared values with the project `format`.
|
|
159
|
+
|
|
58
160
|
```json
|
|
59
161
|
{
|
|
60
162
|
"ok": true,
|
|
61
163
|
"command": "check",
|
|
164
|
+
"kind": "animated",
|
|
62
165
|
"composition": "hello",
|
|
63
166
|
"entry": "compositions/hello.html",
|
|
64
167
|
"controller": { "kind": "inline" },
|
|
@@ -89,7 +192,28 @@ Static validation diagnostics include source locations. Runtime diagnostics may
|
|
|
89
192
|
}
|
|
90
193
|
```
|
|
91
194
|
|
|
92
|
-
`entry` is the project-relative
|
|
195
|
+
`entry` is the project-relative composition fragment path. `controller` is `{ kind: "inline" }`, `{ kind: "external", src }`, or `null`.
|
|
196
|
+
|
|
197
|
+
A static composition result reports `kind: "static"`, dimensions only, `framesChecked: 1`, and no audio/transcript fields:
|
|
198
|
+
|
|
199
|
+
```json
|
|
200
|
+
{
|
|
201
|
+
"ok": true,
|
|
202
|
+
"command": "check",
|
|
203
|
+
"kind": "static",
|
|
204
|
+
"composition": "still",
|
|
205
|
+
"entry": "compositions/still.html",
|
|
206
|
+
"controller": null,
|
|
207
|
+
"metadata": { "width": 1920, "height": 1080, "static": true },
|
|
208
|
+
"framesChecked": 1,
|
|
209
|
+
"diagnostics": [],
|
|
210
|
+
"elapsedMs": 600
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Timeline check
|
|
215
|
+
|
|
216
|
+
A timeline check reports `timeline`, `entry`, `format`, `durationInFrames`, `framesChecked`, `tracks`, `clips`, `transitions`, `audio`, `transcripts`, `diagnostics`, and `elapsedMs`. `framesChecked` equals the timeline duration; `transitions` is the resolved count, and transition diagnostics carry `from`/`to` and `jsonPath` in `details`.
|
|
93
217
|
|
|
94
218
|
## still
|
|
95
219
|
|
|
@@ -111,14 +235,17 @@ Static validation diagnostics include source locations. Runtime diagnostics may
|
|
|
111
235
|
}
|
|
112
236
|
```
|
|
113
237
|
|
|
114
|
-
`frames` is always present and follows the expanded `--frame` order. `frame` and `path` are also present only when exactly one frame was captured. `--frame` accepts a number, an inclusive range (`2-12`), or a comma-separated list; at most 32 unique frames are captured per invocation. With multiple frames, `--out` is a directory and the files are named `still-<id>-<frame>.png`.
|
|
238
|
+
`frames` is always present and follows the expanded `--frame` order. `frame` and `path` are also present only when exactly one frame was captured. `--frame` accepts a number, an inclusive range (`2-12`), or a comma-separated list; at most 32 unique frames are captured per invocation. With multiple frames, `--out` is a directory and the files are named `still-<id>-<frame>.png`. A static composition exposes only frame `0`; other frames fail with `FRAME_OUT_OF_RANGE`.
|
|
115
239
|
|
|
116
240
|
## render
|
|
117
241
|
|
|
242
|
+
Animated composition and timeline results report `kind: "video"`:
|
|
243
|
+
|
|
118
244
|
```json
|
|
119
245
|
{
|
|
120
246
|
"ok": true,
|
|
121
247
|
"command": "render",
|
|
248
|
+
"kind": "video",
|
|
122
249
|
"composition": "hello",
|
|
123
250
|
"entry": "compositions/hello.html",
|
|
124
251
|
"controller": { "kind": "inline" },
|
|
@@ -141,7 +268,26 @@ Static validation diagnostics include source locations. Runtime diagnostics may
|
|
|
141
268
|
}
|
|
142
269
|
```
|
|
143
270
|
|
|
144
|
-
A
|
|
271
|
+
A static composition result reports `kind: "image"` and has no fps, duration, frame count, codec, container, encoder, audio, or transcript fields:
|
|
272
|
+
|
|
273
|
+
```json
|
|
274
|
+
{
|
|
275
|
+
"ok": true,
|
|
276
|
+
"command": "render",
|
|
277
|
+
"kind": "image",
|
|
278
|
+
"composition": "still",
|
|
279
|
+
"entry": "compositions/still.html",
|
|
280
|
+
"controller": null,
|
|
281
|
+
"path": "/absolute/path/out/still.png",
|
|
282
|
+
"width": 1920,
|
|
283
|
+
"height": 1080,
|
|
284
|
+
"bytes": 48210,
|
|
285
|
+
"diagnostics": [],
|
|
286
|
+
"elapsedMs": 700
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
A successful render means the final path exists and was published atomically. A nonzero exit means no new partial output was published. Without `--out`, the final path is `out/<composition-id>.<ext>` for video and `out/<composition-id>.png` for a static composition inside the project root. `concurrency` is the number of browser sessions actually used; it is capped by `durationInFrames` and by the CLI maximum of 16, and a static composition rejects it. `container` is `mp4`, `mov`, `mkv`, or `webm`; `codec` is `h264`, `hevc`, or `vp9`; and `encoder` is the resolved encoder (`libx264`, `libx265`, `libvpx-vp9`, `h264_nvenc`, `hevc_nvenc`, `h264_qsv`, or `hevc_qsv`). Timeline results also report the effective `workers` count after the encoder session cap, with an `ENCODER_WARNING` diagnostic when it was reduced.
|
|
145
291
|
|
|
146
292
|
## tts
|
|
147
293
|
|
|
@@ -149,6 +295,7 @@ A successful render means the final path exists and was published atomically. A
|
|
|
149
295
|
{
|
|
150
296
|
"ok": true,
|
|
151
297
|
"command": "tts",
|
|
298
|
+
"engine": "qwen",
|
|
152
299
|
"path": "/absolute/path/assets/voice.wav",
|
|
153
300
|
"bytes": 480000,
|
|
154
301
|
"sha256": "64-character hex digest",
|
|
@@ -156,12 +303,12 @@ A successful render means the final path exists and was published atomically. A
|
|
|
156
303
|
"channels": 1,
|
|
157
304
|
"speaker": "vivian",
|
|
158
305
|
"language": "English",
|
|
159
|
-
"manifest": "/absolute/path/
|
|
306
|
+
"manifest": "/absolute/path/fy.assets.json",
|
|
160
307
|
"elapsedMs": 12000
|
|
161
308
|
}
|
|
162
309
|
```
|
|
163
310
|
|
|
164
|
-
`language` is omitted when it was not supplied.
|
|
311
|
+
`engine` is `qwen` or `supertonic`. `language` is omitted when it was not supplied; Supertonic always supplies it. `device` is present only for qwen.
|
|
165
312
|
|
|
166
313
|
## transcribe
|
|
167
314
|
|
|
@@ -188,7 +335,7 @@ A successful render means the final path exists and was published atomically. A
|
|
|
188
335
|
"sha256": "64-character hex digest"
|
|
189
336
|
}
|
|
190
337
|
],
|
|
191
|
-
"manifest": "/absolute/path/
|
|
338
|
+
"manifest": "/absolute/path/fy.assets.json",
|
|
192
339
|
"elapsedMs": 30000
|
|
193
340
|
}
|
|
194
341
|
```
|
|
@@ -197,6 +344,8 @@ A successful render means the final path exists and was published atomically. A
|
|
|
197
344
|
|
|
198
345
|
## doctor
|
|
199
346
|
|
|
347
|
+
The doctor result adds `policy` and `resources` fields. `policy.status` is `ok` or `error`; an invalid policy is reported as a finding without preventing the environment checks. `resources` reports platform, architecture, CPU count, load average, and total/free memory. `fonts` reports the project font manifest path, whether it exists, `valid`, installed `fonts`/`files`/`bytes`, and an optional `detail` for the first integrity problem.
|
|
348
|
+
|
|
200
349
|
Doctor reports findings rather than throwing for environment problems. `ok: true` means the inspection completed; `healthy` says whether required checks, manifest integrity, explicitly supplied models, and integration compatibility passed. `ffmpeg-opus-encoder` and `ffmpeg-video-encoders` are optional: the video check probes each supported encoder with a one-frame encode and lists any that FFmpeg advertises but cannot open (an old driver, for example), and neither check affects `healthy`.
|
|
201
350
|
|
|
202
351
|
```json
|
|
@@ -229,6 +378,12 @@ Doctor reports findings rather than throwing for environment problems. `ok: true
|
|
|
229
378
|
"status": "missing",
|
|
230
379
|
"requested": false,
|
|
231
380
|
"referenceRevision": "..."
|
|
381
|
+
},
|
|
382
|
+
"sherpaOnnxTts": {
|
|
383
|
+
"name": "sherpa-onnx-offline-tts",
|
|
384
|
+
"status": "missing",
|
|
385
|
+
"requested": false,
|
|
386
|
+
"referenceRevision": "..."
|
|
232
387
|
}
|
|
233
388
|
},
|
|
234
389
|
"models": [
|
|
@@ -240,8 +395,8 @@ Doctor reports findings rather than throwing for environment problems. `ok: true
|
|
|
240
395
|
"sha256": "64-character hex digest"
|
|
241
396
|
}
|
|
242
397
|
],
|
|
243
|
-
"manifest": { "path": "/absolute/path/
|
|
398
|
+
"manifest": { "path": "/absolute/path/fy.assets.json", "exists": true, "valid": true, "artifacts": 2 }
|
|
244
399
|
}
|
|
245
400
|
```
|
|
246
401
|
|
|
247
|
-
`models` is populated only for model paths passed explicitly with `--talker-model`, `--codec-model`, or `--model`. `healthy: false` exits `1`. Missing optional integrations do not fail, but a found executable with incompatible capabilities does.
|
|
402
|
+
`models` is populated only for model paths passed explicitly with `--talker-model`, `--codec-model`, `--model-dir`, or `--model`. A Supertonic `--model-dir` reports one entry with role `supertonic`; `tts` provenance records the seven individual model files. `healthy: false` exits `1`. Missing optional integrations do not fail, but a found executable with incompatible capabilities does.
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# Quick reference
|
|
2
|
+
|
|
3
|
+
Use this page when context is limited or when you need one canonical skeleton.
|
|
4
|
+
Read a topic reference only when the task needs it; the full contract is in
|
|
5
|
+
`SKILL.md` and the linked references.
|
|
6
|
+
|
|
7
|
+
## Choose the smallest authoring level
|
|
8
|
+
|
|
9
|
+
1. **Static composition** for a poster, card, or thumbnail: no `duration-in-frames`, no `fps`, renders to PNG.
|
|
10
|
+
2. **CSS animation** for timed reveals, wipes, and simple motion: `@keyframes` plus `data-fy-anim-*`.
|
|
11
|
+
3. **Bindings** for props-driven text, attributes, classes, conditionals, and repeats.
|
|
12
|
+
4. **Controller** for Canvas 2D, WebGL, karaoke, or per-frame math CSS cannot express.
|
|
13
|
+
5. **Timeline** when several compositions, media clips, or audio tracks must share one deliverable.
|
|
14
|
+
|
|
15
|
+
Do not use a controller when CSS or bindings are enough.
|
|
16
|
+
|
|
17
|
+
## Animated composition
|
|
18
|
+
|
|
19
|
+
A composition is a partial HTML fragment, never a full document. Props, the
|
|
20
|
+
controller, import maps, and styles are top-level siblings of the root.
|
|
21
|
+
|
|
22
|
+
```html
|
|
23
|
+
<script type="application/json" data-fy="props">{ "title": "Hello" }</script>
|
|
24
|
+
<style>
|
|
25
|
+
html, body { margin: 0; width: 100%; height: 100%; }
|
|
26
|
+
@keyframes rise { from { opacity: 0; } to { opacity: 1; } }
|
|
27
|
+
h1 { animation: rise 1s linear both; font: 8vmin system-ui; color: white; }
|
|
28
|
+
body { background: #101820; display: grid; place-items: center; }
|
|
29
|
+
</style>
|
|
30
|
+
<fy-composition duration-in-frames="150">
|
|
31
|
+
<h1 data-fy-text="title" data-fy-anim-start="0" data-fy-anim-duration="30"></h1>
|
|
32
|
+
</fy-composition>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`width`, `height`, and `fps` are optional and inherit the project `format`.
|
|
36
|
+
Declare both `width` and `height` together. Never derive metadata from props.
|
|
37
|
+
|
|
38
|
+
## Static composition
|
|
39
|
+
|
|
40
|
+
```html
|
|
41
|
+
<script type="application/json" data-fy="props">{ "title": "Poster" }</script>
|
|
42
|
+
<style>
|
|
43
|
+
body { margin: 0; background: #0c1220; color: #ff7a45; display: grid; place-items: center; }
|
|
44
|
+
h1 { font: 8vmin system-ui; }
|
|
45
|
+
</style>
|
|
46
|
+
<fy-composition>
|
|
47
|
+
<h1 data-fy-text="title"></h1>
|
|
48
|
+
</fy-composition>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
A static composition has no frame clock: no `data-fy-anim-*`, no `<video>`,
|
|
52
|
+
`<audio>`, or `<fy-transcript>`. Its controller runs `mount()` only.
|
|
53
|
+
|
|
54
|
+
## Fonts
|
|
55
|
+
|
|
56
|
+
Fontsource is the default catalog. Search, then install a pinned family:
|
|
57
|
+
|
|
58
|
+
```sh
|
|
59
|
+
npx frameyard font search "space grotesk" --subset latin --json
|
|
60
|
+
npx frameyard font add space-grotesk --subset latin
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Variable families install the `wght` face by default. Use `--static --weight
|
|
64
|
+
400,700` for static files. A local or brand font uses `font add --file`; an
|
|
65
|
+
explicit HTTPS source uses `font add --url` and may pass `--sha256`. A URL
|
|
66
|
+
import without `--license` or `--license-file` is recorded as unknown and
|
|
67
|
+
requires `full`.
|
|
68
|
+
|
|
69
|
+
Then use the family name normally:
|
|
70
|
+
|
|
71
|
+
```css
|
|
72
|
+
h1 { font-family: "Space Grotesk", system-ui, sans-serif; font-weight: 700; }
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The server injects `@font-face` before author styles, uses `font-display: block`,
|
|
76
|
+
and the host waits for `document.fonts.ready`. Run `font verify` after moving
|
|
77
|
+
files. Remote font URLs produce `FONT_REMOTE`; a used face that fails to load
|
|
78
|
+
produces `FONT_LOAD_FAILED`. See [fonts](fonts.md).
|
|
79
|
+
|
|
80
|
+
## Timeline
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"version": 1,
|
|
85
|
+
"tracks": [
|
|
86
|
+
{ "id": "v1", "kind": "video" },
|
|
87
|
+
{ "id": "a1", "kind": "audio" }
|
|
88
|
+
],
|
|
89
|
+
"clips": [
|
|
90
|
+
{
|
|
91
|
+
"id": "intro",
|
|
92
|
+
"track": "v1",
|
|
93
|
+
"source": { "kind": "composition", "id": "intro" },
|
|
94
|
+
"start": 0
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"id": "music",
|
|
98
|
+
"track": "a1",
|
|
99
|
+
"source": { "kind": "audio", "src": "assets/music.wav" },
|
|
100
|
+
"start": 0,
|
|
101
|
+
"duration": 150,
|
|
102
|
+
"audio": { "gain": 0.6 }
|
|
103
|
+
}
|
|
104
|
+
]
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`start`, `sourceIn`, and `duration` are timeline frames. Image clips and static
|
|
109
|
+
composition clips require an explicit `duration`; a static composition clip
|
|
110
|
+
needs `sourceIn: 0` and contributes no audio. Source kinds are `composition`,
|
|
111
|
+
`timeline`, `video`, `image`, and `audio`.
|
|
112
|
+
|
|
113
|
+
## Bindings
|
|
114
|
+
|
|
115
|
+
- `data-fy-text="path"` sets text.
|
|
116
|
+
- `data-fy-attr-src="path"` sets an attribute.
|
|
117
|
+
- `data-fy-class-active="path"` toggles a class.
|
|
118
|
+
- `data-fy-if="path"` removes the element when false.
|
|
119
|
+
- `<template data-fy-repeat="items">` clones content; use `item` and `index`.
|
|
120
|
+
- Paths are dot-separated; missing paths warn and resolve empty.
|
|
121
|
+
|
|
122
|
+
Bindings apply once per load, before `mount()`. Controller-created DOM is not
|
|
123
|
+
re-bound.
|
|
124
|
+
|
|
125
|
+
## Controller
|
|
126
|
+
|
|
127
|
+
```html
|
|
128
|
+
<script type="text/fy-controller">
|
|
129
|
+
export default {
|
|
130
|
+
mount({ root, props }) {},
|
|
131
|
+
update({ frame, props }) {},
|
|
132
|
+
dispose() {},
|
|
133
|
+
};
|
|
134
|
+
</script>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Exactly one controller is allowed, inline or external. `mount` may be async;
|
|
138
|
+
`update` is synchronous and seek-safe. The controller is the only executable
|
|
139
|
+
code. Use `random("stable:key")` from `frameyard/runtime`, never `Math.random()`.
|
|
140
|
+
|
|
141
|
+
## Commands
|
|
142
|
+
|
|
143
|
+
| Command | Use |
|
|
144
|
+
| --- | --- |
|
|
145
|
+
| `npx frameyard context --json` | One compact project digest: format, props, timelines, assets, policy, next commands |
|
|
146
|
+
| `npx frameyard lint <id> --json` | Fast edit loop: static validation, scene/keyframe projection, controller determinism |
|
|
147
|
+
| `npx frameyard check <id> --json` | Full gate: props hooks and every animated frame through Chromium |
|
|
148
|
+
| `npx frameyard still <id> --frame <spec> --json` | Inspect representative frames; policy caps the count |
|
|
149
|
+
| `npx frameyard inspect <image> --json` | Blank, alpha, colors, content bbox, luminance grid, edge density |
|
|
150
|
+
| `npx frameyard compare <a> <b> --json` | Pixel and 3×3 region diff; exits 1 when different |
|
|
151
|
+
| `npx frameyard render <id> --dry-run --json` | Handoff plan without Chromium, FFmpeg, or a model |
|
|
152
|
+
| `npx frameyard render <id> --json` | Produce the video when the policy allows it |
|
|
153
|
+
| `npx frameyard add --list --json` | List project templates |
|
|
154
|
+
| `npx frameyard add composition <id> --template <name> --json` | Write a valid fragment and print the config snippet |
|
|
155
|
+
| `npx frameyard font search <query> --json` | Search Fontsource by name, category, subset, style, or variable |
|
|
156
|
+
| `npx frameyard font add <fontsource-id> --json` | Pin and vendor a Fontsource family; variable `wght` by default |
|
|
157
|
+
| `npx frameyard font add <fontsource-id> --static --weight 400,700 --json` | Install explicit static weights |
|
|
158
|
+
| `npx frameyard font add --file <path> --family <name> --json` | Vendor a local font into `assets/fonts/` and update `fy.fonts.json` |
|
|
159
|
+
| `npx frameyard font add --url <https-url> --family <name> --json` | Download and vendor an HTTPS font, optionally with `--sha256` |
|
|
160
|
+
| `npx frameyard font list --json` | Installed families, subsets, licenses, files, and status |
|
|
161
|
+
| `npx frameyard font verify --json` | Manifest paths, hashes, licenses, and orphaned directories |
|
|
162
|
+
| `npx frameyard font remove <id> --json` | Remove a font and its directory; `--keep-files` keeps the binaries |
|
|
163
|
+
| `npx frameyard doctor --json` | Environment, integrations, policy, fonts, and resources |
|
|
164
|
+
|
|
165
|
+
Every non-interactive command accepts `--json`. Parse stdout; read stderr for
|
|
166
|
+
progress and diagnostics.
|
|
167
|
+
|
|
168
|
+
## Resource policy
|
|
169
|
+
|
|
170
|
+
`fy.policy.json` is discovered from the working directory upward,
|
|
171
|
+
independent of `fy.config.js`.
|
|
172
|
+
|
|
173
|
+
| Tier | `still` | `check` | `tts`/`transcribe`/`render` | overwrite |
|
|
174
|
+
| --- | --- | --- | --- | --- |
|
|
175
|
+
| `light` | 1 frame | blocked | blocked | denied |
|
|
176
|
+
| `authoring` | 4 frames | low priority | blocked | denied |
|
|
177
|
+
| `full` | 32 frames | allowed | allowed | allowed |
|
|
178
|
+
|
|
179
|
+
`lint`, `context`, `doctor`, `add`, `inspect`, `compare`, and `--dry-run` are
|
|
180
|
+
available in every tier. `font search`, `font list`, and `font verify` are
|
|
181
|
+
available in every tier; `font add` requires `authoring` or `full`; `font
|
|
182
|
+
remove`, `font add --force`, and `font add --url` without
|
|
183
|
+
`--license`/`--license-file` require `full`. When a heavy command is blocked, run it with `--dry-run`, report `deferred: true`, and give the user
|
|
184
|
+
`commandLine`, `prerequisites`, and `blockers`.
|
|
185
|
+
|
|
186
|
+
## Ten diagnostics that matter
|
|
187
|
+
|
|
188
|
+
| Code | Fix |
|
|
189
|
+
| --- | --- |
|
|
190
|
+
| `COMPOSITION_DOCUMENT_SHELL` | Remove `<!doctype>`, `<html>`, `<head>`, and `<body>`; compositions are fragments |
|
|
191
|
+
| `COMPOSITION_FORMAT_UNRESOLVED` | Declare `width`/`height` or add project `format` |
|
|
192
|
+
| `COMPOSITION_INVALID` | Check the single `<fy-composition>` root and metadata |
|
|
193
|
+
| `CONTROLLER_INVALID` | Exactly one controller; inline XOR `src`; at least one export |
|
|
194
|
+
| `SCRIPT_NOT_ALLOWED` | Move executable code into the controller |
|
|
195
|
+
| `BINDING_PATH_MISSING` | Fix the props path; use the diagnostic suggestion |
|
|
196
|
+
| `BINDING_INVALID` | Unknown `data-fy-*` attribute; use a documented binding |
|
|
197
|
+
| `TIMELINE_CLIP_OUT_OF_RANGE` | Keyframes cannot extend a clip; lengthen the clip or move the key |
|
|
198
|
+
| `TIMELINE_CLIP_OVERLAP` | Declare a transition or move the clip |
|
|
199
|
+
| `RESOURCE_POLICY_BLOCKED` | Use `--dry-run`, or ask the user for `FRAMEYARD_POLICY=full` |
|
|
200
|
+
|
|
201
|
+
Font diagnostics: `FONT_HASH_MISMATCH` means the vendored file changed; restore
|
|
202
|
+
it or reinstall with `font add --force`. `FONT_LOAD_FAILED` means a used face
|
|
203
|
+
did not load; check the manifest and `font verify`. `FONT_REMOTE` is a warning
|
|
204
|
+
that the composition still depends on a remote font URL.
|
|
205
|
+
|
|
206
|
+
## Do not
|
|
207
|
+
|
|
208
|
+
- Use `Date.now()`, `performance.now()`, timers, `requestAnimationFrame` loops, or CSS transitions as animation inputs.
|
|
209
|
+
- Call `play()`, `pause()`, or set `currentTime` on embedded media.
|
|
210
|
+
- Fetch remote data from `update()`; load during `mount()`.
|
|
211
|
+
- Put visual content outside `<fy-composition>`.
|
|
212
|
+
- Edit `fy.policy.json`, host configuration, or the skill source.
|
|
213
|
+
- Claim success when `check` fails, a still is missing, or a render did not run.
|
|
214
|
+
|
|
215
|
+
## Next
|
|
216
|
+
|
|
217
|
+
- Full authoring rules: [deterministic authoring](deterministic-authoring.md)
|
|
218
|
+
- Fonts: [fonts](fonts.md)
|
|
219
|
+
- Timelines and keyframes: [timelines](timelines.md)
|
|
220
|
+
- Error codes: [diagnostics](diagnostics.md)
|
|
221
|
+
- Result shapes: [JSON results](json-results.md)
|
|
222
|
+
- Recovery loops: [failure recovery](failure-recovery.md)
|