reframe-video 0.6.34 → 0.6.39

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.
@@ -83,6 +83,12 @@ export interface ComposeReport {
83
83
  }[];
84
84
  warnings: string[];
85
85
  }
86
+ /**
87
+ * Which params an overlay may patch on a labeled timeline step, per kind — the
88
+ * single source of truth for both `applyOverlay` (what it accepts) and
89
+ * `sceneManifest` (what it advertises as patchable). Keep them from drifting.
90
+ */
91
+ export declare const TIMELINE_PATCHABLE: Record<string, string[]>;
86
92
  export declare function composeScene(base: SceneIR, ...overlays: OverlayDoc[]): {
87
93
  ir: SceneIR;
88
94
  report: ComposeReport;
@@ -1,12 +1,28 @@
1
1
  /**
2
- * Device-mockup presets: a parametric vector frame (phone/laptop/browser/…) with
2
+ * Device-mockup presets a parametric vector frame (phone/laptop/browser/…) with
3
3
  * a CLIPPED screen "content slot". The sibling of motionPreset — that generates
4
4
  * a TimelineIR, this generates a NodeIR subtree. Pure primitives + clip, so no
5
- * assets and fully deterministic (plain JSON, no Date/random). A 2.5D vector
6
- * tier — no true perspective.
5
+ * assets and fully deterministic (plain JSON, no Date/random).
7
6
  *
8
7
  * devicePreset("phone", { id: "hero", content: [ ...your UI nodes ] })
9
8
  *
9
+ * Redesigned around three orthogonal layers (all back-compat; the public surface
10
+ * and the stable ids `${id}` / `${id}-screen` / `${id}-content` are unchanged):
11
+ *
12
+ * 1. A `DeviceCtx` resolved once (palette + dims + material + style + a seeded
13
+ * PRNG) and threaded to every part.
14
+ * 2. A small PARTS vocabulary (`slab`, `screenStack`, `phoneNotch`, …) where the
15
+ * material/lighting lives ONCE, so every chassis — and every future chassis —
16
+ * inherits the premium look for free.
17
+ * 3. A `CHASSIS` registry (name → builder) that just ARRANGES parts; adding a
18
+ * device is one entry + one `SCREENS`/`BOUNDS` row, not a new `switch` arm.
19
+ *
20
+ * Material is PREMIUM by default (gradient body, ambient screen glow, soft contact
21
+ * shadow, glass glare) — `material:"flat"` opts back to clean flat fills. `style`
22
+ * picks "glass" (realistic) or "neon" (graphic, additive edge glow). Each instance
23
+ * auto-varies from its `id` (a deterministic seed) within bounded, on-model ranges;
24
+ * pass `seed` to pin or explore. A 2.5D vector tier — no true perspective.
25
+ *
10
26
  * Each instance needs a distinct `id` (it prefixes every generated node id);
11
27
  * two with the same prefix collide via the scene's duplicate-id validation.
12
28
  *
@@ -18,6 +34,14 @@
18
34
  import type { NodeIR } from "./ir.js";
19
35
  export declare const DEVICE_PRESET_NAMES: readonly ["phone", "tablet", "laptop", "browser", "watch", "monitor", "tv", "foldable", "terminal", "car"];
20
36
  export type DevicePresetName = (typeof DEVICE_PRESET_NAMES)[number];
37
+ /** Visual fidelity tier. `premium` (default) layers gradient/glow/shadow on top
38
+ * of the silhouette; `flat` is clean solid fills (lightest, golden-style). */
39
+ export type DeviceMaterial = "premium" | "flat";
40
+ /** Premium aesthetic. `glass` = realistic glass/metal + soft shadow; `neon` =
41
+ * flat body + additive edge glow (graphic, motion-graphics punch). */
42
+ export type DeviceStyle = "glass" | "neon";
43
+ /** Phone front-camera treatment. Defaults to the iOS-style dynamic island. */
44
+ export type DeviceNotch = "island" | "notch" | "punch" | "none";
21
45
  export interface DevicePresetOpts {
22
46
  /** Id PREFIX for every generated node (default "device"). Make it unique per instance. */
23
47
  id?: string;
@@ -38,6 +62,15 @@ export interface DevicePresetOpts {
38
62
  content?: NodeIR[];
39
63
  /** Browser/terminal address-bar text. */
40
64
  url?: string;
65
+ /** Visual tier (default "premium"). */
66
+ material?: DeviceMaterial;
67
+ /** Premium aesthetic (default "glass"). */
68
+ style?: DeviceStyle;
69
+ /** Deterministic variation. Omit ⇒ derived from `id` (each instance differs);
70
+ * same value ⇒ identical; different value ⇒ same family, varied. */
71
+ seed?: number;
72
+ /** Phone front-camera style (default "island"). */
73
+ notch?: DeviceNotch;
41
74
  }
42
75
  /** The screen's content area (content-local coords: origin 0,0 = screen centre,
43
76
  * pre-scale). Author/scroll `content` against these bounds. */
@@ -59,9 +59,10 @@ export interface BeatOpts {
59
59
  nodes?: string[];
60
60
  /** Group children in parallel instead of sequence. */
61
61
  parallel?: boolean;
62
- /** Absolute start (rigid placement). */
63
- at?: number;
64
- /** Relative shift before the beat. */
62
+ /** Absolute start (number), or a timeline label to anchor to (string) — the
63
+ * beat starts at that label's time, `gap` offsetting it. Keep anchor beats in a `par`. */
64
+ at?: number | string;
65
+ /** Relative shift before the beat (with a label `at`, the offset from the label). */
65
66
  gap?: number;
66
67
  /** Interior time-stretch factor. */
67
68
  scale?: number;
@@ -2,7 +2,8 @@ export * from "./ir.js";
2
2
  export * from "./dsl.js";
3
3
  export { validateScene, validateComposition, SceneValidationError, PROPS_BY_TYPE } from "./validate.js";
4
4
  export { compileComposition, type CompiledComposition, type ScenePlacement, } from "./composeComposition.js";
5
- export { composeScene, formatComposeReport, type OverlayDoc, type ComposeReport, } from "./compose.js";
5
+ export { composeScene, formatComposeReport, TIMELINE_PATCHABLE, type OverlayDoc, type ComposeReport, } from "./compose.js";
6
+ export { sceneManifest, lintScene, type SceneManifest, type NodeAddress, type StateAddress, type TimelineAddress, type BeatAddress, type BehaviorAddress, type ManifestSummary, type LintFinding, } from "./manifest.js";
6
7
  export { compileScene, type CompiledScene, type PropertySegment, type LabelSpan, type MotionDriver } from "./compile.js";
7
8
  export { pathPoint, pathTangentAngle, type Pt } from "./path.js";
8
9
  export { cameraTo, cameraFit, cameraMatrix, CAMERA_ID, CAMERA_PROPS } from "./camera.js";
@@ -11,8 +12,9 @@ export { linearGradient, radialGradient, conicGradient, isGradient } from "./gra
11
12
  export { glow, dropShadow } from "./effects.js";
12
13
  export { row, column, grid, type RowOpts, type GridOpts } from "./layout.js";
13
14
  export { photoMontage, videoMontage, type MontageImage, type MontageOpts, type MontageResult, type KenBurns } from "./montage.js";
15
+ export { title, lowerThird, type TitleOpts, type TitleResult, type LowerThirdOpts, type LowerThirdResult } from "./titles.js";
14
16
  export { motionPreset, PRESET_NAMES, type PresetName, type PresetRig, type PresetOpts } from "./presets.js";
15
- export { devicePreset, deviceScreen, deviceScreenCenter, deviceBounds, deviceScreenPoint, DEVICE_PRESET_NAMES, type DevicePresetName, type DevicePresetOpts } from "./devicePreset.js";
17
+ export { devicePreset, deviceScreen, deviceScreenCenter, deviceBounds, deviceScreenPoint, DEVICE_PRESET_NAMES, type DevicePresetName, type DevicePresetOpts, type DeviceMaterial, type DeviceStyle, type DeviceNotch } from "./devicePreset.js";
16
18
  export { cursor, cursorTo, cursorPath, cursorClick, cursorDouble, type CursorStyle, type CursorOpts, type CursorToOpts, type CursorPathOpts, type CursorClickOpts } from "./cursor.js";
17
19
  export { rig, rigPose, poseTo, ikReach, humanoid, ovalPath, type Bone, type RigOpts, type Pose, type HumanoidOpts } from "./rig.js";
18
20
  export { characterPreset, CHARACTER_PRESET_NAMES, type CharacterPresetName, type CharacterPresetOpts } from "./characterPreset.js";
@@ -243,10 +243,12 @@ export interface VideoProps extends BaseProps {
243
243
  /** Box-fit into width×height, like the image node. `"fill"` (default) | `"cover"`. */
244
244
  fit?: ImageFit;
245
245
  /**
246
- * Scene-time (seconds) at which playback begins. Before it, frame 0 (clipStart) shows;
247
- * the node's visibility is still controlled by opacity/timeline. Default 0.
246
+ * Scene-time at which playback begins. Before it, frame 0 (clipStart) shows; the
247
+ * node's visibility is still controlled by opacity/timeline. Default 0. A NUMBER is
248
+ * an absolute time; a STRING anchors the start to that timeline label's t0 (like
249
+ * `beat.at`), so the clip follows when its shot is retimed (e.g. `start: "shot-2"`).
248
250
  */
249
- start?: number;
251
+ start?: number | string;
250
252
  /** Playback speed multiplier (2 = double speed). Default 1. */
251
253
  rate?: number;
252
254
  /** Source in-point (seconds) shown at `start`. Default 0. */
@@ -373,8 +375,14 @@ export type TimelineIR = {
373
375
  */
374
376
  nodes?: string[];
375
377
  parallel?: boolean;
376
- /** Absolute start (rigid placement). Overrides sequential flow. */
377
- at?: number;
378
+ /**
379
+ * Start placement (overrides sequential flow). A NUMBER is an absolute time;
380
+ * a STRING anchors the beat to that timeline label's start (e.g.
381
+ * `at: "shot-2"`), so the beat stays synced when the target is retimed (the
382
+ * same idea as `audio.cues`). With a label anchor, `gap` is the offset from
383
+ * the label. Anchor beats should sit in a `par` branch, not a sequential flow.
384
+ */
385
+ at?: number | string;
378
386
  /** Relative shift: a leading delay before the beat (and everything after). */
379
387
  gap?: number;
380
388
  /** Interior time-stretch factor (every child offset and duration ×scale). */
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Scene manifest + addressability lint — make the override namespace queryable.
3
+ *
4
+ * Both override stacks (authoring `composeScene`, runtime `sampleProp`) can only
5
+ * find anything through the node-id / timeline-label namespace. That namespace is
6
+ * the entire edit API, but it's implicit. `sceneManifest` enumerates it — every
7
+ * editable address a human or an AI editor can patch — and `lintScene` flags the
8
+ * surface that ISN'T addressable (motion with no label can't be retimed by an
9
+ * overlay). Pure reads over a CompiledScene; no IR/evaluate changes.
10
+ */
11
+ import type { CompiledScene } from "./compile.js";
12
+ import type { NodeIR, Size, TimelineIR } from "./ir.js";
13
+ export interface NodeAddress {
14
+ id: string;
15
+ type: NodeIR["type"];
16
+ /** Enclosing group id (absent for a top-level node). */
17
+ parent?: string;
18
+ /** Overlay address for base-prop patches: `nodes.<id>`. */
19
+ address: string;
20
+ /** Props an overlay may set on this node (PROPS_BY_TYPE for its type). */
21
+ editableProps: string[];
22
+ /** Props this node actually animates (has a tween/to segment or a motion path). */
23
+ animatedProps: string[];
24
+ /** State names that override this node (`states.<name>.<id>` addresses). */
25
+ inStates: string[];
26
+ }
27
+ export interface StateAddress {
28
+ name: string;
29
+ address: string;
30
+ touches: {
31
+ id: string;
32
+ props: string[];
33
+ }[];
34
+ }
35
+ export interface TimelineAddress {
36
+ label: string;
37
+ kind: TimelineIR["kind"];
38
+ t0: number;
39
+ t1: number;
40
+ /** Params an overlay may patch on this step (TIMELINE_PATCHABLE for its kind). */
41
+ patchable: string[];
42
+ address: string;
43
+ }
44
+ export interface BeatAddress {
45
+ name: string;
46
+ t0: number;
47
+ t1: number;
48
+ /** Node ids the beat semantically owns (its `nodes` field). */
49
+ ownsNodes: string[];
50
+ address: string;
51
+ }
52
+ export interface BehaviorAddress {
53
+ target: string;
54
+ prop: string;
55
+ kind: string;
56
+ address: string;
57
+ }
58
+ export interface ManifestSummary {
59
+ nodeCount: number;
60
+ /** Labeled timeline steps + named beats (addressable timing). */
61
+ labeledSteps: number;
62
+ /** Motion steps (tween/to/motionPath) with NO label — unaddressable timing. */
63
+ unlabeledMotionSteps: number;
64
+ /** labeled motion steps / total motion steps (1 when there is no motion). */
65
+ motionAddressableRatio: number;
66
+ }
67
+ export interface SceneManifest {
68
+ scene: {
69
+ id: string;
70
+ duration: number;
71
+ fps: number;
72
+ size: Size;
73
+ background?: string;
74
+ };
75
+ nodes: NodeAddress[];
76
+ states: StateAddress[];
77
+ timeline: TimelineAddress[];
78
+ beats: BeatAddress[];
79
+ behaviors: BehaviorAddress[];
80
+ summary: ManifestSummary;
81
+ }
82
+ export interface LintFinding {
83
+ rule: string;
84
+ severity: "warn" | "error";
85
+ message: string;
86
+ /** Present when the finding refers to an existing address. */
87
+ address?: string;
88
+ }
89
+ /** Enumerate a scene's full addressable / editable surface. Pure + deterministic. */
90
+ export declare function sceneManifest(compiled: CompiledScene): SceneManifest;
91
+ /** Flag the surface that ISN'T overlay-addressable. Static, no render. */
92
+ export declare function lintScene(compiled: CompiledScene): LintFinding[];
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Title + lower-third generators — the motion-graphic overlay vocabulary for a
3
+ * media piece (titles, name straps), the high-level analog of `photoMontage`.
4
+ *
5
+ * `title()` composes the kinetic-text engine (`splitText` + `textIn`/`textOut`);
6
+ * `lowerThird()` is a name/role strap with an accent bar. Both return
7
+ * `{ nodes, timeline }` (house style) so a caller spreads the nodes into the
8
+ * scene and composes the timeline with `seq`/`par`. Pure + deterministic; stable
9
+ * ids so overlay edits address them.
10
+ */
11
+ import type { NodeIR, TimelineIR } from "./ir.js";
12
+ import { type FontWeight, type TextBlock, type TextInName, type TextOutName } from "./textFx.js";
13
+ export interface TitleOpts {
14
+ /** The headline text. */
15
+ text: string;
16
+ /** Id PREFIX → glyph ids `${id}-${i}` (default "title"). Make it unique. */
17
+ id?: string;
18
+ /** Anchor (default centre of a 1920×1080 frame). */
19
+ x?: number;
20
+ y?: number;
21
+ fontSize?: number;
22
+ fontWeight?: FontWeight;
23
+ fill?: string;
24
+ letterSpacing?: number;
25
+ /** Entrance preset (default "cascade"). */
26
+ entrance?: TextInName;
27
+ /** Optional exit preset — when set, the title plays in, holds, then exits. */
28
+ exit?: TextOutName;
29
+ /** Duration multiplier (>1 faster). */
30
+ speed?: number;
31
+ /** Deterministic per-glyph variation. */
32
+ seed?: number;
33
+ /** Seconds held before the exit (only used with `exit`). Default 2. */
34
+ hold?: number;
35
+ }
36
+ export interface TitleResult {
37
+ nodes: NodeIR[];
38
+ timeline: TimelineIR;
39
+ /** The laid-out text block — add `textLoop` behaviors or extra tweens off this. */
40
+ block: TextBlock;
41
+ }
42
+ /** A kinetic headline. Labels: `${id}-in` (entrance) and `${id}-out` (exit). */
43
+ export declare function title(opts: TitleOpts): TitleResult;
44
+ export interface LowerThirdOpts {
45
+ /** Main line (e.g. a name). */
46
+ name: string;
47
+ /** Sub line (e.g. a role). Omit for a single-line strap. */
48
+ role?: string;
49
+ /** Id PREFIX → `${id}` group + `${id}-bar`/`${id}-name`/`${id}-role` (default "lt"). */
50
+ id?: string;
51
+ /** Group anchor (default a bottom-left title-safe position). */
52
+ x?: number;
53
+ y?: number;
54
+ /** Accent bar colour (default "#FF4D00"). */
55
+ accent?: string;
56
+ /** Name colour (default "#FFFFFF"). */
57
+ fill?: string;
58
+ /** Role colour (default "#C9C9C9"). */
59
+ subFill?: string;
60
+ /** Name font size (default 48); the role is ~0.58× of it. */
61
+ fontSize?: number;
62
+ /** Seconds the strap holds before it exits. Default 3. */
63
+ hold?: number;
64
+ }
65
+ export interface LowerThirdResult {
66
+ nodes: NodeIR[];
67
+ timeline: TimelineIR;
68
+ }
69
+ /** A name/role strap with an accent bar that grows in, text sliding + fading.
70
+ * Labels: `${id}-in` (entrance) and `${id}-out` (exit). */
71
+ export declare function lowerThird(opts: LowerThirdOpts): LowerThirdResult;