visualfries 0.1.10120 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/README.md +97 -0
  2. package/bin/visualfries.js +1570 -0
  3. package/dist/DIContainer.d.ts +2 -1
  4. package/dist/DIContainer.js +16 -5
  5. package/dist/SceneBuilder.svelte.d.ts +70 -1
  6. package/dist/SceneBuilder.svelte.js +96 -29
  7. package/dist/agent/audioMixer.d.ts +34 -0
  8. package/dist/agent/audioMixer.js +308 -0
  9. package/dist/agent/broll.d.ts +35 -0
  10. package/dist/agent/broll.js +226 -0
  11. package/dist/agent/capabilities.d.ts +34 -0
  12. package/dist/agent/capabilities.js +246 -0
  13. package/dist/agent/captionScene.d.ts +23 -0
  14. package/dist/agent/captionScene.js +204 -0
  15. package/dist/agent/catalog.d.ts +24 -0
  16. package/dist/agent/catalog.js +67 -0
  17. package/dist/agent/cueFiles.d.ts +54 -0
  18. package/dist/agent/cueFiles.js +219 -0
  19. package/dist/agent/cuePresets.d.ts +7 -0
  20. package/dist/agent/cuePresets.js +50 -0
  21. package/dist/agent/deterministicMedia.d.ts +61 -0
  22. package/dist/agent/deterministicMedia.js +303 -0
  23. package/dist/agent/index.d.ts +18 -0
  24. package/dist/agent/index.js +18 -0
  25. package/dist/agent/inspectScene.d.ts +36 -0
  26. package/dist/agent/inspectScene.js +139 -0
  27. package/dist/agent/localRender.d.ts +82 -0
  28. package/dist/agent/localRender.js +702 -0
  29. package/dist/agent/overlays.d.ts +40 -0
  30. package/dist/agent/overlays.js +325 -0
  31. package/dist/agent/productionPlan.d.ts +131 -0
  32. package/dist/agent/productionPlan.js +322 -0
  33. package/dist/agent/renderPlan.d.ts +27 -0
  34. package/dist/agent/renderPlan.js +68 -0
  35. package/dist/agent/renderRanges.d.ts +24 -0
  36. package/dist/agent/renderRanges.js +73 -0
  37. package/dist/agent/runtimeSupport.d.ts +19 -0
  38. package/dist/agent/runtimeSupport.js +192 -0
  39. package/dist/agent/streamingEncoder.d.ts +31 -0
  40. package/dist/agent/streamingEncoder.js +208 -0
  41. package/dist/agent/transcripts.d.ts +29 -0
  42. package/dist/agent/transcripts.js +146 -0
  43. package/dist/agent/transitions.d.ts +20 -0
  44. package/dist/agent/transitions.js +169 -0
  45. package/dist/animations/PixiAnimationTarget.d.ts +29 -0
  46. package/dist/animations/PixiAnimationTarget.js +63 -0
  47. package/dist/animations/builders/LineHighlighterAnimationBuilder.js +20 -3
  48. package/dist/animations/builders/WordHighlighterAnimationBuilder.js +15 -2
  49. package/dist/browser/browserExport.d.ts +73 -0
  50. package/dist/browser/browserExport.js +180 -0
  51. package/dist/browser/glTransitions.d.ts +37 -0
  52. package/dist/browser/glTransitions.js +261 -0
  53. package/dist/browser/index.d.ts +3 -0
  54. package/dist/browser/index.js +3 -0
  55. package/dist/browser/mediaDecode.d.ts +31 -0
  56. package/dist/browser/mediaDecode.js +152 -0
  57. package/dist/builders/PixiComponentBuilder.d.ts +6 -0
  58. package/dist/builders/PixiComponentBuilder.js +12 -0
  59. package/dist/builders/_ComponentState.svelte.d.ts +7 -5
  60. package/dist/builders/_ComponentState.svelte.js +29 -15
  61. package/dist/builders/html/StyleBuilder.js +9 -8
  62. package/dist/builders/html/TextComponentHtmlBuilder.js +4 -2
  63. package/dist/builders/html/processors/AppearanceStyleProcessor.js +1 -1
  64. package/dist/builders/html/processors/TextAppearanceStyleProcessor.js +7 -0
  65. package/dist/builders/html/processors/TextEffectsStyleProcessor.js +32 -13
  66. package/dist/commands/ReplaceSourceOnTimeCommand.js +9 -1
  67. package/dist/commands/SeekCommand.js +19 -6
  68. package/dist/components/AnimatedGIF.d.ts +3 -0
  69. package/dist/components/AnimatedGIF.js +28 -1
  70. package/dist/components/Component.svelte.d.ts +5 -5
  71. package/dist/components/Component.svelte.js +29 -13
  72. package/dist/components/ComponentContext.svelte.js +68 -23
  73. package/dist/components/hooks/AnimationHook.js +1 -1
  74. package/dist/components/hooks/CanvasFillHook.d.ts +12 -0
  75. package/dist/components/hooks/CanvasFillHook.js +75 -0
  76. package/dist/components/hooks/DeterministicMediaFrameHook.js +3 -0
  77. package/dist/components/hooks/HtmlTextHook.js +11 -3
  78. package/dist/components/hooks/HtmlToCanvasHook.js +8 -25
  79. package/dist/components/hooks/MediaHook.js +172 -47
  80. package/dist/components/hooks/MediaSeekingHook.js +138 -88
  81. package/dist/components/hooks/PixiGifHook.js +4 -4
  82. package/dist/components/hooks/PixiSplitScreenDisplayObjectHook.js +73 -6
  83. package/dist/components/hooks/PixiVideoTextureHook.js +10 -4
  84. package/dist/components/hooks/PixiVisualTransformHook.d.ts +16 -0
  85. package/dist/components/hooks/PixiVisualTransformHook.js +102 -0
  86. package/dist/components/hooks/SubtitlesHook.js +48 -24
  87. package/dist/components/hooks/VerifyMediaHook.js +2 -2
  88. package/dist/directors/ComponentDirector.d.ts +1 -0
  89. package/dist/directors/ComponentDirector.js +41 -8
  90. package/dist/fonts/fontDiscovery.js +12 -1
  91. package/dist/layers/Layer.svelte.d.ts +54 -0
  92. package/dist/layers/Layer.svelte.js +2 -25
  93. package/dist/managers/AppManager.svelte.js +8 -5
  94. package/dist/managers/ComponentsManager.svelte.d.ts +7 -7
  95. package/dist/managers/ComponentsManager.svelte.js +29 -15
  96. package/dist/managers/DeterministicMediaManager.js +38 -3
  97. package/dist/managers/EventManager.js +3 -1
  98. package/dist/managers/LayersManager.svelte.d.ts +54 -0
  99. package/dist/managers/RenderManager.d.ts +5 -0
  100. package/dist/managers/RenderManager.js +67 -21
  101. package/dist/managers/StateManager.svelte.d.ts +56 -0
  102. package/dist/managers/StateManager.svelte.js +60 -58
  103. package/dist/managers/SubtitlesManager.svelte.js +1 -3
  104. package/dist/managers/TimeManager.svelte.d.ts +4 -0
  105. package/dist/managers/TimeManager.svelte.js +23 -7
  106. package/dist/schemas/runtime/deterministic.js +5 -1
  107. package/dist/schemas/runtime/types.d.ts +36 -15
  108. package/dist/schemas/scene/components.d.ts +126 -0
  109. package/dist/schemas/scene/components.js +11 -0
  110. package/dist/schemas/scene/core.d.ts +109 -10
  111. package/dist/schemas/scene/core.js +1 -1
  112. package/dist/utils/mediaWindow.d.ts +13 -0
  113. package/dist/utils/mediaWindow.js +25 -0
  114. package/dist/utils/svgGenerator.js +1 -1
  115. package/dist/utils/timelineWindow.d.ts +2 -0
  116. package/dist/utils/timelineWindow.js +7 -0
  117. package/dist/utils/utils.js +2 -4
  118. package/docs/AGENT_PATTERNS.md +243 -0
  119. package/docs/AGENT_WORKFLOW.md +364 -0
  120. package/docs/AUTHORING_BEST_PRACTICES.md +188 -0
  121. package/docs/AUTHORING_SYSTEM_AUDIT.md +98 -0
  122. package/docs/BROWSER_EXPORT_SPIKE.md +55 -0
  123. package/docs/DETERMINISTIC_RENDERER.md +83 -0
  124. package/docs/NEXT_RELEASE.md +28 -0
  125. package/docs/PROPOSED_VISUALFRIES_SKILL.md +68 -0
  126. package/docs/examples/agent-cues.json +49 -0
  127. package/docs/examples/agent-transcript.json +23 -0
  128. package/docs/examples/agent-transcript.srt +7 -0
  129. package/docs/examples/agent-transcript.vtt +7 -0
  130. package/docs/examples/image-animation.json +87 -0
  131. package/docs/examples/native-text-metric-badge.json +109 -0
  132. package/package.json +133 -100
  133. package/skills/visualfries/SKILL.md +328 -0
@@ -0,0 +1,246 @@
1
+ export const VISUAL_COMPONENT_TYPES = [
2
+ 'TEXT',
3
+ 'SUBTITLES',
4
+ 'IMAGE',
5
+ 'VIDEO',
6
+ 'GIF',
7
+ 'SHAPE',
8
+ 'COLOR',
9
+ 'GRADIENT'
10
+ ];
11
+ export const COMPONENT_TYPES = [...VISUAL_COMPONENT_TYPES, 'AUDIO'];
12
+ const VISUAL_TRANSFORMS = [
13
+ 'x',
14
+ 'y',
15
+ 'opacity',
16
+ 'rotation',
17
+ 'scale',
18
+ 'scaleX',
19
+ 'scaleY'
20
+ ];
21
+ const GENERIC_VALIDATION_ONLY_EFFECTS = ['blur', 'colorAdjustment', 'rotationRandomizer'];
22
+ export const COMPONENT_CAPABILITIES = {
23
+ TEXT: {
24
+ type: 'TEXT',
25
+ visual: true,
26
+ renderers: {
27
+ preview: 'html',
28
+ final: 'pixi',
29
+ parity: 'different-representation'
30
+ },
31
+ animation: {
32
+ attached: true,
33
+ target: 'html-element-or-wrapper',
34
+ transforms: [...VISUAL_TRANSFORMS],
35
+ selectors: ['container', 'words', 'lines', 'chars', 'css'],
36
+ coordinateSpace: 'css-transform',
37
+ transformOrigin: 'css-center-fixed',
38
+ seekDeterministic: true
39
+ },
40
+ effects: {
41
+ supported: ['textShadow', 'textOutline'],
42
+ validationOnly: [...GENERIC_VALIDATION_ONLY_EFFECTS]
43
+ },
44
+ backgrounds: ['solid-wrapper', 'gradient-wrapper', 'solid-element', 'gradient-element'],
45
+ textFeatures: [
46
+ 'font',
47
+ 'solid-color',
48
+ 'gradient-color',
49
+ 'alignment',
50
+ 'transform',
51
+ 'outline-solid',
52
+ 'shadow',
53
+ 'active-word-color-background',
54
+ 'active-line-color-background',
55
+ 'active-word-line-scale',
56
+ 'solid-highlight-color-cycling',
57
+ 'px-padding',
58
+ 'split-words-lines-chars'
59
+ ],
60
+ caveats: [
61
+ 'Preview uses HTML while final output rasterizes HTML into Pixi.',
62
+ 'Element background padding defaults to 0.22em only when explicit padding is absent.',
63
+ 'clipColor is not implemented; highlight color cycling supports solid colors only.'
64
+ ]
65
+ },
66
+ SUBTITLES: {
67
+ type: 'SUBTITLES',
68
+ visual: true,
69
+ renderers: { preview: 'html', final: 'pixi', parity: 'different-representation' },
70
+ animation: {
71
+ attached: true,
72
+ target: 'html-element-or-wrapper',
73
+ transforms: [...VISUAL_TRANSFORMS],
74
+ selectors: ['container', 'words', 'lines', 'chars', 'css'],
75
+ coordinateSpace: 'css-transform',
76
+ transformOrigin: 'css-center-fixed',
77
+ seekDeterministic: true
78
+ },
79
+ effects: {
80
+ supported: ['textShadow', 'textOutline'],
81
+ validationOnly: [...GENERIC_VALIDATION_ONLY_EFFECTS]
82
+ },
83
+ backgrounds: ['solid-wrapper', 'gradient-wrapper', 'solid-element', 'gradient-element'],
84
+ textFeatures: [
85
+ 'font',
86
+ 'solid-color',
87
+ 'gradient-color',
88
+ 'active-word-color-background',
89
+ 'active-line-color-background',
90
+ 'active-word-line-scale',
91
+ 'solid-highlight-color-cycling',
92
+ 'px-padding',
93
+ 'timed-words'
94
+ ],
95
+ caveats: ['Advanced out anchors depend on cue/component duration and require frame QA.']
96
+ },
97
+ IMAGE: {
98
+ type: 'IMAGE',
99
+ visual: true,
100
+ renderers: { preview: 'pixi', final: 'pixi', parity: 'same-representation' },
101
+ animation: {
102
+ attached: true,
103
+ target: 'pixi-container',
104
+ transforms: [...VISUAL_TRANSFORMS],
105
+ selectors: ['container'],
106
+ coordinateSpace: 'component-relative-offset',
107
+ transformOrigin: 'component-center-fixed',
108
+ seekDeterministic: true
109
+ },
110
+ effects: {
111
+ supported: ['layoutSplit', 'fillBackgroundBlur'],
112
+ validationOnly: [...GENERIC_VALIDATION_ONLY_EFFECTS]
113
+ },
114
+ backgrounds: [],
115
+ textFeatures: [],
116
+ caveats: ['source.url is required by the image runtime even when assetId is present.']
117
+ },
118
+ VIDEO: {
119
+ type: 'VIDEO',
120
+ visual: true,
121
+ renderers: {
122
+ preview: 'native-media',
123
+ final: 'deterministic-media-pixi',
124
+ parity: 'media-predecoded'
125
+ },
126
+ animation: {
127
+ attached: true,
128
+ target: 'pixi-container',
129
+ transforms: [...VISUAL_TRANSFORMS],
130
+ selectors: ['container'],
131
+ coordinateSpace: 'component-relative-offset',
132
+ transformOrigin: 'component-center-fixed',
133
+ seekDeterministic: true
134
+ },
135
+ effects: {
136
+ supported: ['layoutSplit', 'fillBackgroundBlur'],
137
+ validationOnly: [...GENERIC_VALIDATION_ONLY_EFFECTS]
138
+ },
139
+ backgrounds: [],
140
+ textFeatures: [],
141
+ caveats: ['Final media frames are predecoded; browser media is preview-only.']
142
+ },
143
+ GIF: {
144
+ type: 'GIF',
145
+ visual: true,
146
+ renderers: {
147
+ preview: 'native-media',
148
+ final: 'deterministic-media-pixi',
149
+ parity: 'media-predecoded'
150
+ },
151
+ animation: {
152
+ attached: true,
153
+ target: 'pixi-container',
154
+ transforms: [...VISUAL_TRANSFORMS],
155
+ selectors: ['container'],
156
+ coordinateSpace: 'component-relative-offset',
157
+ transformOrigin: 'component-center-fixed',
158
+ seekDeterministic: true
159
+ },
160
+ effects: { supported: [], validationOnly: [...GENERIC_VALIDATION_ONLY_EFFECTS] },
161
+ backgrounds: [],
162
+ textFeatures: [],
163
+ caveats: ['Final GIF frames are predecoded; browser GIF playback is preview-only.']
164
+ },
165
+ SHAPE: {
166
+ type: 'SHAPE',
167
+ visual: true,
168
+ renderers: { preview: 'pixi', final: 'pixi', parity: 'same-representation' },
169
+ animation: {
170
+ attached: true,
171
+ target: 'pixi-container',
172
+ transforms: [...VISUAL_TRANSFORMS],
173
+ selectors: ['container'],
174
+ coordinateSpace: 'component-relative-offset',
175
+ transformOrigin: 'component-center-fixed',
176
+ seekDeterministic: true
177
+ },
178
+ effects: { supported: [], validationOnly: [...GENERIC_VALIDATION_ONLY_EFFECTS] },
179
+ backgrounds: ['solid-fill'],
180
+ textFeatures: [],
181
+ caveats: ['Rectangle cornerRadius and gradient fill are not production-proven.']
182
+ },
183
+ COLOR: {
184
+ type: 'COLOR',
185
+ visual: true,
186
+ renderers: { preview: 'pixi', final: 'pixi', parity: 'same-representation' },
187
+ animation: {
188
+ attached: true,
189
+ target: 'pixi-container',
190
+ transforms: [...VISUAL_TRANSFORMS],
191
+ selectors: ['container'],
192
+ coordinateSpace: 'component-relative-offset',
193
+ transformOrigin: 'component-center-fixed',
194
+ seekDeterministic: true
195
+ },
196
+ effects: { supported: [], validationOnly: [...GENERIC_VALIDATION_ONLY_EFFECTS] },
197
+ backgrounds: ['solid-canvas-fill'],
198
+ textFeatures: [],
199
+ caveats: []
200
+ },
201
+ GRADIENT: {
202
+ type: 'GRADIENT',
203
+ visual: true,
204
+ renderers: { preview: 'pixi', final: 'pixi', parity: 'same-representation' },
205
+ animation: {
206
+ attached: true,
207
+ target: 'pixi-container',
208
+ transforms: [...VISUAL_TRANSFORMS],
209
+ selectors: ['container'],
210
+ coordinateSpace: 'component-relative-offset',
211
+ transformOrigin: 'component-center-fixed',
212
+ seekDeterministic: true
213
+ },
214
+ effects: { supported: [], validationOnly: [...GENERIC_VALIDATION_ONLY_EFFECTS] },
215
+ backgrounds: ['linear-canvas-gradient', 'radial-canvas-gradient'],
216
+ textFeatures: [],
217
+ caveats: ['Radial shape/position fields currently use a centered max-radius fallback.']
218
+ },
219
+ AUDIO: {
220
+ type: 'AUDIO',
221
+ visual: false,
222
+ renderers: { preview: 'none', final: 'audio-mix', parity: 'not-applicable' },
223
+ animation: {
224
+ attached: false,
225
+ target: 'none',
226
+ transforms: [],
227
+ selectors: [],
228
+ coordinateSpace: 'none',
229
+ transformOrigin: 'none',
230
+ seekDeterministic: false
231
+ },
232
+ effects: { supported: [], validationOnly: [] },
233
+ backgrounds: [],
234
+ textFeatures: [],
235
+ caveats: ['AUDIO has no visual animation contract.']
236
+ }
237
+ };
238
+ export function getComponentCapability(type) {
239
+ return COMPONENT_CAPABILITIES[type];
240
+ }
241
+ export function getCapabilityCatalog() {
242
+ return COMPONENT_TYPES.map((type) => COMPONENT_CAPABILITIES[type]);
243
+ }
244
+ export function componentSupportsRuntimeAnimation(type) {
245
+ return getComponentCapability(type)?.animation.attached === true;
246
+ }
@@ -0,0 +1,23 @@
1
+ import { type Scene } from '../schemas/scene/index.js';
2
+ import { type TranscriptInput } from './transcripts.js';
3
+ export type CaptionScenePreset = 'reels-center' | 'reels-lower' | 'podcast-clean' | 'hidden-engine-center';
4
+ export type CaptionSceneInput = {
5
+ id?: string;
6
+ video: {
7
+ url: string;
8
+ assetId?: string;
9
+ width?: number;
10
+ height?: number;
11
+ duration?: number;
12
+ hasAudio?: boolean;
13
+ };
14
+ transcript: TranscriptInput;
15
+ preset?: CaptionScenePreset;
16
+ language?: string;
17
+ width?: number;
18
+ height?: number;
19
+ fps?: number;
20
+ duration?: number;
21
+ backgroundColor?: string;
22
+ };
23
+ export declare function createCaptionScene(input: CaptionSceneInput): Scene;
@@ -0,0 +1,204 @@
1
+ import { SceneShape } from '../schemas/scene/index.js';
2
+ import { inferTranscriptDuration, normalizeTranscript } from './transcripts.js';
3
+ function captionPreset(preset, width, height) {
4
+ const safeWidth = Math.round(width * 0.86);
5
+ const x = Math.round((width - safeWidth) / 2);
6
+ if (preset === 'reels-lower') {
7
+ return {
8
+ x,
9
+ y: Math.round(height * 0.68),
10
+ width: safeWidth,
11
+ height: Math.round(height * 0.18),
12
+ fontSize: Math.round(width * 0.065),
13
+ fontFamily: 'Montserrat',
14
+ fontWeight: '900',
15
+ color: '#FFFFFF',
16
+ activeColor: '#FFDD55',
17
+ activeBackgroundColor: '#083F36',
18
+ backgroundColor: 'rgba(0, 0, 0, 0.42)',
19
+ backgroundAlwaysVisible: false,
20
+ textTransform: 'uppercase',
21
+ shadowBlur: 12
22
+ };
23
+ }
24
+ if (preset === 'podcast-clean') {
25
+ return {
26
+ x,
27
+ y: Math.round(height * 0.7),
28
+ width: safeWidth,
29
+ height: Math.round(height * 0.16),
30
+ fontSize: Math.round(width * 0.054),
31
+ fontFamily: 'Inter',
32
+ fontWeight: '800',
33
+ color: '#FFFFFF',
34
+ activeColor: '#FFFFFF',
35
+ activeBackgroundColor: '#0D5C4A',
36
+ backgroundColor: 'rgba(0, 0, 0, 0.34)',
37
+ backgroundAlwaysVisible: false,
38
+ textTransform: 'none',
39
+ shadowBlur: 8
40
+ };
41
+ }
42
+ if (preset === 'hidden-engine-center') {
43
+ return {
44
+ x,
45
+ y: Math.round(height * 0.44),
46
+ width: safeWidth,
47
+ height: Math.round(height * 0.2),
48
+ fontSize: Math.round(width * 0.066),
49
+ fontFamily: 'Montserrat',
50
+ fontWeight: '900',
51
+ color: '#F7F7F2',
52
+ activeColor: '#FFDF5A',
53
+ activeBackgroundColor: '#06483D',
54
+ backgroundColor: 'rgba(0, 0, 0, 0.28)',
55
+ backgroundAlwaysVisible: false,
56
+ textTransform: 'uppercase',
57
+ shadowBlur: 10
58
+ };
59
+ }
60
+ return {
61
+ x,
62
+ y: Math.round(height * 0.48),
63
+ width: safeWidth,
64
+ height: Math.round(height * 0.2),
65
+ fontSize: Math.round(width * 0.064),
66
+ fontFamily: 'Montserrat',
67
+ fontWeight: '900',
68
+ color: '#FFFFFF',
69
+ activeColor: '#FFD84D',
70
+ activeBackgroundColor: '#054D42',
71
+ backgroundColor: 'rgba(0, 0, 0, 0.3)',
72
+ backgroundAlwaysVisible: false,
73
+ textTransform: 'uppercase',
74
+ shadowBlur: 10
75
+ };
76
+ }
77
+ export function createCaptionScene(input) {
78
+ const width = input.width ?? 1080;
79
+ const height = input.height ?? 1920;
80
+ const fps = input.fps ?? 30;
81
+ const language = input.language ?? 'en';
82
+ const assetId = input.video.assetId ?? 'main-video';
83
+ const subtitles = normalizeTranscript(input.transcript);
84
+ const duration = input.duration ?? input.video.duration ?? inferTranscriptDuration(subtitles);
85
+ const sceneDuration = Math.max(0.1, duration);
86
+ const videoUrl = input.video.url;
87
+ const preset = captionPreset(input.preset ?? 'reels-center', width, height);
88
+ const videoAsset = {
89
+ id: assetId,
90
+ type: 'VIDEO',
91
+ url: videoUrl,
92
+ metadata: {
93
+ width: input.video.width ?? width,
94
+ height: input.video.height ?? height,
95
+ duration: sceneDuration,
96
+ hasAudio: input.video.hasAudio ?? true
97
+ }
98
+ };
99
+ const video = {
100
+ id: 'video-main',
101
+ type: 'VIDEO',
102
+ name: 'Main video',
103
+ timeline: { startAt: 0, endAt: sceneDuration },
104
+ source: { url: videoUrl, assetId, metadata: videoAsset.metadata },
105
+ appearance: { x: 0, y: 0, width, height },
106
+ volume: 1,
107
+ muted: false,
108
+ playback: { autoplay: true, loop: false, playbackRate: 1 },
109
+ crop: { x: 0, y: 0, width: 1, height: 1 },
110
+ order: 0
111
+ };
112
+ const captions = {
113
+ id: 'subtitles-main',
114
+ type: 'SUBTITLES',
115
+ name: 'Captions',
116
+ timeline: { startAt: 0, endAt: sceneDuration },
117
+ source: { assetId, languageCode: language },
118
+ timingAnchor: {
119
+ mode: 'ASSET_USAGE',
120
+ assetId,
121
+ offset: 0
122
+ },
123
+ appearance: {
124
+ x: preset.x,
125
+ y: preset.y,
126
+ width: preset.width,
127
+ height: preset.height,
128
+ horizontalAlign: 'center',
129
+ verticalAlign: 'center',
130
+ ...(preset.backgroundColor
131
+ ? {
132
+ background: {
133
+ enabled: true,
134
+ color: preset.backgroundColor,
135
+ target: 'wrapper',
136
+ radius: 18
137
+ }
138
+ }
139
+ : {}),
140
+ backgroundAlwaysVisible: preset.backgroundAlwaysVisible,
141
+ text: {
142
+ fontFamily: preset.fontFamily,
143
+ fontSize: { value: preset.fontSize, unit: 'px' },
144
+ fontWeight: preset.fontWeight,
145
+ color: preset.color,
146
+ textAlign: 'center',
147
+ textTransform: preset.textTransform,
148
+ lineHeight: { value: 1.05, unit: 'em' },
149
+ shadow: {
150
+ enabled: true,
151
+ color: '#000000',
152
+ blur: preset.shadowBlur,
153
+ offsetX: 0,
154
+ offsetY: 3
155
+ },
156
+ activeWord: {
157
+ enabled: true,
158
+ color: preset.activeColor,
159
+ backgroundColor: preset.activeBackgroundColor,
160
+ scale: 1.08,
161
+ backgroundPaddingX: 14,
162
+ backgroundPaddingY: 6,
163
+ backgroundBorderRadius: 10
164
+ }
165
+ }
166
+ },
167
+ order: 10
168
+ };
169
+ const mediaLayer = {
170
+ id: 'layer-media',
171
+ name: 'Media',
172
+ order: 0,
173
+ components: [video]
174
+ };
175
+ const captionLayer = {
176
+ id: 'layer-captions',
177
+ name: 'Captions',
178
+ order: 10,
179
+ components: [captions]
180
+ };
181
+ const scene = {
182
+ id: input.id ?? 'visualfries-caption-scene',
183
+ name: 'Agent Caption Scene',
184
+ settings: {
185
+ width,
186
+ height,
187
+ duration: sceneDuration,
188
+ fps,
189
+ backgroundColor: input.backgroundColor ?? '#000000',
190
+ subtitles: {
191
+ punctuation: true,
192
+ mergeGap: 0.2,
193
+ data: {
194
+ [assetId]: {
195
+ [language]: subtitles
196
+ }
197
+ }
198
+ }
199
+ },
200
+ assets: [videoAsset],
201
+ layers: [mediaLayer, captionLayer]
202
+ };
203
+ return SceneShape.parse(scene);
204
+ }
@@ -0,0 +1,24 @@
1
+ import { type CapabilityComponentType } from './capabilities.js';
2
+ export declare const AGENT_CAPTION_PRESETS: readonly ["reels-center", "reels-lower", "podcast-clean", "hidden-engine-center"];
3
+ export declare const AGENT_CUE_PRESETS: readonly ["hidden-engine-dynamic", "captioned-clean"];
4
+ export declare const AGENT_OVERLAY_STYLES: readonly ["pop-label", "shock-word", "soft-card", "hook-punch", "proof-pill", "danger-crossout", "metric-badge", "cta-card"];
5
+ export declare const AGENT_BROLL_MOTIONS: readonly ["none", "slow-zoom-in", "slow-zoom-out", "drift-up"];
6
+ export declare const AGENT_TRANSITION_STYLES: readonly ["dip-to-black", "flash", "swipe-left", "swipe-up"];
7
+ export declare const AGENT_TRANSCRIPT_FORMATS: readonly ["json", "srt", "vtt"];
8
+ export declare const AGENT_CLI_COMMANDS: readonly ["doctor", "catalog", "validate", "init", "caption-scene", "preset-cues", "apply-cues", "validate-cues", "qa", "inspect", "explain", "parity", "render", "compose", "produce"];
9
+ export declare function getAgentCatalog(options?: {
10
+ component?: CapabilityComponentType;
11
+ }): {
12
+ captionPresets: ("reels-center" | "reels-lower" | "podcast-clean" | "hidden-engine-center")[];
13
+ cuePresets: ("hidden-engine-dynamic" | "captioned-clean")[];
14
+ overlayStyles: ("pop-label" | "shock-word" | "soft-card" | "hook-punch" | "proof-pill" | "danger-crossout" | "metric-badge" | "cta-card")[];
15
+ brollMotions: ("none" | "slow-zoom-in" | "slow-zoom-out" | "drift-up")[];
16
+ transitionStyles: ("dip-to-black" | "flash" | "swipe-left" | "swipe-up")[];
17
+ transcriptFormats: ("srt" | "vtt" | "json")[];
18
+ cliCommands: ("render" | "doctor" | "catalog" | "validate" | "init" | "caption-scene" | "preset-cues" | "apply-cues" | "validate-cues" | "qa" | "inspect" | "explain" | "parity" | "compose" | "produce")[];
19
+ capabilities: import("./capabilities.js").ComponentCapability[];
20
+ recommendedWorkflow: {
21
+ routine: string;
22
+ debug: string[];
23
+ };
24
+ };
@@ -0,0 +1,67 @@
1
+ import { getCapabilityCatalog, getComponentCapability } from './capabilities.js';
2
+ export const AGENT_CAPTION_PRESETS = [
3
+ 'reels-center',
4
+ 'reels-lower',
5
+ 'podcast-clean',
6
+ 'hidden-engine-center'
7
+ ];
8
+ export const AGENT_CUE_PRESETS = ['hidden-engine-dynamic', 'captioned-clean'];
9
+ export const AGENT_OVERLAY_STYLES = [
10
+ 'pop-label',
11
+ 'shock-word',
12
+ 'soft-card',
13
+ 'hook-punch',
14
+ 'proof-pill',
15
+ 'danger-crossout',
16
+ 'metric-badge',
17
+ 'cta-card'
18
+ ];
19
+ export const AGENT_BROLL_MOTIONS = ['none', 'slow-zoom-in', 'slow-zoom-out', 'drift-up'];
20
+ export const AGENT_TRANSITION_STYLES = ['dip-to-black', 'flash', 'swipe-left', 'swipe-up'];
21
+ export const AGENT_TRANSCRIPT_FORMATS = ['json', 'srt', 'vtt'];
22
+ export const AGENT_CLI_COMMANDS = [
23
+ 'doctor',
24
+ 'catalog',
25
+ 'validate',
26
+ 'init',
27
+ 'caption-scene',
28
+ 'preset-cues',
29
+ 'apply-cues',
30
+ 'validate-cues',
31
+ 'qa',
32
+ 'inspect',
33
+ 'explain',
34
+ 'parity',
35
+ 'render',
36
+ 'compose',
37
+ 'produce'
38
+ ];
39
+ export function getAgentCatalog(options = {}) {
40
+ const componentCapability = options.component
41
+ ? getComponentCapability(options.component)
42
+ : undefined;
43
+ if (options.component && !componentCapability) {
44
+ throw new Error(`Unknown VisualFries component type: ${options.component}`);
45
+ }
46
+ return {
47
+ captionPresets: [...AGENT_CAPTION_PRESETS],
48
+ cuePresets: [...AGENT_CUE_PRESETS],
49
+ overlayStyles: [...AGENT_OVERLAY_STYLES],
50
+ brollMotions: [...AGENT_BROLL_MOTIONS],
51
+ transitionStyles: [...AGENT_TRANSITION_STYLES],
52
+ transcriptFormats: [...AGENT_TRANSCRIPT_FORMATS],
53
+ cliCommands: [...AGENT_CLI_COMMANDS],
54
+ capabilities: componentCapability ? [componentCapability] : getCapabilityCatalog(),
55
+ recommendedWorkflow: {
56
+ routine: 'visualfries compose --video ./input.mp4 --transcript ./captions.srt --cue-preset hidden-engine-dynamic --cues ./cues.json --scene-output ./scene.json --qa-output ./qa/frames --render-mode preview --output ./preview.mp4',
57
+ debug: [
58
+ 'visualfries doctor --json',
59
+ 'visualfries caption-scene --video ./input.mp4 --transcript ./captions.srt --preset hidden-engine-center --output ./scene.json',
60
+ 'visualfries preset-cues --duration 45 --preset hidden-engine-dynamic --output ./cues.json',
61
+ 'visualfries apply-cues ./scene.json --cues ./cues.json --output ./scene.with-cues.json',
62
+ 'visualfries inspect ./scene.with-cues.json --screenshots --samples 3 --output ./qa/frames --json',
63
+ 'visualfries render ./scene.with-cues.json --render-mode preview --output ./preview.mp4'
64
+ ]
65
+ }
66
+ };
67
+ }
@@ -0,0 +1,54 @@
1
+ import { type AgentBrollCue } from './broll.js';
2
+ import { type AgentTextOverlayCue } from './overlays.js';
3
+ import { type AgentTransitionCue } from './transitions.js';
4
+ import { type Scene, type SceneInput } from '../schemas/scene/index.js';
5
+ export type AgentCueFile = {
6
+ broll?: AgentBrollCue[];
7
+ overlays?: AgentTextOverlayCue[];
8
+ transitions?: AgentTransitionCue[];
9
+ brollLayerId?: string;
10
+ brollLayerName?: string;
11
+ brollLayerOrder?: number;
12
+ overlayLayerId?: string;
13
+ overlayLayerName?: string;
14
+ overlayLayerOrder?: number;
15
+ transitionLayerId?: string;
16
+ transitionLayerName?: string;
17
+ transitionLayerOrder?: number;
18
+ };
19
+ export type ApplyAgentCueFileInput = {
20
+ scene: Scene | SceneInput;
21
+ cues: AgentCueFile;
22
+ cueFilePath?: string;
23
+ };
24
+ export type ApplyAgentCueFileResult = {
25
+ scene: Scene;
26
+ applied: {
27
+ broll: number;
28
+ overlays: number;
29
+ transitions: number;
30
+ };
31
+ };
32
+ export type AgentCueValidationIssue = {
33
+ level: 'error' | 'warning';
34
+ path: string;
35
+ message: string;
36
+ };
37
+ export type ValidateAgentCueFileInput = {
38
+ cues: AgentCueFile;
39
+ duration?: number;
40
+ cueFilePath?: string;
41
+ };
42
+ export type AgentCueValidationReport = {
43
+ valid: boolean;
44
+ issues: AgentCueValidationIssue[];
45
+ summary: {
46
+ broll: number;
47
+ overlays: number;
48
+ transitions: number;
49
+ };
50
+ };
51
+ export declare function mergeAgentCueFiles(...cueFiles: AgentCueFile[]): AgentCueFile;
52
+ export declare function normalizeAgentCueFile(cues: AgentCueFile, cueFilePath?: string): AgentCueFile;
53
+ export declare function validateAgentCueFile(input: ValidateAgentCueFileInput): AgentCueValidationReport;
54
+ export declare function applyAgentCueFile(input: ApplyAgentCueFileInput): ApplyAgentCueFileResult;