@dojo-video-engine/layout 0.0.0-stage → 1.1.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.
- package/LICENSE +21 -0
- package/README.md +109 -2
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +48 -0
- package/dist/index.js.map +1 -0
- package/dist/schema.d.ts +2109 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +371 -0
- package/dist/schema.js.map +1 -0
- package/dist/solver.d.ts +6 -0
- package/dist/solver.d.ts.map +1 -0
- package/dist/solver.js +1736 -0
- package/dist/solver.js.map +1 -0
- package/dist/text.d.ts +136 -0
- package/dist/text.d.ts.map +1 -0
- package/dist/text.js +1359 -0
- package/dist/text.js.map +1 -0
- package/dist/types.d.ts +126 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +39 -0
- package/dist/types.js.map +1 -0
- package/package.json +54 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Dojo Video Engine contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,110 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @dojo-video-engine/layout
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`@dojo-video-engine/layout` is Dojo Video Engine's bounded semantic authoring layer for
|
|
4
|
+
stacks, wrapping rows/columns, grids, overlays, intrinsic sizing, safe areas,
|
|
5
|
+
and small sibling-relative constraints. It compiles a flat plan over existing
|
|
6
|
+
child IDs into ordinary numeric Scene v1 geometry.
|
|
7
|
+
|
|
8
|
+
It is not a second render format. Plans are transient authoring input; the
|
|
9
|
+
compiler returns a valid Scene v1 and the renderer, player, export worker, and
|
|
10
|
+
stored project continue to consume only that Scene.
|
|
11
|
+
|
|
12
|
+
The compiled Scene is a target-size-specific render projection, not responsive
|
|
13
|
+
authoring source. An editor that needs to reflow later must retain the original
|
|
14
|
+
source Scene plus its LayoutPlan(s) and recompile those for the new target.
|
|
15
|
+
Never keep only the compiled projection as the sole editable source: its
|
|
16
|
+
semantic `hug`/`fill`/track/constraint intent has deliberately compiled away.
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import { compileLayout, item, row } from "@dojo-video-engine/layout";
|
|
20
|
+
|
|
21
|
+
const plan = row({
|
|
22
|
+
items: [
|
|
23
|
+
item("portrait", { width: "fill", aspectRatio: 1 }),
|
|
24
|
+
item("copy", { width: "fill" }),
|
|
25
|
+
],
|
|
26
|
+
gap: "4%",
|
|
27
|
+
padding: { x: "6%", y: "5%" },
|
|
28
|
+
align: "center",
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const result = compileLayout(scene, plan, {
|
|
32
|
+
textMetrics,
|
|
33
|
+
mediaMetrics,
|
|
34
|
+
missingMediaMetrics: { mode: "error" },
|
|
35
|
+
fontFallbackPolicy: "allow-system", // deterministic projects use a font asset
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Contract
|
|
40
|
+
|
|
41
|
+
The public tool shape is deliberately flat and non-recursive:
|
|
42
|
+
|
|
43
|
+
- `containerId` is `$root` or one existing Scene node;
|
|
44
|
+
- every `items[].id` names one direct visual child;
|
|
45
|
+
- item order controls flow and grid auto-placement without reordering Scene
|
|
46
|
+
paint order;
|
|
47
|
+
- `layout.kind` is `stack`, `grid`, or `overlay`;
|
|
48
|
+
- `row()` and `column()` are typed sugar for `stack` axes;
|
|
49
|
+
- sizes are fixed pixels, percentages, `hug`, or `fill`;
|
|
50
|
+
- grow/shrink, min/max, aspect ratio, margins, gaps, wrapping, distribution,
|
|
51
|
+
grid spans, overlay anchors, and bounded sibling constraints are explicit;
|
|
52
|
+
- safe-area and padding insets are resolved against the target container;
|
|
53
|
+
- output children have numeric `position`, `left`, `top`, `width`, and
|
|
54
|
+
`height` and no stale Scene-v1 geometry fields.
|
|
55
|
+
|
|
56
|
+
`layoutPlanSchema` and `validateLayoutPlan()` own the complete runtime contract.
|
|
57
|
+
`layoutPlanJsonSchema()` exposes its generated draft-07 structural shape and
|
|
58
|
+
adds kind-specific conditions, so tool validators reject fields a layout kind
|
|
59
|
+
cannot consume. Draft-07 cannot express uniqueness by an object's `id` value;
|
|
60
|
+
every tool host must still call `validateLayoutPlan()` before compilation.
|
|
61
|
+
`tryCompileLayout()` returns portable structured failures; `compileLayout()`
|
|
62
|
+
throws `LayoutCompileError`.
|
|
63
|
+
|
|
64
|
+
## Intrinsic metrics
|
|
65
|
+
|
|
66
|
+
The compiler uses core's prepared, synchronous `TextMetricsProvider` and
|
|
67
|
+
`MediaMetricsProvider`. Every measurement reports field-level `exact`,
|
|
68
|
+
`declared`, or `estimated` provenance. Media with missing intrinsic dimensions
|
|
69
|
+
never receives a hidden default: choose `mode: "error"` or provide explicit
|
|
70
|
+
type-specific fallback sizes.
|
|
71
|
+
|
|
72
|
+
Text planning defaults to `fontFallbackPolicy: "require-prepared"`. Family
|
|
73
|
+
lists are parsed in author order and the first family matching a declared font
|
|
74
|
+
asset is compiled to that exact asset id; the id itself must be representable
|
|
75
|
+
as one unambiguous Scene font family (spaces are safe, comma/quote escapes are
|
|
76
|
+
not). A prepared text-metrics provider is also required. `"allow-system"` is an
|
|
77
|
+
explicit portability escape hatch and always emits estimated font evidence
|
|
78
|
+
plus a warning.
|
|
79
|
+
|
|
80
|
+
Layout v2 text resolves an omitted direction through its bundled deterministic
|
|
81
|
+
first-strong scan; explicit `ltr`/`rtl` wins and host-dependent `inherit` is
|
|
82
|
+
rejected. Rich runs are rejected for intrinsic fitting by default; the
|
|
83
|
+
legacy-unsafe opt-in is intentionally visible. Fixed boxes can still carry
|
|
84
|
+
legacy rich text because no v2 shaping decision is made.
|
|
85
|
+
Successful item measurements retain the detached text plan—source cluster
|
|
86
|
+
ranges, planned lines/ellipsis, fit status, direction, and provenance—so an
|
|
87
|
+
editor or agent can explain the compiled Scene-v1 text.
|
|
88
|
+
|
|
89
|
+
The bundled cluster segmenter covers combining marks, emoji modifiers/ZWJ,
|
|
90
|
+
regional-indicator flags, and CRLF without depending on host Unicode data. It
|
|
91
|
+
is deliberately not a complete UAX #29 implementation for modern Indic
|
|
92
|
+
conjunct chains without explicit ZWJ or decomposed Hangul Jamo; prefer
|
|
93
|
+
precomposed/shaped input for those cases.
|
|
94
|
+
|
|
95
|
+
## Determinism and limits
|
|
96
|
+
|
|
97
|
+
Grid auto-placement is stable and non-dense; declared cells reserve their spans
|
|
98
|
+
before auto placement. Implicit row tracks fill the bounded grid, while column
|
|
99
|
+
auto-flow requires explicit rows so guard budgets never affect geometry. Grid
|
|
100
|
+
stretch applies only to `fill` or omitted/auto item sizes, never explicit fixed
|
|
101
|
+
sizes. Sibling constraints form a
|
|
102
|
+
bounded dependency DAG; unknown targets, cycles, multiple writers, collisions,
|
|
103
|
+
and out-of-bounds constrained results are errors. Plans, tracks, constraints,
|
|
104
|
+
text, solver steps, and coordinates all have host-tightenable budgets.
|
|
105
|
+
|
|
106
|
+
Semantic layout is a target-size snapshot. Recompile the same source Scene and
|
|
107
|
+
plan for portrait, square, or landscape output. Keep that source/plan pair for
|
|
108
|
+
future edits; the projection alone cannot recover semantic intent. Animating compiler-owned
|
|
109
|
+
geometry is rejected: retaining and reevaluating semantic layout per frame
|
|
110
|
+
would require a future Scene version and is outside this Scene v1 compiler.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export * from "./schema.js";
|
|
2
|
+
export * from "./types.js";
|
|
3
|
+
export * from "./text.js";
|
|
4
|
+
export { compileLayout, tryCompileLayout } from "./solver.js";
|
|
5
|
+
import { type GridLayout, type LayoutItem, type LayoutPlan, type OverlayLayout, type StackLayout } from "./schema.js";
|
|
6
|
+
export type LayoutItemOptions = Omit<LayoutItem, "id">;
|
|
7
|
+
/** Detached ergonomic item descriptor for TypeScript authoring. */
|
|
8
|
+
export declare function item(id: string, options?: LayoutItemOptions): LayoutItem;
|
|
9
|
+
type StackPlanOptions = Omit<StackLayout, "kind" | "axis"> & {
|
|
10
|
+
containerId?: string;
|
|
11
|
+
items: LayoutItem[];
|
|
12
|
+
};
|
|
13
|
+
/** Canonical one-dimensional layout constructor. */
|
|
14
|
+
export declare function stack(axis: "row" | "column", options: StackPlanOptions): LayoutPlan;
|
|
15
|
+
export declare function row(options: StackPlanOptions): LayoutPlan;
|
|
16
|
+
export declare function column(options: StackPlanOptions): LayoutPlan;
|
|
17
|
+
type GridPlanOptions = Omit<GridLayout, "kind"> & {
|
|
18
|
+
containerId?: string;
|
|
19
|
+
items: LayoutItem[];
|
|
20
|
+
};
|
|
21
|
+
export declare function grid(options: GridPlanOptions): LayoutPlan;
|
|
22
|
+
type OverlayPlanOptions = Omit<OverlayLayout, "kind"> & {
|
|
23
|
+
containerId?: string;
|
|
24
|
+
items: LayoutItem[];
|
|
25
|
+
};
|
|
26
|
+
export declare function overlay(options: OverlayPlanOptions): LayoutPlan;
|
|
27
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE9D,OAAO,EAIL,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,WAAW,EACjB,MAAM,aAAa,CAAC;AAErB,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;AAEvD,mEAAmE;AACnE,wBAAgB,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,UAAU,CAE5E;AAED,KAAK,gBAAgB,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB,CAAC;AAEF,oDAAoD;AACpD,wBAAgB,KAAK,CACnB,IAAI,EAAE,KAAK,GAAG,QAAQ,EACtB,OAAO,EAAE,gBAAgB,GACxB,UAAU,CAMZ;AAED,wBAAgB,GAAG,CAAC,OAAO,EAAE,gBAAgB,GAAG,UAAU,CAEzD;AAED,wBAAgB,MAAM,CAAC,OAAO,EAAE,gBAAgB,GAAG,UAAU,CAE5D;AAED,KAAK,eAAe,GAAG,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,GAAG;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB,CAAC;AAEF,wBAAgB,IAAI,CAAC,OAAO,EAAE,eAAe,GAAG,UAAU,CAKzD;AAED,KAAK,kBAAkB,GAAG,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,GAAG;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB,CAAC;AAEF,wBAAgB,OAAO,CAAC,OAAO,EAAE,kBAAkB,GAAG,UAAU,CAK/D"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export * from "./schema.js";
|
|
2
|
+
export * from "./types.js";
|
|
3
|
+
export * from "./text.js";
|
|
4
|
+
export { compileLayout, tryCompileLayout } from "./solver.js";
|
|
5
|
+
import { LAYOUT_CONTRACT_VERSION, LAYOUT_ROOT, layoutPlanSchema, } from "./schema.js";
|
|
6
|
+
/** Detached ergonomic item descriptor for TypeScript authoring. */
|
|
7
|
+
export function item(id, options = {}) {
|
|
8
|
+
return structuredClone({ id, ...options });
|
|
9
|
+
}
|
|
10
|
+
/** Canonical one-dimensional layout constructor. */
|
|
11
|
+
export function stack(axis, options) {
|
|
12
|
+
return makePlan(options.containerId, options.items, {
|
|
13
|
+
...withoutPlanFields(options),
|
|
14
|
+
kind: "stack",
|
|
15
|
+
axis,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
export function row(options) {
|
|
19
|
+
return stack("row", options);
|
|
20
|
+
}
|
|
21
|
+
export function column(options) {
|
|
22
|
+
return stack("column", options);
|
|
23
|
+
}
|
|
24
|
+
export function grid(options) {
|
|
25
|
+
return makePlan(options.containerId, options.items, {
|
|
26
|
+
...withoutPlanFields(options),
|
|
27
|
+
kind: "grid",
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
export function overlay(options) {
|
|
31
|
+
return makePlan(options.containerId, options.items, {
|
|
32
|
+
...withoutPlanFields(options),
|
|
33
|
+
kind: "overlay",
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function makePlan(containerId, items, layout) {
|
|
37
|
+
return layoutPlanSchema.parse({
|
|
38
|
+
layoutVersion: LAYOUT_CONTRACT_VERSION,
|
|
39
|
+
containerId: containerId ?? LAYOUT_ROOT,
|
|
40
|
+
layout,
|
|
41
|
+
items,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
function withoutPlanFields(value) {
|
|
45
|
+
const { containerId: _containerId, items: _items, ...rest } = value;
|
|
46
|
+
return rest;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE9D,OAAO,EACL,uBAAuB,EACvB,WAAW,EACX,gBAAgB,GAMjB,MAAM,aAAa,CAAC;AAIrB,mEAAmE;AACnE,MAAM,UAAU,IAAI,CAAC,EAAU,EAAE,UAA6B,EAAE;IAC9D,OAAO,eAAe,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;AAC7C,CAAC;AAOD,oDAAoD;AACpD,MAAM,UAAU,KAAK,CACnB,IAAsB,EACtB,OAAyB;IAEzB,OAAO,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,KAAK,EAAE;QAClD,GAAG,iBAAiB,CAAC,OAAO,CAAC;QAC7B,IAAI,EAAE,OAAO;QACb,IAAI;KACL,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,OAAyB;IAC3C,OAAO,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,OAAyB;IAC9C,OAAO,KAAK,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AAClC,CAAC;AAOD,MAAM,UAAU,IAAI,CAAC,OAAwB;IAC3C,OAAO,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,KAAK,EAAE;QAClD,GAAG,iBAAiB,CAAC,OAAO,CAAC;QAC7B,IAAI,EAAE,MAAM;KACb,CAAC,CAAC;AACL,CAAC;AAOD,MAAM,UAAU,OAAO,CAAC,OAA2B;IACjD,OAAO,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,KAAK,EAAE;QAClD,GAAG,iBAAiB,CAAC,OAAO,CAAC;QAC7B,IAAI,EAAE,SAAS;KAChB,CAAC,CAAC;AACL,CAAC;AAED,SAAS,QAAQ,CACf,WAA+B,EAC/B,KAAmB,EACnB,MAA4B;IAE5B,OAAO,gBAAgB,CAAC,KAAK,CAAC;QAC5B,aAAa,EAAE,uBAAuB;QACtC,WAAW,EAAE,WAAW,IAAI,WAAW;QACvC,MAAM;QACN,KAAK;KACN,CAAC,CAAC;AACL,CAAC;AAED,SAAS,iBAAiB,CAExB,KAAQ;IACR,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,CAAC;IACpE,OAAO,IAAI,CAAC;AACd,CAAC"}
|