visualfries 0.1.10115 → 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.
- package/README.md +122 -0
- package/bin/visualfries.js +1570 -0
- package/dist/DIContainer.d.ts +2 -1
- package/dist/DIContainer.js +16 -5
- package/dist/SceneBuilder.svelte.d.ts +70 -1
- package/dist/SceneBuilder.svelte.js +96 -29
- package/dist/agent/audioMixer.d.ts +34 -0
- package/dist/agent/audioMixer.js +308 -0
- package/dist/agent/broll.d.ts +35 -0
- package/dist/agent/broll.js +226 -0
- package/dist/agent/capabilities.d.ts +34 -0
- package/dist/agent/capabilities.js +246 -0
- package/dist/agent/captionScene.d.ts +23 -0
- package/dist/agent/captionScene.js +204 -0
- package/dist/agent/catalog.d.ts +24 -0
- package/dist/agent/catalog.js +67 -0
- package/dist/agent/cueFiles.d.ts +54 -0
- package/dist/agent/cueFiles.js +219 -0
- package/dist/agent/cuePresets.d.ts +7 -0
- package/dist/agent/cuePresets.js +50 -0
- package/dist/agent/deterministicMedia.d.ts +61 -0
- package/dist/agent/deterministicMedia.js +303 -0
- package/dist/agent/index.d.ts +18 -0
- package/dist/agent/index.js +18 -0
- package/dist/agent/inspectScene.d.ts +36 -0
- package/dist/agent/inspectScene.js +139 -0
- package/dist/agent/localRender.d.ts +82 -0
- package/dist/agent/localRender.js +702 -0
- package/dist/agent/overlays.d.ts +40 -0
- package/dist/agent/overlays.js +325 -0
- package/dist/agent/productionPlan.d.ts +131 -0
- package/dist/agent/productionPlan.js +322 -0
- package/dist/agent/renderPlan.d.ts +27 -0
- package/dist/agent/renderPlan.js +68 -0
- package/dist/agent/renderRanges.d.ts +24 -0
- package/dist/agent/renderRanges.js +73 -0
- package/dist/agent/runtimeSupport.d.ts +19 -0
- package/dist/agent/runtimeSupport.js +192 -0
- package/dist/agent/streamingEncoder.d.ts +31 -0
- package/dist/agent/streamingEncoder.js +208 -0
- package/dist/agent/transcripts.d.ts +29 -0
- package/dist/agent/transcripts.js +146 -0
- package/dist/agent/transitions.d.ts +20 -0
- package/dist/agent/transitions.js +169 -0
- package/dist/animations/PixiAnimationTarget.d.ts +29 -0
- package/dist/animations/PixiAnimationTarget.js +63 -0
- package/dist/animations/builders/LineHighlighterAnimationBuilder.js +20 -3
- package/dist/animations/builders/WordHighlighterAnimationBuilder.js +15 -2
- package/dist/browser/browserExport.d.ts +73 -0
- package/dist/browser/browserExport.js +180 -0
- package/dist/browser/glTransitions.d.ts +37 -0
- package/dist/browser/glTransitions.js +261 -0
- package/dist/browser/index.d.ts +3 -0
- package/dist/browser/index.js +3 -0
- package/dist/browser/mediaDecode.d.ts +31 -0
- package/dist/browser/mediaDecode.js +152 -0
- package/dist/builders/PixiComponentBuilder.d.ts +6 -0
- package/dist/builders/PixiComponentBuilder.js +12 -0
- package/dist/builders/_ComponentState.svelte.d.ts +7 -5
- package/dist/builders/_ComponentState.svelte.js +29 -15
- package/dist/builders/html/StyleBuilder.js +9 -8
- package/dist/builders/html/TextComponentHtmlBuilder.js +4 -2
- package/dist/builders/html/processors/AppearanceStyleProcessor.js +1 -1
- package/dist/builders/html/processors/TextAppearanceStyleProcessor.js +7 -0
- package/dist/builders/html/processors/TextEffectsStyleProcessor.js +32 -13
- package/dist/commands/ReplaceSourceOnTimeCommand.js +9 -1
- package/dist/commands/SeekCommand.js +19 -6
- package/dist/components/AnimatedGIF.d.ts +3 -0
- package/dist/components/AnimatedGIF.js +28 -1
- package/dist/components/Component.svelte.d.ts +5 -5
- package/dist/components/Component.svelte.js +29 -13
- package/dist/components/ComponentContext.svelte.js +68 -23
- package/dist/components/hooks/AnimationHook.js +1 -1
- package/dist/components/hooks/CanvasFillHook.d.ts +12 -0
- package/dist/components/hooks/CanvasFillHook.js +75 -0
- package/dist/components/hooks/DeterministicMediaFrameHook.js +3 -0
- package/dist/components/hooks/HtmlTextHook.js +11 -3
- package/dist/components/hooks/HtmlToCanvasHook.js +8 -25
- package/dist/components/hooks/MediaHook.js +172 -47
- package/dist/components/hooks/MediaSeekingHook.js +138 -88
- package/dist/components/hooks/PixiGifHook.js +4 -4
- package/dist/components/hooks/PixiSplitScreenDisplayObjectHook.d.ts +3 -0
- package/dist/components/hooks/PixiSplitScreenDisplayObjectHook.js +85 -8
- package/dist/components/hooks/PixiVideoTextureHook.js +10 -4
- package/dist/components/hooks/PixiVisualTransformHook.d.ts +16 -0
- package/dist/components/hooks/PixiVisualTransformHook.js +102 -0
- package/dist/components/hooks/SubtitlesHook.js +48 -24
- package/dist/components/hooks/VerifyMediaHook.js +2 -2
- package/dist/directors/ComponentDirector.d.ts +1 -0
- package/dist/directors/ComponentDirector.js +41 -8
- package/dist/factories/SceneBuilderFactory.d.ts +3 -0
- package/dist/factories/SceneBuilderFactory.js +6 -0
- package/dist/fonts/fontDiscovery.js +12 -1
- package/dist/layers/Layer.svelte.d.ts +54 -0
- package/dist/layers/Layer.svelte.js +2 -25
- package/dist/managers/AppManager.svelte.d.ts +12 -0
- package/dist/managers/AppManager.svelte.js +180 -8
- package/dist/managers/ComponentsManager.svelte.d.ts +7 -7
- package/dist/managers/ComponentsManager.svelte.js +29 -15
- package/dist/managers/DeterministicMediaManager.d.ts +6 -0
- package/dist/managers/DeterministicMediaManager.js +57 -3
- package/dist/managers/EventManager.js +3 -1
- package/dist/managers/LayersManager.svelte.d.ts +54 -0
- package/dist/managers/RenderManager.d.ts +5 -0
- package/dist/managers/RenderManager.js +67 -21
- package/dist/managers/StateManager.svelte.d.ts +56 -0
- package/dist/managers/StateManager.svelte.js +60 -58
- package/dist/managers/SubtitlesManager.svelte.js +1 -3
- package/dist/managers/TimeManager.svelte.d.ts +4 -0
- package/dist/managers/TimeManager.svelte.js +23 -7
- package/dist/schemas/runtime/deterministic.d.ts +3 -0
- package/dist/schemas/runtime/deterministic.js +5 -1
- package/dist/schemas/runtime/types.d.ts +36 -15
- package/dist/schemas/scene/components.d.ts +126 -0
- package/dist/schemas/scene/components.js +11 -0
- package/dist/schemas/scene/core.d.ts +109 -10
- package/dist/schemas/scene/core.js +1 -1
- package/dist/utils/mediaWindow.d.ts +13 -0
- package/dist/utils/mediaWindow.js +25 -0
- package/dist/utils/svgGenerator.js +1 -1
- package/dist/utils/timelineWindow.d.ts +2 -0
- package/dist/utils/timelineWindow.js +7 -0
- package/dist/utils/utils.js +2 -4
- package/docs/AGENT_PATTERNS.md +243 -0
- package/docs/AGENT_WORKFLOW.md +364 -0
- package/docs/AUTHORING_BEST_PRACTICES.md +188 -0
- package/docs/AUTHORING_SYSTEM_AUDIT.md +98 -0
- package/docs/BROWSER_EXPORT_SPIKE.md +55 -0
- package/docs/DETERMINISTIC_RENDERER.md +83 -0
- package/docs/NEXT_RELEASE.md +28 -0
- package/docs/PROPOSED_VISUALFRIES_SKILL.md +68 -0
- package/docs/examples/agent-cues.json +49 -0
- package/docs/examples/agent-transcript.json +23 -0
- package/docs/examples/agent-transcript.srt +7 -0
- package/docs/examples/agent-transcript.vtt +7 -0
- package/docs/examples/image-animation.json +87 -0
- package/docs/examples/native-text-metric-badge.json +109 -0
- package/package.json +133 -100
- 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;
|