@warpgogol/forge 0.14.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/AGENTS.md +3 -3
  2. package/README.md +58 -5
  3. package/dist/bin/cli.js +0 -0
  4. package/dist/os/core/core.module.d.ts.map +1 -1
  5. package/dist/os/core/core.module.js +9 -0
  6. package/dist/os/core/core.module.js.map +1 -1
  7. package/dist/src/onboarding/create.d.ts.map +1 -1
  8. package/dist/src/onboarding/create.js +5 -2
  9. package/dist/src/onboarding/create.js.map +1 -1
  10. package/dist/src/onboarding/doctor.d.ts.map +1 -1
  11. package/dist/src/onboarding/doctor.js +38 -0
  12. package/dist/src/onboarding/doctor.js.map +1 -1
  13. package/dist/src/onboarding/invariant-engine.d.ts.map +1 -1
  14. package/dist/src/onboarding/invariant-engine.js +14 -7
  15. package/dist/src/onboarding/invariant-engine.js.map +1 -1
  16. package/dist/src/onboarding/scaffold-project.d.ts.map +1 -1
  17. package/dist/src/onboarding/scaffold-project.js +25 -5
  18. package/dist/src/onboarding/scaffold-project.js.map +1 -1
  19. package/dist/src/profiles/profile-schema.d.ts +73 -8
  20. package/dist/src/profiles/profile-schema.d.ts.map +1 -1
  21. package/dist/src/profiles/profile-schema.js +35 -10
  22. package/dist/src/profiles/profile-schema.js.map +1 -1
  23. package/dist/src/profiles/stack-profile.d.ts +26 -2
  24. package/dist/src/profiles/stack-profile.d.ts.map +1 -1
  25. package/dist/src/profiles/stack-profile.js +4 -0
  26. package/dist/src/profiles/stack-profile.js.map +1 -1
  27. package/package.json +162 -60
  28. package/profiles/editframe-templates/composition-agents.md +70 -0
  29. package/profiles/editframe-templates/composition.tsx +33 -0
  30. package/profiles/{editframe-html-templates/composition-agents.md → editframe-templates/html-composition-agents.md} +15 -16
  31. package/profiles/{editframe-html.yaml → editframe.yaml} +170 -56
  32. package/skills/fo/ef-brand-video-generator/SKILL.md +101 -0
  33. package/skills/fo/ef-composition/SKILL.md +147 -0
  34. package/skills/fo/ef-composition-review/SKILL.md +10 -10
  35. package/skills/fo/ef-dev-server/SKILL.md +107 -0
  36. package/skills/fo/ef-editor-gui/SKILL.md +131 -0
  37. package/skills/fo/ef-motion-design/SKILL.md +118 -0
  38. package/skills/fo/ef-onboard/SKILL.md +16 -29
  39. package/skills/fo/ef-render-verify/SKILL.md +2 -2
  40. package/skills/fo/ef-webhooks/SKILL.md +95 -0
  41. package/skills/fo/fo-session-retro/SKILL.md +2 -2
  42. package/profiles/editframe-html-templates/composition.html +0 -32
@@ -1,6 +1,6 @@
1
1
  schema: forge/stack-profile@1
2
- id: editframe-html
3
- displayName: Editframe HTML Video
2
+ id: editframe
3
+ displayName: Editframe Video
4
4
  detect:
5
5
  anyOf:
6
6
  - editframe.config.*
@@ -20,8 +20,8 @@ devServer:
20
20
  artifacts:
21
21
  - id: composition
22
22
  extensions:
23
- - .html
24
23
  - .tsx
24
+ - .html
25
25
  produce:
26
26
  command: editframe render
27
27
  output: dist/{composition}.mp4
@@ -30,6 +30,7 @@ artifacts:
30
30
  determinism:
31
31
  hashable: true
32
32
  inputs:
33
+ - compositions/**/*.tsx
33
34
  - compositions/**/*.html
34
35
  - assets/**
35
36
  assets:
@@ -48,8 +49,29 @@ release:
48
49
  target: local
49
50
  outputDir: release
50
51
  manifestName: release-manifest.json
52
+ prerequisites:
53
+ - id: nodejs
54
+ name: Node.js 18+
55
+ check: node --version
56
+ installHint: "https://nodejs.org/en/download/"
57
+ severity: error
58
+ - id: ffmpeg
59
+ name: FFmpeg
60
+ check: ffmpeg -version
61
+ installHint: "https://ffmpeg.org/download.html"
62
+ severity: error
51
63
  workspaceTypes:
52
64
  - id: composition
65
+ detect:
66
+ glob: "*.tsx"
67
+ contains: TimelineRoot
68
+ packageJsonDep: "@editframe/react"
69
+ skills:
70
+ - ef-onboard
71
+ - ef-composition-review
72
+ - ef-render-verify
73
+ agentsMdTemplate: editframe-templates/composition-agents.md
74
+ - id: html-composition
53
75
  detect:
54
76
  glob: "*.html"
55
77
  contains: ef-timegroup
@@ -58,77 +80,85 @@ workspaceTypes:
58
80
  - ef-onboard
59
81
  - ef-composition-review
60
82
  - ef-render-verify
61
- agentsMdTemplate: editframe-html-templates/composition-agents.md
83
+ agentsMdTemplate: editframe-templates/html-composition-agents.md
62
84
  invariants:
63
85
  - id: VIDEO-01
64
86
  rule: Composition filenames must use kebab-case (lowercase letters, digits, hyphens only)
65
87
  severity: error
66
88
  check:
67
89
  kind: filename-pattern
68
- glob: "compositions/**/*.{html,tsx}"
69
- pattern: "^[a-z0-9-]+\\.(html|tsx)$"
90
+ glob: "compositions/**/*.{tsx,html}"
91
+ pattern: "^[a-z0-9-]+\\.(tsx|html)$"
70
92
  - id: VIDEO-02
71
93
  rule: Scene durations must use contain mode by default to avoid unexpected cropping
72
94
  severity: warning
73
95
  check:
74
96
  kind: file-contains
75
- glob: "compositions/**/*.html"
97
+ glob: "compositions/**/*.{tsx,html}"
76
98
  pattern: contain
77
99
  - id: VIDEO-03
78
- rule: All speech audio elements must have corresponding ef-captions elements for accessibility
100
+ rule: All speech audio elements must have corresponding Captions components for accessibility
79
101
  severity: error
80
102
  check:
81
103
  kind: file-contains
82
- glob: "compositions/**/*.html"
83
- pattern: ef-captions
104
+ glob: "compositions/**/*.{tsx,html}"
105
+ pattern: Captions
84
106
  - id: VIDEO-04
85
- rule: 'Root ef-timegroup must declare duration or use mode="contain" or mode="fit"'
107
+ rule: Root Timegroup must declare duration or use mode="contain" or mode="fit"
86
108
  severity: error
87
109
  check:
88
110
  kind: file-contains
89
- glob: "compositions/**/*.html"
90
- pattern: 'ef-timegroup[^>]*(duration|mode="contain"|mode="fit")[^>]*>'
111
+ glob: "compositions/**/*.{tsx,html}"
112
+ pattern: 'Timegroup[^>]*(duration|mode="contain"|mode="fit")[^>]*>|ef-timegroup[^>]*(duration|mode="contain"|mode="fit")[^>]*>'
91
113
  - id: VIDEO-05
92
114
  rule: All duration values must be valid CSS time strings (e.g. 5s, 500ms, 2.5s)
93
115
  severity: error
94
116
  check:
95
- kind: html-attribute-pattern
96
- glob: "compositions/**/*.html"
97
- element: "ef-timegroup"
117
+ kind: attribute-pattern
118
+ glob: "compositions/**/*.{tsx,html}"
119
+ elements:
120
+ - ef-timegroup
121
+ - Timegroup
98
122
  attribute: "duration"
99
123
  pattern: "^\\d+(\\.\\d+)?(s|ms)$"
100
124
  - id: VIDEO-06
101
125
  rule: "mode attribute must be one of: sequence, fixed, contain, fit"
102
126
  severity: error
103
127
  check:
104
- kind: html-attribute-pattern
105
- glob: "compositions/**/*.html"
106
- element: "ef-timegroup"
128
+ kind: attribute-pattern
129
+ glob: "compositions/**/*.{tsx,html}"
130
+ elements:
131
+ - ef-timegroup
132
+ - Timegroup
107
133
  attribute: "mode"
108
134
  pattern: "^(sequence|fixed|contain|fit)$"
109
135
  - id: VIDEO-07
110
136
  rule: fps must be a positive integer (default 30)
111
137
  severity: warning
112
138
  check:
113
- kind: html-attribute-pattern
114
- glob: "compositions/**/*.html"
115
- element: "ef-timegroup"
139
+ kind: attribute-pattern
140
+ glob: "compositions/**/*.{tsx,html}"
141
+ elements:
142
+ - ef-timegroup
143
+ - Timegroup
116
144
  attribute: "fps"
117
145
  pattern: "^[1-9]\\d*$"
118
146
  - id: VIDEO-08
119
- rule: loop attribute should only be used on the root ef-timegroup (no effect on render for nested groups)
147
+ rule: loop attribute should only be used on the root Timegroup (no effect on render for nested groups)
120
148
  severity: warning
121
149
  check:
122
150
  kind: file-not-contains
123
- glob: "compositions/**/*.html"
124
- negatedPattern: "<ef-timegroup[^>]*loop[^>]*>[\\s\\S]*<ef-timegroup[^>]*loop"
151
+ glob: "compositions/**/*.{tsx,html}"
152
+ negatedPattern: "<(Timegroup|ef-timegroup)[^>]*loop[^>]*>[\\s\\S]*<(Timegroup|ef-timegroup)[^>]*loop"
125
153
  - id: VIDEO-09
126
154
  rule: offset values must be valid CSS time strings (e.g. 0.5s, 3s, 500ms)
127
155
  severity: warning
128
156
  check:
129
- kind: html-attribute-pattern
130
- glob: "compositions/**/*.html"
131
- element: "ef-timegroup"
157
+ kind: attribute-pattern
158
+ glob: "compositions/**/*.{tsx,html}"
159
+ elements:
160
+ - ef-timegroup
161
+ - Timegroup
132
162
  attribute: "offset"
133
163
  pattern: "^\\d+(\\.\\d+)?(s|ms)$"
134
164
  workspace:
@@ -331,34 +361,118 @@ firstWorkspace:
331
361
  "check": "editframe check"
332
362
  }
333
363
  }
334
- - path: composition.html
364
+ - path: composition.tsx
335
365
  content: |
336
- <!--
337
- Editframe HTML composition — my-first-video
338
- This file declares a video composition using Editframe custom elements.
366
+ /*
367
+ Editframe React composition — my-first-video
368
+ This file declares a video composition using @editframe/react components.
339
369
  Run `editframe preview` to preview, `editframe render` to produce output.
340
- -->
341
- <ef-timegroup duration="10s">
342
- <ef-video
343
- src="assets/background.mp4"
344
- fit="contain"
345
- duration="10s"
346
- ></ef-video>
347
- <ef-text
348
- text="Hello, Editframe!"
349
- x="50%"
350
- y="50%"
351
- font-size="48px"
352
- color="white"
353
- text-align="center"
354
- duration="5s"
355
- ></ef-text>
356
- <ef-audio
357
- src="assets/narration.mp3"
358
- ></ef-audio>
359
- <ef-captions
360
- src="assets/captions.vtt"
361
- ></ef-captions>
362
- </ef-timegroup>
370
+ */
371
+ import { TimelineRoot, Timegroup, Video, Text, Audio, Captions } from "@editframe/react";
372
+
373
+ export default function Composition() {
374
+ return (
375
+ <TimelineRoot>
376
+ <Timegroup duration="10s">
377
+ <Video src="assets/background.mp4" fit="contain" duration="10s" />
378
+ <Text
379
+ text="Hello, Editframe!"
380
+ x="50%"
381
+ y="50%"
382
+ fontSize="48px"
383
+ color="white"
384
+ textAlign="center"
385
+ duration="5s"
386
+ />
387
+ <Audio src="assets/narration.mp3" />
388
+ <Captions src="assets/captions.vtt" />
389
+ </Timegroup>
390
+ </TimelineRoot>
391
+ );
392
+ }
363
393
  install:
364
- - pnpm add -D vitest
394
+ - pnpm add -D @editframe/react @editframe/vite-plugin react react-dom typescript @types/react @types/react-dom vite @vitejs/plugin-react tailwindcss @tailwindcss/vite vitest
395
+ templates:
396
+ - id: react
397
+ default: true
398
+ firstWorkspace:
399
+ path: compositions/my-first-video
400
+ files:
401
+ - path: package.json
402
+ content: |
403
+ {
404
+ "name": "my-first-video",
405
+ "version": "0.1.0",
406
+ "private": true,
407
+ "type": "module",
408
+ "scripts": {
409
+ "preview": "editframe preview",
410
+ "render": "editframe render -o dist/my-first-video.mp4",
411
+ "check": "editframe check"
412
+ }
413
+ }
414
+ - path: composition.tsx
415
+ content: |
416
+ /*
417
+ Editframe React composition — my-first-video
418
+ This file declares a video composition using @editframe/react components.
419
+ Run `editframe preview` to preview, `editframe render` to produce output.
420
+ */
421
+ import { TimelineRoot, Timegroup, Video, Text, Audio, Captions } from "@editframe/react";
422
+
423
+ export default function Composition() {
424
+ return (
425
+ <TimelineRoot>
426
+ <Timegroup duration="10s">
427
+ <Video src="assets/background.mp4" fit="contain" duration="10s" />
428
+ <Text
429
+ text="Hello, Editframe!"
430
+ x="50%"
431
+ y="50%"
432
+ fontSize="48px"
433
+ color="white"
434
+ textAlign="center"
435
+ duration="5s"
436
+ />
437
+ <Audio src="assets/narration.mp3" />
438
+ <Captions src="assets/captions.vtt" />
439
+ </Timegroup>
440
+ </TimelineRoot>
441
+ );
442
+ }
443
+ install:
444
+ - pnpm add -D @editframe/react @editframe/vite-plugin react react-dom typescript @types/react @types/react-dom vite @vitejs/plugin-react tailwindcss @tailwindcss/vite vitest
445
+ - id: html
446
+ firstWorkspace:
447
+ path: compositions/my-first-video
448
+ files:
449
+ - path: package.json
450
+ content: |
451
+ {
452
+ "name": "my-first-video",
453
+ "version": "0.1.0",
454
+ "private": true,
455
+ "type": "module",
456
+ "scripts": {
457
+ "preview": "editframe preview",
458
+ "render": "editframe render -o dist/my-first-video.mp4",
459
+ "check": "editframe check"
460
+ }
461
+ }
462
+ - path: index.html
463
+ content: |
464
+ <!--
465
+ Editframe HTML composition — my-first-video
466
+ This file declares a video composition using Editframe web components.
467
+ Run `editframe preview` to preview, `editframe render` to produce output.
468
+ -->
469
+ <ef-timeline duration="10s">
470
+ <ef-timegroup duration="10s" mode="contain">
471
+ <ef-video src="assets/background.mp4" fit="contain" duration="10s"></ef-video>
472
+ <ef-text text="Hello, Editframe!" x="50%" y="50%" font-size="48px" color="white" text-align="center" duration="5s"></ef-text>
473
+ <ef-audio src="assets/narration.mp3"></ef-audio>
474
+ <ef-captions src="assets/captions.vtt"></ef-captions>
475
+ </ef-timegroup>
476
+ </ef-timeline>
477
+ install:
478
+ - pnpm add -D vitest
@@ -0,0 +1,101 @@
1
+ ---
2
+ name: ef-brand-video-generator
3
+ description: "Generate brand video compositions from templates — logo animation, intro/outro, brand colors, typography. Use when the operator asks to generate a brand video."
4
+ invocation: user
5
+ category: fo
6
+ concerns: content-mutation
7
+ dependsOn: []
8
+ languagePolicy: ref(PREFERENCES.md)
9
+ triggers:
10
+ - "generate a brand video"
11
+ - "create a logo animation"
12
+ - "brand intro video"
13
+ - "brand outro video"
14
+ source: domain-knowledge
15
+ ---
16
+
17
+ <!-- skill-lint-disable SKILL-17 -->
18
+
19
+ Before starting, read `PREFERENCES.md` at the repository root. If the file is missing or `aiLanguage` is unset, ask the operator once and create the file using the `my-preferences` skill semantics.
20
+
21
+ # Brand Video Generator
22
+
23
+ Generate brand video compositions from reusable templates. Brand videos typically include logo animations, intro/outro sequences, brand color overlays, and typography that matches brand guidelines.
24
+
25
+ ## Template structure
26
+
27
+ A brand video composition uses `@editframe/react` components with brand-specific assets:
28
+
29
+ ```tsx
30
+ import { TimelineRoot, Timegroup, Video, Image, Text } from "@editframe/react";
31
+
32
+ export default function BrandIntro() {
33
+ return (
34
+ <TimelineRoot>
35
+ <Timegroup duration="3s" mode="sequence">
36
+ <Image src="assets/logo.svg" duration="1s" fit="contain" />
37
+ <Text
38
+ text="Your Brand"
39
+ x="50%"
40
+ y="50%"
41
+ fontSize="64px"
42
+ color="#FF6B00"
43
+ duration="1s"
44
+ />
45
+ <Video src="assets/brand-bg.mp4" fit="cover" duration="1s" />
46
+ </Timegroup>
47
+ </TimelineRoot>
48
+ );
49
+ }
50
+ ```
51
+
52
+ ## Brand asset checklist
53
+
54
+ - **Logo** — SVG or PNG with transparent background
55
+ - **Brand colors** — primary, secondary, accent as CSS color values
56
+ - **Typography** — brand font family, weights, sizes
57
+ - **Background video** — optional branded background clip
58
+ - **Audio** — optional brand jingle or voiceover
59
+
60
+ ## Common brand video patterns
61
+
62
+ ### Logo animation
63
+
64
+ Animate the logo in with a `Timegroup` using `mode="sequence"`:
65
+
66
+ ```tsx
67
+ <Timegroup duration="2s" mode="sequence">
68
+ <Image src="assets/logo.svg" duration="0.5s" fit="contain" />
69
+ <Text text="Your Brand" fontSize="48px" color="#FF6B00" duration="1.5s" />
70
+ </Timegroup>
71
+ ```
72
+
73
+ ### Intro/outro pair
74
+
75
+ Create separate compositions for intro and outro, then combine them in a parent `Timegroup`:
76
+
77
+ ```tsx
78
+ <TimelineRoot>
79
+ <Timegroup duration="15s" mode="sequence">
80
+ <BrandIntro />
81
+ <MainContent />
82
+ <BrandOutro />
83
+ </Timegroup>
84
+ </TimelineRoot>
85
+ ```
86
+
87
+ ### Brand color overlay
88
+
89
+ Use a semi-transparent `Image` or `Text` overlay with brand colors:
90
+
91
+ ```tsx
92
+ <Image src="assets/brand-overlay.png" duration="10s" fit="cover" />
93
+ ```
94
+
95
+ ## Rendering
96
+
97
+ Run `ref(forge.yaml bindings.commands.build)` to render the brand video. Use `ref(forge.yaml bindings.commands.validate)` to check the composition before rendering.
98
+
99
+ ## Customization
100
+
101
+ Each brand video template accepts parameters for logo, colors, text, and timing. Adjust the `duration`, `mode`, and asset paths to match the brand guidelines.
@@ -0,0 +1,147 @@
1
+ ---
2
+ name: ef-composition
3
+ description: "Guide creating a video composition with Editframe React components — time model, media elements, rendering. Use when the operator asks to create or build a video composition."
4
+ invocation: user
5
+ category: fo
6
+ concerns: content-mutation
7
+ dependsOn: []
8
+ languagePolicy: ref(PREFERENCES.md)
9
+ triggers:
10
+ - "create a video composition"
11
+ - "build a video with editframe"
12
+ - "create a composition"
13
+ - "add a scene to my video"
14
+ source: https://editframe.com/skills/composition.md
15
+ ---
16
+
17
+ <!-- skill-lint-disable SKILL-17 -->
18
+
19
+ Before starting, read `PREFERENCES.md` at the repository root. If the file is missing or `aiLanguage` is unset, ask the operator once and create the file using the `my-preferences` skill semantics.
20
+
21
+ # Video Composition
22
+
23
+ Build video scenes with React components from `@editframe/react`, for example `<Timegroup>` and `<Video>`. Both HTML web component syntax (`<ef-timegroup>`) and React syntax (`<Timegroup>`) share the same composition model and rendering pipeline.
24
+
25
+ Web component attributes use kebab-case (`file-id`, `api-host`). React props use camelCase (`fileId`, `apiHost`). Four attributes break this pattern: `sourcein`, `sourceout`, `trimstart`, `trimend` — same lowercase string in both forms.
26
+
27
+ ## Quick Start
28
+
29
+ ```tsx
30
+ import { TimelineRoot, Timegroup, Video, Text, Audio, Captions } from "@editframe/react";
31
+
32
+ export default function Composition() {
33
+ return (
34
+ <TimelineRoot>
35
+ <Timegroup duration="10s">
36
+ <Video src="assets/background.mp4" fit="contain" duration="10s" />
37
+ <Text text="Hello, Editframe!" x="50%" y="50%" fontSize="48px" color="white" duration="5s" />
38
+ <Audio src="assets/narration.mp3" />
39
+ <Captions src="assets/captions.vtt" />
40
+ </Timegroup>
41
+ </TimelineRoot>
42
+ );
43
+ }
44
+ ```
45
+
46
+ Run `ref(forge.yaml bindings.commands.devServer)` to preview. Run `ref(forge.yaml bindings.commands.build)` to render.
47
+
48
+ ## Duration units
49
+
50
+ - `5s` — seconds
51
+ - `500ms` — milliseconds
52
+ - `2.5s` — fractional seconds
53
+
54
+ ## Core concepts
55
+
56
+ ### Time model
57
+
58
+ A composition is a tree of `Timegroup` elements. The root `Timegroup` defines the composition's total duration. Child elements inherit timing context from their parent.
59
+
60
+ ### Timegroups and sequencing
61
+
62
+ - **`mode="sequence"`** — children play one after another
63
+ - **`mode="fixed"`** — children play at absolute offsets
64
+ - **`mode="contain"`** (default) — children fit within parent duration
65
+ - **`mode="fit"`** — children scale to fit
66
+
67
+ ### Transitions
68
+
69
+ Use `ef-transition` or the `transition` prop to declare CSS-like transitions between scenes.
70
+
71
+ ### Scripting
72
+
73
+ Compositions support inline scripting via `ef-script` or the `script` prop for dynamic behavior during rendering.
74
+
75
+ ## Media elements
76
+
77
+ - **`Video`** (`ef-video`) — video source with `fit` mode (`contain`, `cover`, `fill`)
78
+ - **`Audio`** (`ef-audio`) — audio source with FFT analysis (`fftSize`, `fftGain`, `fftDecay`)
79
+ - **`Image`** (`ef-image`) — image source
80
+ - **`Text`** (`ef-text`) — text overlay with positioning. Splits text into `ef-text-segment` children (`split="word"`, `split="char"`, `split="line"`). Set `stagger` to delay each segment's start. Segments render in light DOM with `data-active` attribute and `--ef-index`, `--ef-word-index`, `--ef-stagger-offset`, `--ef-seed` custom properties.
81
+ - **`Captions`** (`ef-captions`) — synchronized captions with word-level highlighting. Accepts caption data via `captionsSrc` (URL to JSON), `captionsScript` (inline script id), or `captionsData` (JS property). JSON uses `segments` or `word_segments` shape with `start`/`end` times.
82
+ - **`Waveform`** (`ef-waveform`) — visualizes an `ef-audio` or `ef-video` `target`. Modes: `bars`, `line`, `curve`, `bricks`, `pixel`, `wave`, `spikes`, `roundBars`.
83
+ - **`Surface`** (`ef-surface`) — mirrors another element's pixels onto its own canvas. Set `target` to a canvas or any `HTMLElement` to reuse a video's decoded frames without re-decoding.
84
+ - **`PanZoom`** (`ef-pan-zoom`) — pan and zoom control for video/image elements.
85
+ - **`MotionBlur`** (`ef-motionblur`) — motion blur effect.
86
+ - **`Configuration`** (`ef-configuration`) — opt-in element for API authentication. Add when deploying against the Editframe API: `apiHost` and `signingUrl` for signed-URL auth on cross-origin media, `imageProxy` for cross-origin image proxying. Skip for compositions using only local files.
87
+
88
+ ## Rendering
89
+
90
+ **Browser export.** Call `renderTimegroupToVideo(timegroup, options)` from `@editframe/elements` to encode a live `ef-timegroup` to a video file. Uses WebCodecs. Key options: `width`/`height`/`fps`, `from`/`to` (export range in seconds), `videoCodec`/`audioCodec`/`videoBitrate`/`audioBitrate`, `target` (mediabunny output target), `signal` (AbortSignal), `onProgress`.
91
+
92
+ For in-app export from an interactive preview, use `ef-workbench`'s `exportVideo()` method (see the `ef-editor-gui` skill). For CLI/cloud rendering (`editframe render`), the `window.EF_RENDER` path handles offscreen cloning automatically.
93
+
94
+ **Custom render data.** A CLI or Playwright host can inject arbitrary JSON into `window.EF_RENDER_DATA` before running the composition. Read it with `getRenderData<T>()` (module-level function) or `useRenderData<T>()` (React hook). Use this to parameterize a render without templating the composition.
95
+
96
+ Run `ref(forge.yaml bindings.commands.build)` to produce the final video output. Use `ref(forge.yaml bindings.commands.validate)` to check composition structure before rendering.
97
+
98
+ ## React
99
+
100
+ Import components from `@editframe/react`. React props use camelCase. The composition is a standard React component that returns JSX.
101
+
102
+ ### React Three Fiber
103
+
104
+ Wrap a `<Timegroup>` child in `<CompositionCanvas>` from `@editframe/react/r3f` to get an R3F `<Canvas>` synced to composition time. Read the clock with `useCompositionTime()` which returns `{ time, duration }` in seconds.
105
+
106
+ ```tsx
107
+ <Timegroup mode="fixed" duration="14s">
108
+ <CompositionCanvas shadows>
109
+ <MyScene />
110
+ </CompositionCanvas>
111
+ </Timegroup>
112
+ ```
113
+
114
+ For 3D in a Web Worker, use `OffscreenCompositionCanvas` with `@react-three/offscreen`.
115
+
116
+ ### Server-side rendering
117
+
118
+ `@editframe/react/server` and `@editframe/elements/server` export composition components and types only — no custom-element registration, no DOM, canvas, or WebCodecs code. Import safely in Next.js or Remix server code. These server entry points do not include GUI components or hooks — render those on the client with `dynamic(() => import("@editframe/react"), { ssr: false })`.
119
+
120
+ ### Package entry points
121
+
122
+ | Import | Environment | Contains |
123
+ | --- | --- | --- |
124
+ | `@editframe/elements` | Browser | All custom elements, canvas/WebCodecs rendering |
125
+ | `@editframe/elements/server` | Browser, Node, SSR | Types only, plus `getRenderInfo()` (browser-only at runtime) |
126
+ | `@editframe/elements/gui` | Browser | Editor GUI custom elements (timeline, scrubber, handles) |
127
+ | `@editframe/elements/styles.css` | Browser | Base + theme styles |
128
+ | `@editframe/react` | Browser | React composition + GUI components, hooks |
129
+ | `@editframe/react/server` | Browser, Node, SSR | Composition components only, no hooks/GUI |
130
+ | `@editframe/react/r3f` | Browser | `CompositionCanvas`, `OffscreenCompositionCanvas`, `useCompositionTime` |
131
+
132
+ ## Element reference
133
+
134
+ | Element | React component | Key props |
135
+ | --- | --- | --- |
136
+ | `ef-timegroup` | `Timegroup` | `duration`, `mode`, `fps`, `offset`, `loop` |
137
+ | `ef-video` | `Video` | `src`, `fit`, `duration`, `fileId`, `sourcein`, `sourceout`, `trimstart`, `trimend` |
138
+ | `ef-audio` | `Audio` | `src`, `duration`, `volume`, `mute`, `loop`, `fftSize`, `fftGain` |
139
+ | `ef-text` | `Text` | `text`, `x`, `y`, `fontSize`, `color`, `textAlign`, `duration`, `split`, `stagger` |
140
+ | `ef-captions` | `Captions` | `captionsSrc`, `captionsScript`, `target`, `wordStyle`, `duration` |
141
+ | `ef-image` | `Image` | `src`, `fit`, `duration`, `fileId` |
142
+ | `ef-waveform` | `Waveform` | `target`, `mode`, `color` |
143
+ | `ef-surface` | `Surface` | `target` |
144
+ | `ef-pan-zoom` | `PanZoom` | `target`, `pan`, `zoom` |
145
+ | `ef-configuration` | `Configuration` | `apiHost`, `signingUrl`, `imageProxy` |
146
+ | `ef-transition` | `Transition` | `type`, `duration` |
147
+ | `ef-script` | `Script` | `src`, `inline` |
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: ef-composition-review
3
- description: Review an Editframe HTML composition for time model correctness, accessibility, and best practices
3
+ description: Review an Editframe React composition for time model correctness, accessibility, and best practices
4
4
  invocation: user
5
5
  category: fo
6
6
  concerns: read-only
@@ -14,41 +14,41 @@ languagePolicy: ref(PREFERENCES.md)
14
14
 
15
15
  Before starting, read `PREFERENCES.md` at the repository root. If the file is missing or `aiLanguage` is unset, ask the operator once and create the file using the `my-preferences` skill semantics.
16
16
 
17
- A read-only review of an Editframe HTML composition file. The skill checks time model correctness, accessibility, asset references, automated invariants, and manual best practices. It does **not** modify any file — it produces a structured report and stops.
17
+ A read-only review of an Editframe React composition file. The skill checks time model correctness, accessibility, asset references, automated invariants, and manual best practices. It does **not** modify any file — it produces a structured report and stops.
18
18
 
19
19
  ## Scope
20
20
 
21
- This skill reviews `.html` composition files that use Editframe custom elements (`ef-timegroup`, `ef-video`, `ef-audio`, `ef-text`, `ef-captions`). It is designed for projects using the `editframe-html` stack profile.
21
+ This skill reviews `.tsx` composition files that use `@editframe/react` components (`TimelineRoot`, `Timegroup`, `Video`, `Audio`, `Text`, `Captions`). It is designed for projects using the `editframe` stack profile.
22
22
 
23
23
  ## Process
24
24
 
25
25
  ### 1. Empty state check
26
26
 
27
- Scan the `compositions/` directory for `.html` files. If no compositions are found, report "No compositions found — nothing to review" and stop. Do not report false positives on an empty project.
27
+ Scan the `compositions/` directory for `.tsx` files. If no compositions are found, report "No compositions found — nothing to review" and stop. Do not report false positives on an empty project.
28
28
 
29
29
  ### 2. Time model review
30
30
 
31
31
  For each composition file:
32
32
 
33
- - Check that the root `ef-timegroup` declares a `duration` attribute or uses `mode="contain"` / `mode="fit"`.
33
+ - Check that the root `Timegroup` declares a `duration` prop or uses `mode="contain"` / `mode="fit"`.
34
34
  - Check that all `duration` and `offset` values are valid CSS time strings (e.g. `5s`, `300ms`, `2.5s`).
35
35
  - Check that `mode` values are one of: `sequence`, `fixed`, `contain`, `fit`.
36
36
  - Check that `fps` is a positive integer (e.g. `30`, `60`).
37
- - Check that `loop` is only present on the root `ef-timegroup` — nested timegroups should not loop.
37
+ - Check that `loop` is only present on the root `Timegroup` — nested Timegroups should not loop.
38
38
 
39
39
  ### 3. Accessibility review
40
40
 
41
- - Check that all `ef-audio` elements with speech content have corresponding `ef-captions` elements.
42
- - Check that `ef-text` elements have sufficient contrast between foreground and background colors (if declared via inline styles or CSS classes).
41
+ - Check that all `Audio` components with speech content have corresponding `Captions` components.
42
+ - Check that `Text` components have sufficient contrast between foreground and background colors (if declared via inline styles or CSS classes).
43
43
 
44
44
  ### 4. Asset reference review
45
45
 
46
- - Check that all `src` attributes in `ef-video`, `ef-audio`, and `ef-image` elements point to files that exist in the `assets/` directory.
46
+ - Check that all `src` props in `Video`, `Audio`, and `Image` components point to files that exist in the `assets/` directory.
47
47
  - Check that asset filenames use kebab-case (lowercase letters, digits, hyphens only).
48
48
 
49
49
  ### 5. Invariant check
50
50
 
51
- Run `forge doctor` to check all profile invariants automatically. For the `editframe-html` profile, this covers VIDEO-01 through VIDEO-09 (filename conventions, scene fit modes, captions, and time model invariants). Review the output and include any violations in the report.
51
+ Run `forge doctor` to check all profile invariants automatically. For the `editframe` profile, this covers VIDEO-01 through VIDEO-09 (filename conventions, scene fit modes, captions, and time model invariants). Review the output and include any violations in the report.
52
52
 
53
53
  ### 6. Manual best practices
54
54