frameyard 0.8.0 → 0.10.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 +177 -14
- package/GLOSSARY.md +112 -2
- package/README.md +302 -265
- 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 +1685 -93
- package/dist/cli.js.map +1 -1
- package/dist/composition/format.d.ts +1 -1
- package/dist/composition/format.d.ts.map +1 -1
- package/dist/composition/format.js +1 -1
- package/dist/composition/format.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 +25 -0
- package/dist/contracts.d.ts.map +1 -1
- 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/validate.d.ts.map +1 -1
- package/dist/html/validate.js +59 -0
- package/dist/html/validate.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- 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/fonts/LICENSE-figtree.txt +93 -0
- package/dist/preview/fonts/LICENSE-space-mono.txt +93 -0
- package/dist/preview/fonts/README.md +23 -0
- package/dist/preview/fonts/figtree-latin-wght-normal.woff2 +0 -0
- package/dist/preview/fonts/space-mono-latin-400-normal.woff2 +0 -0
- package/dist/preview/fonts/space-mono-latin-700-normal.woff2 +0 -0
- package/dist/preview/main.js +5 -2
- package/dist/preview/main.js.map +1 -1
- package/dist/preview/timeline-data.d.ts +17 -69
- 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 +70 -45
- 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 +88 -27
- package/dist/preview/timeline-main.js.map +1 -1
- package/dist/project.d.ts +10 -3
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +20 -17
- package/dist/project.js.map +1 -1
- package/dist/renderer/audio.d.ts +6 -0
- package/dist/renderer/audio.d.ts.map +1 -1
- package/dist/renderer/audio.js +3 -1
- package/dist/renderer/audio.js.map +1 -1
- package/dist/renderer/browser.d.ts.map +1 -1
- package/dist/renderer/browser.js +13 -0
- package/dist/renderer/browser.js.map +1 -1
- package/dist/renderer/concurrency.d.ts +6 -0
- package/dist/renderer/concurrency.d.ts.map +1 -0
- package/dist/renderer/concurrency.js +27 -0
- package/dist/renderer/concurrency.js.map +1 -0
- package/dist/renderer/ffmpeg.d.ts +104 -5
- package/dist/renderer/ffmpeg.d.ts.map +1 -1
- package/dist/renderer/ffmpeg.js +580 -67
- package/dist/renderer/ffmpeg.js.map +1 -1
- package/dist/renderer/index.js +1 -1
- 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/session-pool.d.ts +28 -0
- package/dist/renderer/session-pool.d.ts.map +1 -0
- package/dist/renderer/session-pool.js +91 -0
- package/dist/renderer/session-pool.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 +600 -147
- package/dist/renderer/timeline.js.map +1 -1
- package/dist/renderer/timings.d.ts +13 -0
- package/dist/renderer/timings.d.ts.map +1 -0
- package/dist/renderer/timings.js +29 -0
- package/dist/renderer/timings.js.map +1 -0
- package/dist/runtime/host.d.ts.map +1 -1
- package/dist/runtime/host.js +4 -0
- 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 -320
- package/dist/scaffold.js.map +1 -1
- package/dist/server/composition-html.d.ts +2 -0
- package/dist/server/composition-html.d.ts.map +1 -1
- package/dist/server/composition-html.js +7 -0
- package/dist/server/composition-html.js.map +1 -1
- package/dist/server/preview-html.d.ts.map +1 -1
- package/dist/server/preview-html.js +74 -188
- package/dist/server/preview-html.js.map +1 -1
- package/dist/server/preview-style.d.ts +11 -0
- package/dist/server/preview-style.d.ts.map +1 -0
- package/dist/server/preview-style.js +298 -0
- package/dist/server/preview-style.js.map +1 -0
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +31 -1
- 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 -34
- 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 +140 -148
- 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 +12 -0
- package/dist/timeline/resolve.d.ts.map +1 -1
- package/dist/timeline/resolve.js +105 -9
- 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 +31 -0
- package/dist/timeline/schema.d.ts.map +1 -1
- package/dist/timeline/schema.js +240 -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.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/docs/adr/0007-make-html-documents-the-composition-unit.md +1 -1
- package/docs/adr/0010-make-timelines-the-render-unit.md +3 -2
- 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 +2 -1
- package/docs/adr/0015-inherit-composition-format-from-the-project.md +2 -2
- package/docs/adr/0016-author-compositions-as-html-fragments.md +1 -1
- 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/adr/0024-stream-composition-captures-and-skip-trivial-composites.md +86 -0
- package/docs/adr/0025-capture-timeline-layers-in-parallel-with-a-global-limit.md +67 -0
- package/docs/adr/0026-reuse-loaded-composition-sessions-across-segments.md +70 -0
- package/docs/adr/0027-encode-two-full-frame-layers-through-dual-pipes.md +76 -0
- package/docs/adr/0028-encode-full-frame-video-segments-directly.md +65 -0
- package/docs/migration-0.4.md +2 -2
- package/docs/preview-testing.md +27 -6
- package/docs/{v0.1-design.md → v0.x-design.md} +57 -32
- package/examples/blend/README.md +3 -3
- package/examples/demo/README.md +2 -2
- 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 +2 -2
- 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/webgl/README.md +1 -1
- package/package.json +13 -6
- 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 -61
- package/skills/frameyard/references/audio-assets.md +32 -3
- package/skills/frameyard/references/common-mistakes.md +53 -2
- package/skills/frameyard/references/deterministic-authoring.md +10 -3
- package/skills/frameyard/references/diagnostics.md +31 -1
- package/skills/frameyard/references/failure-recovery.md +32 -6
- package/skills/frameyard/references/fonts.md +132 -0
- package/skills/frameyard/references/json-results.md +119 -6
- package/skills/frameyard/references/quick-reference.md +222 -0
- package/skills/frameyard/references/timelines.md +97 -7
- /package/examples/blend/{video.config.js → fy.config.js} +0 -0
- /package/examples/demo/{video.config.js → fy.config.js} +0 -0
- /package/examples/static/{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,131 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
This project produces deterministic, parameterized video with Frameyard. This file is the local summary; the official skill has the full contract.
|
|
4
|
+
|
|
5
|
+
## Project layout
|
|
6
|
+
|
|
7
|
+
- `fy.config.js` explicitly maps project IDs to sources. There is no directory scanning. It declares the project `format`, `compositions`, and `timelines`.
|
|
8
|
+
- `compositions/` contains HTML fragments; an optional controller lives beside the fragment as a `.controller.js` module.
|
|
9
|
+
- `timelines/` contains JSON timeline documents that assemble clips into one video.
|
|
10
|
+
- `props/hello.json` contains composition props; `props/main.json` contains timeline overrides keyed by composition clip ID.
|
|
11
|
+
- `out/` contains rendered files and is gitignored. `assets/` contains local media and generated assets.
|
|
12
|
+
- `package.json` pins the CLI in `dev`, `check`, `render`, and `still` scripts.
|
|
13
|
+
|
|
14
|
+
An animated composition declares `duration-in-frames`. A composition with neither `duration-in-frames` nor `fps` is static: it is captured once, renders to PNG, and cannot use animation, media, or transcripts. `width`, `height`, and `fps` inherit the project `format`; declare `width` and `height` together or not at all.
|
|
15
|
+
|
|
16
|
+
## Composition skeleton
|
|
17
|
+
|
|
18
|
+
A composition is a partial HTML fragment, not a full document. Keep one top-level `<fy-composition>`; props, the controller, import maps, and styles are top-level siblings. Do not add `<!doctype>`, `<html>`, `<head>`, `<body>`, `<title>`, or `<meta>`.
|
|
19
|
+
|
|
20
|
+
```html
|
|
21
|
+
<script type="application/json" data-fy="props">{ "title": "Hello" }</script>
|
|
22
|
+
<style>
|
|
23
|
+
html, body { margin: 0; width: 100%; height: 100%; }
|
|
24
|
+
</style>
|
|
25
|
+
<fy-composition width="1280" height="720" fps="30" duration-in-frames="150">
|
|
26
|
+
<h1 data-fy-text="title"></h1>
|
|
27
|
+
</fy-composition>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Timeline skeleton
|
|
31
|
+
|
|
32
|
+
`timelines/main.timeline.json` assembles clips in the project format:
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"version": 1,
|
|
37
|
+
"tracks": [{ "id": "v1", "kind": "video" }],
|
|
38
|
+
"clips": [
|
|
39
|
+
{
|
|
40
|
+
"id": "hello",
|
|
41
|
+
"track": "v1",
|
|
42
|
+
"source": { "kind": "composition", "id": "hello" },
|
|
43
|
+
"start": 0
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
- `source.kind` is `composition`, `timeline`, `video`, `image`, or `audio`. `start`, `sourceIn`, and `duration` are timeline frames. Image clips require a duration.
|
|
50
|
+
- A static composition clip needs an explicit `duration` and `sourceIn: 0`. It contributes no audio.
|
|
51
|
+
- Tracks composite bottom-to-top. Same-track overlap requires a timeline `transitions` entry; see the skill for transforms, keyframes, blends, and transitions.
|
|
52
|
+
|
|
53
|
+
## Bindings and animation
|
|
54
|
+
|
|
55
|
+
- Bindings: `data-fy-text`, `data-fy-attr-*`, `data-fy-class-*`, `data-fy-if`, and `<template data-fy-repeat>`. Primitive top-level props are also `--fy-prop-<name>` CSS variables.
|
|
56
|
+
- Bindings apply once, before `mount`; controller-created DOM is not re-bound.
|
|
57
|
+
- CSS/WAAPI animations are seeked from the frame clock. `data-fy-anim-start`, `data-fy-anim-duration`, and `data-fy-anim-easing` schedule one animation in frames.
|
|
58
|
+
- Frame state on `:root`: `--fy-frame`, `--fy-time`, `--fy-progress`, `--fy-fps`, `--fy-duration`, `--fy-duration-frames`.
|
|
59
|
+
|
|
60
|
+
## Controller
|
|
61
|
+
|
|
62
|
+
Exactly one optional controller is allowed, inline or external, as a top-level sibling. It may export `mount`, `update`, `dispose`, and `validateProps`; at least one is required. `mount` may be async; `update` is synchronous and seek-safe. The controller is the only executable code; other scripts and `on*` handlers are rejected. Extract large or reusable controllers to an external module.
|
|
63
|
+
|
|
64
|
+
```html
|
|
65
|
+
<script type="text/fy-controller">
|
|
66
|
+
export default {
|
|
67
|
+
mount({ root, props }) {},
|
|
68
|
+
update({ frame, props }) {},
|
|
69
|
+
};
|
|
70
|
+
</script>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Determinism
|
|
74
|
+
|
|
75
|
+
- A frame depends only on its integer `frame`, immutable `props`, and assets loaded before frame production.
|
|
76
|
+
- Use `random("stable:key")` from `frameyard/runtime`; never `Math.random()`, `Date.now()`, `performance.now()`, timers, independent `requestAnimationFrame` loops, or CSS transitions.
|
|
77
|
+
- Load remote data, fonts, and images before frames. Network is blocked during capture; do not `fetch()` from `update()`.
|
|
78
|
+
- Vendor fonts with `npx frameyard font add --file`; do not rely on a remote Google Fonts link for a deterministic render. The server injects `@font-face` rules and the host waits for `document.fonts.ready`.
|
|
79
|
+
- Let the runtime seek embedded video; do not play, pause, or set `currentTime`. Redraw Canvas/WebGL from the current frame.
|
|
80
|
+
- Do not run model inference inside `mount()`, `update()`, or frame production.
|
|
81
|
+
|
|
82
|
+
## Fonts
|
|
83
|
+
|
|
84
|
+
- `fy.fonts.json` records installed families, licenses, and SHA-256 values; commit it with `assets/fonts/`.
|
|
85
|
+
- Search Fontsource with `npx frameyard font search "<query>" --json`, then install a family with `npx frameyard font add <fontsource-id> --json`. Variable `wght` is the default; add `--static --weight 400,700` for static files.
|
|
86
|
+
- Use `npx frameyard font add --file <path> --family "<name>" --license <id> --license-file <path>` for a local or brand font. Use `--url` for an explicit HTTPS source with `--sha256`.
|
|
87
|
+
- Run `npx frameyard font list --json` and `npx frameyard font verify --json` after moving files. Do not edit manifest hashes by hand.
|
|
88
|
+
- `font add` requires `authoring` or `full`; `font remove`, `font add --force`, and an unlicensed `--url` import require `full`.
|
|
89
|
+
|
|
90
|
+
## Media and transcripts
|
|
91
|
+
|
|
92
|
+
- Composition audio uses `<audio>` with `data-fy-start` (frames), `data-fy-trim` (seconds), optional `data-fy-duration` (seconds), and `data-fy-volume` (0-1). Timeline audio uses frames and audio tracks.
|
|
93
|
+
- Media and transcript `src` values resolve from the project root; controller `src` and ordinary HTML URLs resolve from the composition URL.
|
|
94
|
+
- Declare transcripts with `<fy-transcript src="assets/voice.transcript.json" words>`. `words` requires measured word timings; never interpolate segment timings.
|
|
95
|
+
- Use Frameyard's `tts`/`transcribe` wrappers; never call `qwen-tts`, `sherpa-onnx-offline-tts`, or `whisper-cli` directly. Do not overwrite generated assets without approval. Commit `fy.assets.json` when present; do not edit hashes.
|
|
96
|
+
|
|
97
|
+
## Resource policy
|
|
98
|
+
|
|
99
|
+
A workspace can commit `fy.policy.json` to gate expensive operations. The nearest file from the working directory upward applies, independent of `fy.config.js`; `FRAMEYARD_POLICY` overrides it. `light` allows one still frame and blocks `check`, `tts`, `transcribe`, and `render`; `authoring` allows four still frames and `check` at low priority and blocks the three heavy operations; `full` allows everything up to the 32-frame still cap. `--profile shared-cpu` caps timeline workers at 2 and composition concurrency at 1. `tts`, `transcribe`, and `render` accept `--dry-run`; use it and report the handoff when blocked. The policy is a guardrail, not a security boundary.
|
|
100
|
+
|
|
101
|
+
## Agent workflow
|
|
102
|
+
|
|
103
|
+
1. Read `fy.config.js`, the timeline, the composition, its controller, and the props. Run `npx frameyard context --json` first.
|
|
104
|
+
2. Author with native HTML, CSS, SVG, Canvas, WebGL, and an optional controller. Use `npx frameyard add --list --json` for templates and merge the returned registration object into `fy.config.js`.
|
|
105
|
+
3. Lint the edit loop with `npx frameyard lint main --json`. It does not run `validateProps` or composition runtime.
|
|
106
|
+
4. Run `npx frameyard check main --json` for the full gate when the policy allows it; read diagnostics and warnings.
|
|
107
|
+
5. Inspect with `npx frameyard still main --frame <spec> --out <dir|file.png> --json`. The policy captures at most 32 unique frames in `full` (4 in `authoring`, 1 in `light`). Use `npx frameyard inspect`/`compare` for text facts; view the PNGs when possible.
|
|
108
|
+
6. Render with `npx frameyard render main --props props/main.json [--workers <n>] [--scratch <dir>] --json`. If the policy blocks it, use `--dry-run` and report the handoff.
|
|
109
|
+
7. Report sources, props, diagnostics, still paths, inspection status, output path, and failures. Never claim success when `check` fails, a still is missing, or a render exits nonzero.
|
|
110
|
+
|
|
111
|
+
## Commands
|
|
112
|
+
|
|
113
|
+
```sh
|
|
114
|
+
npx frameyard dev
|
|
115
|
+
npx frameyard context --json
|
|
116
|
+
npx frameyard doctor --json
|
|
117
|
+
npx frameyard add --list --json
|
|
118
|
+
npx frameyard lint main --json
|
|
119
|
+
npx frameyard check main --json
|
|
120
|
+
npx frameyard still main --frame 42 --out main-42.png --json
|
|
121
|
+
npx frameyard inspect main-42.png --json
|
|
122
|
+
npx frameyard render main --props props/main.json --workers 8 --scratch /path/to/scratch --json
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
- Use `--json` for non-interactive commands. Parse stdout; keep stderr for progress and diagnostics.
|
|
126
|
+
- Use `--project <dir>` outside the project root. Outputs default to `out/<id>.mp4` or `out/<id>.png`.
|
|
127
|
+
- `--concurrency` is for animated compositions; `--workers`/`--scratch` are for timelines. `--container <mp4|mov|mkv|webm>`, `--codec <h264|hevc|vp9>`, and `--encoder <auto|software|nvenc|qsv>` select delivery; the extension must match.
|
|
128
|
+
- `--dry-run` validates and prints a handoff plan. `--profile shared-cpu` caps workers/concurrency and lowers priority.
|
|
129
|
+
- `still`/`render` replace outputs only with `--overwrite`; generated assets only with `--force`, and only with approval. The resource policy denies both outside `full`.
|
|
130
|
+
|
|
131
|
+
The official `frameyard` agent skill has the full contract. Install it with `npx skills add vladiantio/frameyard`. This project was scaffolded with frameyard {{VERSION}}; `npx frameyard` resolves the latest version, so run `npx frameyard@{{VERSION}}` when you need the scaffolding version.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# My Frameyard project
|
|
2
|
+
|
|
3
|
+
Coding agents should read `AGENTS.md` for the project rules and the lint, check, still, and render workflow.
|
|
4
|
+
|
|
5
|
+
The reusable composition is a partial HTML fragment at `compositions/hello.html`. The edit is `timelines/main.timeline.json`, which places that composition as a clip in the project format. The project format is fixed in `fy.config.js`.
|
|
6
|
+
|
|
7
|
+
Start the preview:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npx frameyard dev
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The preview lists the timeline next to the compositions. Open the timeline to scrub it and inspect the program monitor.
|
|
14
|
+
|
|
15
|
+
Validate and render the timeline:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
npx frameyard doctor
|
|
19
|
+
npx frameyard check main
|
|
20
|
+
npx frameyard render main --props props/main.json
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`props/main.json` maps composition clip IDs to props overrides. The video is written to `out/main.mp4` in the project. Pass `--out <file.mp4>` to choose another path. Timelines with heavy composition work accept `--workers <n>` and `--scratch <dir>`.
|
|
24
|
+
|
|
25
|
+
The composition can still be previewed and rendered on its own:
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
npx frameyard check hello
|
|
29
|
+
npx frameyard render hello --props props/hello.json
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Install a font when the design needs one:
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
npx frameyard font search "space grotesk" --subset latin --json
|
|
36
|
+
npx frameyard font add space-grotesk --subset latin
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Or vendor a local font:
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
npx frameyard font add --file ./fonts/SpaceGrotesk.woff2 \
|
|
43
|
+
--family "Space Grotesk" --license OFL-1.1 --license-file ./fonts/OFL.txt
|
|
44
|
+
npx frameyard font verify
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The server injects the font sheet into every composition; use the family name in CSS. Commit `fy.fonts.json`, `assets/fonts/`, and license files. See `AGENTS.md` for the policy limits.
|
|
48
|
+
|
|
49
|
+
Or run the pinned scripts from `package.json`:
|
|
50
|
+
|
|
51
|
+
```sh
|
|
52
|
+
npm run dev
|
|
53
|
+
npm run check -- main
|
|
54
|
+
npm run render -- main --props props/main.json
|
|
55
|
+
npm run still -- main --frame 42 --out main-42.png
|
|
56
|
+
```
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<script type="application/json" data-fy="props">
|
|
2
|
+
{ "title": "Hello, Frameyard", "accent": "#b8f36b" }
|
|
3
|
+
</script>
|
|
4
|
+
<style>
|
|
5
|
+
@keyframes fade-up {
|
|
6
|
+
from {
|
|
7
|
+
opacity: 0;
|
|
8
|
+
transform: translateY(28px);
|
|
9
|
+
}
|
|
10
|
+
to {
|
|
11
|
+
opacity: 1;
|
|
12
|
+
transform: translateY(0);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
@keyframes drift {
|
|
16
|
+
from {
|
|
17
|
+
transform: translate(-120px, -80px);
|
|
18
|
+
}
|
|
19
|
+
to {
|
|
20
|
+
transform: translate(120px, 80px);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
#hello {
|
|
24
|
+
position: relative;
|
|
25
|
+
width: 100%;
|
|
26
|
+
height: 100%;
|
|
27
|
+
display: grid;
|
|
28
|
+
place-items: center;
|
|
29
|
+
overflow: hidden;
|
|
30
|
+
background: #0b0d10;
|
|
31
|
+
color: #e8edf3;
|
|
32
|
+
font-family: Inter, system-ui, sans-serif;
|
|
33
|
+
}
|
|
34
|
+
#hello h1 {
|
|
35
|
+
position: relative;
|
|
36
|
+
margin: 0;
|
|
37
|
+
font-size: 96px;
|
|
38
|
+
letter-spacing: -0.04em;
|
|
39
|
+
opacity: 0;
|
|
40
|
+
animation: fade-up 1s cubic-bezier(0.215, 0.61, 0.355, 1) both;
|
|
41
|
+
}
|
|
42
|
+
#hello p {
|
|
43
|
+
position: relative;
|
|
44
|
+
margin: 18px 0 0;
|
|
45
|
+
color: #8a97a6;
|
|
46
|
+
font-size: 26px;
|
|
47
|
+
}
|
|
48
|
+
#glow {
|
|
49
|
+
position: absolute;
|
|
50
|
+
left: 50%;
|
|
51
|
+
top: 50%;
|
|
52
|
+
width: 520px;
|
|
53
|
+
height: 520px;
|
|
54
|
+
margin: -260px 0 0 -260px;
|
|
55
|
+
border-radius: 50%;
|
|
56
|
+
background: var(--fy-prop-accent);
|
|
57
|
+
filter: blur(120px);
|
|
58
|
+
opacity: 0.16;
|
|
59
|
+
animation: drift 12s ease-in-out infinite alternate;
|
|
60
|
+
}
|
|
61
|
+
#sweep {
|
|
62
|
+
position: absolute;
|
|
63
|
+
left: 0;
|
|
64
|
+
bottom: 0;
|
|
65
|
+
width: calc(var(--fy-progress) * 100%);
|
|
66
|
+
height: 4px;
|
|
67
|
+
background: var(--fy-prop-accent);
|
|
68
|
+
}
|
|
69
|
+
</style>
|
|
70
|
+
<fy-composition width="1280" height="720" fps="30" duration-in-frames="150">
|
|
71
|
+
<div id="hello">
|
|
72
|
+
<div id="glow"></div>
|
|
73
|
+
<div style="position: relative; text-align: center">
|
|
74
|
+
<h1 id="title" data-fy-text="title" data-fy-anim-start="0" data-fy-anim-duration="24"></h1>
|
|
75
|
+
<p>Deterministic video, authored on the web.</p>
|
|
76
|
+
</div>
|
|
77
|
+
<div id="sweep"></div>
|
|
78
|
+
</div>
|
|
79
|
+
</fy-composition>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
out/
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{PROJECT_NAME}}",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "npx --yes frameyard@{{VERSION}} dev",
|
|
7
|
+
"check": "npx --yes frameyard@{{VERSION}} check",
|
|
8
|
+
"render": "npx --yes frameyard@{{VERSION}} render",
|
|
9
|
+
"still": "npx --yes frameyard@{{VERSION}} still"
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Optional local-model scaffold
|
|
2
|
+
|
|
3
|
+
Install these files into a workspace when a local model and Frameyard share the
|
|
4
|
+
same machine. They are not active in this repository by default.
|
|
5
|
+
|
|
6
|
+
```sh
|
|
7
|
+
npx frameyard add local-models
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
For a new project, install the normal scaffold and the host setup together:
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
npx frameyard init my-project --local-models
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Manual copy is still possible:
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
mkdir -p .opencode .pi
|
|
20
|
+
cp -R scaffolds/local-models/opencode/. .opencode/
|
|
21
|
+
cp -R scaffolds/local-models/pi/. .pi/
|
|
22
|
+
cp scaffolds/local-models/fy.policy.json .
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The CLI refuses to overwrite an existing file. If the target workspace already
|
|
26
|
+
has an `.opencode/opencode.jsonc` or `.pi/` configuration, merge the scaffold
|
|
27
|
+
instead of copying over it.
|
|
28
|
+
|
|
29
|
+
## What each file does
|
|
30
|
+
|
|
31
|
+
- `fy.policy.json`: the `authoring` tier and `shared-cpu` profile. It
|
|
32
|
+
blocks `tts`, `transcribe`, and `render`; allows `lint`, `context`, `doctor`,
|
|
33
|
+
`add`, `inspect`, `compare`, `font search`, `font list`, `font verify`,
|
|
34
|
+
`font add` without `--force`, `check`, and at most four still frames; and
|
|
35
|
+
denies `--force`/`--overwrite`, `font remove`, and an unlicensed `font add
|
|
36
|
+
--url`. Adjust the tier or profile for the machine. Remove the file to return
|
|
37
|
+
to the default `full` tier.
|
|
38
|
+
- `.opencode/opencode.jsonc`: project-local OpenCode permissions for a local
|
|
39
|
+
model session. It denies the common heavy shell forms and protects
|
|
40
|
+
`fy.policy.json`, `.opencode/`, `.pi/`, and `skills/frameyard/` from
|
|
41
|
+
edits. It also adds `./skills` as a skill search path, which assumes the
|
|
42
|
+
official skill lives in the workspace; remove that line if it does not.
|
|
43
|
+
- `.pi/settings.json`: points Pi at `http://127.0.0.1:9931` and defaults to
|
|
44
|
+
`LFM3-1.7B-Q8_0`, with only `read`, `bash`, `edit`, and `write` enabled.
|
|
45
|
+
- `.pi/APPEND_SYSTEM.md`: the local-model workflow: `context` → `lint` →
|
|
46
|
+
`still` → `check` → handoff with `--dry-run`.
|
|
47
|
+
- `.pi/sandbox.json`: committed but `enabled: false`. Enable it only after
|
|
48
|
+
testing Chromium, FFmpeg, and the local router with the filesystem/network
|
|
49
|
+
rules you need.
|
|
50
|
+
|
|
51
|
+
## Human overrides
|
|
52
|
+
|
|
53
|
+
The policy is a guardrail, not a security boundary. A human who intends to run
|
|
54
|
+
a heavy operation can override it:
|
|
55
|
+
|
|
56
|
+
```sh
|
|
57
|
+
FRAMEYARD_POLICY=full npx frameyard render main --props props/main.json
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The generated example READMEs in this repository use that prefix because they
|
|
61
|
+
may be run with the scaffold installed.
|
|
62
|
+
|
|
63
|
+
## Pi project trust
|
|
64
|
+
|
|
65
|
+
Pi loads `.pi/` only for trusted projects. Either start Pi with:
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
pi --approve
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
or add the project to `~/.pi/agent/trust.json` once. The trust entry is the only
|
|
72
|
+
global change; the rest stays in the workspace.
|
|
73
|
+
|
|
74
|
+
## Opting out
|
|
75
|
+
|
|
76
|
+
Remove `fy.policy.json` and the `.opencode/`/`.pi/` files you copied.
|
|
77
|
+
The CLI then defaults to `full`, and the host configuration no longer applies.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://opencode.ai/config.json",
|
|
3
|
+
"skills": ["./skills"],
|
|
4
|
+
"permissions": [
|
|
5
|
+
{ "action": "edit", "resource": "fy.policy.json", "effect": "deny" },
|
|
6
|
+
{ "action": "edit", "resource": ".opencode/**", "effect": "deny" },
|
|
7
|
+
{ "action": "edit", "resource": ".pi/**", "effect": "deny" },
|
|
8
|
+
{ "action": "edit", "resource": "skills/frameyard/**", "effect": "deny" },
|
|
9
|
+
{ "action": "shell", "resource": "*frameyard render*", "effect": "deny" },
|
|
10
|
+
{ "action": "shell", "resource": "*frameyard tts*", "effect": "deny" },
|
|
11
|
+
{ "action": "shell", "resource": "*frameyard transcribe*", "effect": "deny" },
|
|
12
|
+
{ "action": "shell", "resource": "*dist/cli.js render*", "effect": "deny" },
|
|
13
|
+
{ "action": "shell", "resource": "*dist/cli.js tts*", "effect": "deny" },
|
|
14
|
+
{ "action": "shell", "resource": "*dist/cli.js transcribe*", "effect": "deny" },
|
|
15
|
+
{ "action": "shell", "resource": "*--dry-run*", "effect": "allow" },
|
|
16
|
+
],
|
|
17
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Frameyard resource policy
|
|
2
|
+
|
|
3
|
+
This workspace uses `fy.policy.json` at the repository root. Do not edit that
|
|
4
|
+
file, `.pi/`, `.opencode/`, or `skills/frameyard/`.
|
|
5
|
+
|
|
6
|
+
## Working loop
|
|
7
|
+
|
|
8
|
+
1. Run `frameyard lint <id> --json` while editing.
|
|
9
|
+
2. Inspect at most four representative stills with `frameyard still <id> --frame <spec> --json`.
|
|
10
|
+
3. Run `frameyard check <id> --json` once at the end when the active policy allows it.
|
|
11
|
+
4. Do not run `frameyard tts`, `frameyard transcribe`, or `frameyard render` unless the
|
|
12
|
+
user explicitly asks. Use `--dry-run` and report `deferred: true` with the exact
|
|
13
|
+
handoff command instead.
|
|
14
|
+
5. `frameyard font search`, `font list`, and `font verify` are allowed; `font add`
|
|
15
|
+
is allowed without `--force`. `font remove`, `font add --force`, and an
|
|
16
|
+
unlicensed `font add --url` require the `full` policy.
|
|
17
|
+
6. Read `AGENTS.md` and `skills/frameyard/SKILL.md` before changing public behavior.
|
|
18
|
+
|
|
19
|
+
The local llama.cpp router is at `http://127.0.0.1:9931`. Use a small text model for
|
|
20
|
+
the lint loop and a vision-capable model only for representative stills. Do not
|
|
21
|
+
switch to a larger local model just to re-read the same files.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"enabled": false,
|
|
3
|
+
"allowBrowserProcess": false,
|
|
4
|
+
"network": {
|
|
5
|
+
"allowLocalBinding": true,
|
|
6
|
+
"allowAllUnixSockets": true,
|
|
7
|
+
"allowedDomains": [],
|
|
8
|
+
"deniedDomains": []
|
|
9
|
+
},
|
|
10
|
+
"filesystem": {
|
|
11
|
+
"allowRead": [".", "~/.config", "~/.local"],
|
|
12
|
+
"allowWrite": [".", "/tmp"],
|
|
13
|
+
"denyWrite": ["fy.policy.json", ".pi", ".opencode", "skills/frameyard"]
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://pi.dev/schemas/settings.schema.json",
|
|
3
|
+
"llamaSettings": {
|
|
4
|
+
"servers": [
|
|
5
|
+
{
|
|
6
|
+
"url": "http://127.0.0.1:9931",
|
|
7
|
+
"id": "local",
|
|
8
|
+
"name": "Local llama.cpp"
|
|
9
|
+
}
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
"defaultTools": ["read", "bash", "edit", "write"],
|
|
13
|
+
"defaultProvider": "local",
|
|
14
|
+
"defaultModel": "LFM3-1.7B-Q8_0"
|
|
15
|
+
}
|
|
@@ -25,6 +25,7 @@ When you work inside the Frameyard repository itself, `npx frameyard` resolves t
|
|
|
25
25
|
## Contents
|
|
26
26
|
|
|
27
27
|
- `SKILL.md`: trigger description and operating workflow
|
|
28
|
+
- `references/quick-reference.md`: compact skeletons, command table, policy table, and common fixes
|
|
28
29
|
- `references/deterministic-authoring.md`
|
|
29
30
|
- `references/bindings.md`
|
|
30
31
|
- `references/controllers.md`
|