machinalayout 0.1.0 → 0.3.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/README.md +295 -49
- package/dist/chunk-2ZQ2RFFI.js +400 -0
- package/dist/chunk-33CKBEJH.js +186 -0
- package/dist/chunk-BJOQRPPX.js +382 -0
- package/dist/chunk-KYWOCAHK.js +205 -0
- package/dist/chunk-RJYRJ3LD.js +0 -0
- package/dist/chunk-SVWYWI7I.js +59 -0
- package/dist/chunk-VREK57S3.js +13 -0
- package/dist/chunk-ZVDE7PX4.js +222 -0
- package/dist/debugOverlay-pJpj0n5H.d.ts +125 -0
- package/dist/deus/index.d.ts +14 -0
- package/dist/deus/index.js +26 -0
- package/dist/dispatch/index.d.ts +49 -0
- package/dist/dispatch/index.js +217 -0
- package/dist/handoff/index.d.ts +44 -0
- package/dist/handoff/index.js +83 -0
- package/dist/index.d.ts +54 -236
- package/dist/index.js +753 -583
- package/dist/inspect/index.d.ts +8 -0
- package/dist/inspect/index.js +97 -0
- package/dist/react/index.d.ts +41 -0
- package/dist/react/index.js +9 -0
- package/dist/react-native/index.d.ts +30 -0
- package/dist/react-native/index.js +84 -0
- package/dist/screenCatalog-ZjonGiOi.d.ts +46 -0
- package/dist/text/index.d.ts +10 -0
- package/dist/text/index.js +9 -0
- package/dist/text/react/index.d.ts +14 -0
- package/dist/text/react/index.js +7 -0
- package/dist/text/react-native/index.d.ts +16 -0
- package/dist/text/react-native/index.js +155 -0
- package/dist/text/vue/index.d.ts +113 -0
- package/dist/text/vue/index.js +202 -0
- package/dist/types-B90jb3RW.d.ts +184 -0
- package/dist/types-C4poVJpR.d.ts +74 -0
- package/dist/types-DLYAhNXw.d.ts +32 -0
- package/dist/vue/index.d.ts +173 -0
- package/dist/vue/index.js +112 -0
- package/docs/adapter-packaging-a0-plan.md +352 -0
- package/docs/adapters.md +19 -0
- package/docs/api-coherence-m8-audit.md +397 -0
- package/docs/deusmachina.md +108 -0
- package/docs/error-codes.md +95 -0
- package/docs/grid-arrange-m5a-contract.md +480 -0
- package/docs/grid-arrange.md +51 -0
- package/docs/inspection-and-handoff.md +126 -0
- package/docs/layout-interpolation.md +52 -0
- package/docs/machina-dispatch-d0-contract.md +496 -0
- package/docs/machina-dispatch.md +143 -0
- package/docs/named-layers.md +40 -0
- package/docs/react-adapter.md +63 -58
- package/docs/react-native-adapter.md +56 -0
- package/docs/react-native-text-renderer.md +50 -0
- package/docs/reference-alignment-m7a-contract.md +384 -0
- package/docs/reference-alignment.md +44 -0
- package/docs/responsive-variants.md +54 -0
- package/docs/screen-catalog-and-viewports.md +124 -0
- package/docs/stack-geometry-helpers.md +115 -0
- package/docs/vue-adapter.md +55 -0
- package/docs/vue-text-renderer.md +55 -0
- package/package.json +127 -60
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
# API Coherence and Polish Audit (M8)
|
|
2
|
+
|
|
3
|
+
Date: 2026-05-11
|
|
4
|
+
Repository: `MachinaLayout.JS`
|
|
5
|
+
|
|
6
|
+
## 1) Executive summary
|
|
7
|
+
|
|
8
|
+
This pass audited exports, type surfaces, docs, samples, and package outputs for coherence after M5–M7 expansion.
|
|
9
|
+
|
|
10
|
+
High-level result:
|
|
11
|
+
|
|
12
|
+
- Core runtime API is coherent and functionally aligned with current features (`RootFrame`, `GridArrange`, `GuideFrame`, variants, layers, interpolation).
|
|
13
|
+
- React and MachinaText adapter boundaries are mostly clear and remain non-authoritative for layout geometry.
|
|
14
|
+
- Build/test/sample/package verification all pass.
|
|
15
|
+
- Main coherence risks are documentation drift in `README.md` and minor terminology consistency gaps (not runtime/API defects).
|
|
16
|
+
|
|
17
|
+
No runtime behavior or public API changes were made in this audit pass.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 2) Public API inventory
|
|
22
|
+
|
|
23
|
+
Inventory source: `src/index.ts` and nested barrels.
|
|
24
|
+
|
|
25
|
+
### 2.1 Core types
|
|
26
|
+
|
|
27
|
+
Exported via `export * from "./types"`:
|
|
28
|
+
|
|
29
|
+
- Identity/base: `NodeId`, `LayerName`, `Rect`
|
|
30
|
+
- Frame specs: `RootFrame`, `AbsoluteFrame`, `AnchorFrame`, `GuideFrame`, `FixedFrame`, `FillFrame`, `CellFrame`, `FrameSpec`
|
|
31
|
+
- Length/offset/reference: `UiLength`, `OffsetSpec`, `RectEdge`, `EdgeRef`, `GuideLength`
|
|
32
|
+
- Arrange specs: `StackAxis`, `StackJustify`, `StackAlign`, `EdgeInsets`, `StackArrange`, `GridTrack`, `GridArrange`, `ArrangeSpec`
|
|
33
|
+
- Authoring rows/variants: `LayoutVariantCondition`, `LayoutRowVariant`, `LayoutRow`, `LayoutNode`, `LayoutDocument`
|
|
34
|
+
- Resolved output: `ResolvedLayoutNode`, `ResolvedLayoutDocument`, `ResolvedLayoutTree`
|
|
35
|
+
|
|
36
|
+
Exported from errors module:
|
|
37
|
+
|
|
38
|
+
- `MachinaLayoutErrorCode`
|
|
39
|
+
- `MachinaLayoutError`
|
|
40
|
+
|
|
41
|
+
### 2.2 Core functions
|
|
42
|
+
|
|
43
|
+
Exported from root barrel:
|
|
44
|
+
|
|
45
|
+
- Compile/select:
|
|
46
|
+
- `compileLayoutRows`
|
|
47
|
+
- `selectLayoutRowsForRoot`
|
|
48
|
+
- Resolve:
|
|
49
|
+
- `resolveFrame`
|
|
50
|
+
- `resolveLayoutDocument`
|
|
51
|
+
- `resolveLayoutRows`
|
|
52
|
+
- Helpers/utilities:
|
|
53
|
+
- validation helpers (`assertFiniteNumber`, etc.) via `validation`
|
|
54
|
+
- padding helpers via `padding`
|
|
55
|
+
- length helpers (`resolveUiLength`) via `length`
|
|
56
|
+
- offset helpers (`applyOffset`) via `offset`
|
|
57
|
+
- tree conversion helpers (`toResolvedTree`, `flattenResolvedTree`)
|
|
58
|
+
- formatting helper (`formatRect`)
|
|
59
|
+
- Interpolation:
|
|
60
|
+
- `lerpNumber`
|
|
61
|
+
- `lerpRect`
|
|
62
|
+
- `lerpResolvedLayouts`
|
|
63
|
+
|
|
64
|
+
### 2.3 React adapter
|
|
65
|
+
|
|
66
|
+
Exported from `src/react/index.ts` and re-exported from root:
|
|
67
|
+
|
|
68
|
+
- Component: `MachinaReactView`
|
|
69
|
+
- Props types: `MachinaReactViewProps`, `MachinaSlotProps`
|
|
70
|
+
|
|
71
|
+
Observed adapter-facing concepts in type surface/tests/docs:
|
|
72
|
+
|
|
73
|
+
- layer policy + named layer ordering
|
|
74
|
+
- slot/view rendering key (`view ?? slot` semantics)
|
|
75
|
+
- adapter data channels (`viewData`, `nodeData`)
|
|
76
|
+
- containment/content-visibility knobs
|
|
77
|
+
|
|
78
|
+
### 2.4 MachinaText
|
|
79
|
+
|
|
80
|
+
Exported from `src/text/index.ts` and `src/text/react/index.ts`:
|
|
81
|
+
|
|
82
|
+
- Source/spec/domain types:
|
|
83
|
+
- `MachinaTextSource`, `MachinaTextSpec`, `MachinaTextDocument`
|
|
84
|
+
- policy enums/aliases (`MachinaTextVariant`, `MachinaTextWrap`, etc.)
|
|
85
|
+
- AST/content types:
|
|
86
|
+
- `MachinaTextBlock`, `MachinaInline`, `MachinaBulletItem`
|
|
87
|
+
- Diagnostics:
|
|
88
|
+
- `MachinaTextDiagnostic`, `MachinaTextDiagnosticCode`, `MachinaTextDiagnosticLevel`
|
|
89
|
+
- `ParseMachinaTextResult`
|
|
90
|
+
- Parser:
|
|
91
|
+
- `parseMachinaText`
|
|
92
|
+
- `parseMachinaTextInline`
|
|
93
|
+
- React renderer:
|
|
94
|
+
- `MachinaTextView`
|
|
95
|
+
- `MachinaTextViewProps`
|
|
96
|
+
|
|
97
|
+
### 2.5 Public API coherence findings
|
|
98
|
+
|
|
99
|
+
- No clearly accidental/internal export was found in root barrel; exports are broad but intentional for current tests/docs usage.
|
|
100
|
+
- No documented major API appears missing from exports.
|
|
101
|
+
- A few exports (`formatRect`, `flattenResolvedTree`) are minimally documented in top-level README (discoverability issue, not API bug).
|
|
102
|
+
- Documentation is less explicit than code about root barrel re-exporting adapters (`react`, `text`) and may benefit from a short API index section.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## 3) Concept taxonomy
|
|
107
|
+
|
|
108
|
+
Current taxonomy can be expressed cleanly as:
|
|
109
|
+
|
|
110
|
+
1. **Node identity + hierarchy**
|
|
111
|
+
- `id`: stable node key
|
|
112
|
+
- `parent`: coordinate owner relationship
|
|
113
|
+
- `order`: sibling sequence within parent
|
|
114
|
+
|
|
115
|
+
2. **Frame = node rectangle acquisition**
|
|
116
|
+
- `RootFrame`: root-only ownership from `rootRect`
|
|
117
|
+
- `AbsoluteFrame`: explicit parent-local rect
|
|
118
|
+
- `AnchorFrame`: edge/size constraints with `UiLength`
|
|
119
|
+
- `GuideFrame`: reference-assisted placement using resolved targets
|
|
120
|
+
- `FixedFrame`: stack-child explicit size
|
|
121
|
+
- `FillFrame`: stack-child weighted main-axis fill
|
|
122
|
+
- `CellFrame`: grid-child explicit track coordinates/spans
|
|
123
|
+
|
|
124
|
+
3. **Arrange = direct child placement**
|
|
125
|
+
- `StackArrange`: 1D ordered arithmetic placement
|
|
126
|
+
- `GridArrange`: 2D explicit track/cell placement
|
|
127
|
+
|
|
128
|
+
4. **Node metadata**
|
|
129
|
+
- semantic/view keys: `view`, `slot`
|
|
130
|
+
- diagnostics label: `debugLabel`
|
|
131
|
+
- paint ordering: `z` (bounded sibling-local), `layer` (named semantic layer)
|
|
132
|
+
- post-placement nudge: `offset`
|
|
133
|
+
|
|
134
|
+
5. **Authoring-time row features**
|
|
135
|
+
- `variants` on rows only, selected before compile/resolve
|
|
136
|
+
|
|
137
|
+
6. **Resolved output**
|
|
138
|
+
- flat: `ResolvedLayoutDocument`
|
|
139
|
+
- nested projection: `ResolvedLayoutTree`
|
|
140
|
+
|
|
141
|
+
7. **Renderer adapters**
|
|
142
|
+
- React adapter consumes resolved rectangles and paints wrappers in DOM
|
|
143
|
+
|
|
144
|
+
8. **Text subsystem**
|
|
145
|
+
- parser + diagnostics (MachinaText)
|
|
146
|
+
- React text renderer (`MachinaTextView`) inside already-owned rectangles
|
|
147
|
+
|
|
148
|
+
Taxonomy readability in current names is generally good; primary ambiguity is contextual validity of some frame kinds (`Fixed`/`Fill`/`Cell`/`Guide`) which relies on docs + errors rather than type-level separation.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## 4) Naming consistency audit
|
|
153
|
+
|
|
154
|
+
### 4.1 `Frame` vs `Arrange`
|
|
155
|
+
- Consistent and clear: frame answers “this node rect,” arrange answers “direct child placement.”
|
|
156
|
+
|
|
157
|
+
### 4.2 `FillFrame` vs `GridTrack { kind: "fill" }`
|
|
158
|
+
- Potential overload but acceptable: both represent weighted distribution semantics in different contexts.
|
|
159
|
+
- Recommend doc callout clarifying **node-level fill (stack child)** vs **track-level fill (grid template)**.
|
|
160
|
+
|
|
161
|
+
### 4.3 `CellFrame`
|
|
162
|
+
- Reads as grid-only and aligns with behavior/erroring (`CellFrameWithoutGrid` / `GridChildMustBeCell`).
|
|
163
|
+
|
|
164
|
+
### 4.4 `GuideFrame`
|
|
165
|
+
- Mostly clear from reference docs; name can be interpreted as “helper reference” and does communicate non-ownership placement.
|
|
166
|
+
- Recommend one explicit phrase in top README: “GuideFrame reads other nodes; it does not reparent or portal.”
|
|
167
|
+
|
|
168
|
+
### 4.5 `view` vs `slot`
|
|
169
|
+
- Code/docs consistently use `view ?? slot` semantics.
|
|
170
|
+
- `slot` remains valid and adapter-facing; not marked legacy.
|
|
171
|
+
- Some top-level README examples still use only `slot`, reducing emphasis on preferred `view` naming.
|
|
172
|
+
|
|
173
|
+
### 4.6 `layer` vs `z`
|
|
174
|
+
- Coherent: semantic grouping (`layer`) then local order (`z`).
|
|
175
|
+
|
|
176
|
+
### 4.7 `OffsetSpec` and `UiLength`
|
|
177
|
+
- Names are coherent and sufficiently neutral (not overly CSS-like).
|
|
178
|
+
|
|
179
|
+
### 4.8 `variants`
|
|
180
|
+
- Reasonable name; docs mention responsive variants phase separation.
|
|
181
|
+
|
|
182
|
+
### 4.9 `lerpResolvedLayouts`
|
|
183
|
+
- Name is explicit and consistent with accompanying `lerpNumber`/`lerpRect`.
|
|
184
|
+
|
|
185
|
+
### 4.10 `MachinaText*`
|
|
186
|
+
- Consistent prefixing across parser, AST types, diagnostics, and renderer.
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## 5) Type consistency audit
|
|
191
|
+
|
|
192
|
+
### 5.1 Context-restricted frames
|
|
193
|
+
|
|
194
|
+
Status:
|
|
195
|
+
- `FixedFrame` and `FillFrame` stack-only: enforced at runtime/compile and documented.
|
|
196
|
+
- `CellFrame` grid-only: enforced and documented.
|
|
197
|
+
- `GuideFrame` document-level resolver only: `resolveFrame` throws `GuideTargetUnresolved` with explicit guidance.
|
|
198
|
+
- `RootFrame` root-only: compile rejects non-root root frame.
|
|
199
|
+
|
|
200
|
+
Coverage:
|
|
201
|
+
- Restrictions are covered by tests (`resolveFrame`, `compileLayoutRows`, `gridArrange`, `guideFrame`).
|
|
202
|
+
|
|
203
|
+
### 5.2 Metadata preservation
|
|
204
|
+
|
|
205
|
+
Checked `LayoutRow`, `LayoutNode`, `ResolvedLayoutNode`, `ResolvedLayoutTree`:
|
|
206
|
+
- `view`, `slot`, `debugLabel`, `z`, `layer`, `offset` are present and threaded consistently where appropriate.
|
|
207
|
+
|
|
208
|
+
### 5.3 Authoring-only fields
|
|
209
|
+
|
|
210
|
+
- `variants` exists only on `LayoutRow` and is absent from compiled/resolved node types.
|
|
211
|
+
- This matches intended phase separation.
|
|
212
|
+
|
|
213
|
+
### 5.4 Adapter-only props
|
|
214
|
+
|
|
215
|
+
- `viewData`, `nodeData`, `layers`, containment controls are in React adapter props surface, not in core layout types.
|
|
216
|
+
|
|
217
|
+
### 5.5 Text type isolation
|
|
218
|
+
|
|
219
|
+
- Text parser/renderer types are scoped under `src/text/*` and do not pollute core layout model types.
|
|
220
|
+
|
|
221
|
+
Finding: type surface is coherent; no corrective change needed in M8.
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## 6) Error code audit
|
|
226
|
+
|
|
227
|
+
### 6.1 `MachinaLayoutErrorCode` inventory by domain
|
|
228
|
+
|
|
229
|
+
- **Compile/row structure**: `EmptyRows`, `MissingRoot`, `MultipleRoots`, `DuplicateId`, `InvalidId`, `UnknownParent`, `SelfParent`, `Cycle`, `UnreachableNode`, `RootFrameNotRoot`
|
|
230
|
+
- **Numeric/validation**: `NonFiniteNumber`, `NegativeSize`, `NegativeGap`, `NegativePadding`, `InvalidLengthUnit`, `InvalidZ`
|
|
231
|
+
- **Anchor/frame resolution**: `InvalidAnchorHorizontal`, `InvalidAnchorVertical`, `NegativeResolvedSize`, `RootFrameWithoutRoot`
|
|
232
|
+
- **Stack**: `FixedFrameWithoutArranger`, `FillFrameWithoutArranger`, `InvalidFillWeight`, `StackChildMustBeFixed`, `StackContentNegative`, `StackOverflow`
|
|
233
|
+
- **Grid**: `CellFrameWithoutGrid`, `GridChildMustBeCell`, `InvalidGridTrack`, `InvalidGridCell`, `GridContentNegative`, `GridOverflow`
|
|
234
|
+
- **Guide/reference**: `GuideTargetNotFound`, `GuideSelfReference`, `GuideReferenceCycle`, `GuideInvalidEdgeForAxis`, `GuideTooManyReferencesPerAxis`, `InvalidGuideFrame`, `GuideTargetUnresolved`
|
|
235
|
+
- **Variants**: `InvalidVariantCondition`
|
|
236
|
+
- **Interpolation**: `IncompatibleLayouts`
|
|
237
|
+
|
|
238
|
+
### 6.2 Specificity/misuse/dead code check
|
|
239
|
+
|
|
240
|
+
- Codes are sufficiently specific for API-facing debugging.
|
|
241
|
+
- No declared layout error codes found obviously dead/unreachable in this pass.
|
|
242
|
+
- One naming sharp edge: `StackChildMustBeFixed` now allows `FillFrame` too; message string says fixed-or-fill, but code name is legacy-biased and slightly misleading.
|
|
243
|
+
- Recommendation: keep code for compatibility, improve docs note mapping.
|
|
244
|
+
|
|
245
|
+
### 6.3 MachinaText diagnostics audit
|
|
246
|
+
|
|
247
|
+
Declared codes:
|
|
248
|
+
- `unsupported_syntax`
|
|
249
|
+
- `heading_forbidden`
|
|
250
|
+
- `max_list_depth_exceeded`
|
|
251
|
+
- `malformed_link`
|
|
252
|
+
- `unclosed_inline`
|
|
253
|
+
- `invalid_escape`
|
|
254
|
+
|
|
255
|
+
Emitted paths inspected in parser:
|
|
256
|
+
- all declared codes are emitted in concrete branches.
|
|
257
|
+
- no obvious dead diagnostic code found (including `invalid_escape`, previously risky area).
|
|
258
|
+
|
|
259
|
+
Docs coverage:
|
|
260
|
+
- `docs/machina-text-parser.md` currently emphasizes escape behavior; broader code taxonomy documentation is thin.
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## 7) Docs/examples consistency audit
|
|
265
|
+
|
|
266
|
+
Inspected: `README.md`, `docs/*.md`, sample READMEs.
|
|
267
|
+
|
|
268
|
+
### 7.1 Strong points
|
|
269
|
+
- Frame/arrange boundaries and restrictions documented in focused docs (`frames-and-stack`, `grid-arrange`, `reference-alignment`).
|
|
270
|
+
- Explicit boundary statements (“Machina places, CSS paints”) are present across docs.
|
|
271
|
+
- MachinaText ellipsis single-line policy documented.
|
|
272
|
+
|
|
273
|
+
### 7.2 Drift/inconsistency findings
|
|
274
|
+
|
|
275
|
+
1. **Top-level README still branded around “M0 scope” language** despite including later features; this can confuse maturity/state.
|
|
276
|
+
2. README docs index omits some key current docs from the main list (e.g., text docs are less discoverable in the principal section structure).
|
|
277
|
+
3. README quick examples rely mostly on `slot` terminology; current guidance prefers `view` with slot fallback.
|
|
278
|
+
4. README includes note “legacy root Absolute/Anchor remain accepted” (in deeper docs) which is okay for compatibility but should be cross-linked from root section for clarity.
|
|
279
|
+
|
|
280
|
+
No runtime-impacting docs contradiction found for:
|
|
281
|
+
- root via `RootFrame`
|
|
282
|
+
- stack-only fixed/fill
|
|
283
|
+
- grid-only cell
|
|
284
|
+
- guide reference semantics
|
|
285
|
+
- negative positional anchors allowed
|
|
286
|
+
- variants phase separation
|
|
287
|
+
- named layers non-portal semantics
|
|
288
|
+
- no intrinsic text sizing / no CSS geometry authority
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## 8) Sample usage audit
|
|
293
|
+
|
|
294
|
+
Inspected `samples/control-room` and `samples/music-player` plus builds.
|
|
295
|
+
|
|
296
|
+
Findings:
|
|
297
|
+
- Both samples build successfully.
|
|
298
|
+
- Control-room README reflects modern concepts (`view ?? slot`, `UiLength`, `offset`, stable views, text view usage).
|
|
299
|
+
- Music-player README local file dependency instructions are accurate.
|
|
300
|
+
- No obvious sample pattern teaching unstable inline view factories.
|
|
301
|
+
- No evidence samples depend on CSS layout for Machina node placement authority.
|
|
302
|
+
- `package.json` `files` excludes `samples/` from npm tarball already (good).
|
|
303
|
+
|
|
304
|
+
No required sample code updates for M8.
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## 9) Package export/build audit
|
|
309
|
+
|
|
310
|
+
### 9.1 Export map/build outputs
|
|
311
|
+
- `package.json` exports only `.` with `types` and `import` pointed to `dist/index.d.ts` and `dist/index.js`.
|
|
312
|
+
- Build emits matching files in `dist/`.
|
|
313
|
+
- Peer dependencies retain React/ReactDOM as peer deps (correct for adapter).
|
|
314
|
+
|
|
315
|
+
### 9.2 Tarball contents (`npm pack --dry-run`)
|
|
316
|
+
- Includes: `dist`, `README`, `LICENSE`, `docs`, `package.json`.
|
|
317
|
+
- Excludes: `src`, `test`, `samples` (expected and desirable).
|
|
318
|
+
|
|
319
|
+
### 9.3 Dist/API coherence
|
|
320
|
+
- Dist typings generated successfully.
|
|
321
|
+
- Public root import surface validated by existing public API tests and successful build/test pipeline.
|
|
322
|
+
|
|
323
|
+
No package/export corrections required in this pass.
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
## 10) Proposed one-page mental model
|
|
328
|
+
|
|
329
|
+
> MachinaLayout in one page
|
|
330
|
+
|
|
331
|
+
1. **Author layout as flat rows (`LayoutRow[]`)**.
|
|
332
|
+
Each row is a node with `id`, optional `parent`, and optional `order`.
|
|
333
|
+
|
|
334
|
+
2. **Parent means coordinate ownership**.
|
|
335
|
+
A node’s rectangle is resolved in its parent’s coordinate space.
|
|
336
|
+
|
|
337
|
+
3. **Frame decides this node’s rectangle**.
|
|
338
|
+
Use one frame kind per node (`root`, `absolute`, `anchor`, `guide`, `fixed`, `fill`, `cell`) according to context.
|
|
339
|
+
|
|
340
|
+
4. **Arrange decides direct child placement**.
|
|
341
|
+
Parent `arrange` (`stack` or `grid`) places only immediate children.
|
|
342
|
+
|
|
343
|
+
5. **Metadata shapes rendering behavior, not geometry solving**.
|
|
344
|
+
`view/slot` map nodes to renderer views; `layer` + `z` control paint order; `offset` nudges after placement.
|
|
345
|
+
|
|
346
|
+
6. **Variants are authoring-time selection**.
|
|
347
|
+
`variants` are chosen against root size before compile/resolve.
|
|
348
|
+
|
|
349
|
+
7. **Resolver outputs deterministic rectangles**.
|
|
350
|
+
Core output is a resolved document/tree of numeric rects.
|
|
351
|
+
|
|
352
|
+
8. **Adapters render rectangles**.
|
|
353
|
+
React adapter paints absolute wrappers and injects node/view data.
|
|
354
|
+
|
|
355
|
+
9. **Text renders inside owned rectangles**.
|
|
356
|
+
MachinaText parses/paints content inside a rectangle; it does not drive outer layout sizing.
|
|
357
|
+
|
|
358
|
+
10. **CSS paints; Machina places**.
|
|
359
|
+
CSS can style internals, but Machina remains geometry authority for node placement.
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
## 11) Risks / confusing areas
|
|
364
|
+
|
|
365
|
+
1. **README lifecycle terminology drift** (“M0” framing with later feature reality).
|
|
366
|
+
2. **Error-code naming legacy**: `StackChildMustBeFixed` includes fill children now.
|
|
367
|
+
3. **Discoverability gap** for full API index and text docs from root README.
|
|
368
|
+
4. **Contextual frame validity is runtime-validated**, not type-encoded; this is intentional but requires clear docs examples.
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
## 12) Recommended M8 cleanup checklist
|
|
373
|
+
|
|
374
|
+
Concrete follow-up checklist based on findings:
|
|
375
|
+
|
|
376
|
+
- [ ] Refresh top-level README scope/lifecycle section to reflect current post-M7 capability set (remove or clearly contextualize old “M0 scope” framing).
|
|
377
|
+
- [ ] Add a compact “Public API index” in README (core / react / text) mapping names to docs.
|
|
378
|
+
- [ ] Prefer `view` in top README examples while retaining explicit `view ?? slot` compatibility note.
|
|
379
|
+
- [ ] Add short README callout: `GuideFrame` references resolved geometry and does not reparent/portal.
|
|
380
|
+
- [ ] Add error-code reference table in docs (code → when emitted), including note that `StackChildMustBeFixed` means fixed-or-fill for backward compatibility.
|
|
381
|
+
- [ ] Add one lightweight smoke test that imports from built `dist` in a temporary fixture (optional but useful for publish confidence).
|
|
382
|
+
|
|
383
|
+
No runtime/API changes required by this audit.
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
## 13) Exact verification commands run
|
|
388
|
+
|
|
389
|
+
From repository root unless noted:
|
|
390
|
+
|
|
391
|
+
1. `npm test`
|
|
392
|
+
2. `npm run build`
|
|
393
|
+
3. `(cd samples/control-room && npm run build)`
|
|
394
|
+
4. `(cd samples/music-player && npm run build)`
|
|
395
|
+
5. `npm pack --dry-run`
|
|
396
|
+
|
|
397
|
+
All commands completed successfully in this environment.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# DeusMachina
|
|
2
|
+
|
|
3
|
+
DeusMachina is MachinaLayout's tiny behavioral kernel. It is deliberately small: utility judgment, explicit row-first state machines, stack-style state paths, deterministic stepping, and trace output.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { defineDeusMachine, judgeUtility, stepDeusMachine } from "machinalayout/deus";
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Contract summary
|
|
10
|
+
|
|
11
|
+
DeusMachina combines three narrow pieces:
|
|
12
|
+
|
|
13
|
+
1. `judgeUtility(context, candidates, options)` for deterministic utility selection.
|
|
14
|
+
2. `defineDeusMachine(machine)` for validating row-first stack HFSM definitions.
|
|
15
|
+
3. `stepDeusMachine(machine, snapshot, event)` for one synchronous deterministic step with trace output.
|
|
16
|
+
|
|
17
|
+
State paths are non-empty arrays of non-empty strings. Segments are not trimmed; empty or whitespace-only segments are invalid. `formatDeusPath(["a", "b"])` formats paths as `a/b`. DeusMachina treats a path as its own ancestor for transition candidate collection.
|
|
18
|
+
|
|
19
|
+
## Row-first authoring
|
|
20
|
+
|
|
21
|
+
Machines are authored as arrays, not nested objects:
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
defineDeusMachine({
|
|
25
|
+
initial: ["debugOverlay", "collapsed"],
|
|
26
|
+
states: [{ path: ["debugOverlay", "collapsed"] }],
|
|
27
|
+
transitions: [{ key: "show", from: ["debugOverlay", "collapsed"], event: "showOverlay" }],
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Hierarchy comes from stack paths such as `debugOverlay/nonInteractiveOverlay`, not from nested authoring syntax.
|
|
32
|
+
|
|
33
|
+
## Mutable board convention
|
|
34
|
+
|
|
35
|
+
Snapshots keep the board by reference. `stepDeusMachine` returns a new snapshot object and a copied state path, but it does not clone the board. User actions may mutate the board intentionally. Machine definitions are treated as immutable and are copied where DeusMachina normalizes paths.
|
|
36
|
+
|
|
37
|
+
## Purity rules
|
|
38
|
+
|
|
39
|
+
`when`, `score`, and `reason` should be pure. They may read the board and event, but should not mutate them. `do`, `onEnter`, and `onExit` may mutate the board. DeusMachina does not sandbox user functions, so accidental mutation from guards, scores, or reasons is possible and is the caller's responsibility.
|
|
40
|
+
|
|
41
|
+
User errors are not swallowed. If a guard, score, reason, action, enter hook, or exit hook throws, the error propagates to the caller.
|
|
42
|
+
|
|
43
|
+
## Transition selection semantics
|
|
44
|
+
|
|
45
|
+
A step gathers candidate transitions from the exact current state path, then parent paths upward to root. Candidate grouping is leaf first, then parent, then grandparent. Within each `from` path, author transition order is preserved.
|
|
46
|
+
|
|
47
|
+
An omitted transition `event` accepts any event. Otherwise, the transition event must equal `event.type`. An omitted `when` means eligible; a false `when` makes the transition ineligible and keeps it in the trace with score `0`.
|
|
48
|
+
|
|
49
|
+
Eligible transitions score as follows:
|
|
50
|
+
|
|
51
|
+
- omitted transition `score`: `1`
|
|
52
|
+
- numeric or function transition `score`: that finite score
|
|
53
|
+
- utility transition with no explicit transition `score`: selected utility candidate score
|
|
54
|
+
|
|
55
|
+
All gathered eligible candidates compete by score regardless of depth. Highest score wins. Ties are stable by candidate search order, so a leaf transition beats an equal-scored parent transition, and earlier author rows beat later rows within the same path.
|
|
56
|
+
|
|
57
|
+
If no transition is selected, state and board reference are unchanged, but `stepIndex` increments because a step occurred. If a selected transition has no `to`, state remains the same. Same-state transitions do not run exit or enter hooks.
|
|
58
|
+
|
|
59
|
+
Dynamic `to` functions are validated at runtime. They must return a valid path that exists in the machine.
|
|
60
|
+
|
|
61
|
+
## Utility judgment semantics
|
|
62
|
+
|
|
63
|
+
`judgeUtility` preserves candidate array order in its trace. Omitted `when` means eligible. A false `when` makes the candidate ineligible with score `0`, and score functions are evaluated only for eligible candidates. Reason strings or functions are included in trace entries; reason functions are evaluated while building trace entries.
|
|
64
|
+
|
|
65
|
+
Scores must be finite. If no candidate is eligible, `selected` is `null`. Highest score wins and ties are stable by candidate order.
|
|
66
|
+
|
|
67
|
+
Hysteresis accepts a finite margin greater than or equal to `0`. If `previousKey` is present and the previous candidate is still eligible, a challenger must satisfy `challengerScore >= previousScore + margin` to replace it. If margin is `0`, normal highest-score semantics apply. If the previous candidate is missing or ineligible, normal selection applies.
|
|
68
|
+
|
|
69
|
+
`judgeUtility` does not mutate candidate definitions or the context itself, though user-provided functions can mutate external objects if they choose to.
|
|
70
|
+
|
|
71
|
+
## Utility transition semantics
|
|
72
|
+
|
|
73
|
+
A transition with `utility` evaluates utility candidates only after its event and `when` checks pass. If no utility candidate is selected, the transition is not eligible and neither utility `do` nor transition `do` runs.
|
|
74
|
+
|
|
75
|
+
If a utility candidate is selected, its judgment appears in the transition trace. The transition score is the explicit transition score when provided; otherwise it is the selected utility candidate score. Transition `hysteresis` is passed through to the utility judgment via `hysteresis.previous(board)` and `hysteresis.margin`; `undefined` from `previous` means no previous key.
|
|
76
|
+
|
|
77
|
+
Utility candidate `do` receives the original board and event and runs before the outer transition `do`.
|
|
78
|
+
|
|
79
|
+
## Enter, exit, and action order
|
|
80
|
+
|
|
81
|
+
When state changes, execution order is:
|
|
82
|
+
|
|
83
|
+
1. `onExit` for states being exited, deepest first.
|
|
84
|
+
2. Selected utility candidate `do`, if present.
|
|
85
|
+
3. Transition `do`, if present.
|
|
86
|
+
4. `onEnter` for states being entered, shallow to deep.
|
|
87
|
+
|
|
88
|
+
For `root/a/x -> root/b/y`, exit order is `root/a/x`, then `root/a`; enter order is `root/b`, then `root/b/y`. For `root/a/x -> root/a/y`, only `root/a/x` exits and only `root/a/y` enters. For `root/a -> root/a`, no exit or enter hooks run.
|
|
89
|
+
|
|
90
|
+
## Trace contract
|
|
91
|
+
|
|
92
|
+
`stepDeusMachine` returns a trace containing state before, state after, event type, considered transitions, selected transition, transition eligibility, transition score, transition search index, reasons when provided, and inner utility judgment when applicable.
|
|
93
|
+
|
|
94
|
+
Trace data is intended to be JSON-serializable. It does not include function references, the board object, or arbitrary event payloads. `formatDeusStepTrace(trace)` provides a small deterministic one-line summary for selected and unselected steps.
|
|
95
|
+
|
|
96
|
+
## Debug overlay helper
|
|
97
|
+
|
|
98
|
+
`createMachinaDebugOverlayMachine()` returns a validated DeusMachina machine for the controlled React debug overlay modes. `getMachinaDebugOverlayBehavior(board)` maps the board to rendering behavior:
|
|
99
|
+
|
|
100
|
+
- `collapsed`: not visible, `pointerEvents: "none"`, consumes no layout space.
|
|
101
|
+
- `nonInteractiveOverlay`: visible, `pointerEvents: "none"`, consumes no layout space.
|
|
102
|
+
- `interactivePanel`: visible, `pointerEvents: "auto"`, consumes layout space.
|
|
103
|
+
|
|
104
|
+
Labels and borders remain controlled by the board booleans; `false` stays false in overlay and panel modes.
|
|
105
|
+
|
|
106
|
+
## Non-goals
|
|
107
|
+
|
|
108
|
+
DeusMachina intentionally does not include async workflows, tools, actors, persistence, LLM calls, schedulers, nested authoring syntax, uncontrolled React state, or a visual editor.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Error code reference
|
|
2
|
+
|
|
3
|
+
This document summarizes public layout and text diagnostic codes.
|
|
4
|
+
|
|
5
|
+
## MachinaLayoutErrorCode
|
|
6
|
+
|
|
7
|
+
### Row/compile structure
|
|
8
|
+
|
|
9
|
+
- `EmptyRows` — no rows were provided. Typical cause: resolver/compile called with an empty array.
|
|
10
|
+
- `MissingRoot` — no root row exists. Typical cause: no `RootFrame` row in the selected row set.
|
|
11
|
+
- `MultipleRoots` — more than one root row exists. Typical cause: duplicate root definitions.
|
|
12
|
+
- `DuplicateId` — two rows share one id. Typical cause: authoring collision during merge/generation.
|
|
13
|
+
- `InvalidId` — id is blank/invalid. Typical cause: malformed row data.
|
|
14
|
+
- `MissingParent` — non-root row omitted `parent`. Typical cause: incomplete row authoring.
|
|
15
|
+
- `UnknownParent` — parent id does not exist. Typical cause: typo or variant mismatch.
|
|
16
|
+
- `SelfParent` — row points to itself as parent. Typical cause: authoring mistake.
|
|
17
|
+
- `Cycle` — parent graph contains a loop. Typical cause: circular parent references.
|
|
18
|
+
- `UnreachableNode` — node cannot be reached from root. Typical cause: disconnected subtree.
|
|
19
|
+
|
|
20
|
+
### Numeric/length validation
|
|
21
|
+
|
|
22
|
+
- `NonFiniteNumber` — numeric field is `NaN`/`Infinity`. Typical cause: bad arithmetic or unvalidated input.
|
|
23
|
+
- `InvalidLengthUnit` — unsupported `UiLength` unit. Typical cause: unit typo.
|
|
24
|
+
- `InvalidZ` — z metadata is invalid/out of bounds. Typical cause: non-integer or unsupported range.
|
|
25
|
+
- `NegativeSize` — width/height input is negative. Typical cause: invalid frame dimensions.
|
|
26
|
+
- `NegativeGap` — arranger gap is negative. Typical cause: invalid stack/grid config.
|
|
27
|
+
- `NegativePadding` — padding is negative. Typical cause: invalid arranger padding config.
|
|
28
|
+
|
|
29
|
+
### Root/frame context
|
|
30
|
+
|
|
31
|
+
- `RootFrameNotRoot` — `RootFrame` was used on a non-root node. Typical cause: wrong frame kind for child row.
|
|
32
|
+
- `RootFrameWithoutRoot` — root frame resolution lacked root context. Typical cause: incorrect direct frame resolution call.
|
|
33
|
+
- `FixedFrameWithoutArranger` — `FixedFrame` used where parent does not arrange children. Typical cause: fixed child under non-arranger parent.
|
|
34
|
+
- `FillFrameWithoutArranger` — `FillFrame` used where parent does not arrange children. Typical cause: fill child under non-arranger parent.
|
|
35
|
+
- `CellFrameWithoutGrid` — `CellFrame` used under non-grid arranger parent. Typical cause: cell child not placed in a grid container.
|
|
36
|
+
|
|
37
|
+
### Anchor/size resolution
|
|
38
|
+
|
|
39
|
+
- `InvalidAnchorHorizontal` — horizontal anchor constraints are inconsistent. Typical cause: missing/overconstrained left/right/width combination.
|
|
40
|
+
- `InvalidAnchorVertical` — vertical anchor constraints are inconsistent. Typical cause: missing/overconstrained top/bottom/height combination.
|
|
41
|
+
- `NegativeResolvedSize` — resolved width/height became negative. Typical cause: conflicting constraints relative to parent rect.
|
|
42
|
+
|
|
43
|
+
### Stack
|
|
44
|
+
|
|
45
|
+
- `InvalidFillWeight` — fill weight is invalid. Typical cause: zero/negative/non-finite fill weight.
|
|
46
|
+
- `StackChildMustBeFixed` — stack direct child frame kind is unsupported. Typical cause: child is neither `FixedFrame` nor `FillFrame`.
|
|
47
|
+
- Note: this code name is historical and stable; do not rename it.
|
|
48
|
+
- `StackContentNegative` — stack content space became negative. Typical cause: padding/gaps exceed container space.
|
|
49
|
+
- `StackOverflow` — stack children exceed available axis space. Typical cause: fixed sizes + gaps exceed container.
|
|
50
|
+
- `ExpectedStackArrange` — a stack query helper was called on a non-stack node. Typical cause: using stack-only geometry helpers with a plain or grid parent.
|
|
51
|
+
- `StackQueryInvalidRange` — a remaining stack rectangle query produced a negative interval. Typical cause: `afterChildren` resolve after `beforeChildren`.
|
|
52
|
+
|
|
53
|
+
### Grid
|
|
54
|
+
|
|
55
|
+
- `GridChildMustBeCell` — direct grid child is not `CellFrame`. Typical cause: wrong frame kind under grid arranger.
|
|
56
|
+
- `InvalidGridTrack` — track definition is invalid. Typical cause: malformed `GridArrange` track settings.
|
|
57
|
+
- `InvalidGridCell` — cell coordinates/span are invalid. Typical cause: out-of-range row/col/span.
|
|
58
|
+
- `GridContentNegative` — grid content space became negative. Typical cause: padding/gaps exceed container space.
|
|
59
|
+
- `GridOverflow` — grid placement overflows available tracks/space. Typical cause: tracks/cells incompatible with container.
|
|
60
|
+
|
|
61
|
+
### Guide/reference alignment
|
|
62
|
+
|
|
63
|
+
- `GuideTargetNotFound` — guide target id is missing. Typical cause: typo or missing target row.
|
|
64
|
+
- `GuideSelfReference` — guide references its own node. Typical cause: self-targeting guide config.
|
|
65
|
+
- `GuideReferenceCycle` — guide references create a cycle. Typical cause: mutually dependent guide nodes.
|
|
66
|
+
- `GuideInvalidEdgeForAxis` — requested reference edge is invalid for chosen axis. Typical cause: axis/edge mismatch.
|
|
67
|
+
- `GuideTooManyReferencesPerAxis` — too many references were provided for one axis. Typical cause: overconstrained guide input.
|
|
68
|
+
- `InvalidGuideFrame` — guide frame declaration is malformed. Typical cause: incomplete or conflicting guide spec.
|
|
69
|
+
- `GuideTargetUnresolved` — guide target exists but was not resolved when needed. Typical cause: invalid dependency order/cycle.
|
|
70
|
+
|
|
71
|
+
### Screen catalog and viewport matrix
|
|
72
|
+
|
|
73
|
+
- `InvalidViewport` — viewport metadata is malformed. Typical cause: blank key, non-positive dimensions, invalid `deviceScaleFactor`, or invalid lightweight metadata.
|
|
74
|
+
- `DuplicateViewportKey` — two viewport presets share one key. Typical cause: duplicate matrix entries.
|
|
75
|
+
- `UnknownViewportKey` — a requested or screen-referenced viewport key is absent from the matrix. Typical cause: typo or filtered matrix mismatch.
|
|
76
|
+
- `InvalidScreen` — screen catalog metadata is malformed. Typical cause: blank key, blank route, or invalid lightweight metadata.
|
|
77
|
+
- `DuplicateScreenKey` — two screen definitions share one key. Typical cause: duplicate catalog entries.
|
|
78
|
+
- `UnknownScreenKey` — a requested screen key is absent from the catalog. Typical cause: typo in an expansion filter.
|
|
79
|
+
|
|
80
|
+
### Variants
|
|
81
|
+
|
|
82
|
+
- `InvalidVariantCondition` — variant condition is invalid. Typical cause: unsupported operator/value shape.
|
|
83
|
+
|
|
84
|
+
### Interpolation
|
|
85
|
+
|
|
86
|
+
- `IncompatibleLayouts` — two resolved layouts cannot be interpolated safely. Typical cause: node identity/topology mismatch during `lerpResolvedLayouts`.
|
|
87
|
+
|
|
88
|
+
## MachinaText diagnostics
|
|
89
|
+
|
|
90
|
+
- `unsupported_syntax` — source includes unsupported markdown-like construct. Typical cause: blockquotes, task lists, ordered lists, fences, HTML, or unsupported source kind.
|
|
91
|
+
- `heading_forbidden` — heading syntax was used. Typical cause: `#`, `##`, etc. in MachinaText content.
|
|
92
|
+
- `max_list_depth_exceeded` — bullet nesting exceeds supported depth. Typical cause: lists nested deeper than policy allows.
|
|
93
|
+
- `malformed_link` — link syntax is invalid. Typical cause: missing delimiters or empty label/href shape.
|
|
94
|
+
- `unclosed_inline` — inline marker was not closed. Typical cause: unmatched `*`, `**`, or backtick markers.
|
|
95
|
+
- `invalid_escape` — escape sequence is unsupported or dangling. Typical cause: unknown escape like `\q` or trailing `\`.
|