reframe-video 0.6.25 → 0.6.26
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/dist/index.js +9 -0
- package/dist/types/camera.d.ts +27 -0
- package/dist/types/index.d.ts +1 -1
- package/guides/edsl-guide.md +16 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1208,6 +1208,14 @@ function cameraMatrix(cam, size) {
|
|
|
1208
1208
|
const d = Math.cos(r) * zoom;
|
|
1209
1209
|
return [a, b, c, d, W / 2 - a * x - c * y, H / 2 - b * x - d * y];
|
|
1210
1210
|
}
|
|
1211
|
+
function cameraFit(box, opts = {}) {
|
|
1212
|
+
const W = opts.size?.width ?? 1920;
|
|
1213
|
+
const H = opts.size?.height ?? 1080;
|
|
1214
|
+
const m = opts.margin ?? 80;
|
|
1215
|
+
const fit = Math.min(W / (box.width + 2 * m), H / (box.height + 2 * m));
|
|
1216
|
+
const zoom = Math.min(fit, opts.maxZoom ?? 2.4);
|
|
1217
|
+
return { x: box.x + box.width / 2, y: box.y + box.height / 2, zoom };
|
|
1218
|
+
}
|
|
1211
1219
|
function cameraTo(props, opts = {}) {
|
|
1212
1220
|
return tween(CAMERA_ID, props, opts);
|
|
1213
1221
|
}
|
|
@@ -3602,6 +3610,7 @@ export {
|
|
|
3602
3610
|
SFX_DURATION,
|
|
3603
3611
|
SceneValidationError,
|
|
3604
3612
|
beat,
|
|
3613
|
+
cameraFit,
|
|
3605
3614
|
cameraMatrix,
|
|
3606
3615
|
cameraTo,
|
|
3607
3616
|
characterPreset,
|
package/dist/types/camera.d.ts
CHANGED
|
@@ -24,6 +24,33 @@ export declare const CAMERA_PROPS: readonly ["x", "y", "zoom", "rotation", "pers
|
|
|
24
24
|
* collapse to the identity.
|
|
25
25
|
*/
|
|
26
26
|
export declare function cameraMatrix(cam: CameraIR, size: Size): Mat2D;
|
|
27
|
+
/**
|
|
28
|
+
* Frame a scene-space bounding box in the viewport — returns `{ x, y, zoom }` to
|
|
29
|
+
* spread into `cameraTo`, GUARANTEED not to clip the box. The visible scene rect
|
|
30
|
+
* is `W/zoom × H/zoom` centred on `(x, y)`; fitting `box` (+ `margin` padding on
|
|
31
|
+
* the tight axis) means `zoom = min(W/(box.w+2m), H/(box.h+2m))`, capped by
|
|
32
|
+
* `maxZoom` so a tiny target doesn't zoom absurdly close.
|
|
33
|
+
*
|
|
34
|
+
* cameraTo(cameraFit({ x: 200, y: 760, width: 740, height: 360 }, { margin: 90 }),
|
|
35
|
+
* { duration: 1, ease: "easeInOutCubic" })
|
|
36
|
+
*
|
|
37
|
+
* `box` is a top-left rect in scene coords (a centre-anchored panel at (px,py) of
|
|
38
|
+
* size (pw,ph) is `{ x: px-pw/2, y: py-ph/2, width: pw, height: ph }`).
|
|
39
|
+
*/
|
|
40
|
+
export declare function cameraFit(box: {
|
|
41
|
+
x: number;
|
|
42
|
+
y: number;
|
|
43
|
+
width: number;
|
|
44
|
+
height: number;
|
|
45
|
+
}, opts?: {
|
|
46
|
+
size?: Size;
|
|
47
|
+
margin?: number;
|
|
48
|
+
maxZoom?: number;
|
|
49
|
+
}): {
|
|
50
|
+
x: number;
|
|
51
|
+
y: number;
|
|
52
|
+
zoom: number;
|
|
53
|
+
};
|
|
27
54
|
/** Keyframe the camera: a `tween` on the reserved "camera" target. */
|
|
28
55
|
export declare function cameraTo(props: CameraIR, opts?: {
|
|
29
56
|
duration?: number;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { compileComposition, type CompiledComposition, type ScenePlacement, } fr
|
|
|
5
5
|
export { composeScene, formatComposeReport, type OverlayDoc, type ComposeReport, } from "./compose.js";
|
|
6
6
|
export { compileScene, type CompiledScene, type PropertySegment, type LabelSpan, type MotionDriver } from "./compile.js";
|
|
7
7
|
export { pathPoint, pathTangentAngle, type Pt } from "./path.js";
|
|
8
|
-
export { cameraTo, cameraMatrix, CAMERA_ID, CAMERA_PROPS } from "./camera.js";
|
|
8
|
+
export { cameraTo, cameraFit, cameraMatrix, CAMERA_ID, CAMERA_PROPS } from "./camera.js";
|
|
9
9
|
export { linearGradient, radialGradient, conicGradient, isGradient } from "./gradient.js";
|
|
10
10
|
export { glow, dropShadow } from "./effects.js";
|
|
11
11
|
export { row, column, grid, type RowOpts, type GridOpts } from "./layout.js";
|
package/guides/edsl-guide.md
CHANGED
|
@@ -90,6 +90,14 @@ row(3, { center: 960, gap: 60, itemWidth: 440 }).map((x, i) =>
|
|
|
90
90
|
|
|
91
91
|
`column` is `row` for the y axis.
|
|
92
92
|
|
|
93
|
+
**Charts/widgets in a panel — derive geometry from the box, and `clip` it.** Don't
|
|
94
|
+
hand-pick a pixels-per-unit scale (bars routinely overflow the panel that way).
|
|
95
|
+
Define the panel rect ONCE, then size from it — bar height `(v/max) · innerH`, x via
|
|
96
|
+
`row(...)` across the panel width — so a tall value can't exceed the box. As a safety
|
|
97
|
+
net, wrap the chart in a clipped group so nothing can ever punch out the panel:
|
|
98
|
+
`group({ clip: { kind: "rect", x, y, width, height, radius } }, [ ...bars ])`. See
|
|
99
|
+
`examples/scenes/annual-report.ts` (and `cameraFit` above to frame the panel).
|
|
100
|
+
|
|
93
101
|
## States: declare looks, not motion
|
|
94
102
|
|
|
95
103
|
Base props on nodes describe the **finished design**. A state is a sparse
|
|
@@ -178,6 +186,14 @@ scene({
|
|
|
178
186
|
`tween` on the `"camera"` target, so `motionPath("camera", pts, …)` (pan along
|
|
179
187
|
a curve) and `oscillate/wiggle("camera", "rotation"|"x"|…)` (handheld drift)
|
|
180
188
|
also work.
|
|
189
|
+
- **Frame a region without clipping — use `cameraFit`, not a guessed `zoom`.** The
|
|
190
|
+
visible scene rect is `W/zoom × H/zoom` centred on `(camera.x, camera.y)`, so a
|
|
191
|
+
hand-picked `zoom` that's too big crops the target. `cameraFit(box, { margin })`
|
|
192
|
+
returns `{ x, y, zoom }` that frames a scene-space bbox (top-left `{x,y,width,
|
|
193
|
+
height}`) with padding, guaranteed in-bounds: `cameraTo(cameraFit({ x, y, width,
|
|
194
|
+
height }, { margin: 80 }), { duration: 1, ease: "easeInOutCubic" })`. A centre-
|
|
195
|
+
anchored panel at `(px,py)` size `(pw,ph)` is `{ x: px-pw/2, y: py-ph/2, width:
|
|
196
|
+
pw, height: ph }`. `maxZoom` (default 2.4) caps absurd close-ups.
|
|
181
197
|
- **Pin HUD/titles to the screen** with `fixed: true` on a TOP-LEVEL node — the
|
|
182
198
|
camera won't move it (for overlays, watermarks, captions).
|
|
183
199
|
- Defaults are the identity, so a scene without a camera is unchanged. Don't name
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reframe-video",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.26",
|
|
4
4
|
"description": "Declarative motion graphics that AI can write and humans can tweak — human edits survive AI regeneration. Deterministic mp4 renders from a plain-data scene format.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"motion-graphics",
|