@hyprune/schema 0.7.0 → 0.8.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/CHANGELOG.md CHANGED
@@ -298,3 +298,95 @@ Object manifests use the world format numbering: a world may use objects whose
298
298
  ## @hyprune/schema 0.7.0 (2026-10-12)
299
299
 
300
300
  Publishes IPC 0.21 (markers, personal quests, focus sessions) and IPC 0.22 (object catalog, user placements, libraries), plus the object manifest (`object.json` 0.9 and the 0.10 draft), library and library release-record schemas.
301
+
302
+ ## World 0.9: characters, paths, seats and keepClear (RFC-0011 P2)
303
+
304
+ - `objectAssets[]` (at most 32, ids unique) take exactly one source: inline
305
+ `{id, scene, animations?, collision?, lighting?, traits?, slots?}` (the 0.8
306
+ asset plus object.json 0.9 `traits` and `slots`; `decorative`, `collidable`,
307
+ `movable`, `character` and `seat` are allowed, `mover`, `mount`, `machine` and
308
+ `interactive` rejected), `dir {id, dir}` (a package directory holding
309
+ `object.json`, object format at most the world's) or `library {id, library,
310
+ object}` (`library` is `<reverse-domain id>@<semver>`, `object` a slug).
311
+ `animations` is shorthand for `traits.decorative.animations` and `collision`
312
+ for `traits.collidable`; giving both forms of one is invalid.
313
+ - `objects[]` gain `path` (a `route` path; replaces `pose`), `reverse` (only
314
+ with `path`), `seat` (a `seats[]` id, `<objectId>/<anchorId>` or
315
+ `<objectId>`; characters without a path), `accent` (linear RGB 0..1),
316
+ `interactions` (1..8, replacing the asset's list) and `locked` (movable
317
+ assets). `pose` is required unless `path` is set and forbidden with it. A
318
+ character's `scale` must be 1; at most 16 character instances and 8 per path.
319
+ - Instance interactions `{id, label (1..32), prompt? (1..64), action}` with
320
+ `say {lines[1..8]}`, `waypoint {target: {zoneId}|{position}|{anchor}|{object}}`,
321
+ `guide {path}` (a route) or `panel {panel}`. `travel` and `quest` are
322
+ reserved and rejected. Asset-level interactions stay `say`/`panel`.
323
+ - `paths[]` (at most 64, 1,024 points in total): `{id, name?, use?
324
+ (route|track|generic, default generic), closed?, points[2..256] {position,
325
+ type: line|curve|arc}, speed? (0.1..30), stops?[<=32]}`. A stop is `{point,
326
+ seconds? (0.5..600), clip? (look_around|wave|nod|idle_fidget), face?
327
+ ({position}|{anchor}|{object}), seat?}` with at most one of clip, face and
328
+ seat, one stop per point and the point below the point count. Track stops
329
+ take only `point` and `seconds`; generic paths have no stops. An `arc` needs
330
+ a horizontal chord of at least 0.1 m.
331
+ - `seats[]` (at most 64): `{id, pose, height (0.2..1), use? (["sit"]),
332
+ approach? (0.3..2)}`. `keepClear[]` (at most 64): `{id, min, max}`, min
333
+ below max on every axis.
334
+ - `validate('world', manifest, undefined, '0.9', {assets})` adds unique ids,
335
+ asset, path, seat, waypoint and face references, route-only bindings,
336
+ character-only and movable-only fields, pose/path exclusivity, normalised
337
+ seat poses, arc chords, the point total, keepClear ordering and the
338
+ character limits. `assets` maps a dir or library asset id to its parsed
339
+ `object.json`, so its traits are checked like an inline asset's; without it
340
+ those checks skip the asset. Reserved traits and actions are reported with a
341
+ plain reason. `worldLimits` exports the limits.
342
+ - `validate('scene', gltf, undefined, '0.9', {world, asset})` reads an inline
343
+ asset's animations and proxy from either form and checks an inline
344
+ character's skin and clips; dir and library assets are checked as objects.
345
+ - `v0.9/common.schema.json` is the 0.8 common definitions under the 0.9 `$id`
346
+ (the directory's IPC, input, object and library schemas are untouched).
347
+ `examples/world-npcs.json` is a synthetic 0.9 manifest. Everything else is
348
+ inherited from 0.8 unchanged. Inheritance test included.
349
+
350
+ ## IPC 0.23: characters, paths and interactions (RFC-0011 P2)
351
+
352
+ - Required state key `npcs {motion (auto|always|still|off), state
353
+ (none|animating|paused|still|off), reason (null or up to 64 characters, e.g.
354
+ battery), usage {authored, user}, limits {authored (<=16), user (<=8)},
355
+ drawing, aimed, interaction}`. `drawing` is null or `{pathId, use, spawn:
356
+ null|{ref}, bind: null|objectId}` (a `paths.draw` in progress); `aimed` is null
357
+ or `{objectId, name, prompt, interactions[<=8] {id, label, type}}`;
358
+ `interaction` is null or `{objectId, interactionId|null, type
359
+ (choose|say|waypoint|guide|panel), label, choices[<=8] {id, label},
360
+ line|null, lineIndex, lineCount, panel|null}`.
361
+ - `objects.instances[]` gain required `character` (boolean) and `accent`
362
+ (null or linear RGB); `path` is null or a qualified path ref
363
+ (`package/<id>`, `user/<id>`), `activity` null or
364
+ `idle|walking|running|stopped|sitting|guiding|interacting|suspended`, `seat`
365
+ null or a seat ref (up to 192 characters).
366
+ - `editor.paths[]` gain required `use` (route|track|generic), `name`
367
+ (string|null), `speed` (number|null) and `stops` (at most 32, the world 0.9
368
+ stop shape).
369
+ - `interaction.reticle.action` gains `interact`. `graphicsConfig` and
370
+ `graphicsPatch` gain `npc_motion` (`auto`, `always`, `still`, `off`).
371
+ - Methods: `npcs.spawn {ref, path?, pose?, phase?, speed? (0.25..2), accent?,
372
+ reverse?}` (`{revision, id}`; path and pose exclusive, reverse needs a path);
373
+ `npcs.bind {id, path?, pose?, phase?, speed?, accent?, reverse?}` (at least one
374
+ setting); `npcs.disable {id, disabled}`; `npcs.remove {id}|{all:true}`;
375
+ `paths.list {}` (`{paths[<=192]}`: `{ref, source (package|user), id, name,
376
+ use, closed, points, speed, stops, walkable (null for non-routes),
377
+ problems[<=8], bound[<=8]}`); `paths.set {path: {id?, name?, use, closed,
378
+ points[2..256], speed?, stops?}}` (`{revision, id}`); `paths.remove {id,
379
+ unbind?}`; `paths.draw {use?, name?, spawn? {ref, phase?, speed?, accent?},
380
+ bind?}` (`{revision, id}`; spawn and bind exclusive); `paths.finish {}`
381
+ (`{revision, id|null, bound|null}`); `interaction.choose {objectId,
382
+ interactionId|null}`. Path params take a qualified ref or a bare id
383
+ (`package/<id>`); `paths.set/remove/draw/finish` ids are user path ids.
384
+ Grants: `npcs.*` and `paths.set/remove/draw/finish` need `objects.control`,
385
+ `paths.list` needs `state.read`, `interaction.choose` needs `world.control`.
386
+ - Everything else is inherited from 0.22 unchanged (no new grant or event);
387
+ `session.hello` reports `0.23` and lists the ten methods. Inheritance test
388
+ included.
389
+
390
+ ## @hyprune/schema 0.8.0 (2026-10-12)
391
+
392
+ Publishes IPC 0.23 and world format 0.9: characters and NPC instances, authored paths (route/track/generic) with stops, seats, keepClear volumes and NPC interactions.
package/README.md CHANGED
@@ -2,19 +2,19 @@
2
2
 
3
3
  > **Hyprune** is an explorable, world-driven desktop environment for Hyprland: your workspaces become places you can walk through, with live windows on the walls. This repository holds the versioned **schemas** for world packages, IPC and manifests, and their validator. Install Hyprune through the [hyprune](https://github.com/hyprune/hyprune) repository (starter kits, Nix, Arch); learn more at [hyprune.com](https://hyprune.com). Licence: MIT.
4
4
 
5
- Versioned contracts for Hyprune, a world-driven Hyprland desktop: world packages (formats 0.1–0.8), the IPC protocol (0.1–0.22), object and library manifests (0.9, draft 0.10), extension and screen-type manifests and the input keymap. JSON Schema dialect: **2020-12**. Every version is frozen once published; core, the shell and the SDK pin these exact files. Readable reference: [hyprune.com/reference/schema](https://hyprune.com/reference/schema/).
5
+ Versioned contracts for Hyprune, a world-driven Hyprland desktop: world packages (formats 0.1–0.9), the IPC protocol (0.1–0.23), object and library manifests (0.9, draft 0.10), extension and screen-type manifests and the input keymap. JSON Schema dialect: **2020-12**. Every version is frozen once published; core, the shell and the SDK pin these exact files. Readable reference: [hyprune.com/reference/schema](https://hyprune.com/reference/schema/).
6
6
 
7
7
  ## Install
8
8
 
9
9
  ```sh
10
10
  npm i -D @hyprune/schema
11
- npx hyprune-validate world world.json - 0.8 # a world package manifest
12
- npx hyprune-validate scene scene.gltf - 0.8 world.json # its glTF against the world format
11
+ npx hyprune-validate world world.json - 0.9 # a world package manifest
12
+ npx hyprune-validate scene scene.gltf - 0.9 world.json # its glTF against the world format
13
13
  ```
14
14
 
15
15
  ```js
16
16
  import { validate, worldFormats } from '@hyprune/schema';
17
- import schema from '@hyprune/schema/v0.8/world.schema.json' with { type: 'json' };
17
+ import schema from '@hyprune/schema/v0.9/world.schema.json' with { type: 'json' };
18
18
 
19
19
  const result = validate('world', manifest, undefined, worldFormats.at(-1));
20
20
  if (!result.valid) console.error(result.errors.join('\n'));
@@ -127,6 +127,17 @@ from the proxy. Check an asset's glTF with
127
127
  `npm run validate -- scene objects/armillary.gltf - 0.8 world.json armillary`).
128
128
  See RFC-0004 "world 0.8 placed world objects".
129
129
 
130
+ World format **0.9** adds characters, paths, seats and keep-clear volumes
131
+ (RFC-0011 P2). An object asset is an inline package glTF (now with optional
132
+ object.json `traits` and `slots`), a package object directory (`dir`) or a
133
+ library object (`library` + `object`). Instances gain `path` (a `route`; it
134
+ replaces `pose`), `reverse`, `seat`, `accent`, `interactions` (`say`,
135
+ `waypoint`, `guide`, `panel`) and `locked`. New top-level `paths` (route,
136
+ track or generic; stops with a clip, facing or seat), `seats` and `keepClear`.
137
+ Pass the object.json of dir and library assets to check their traits too:
138
+ `validate('world', manifest, undefined, '0.9', {assets: {resident: objectJson}})`.
139
+ `examples/world-npcs.json` is a synthetic example. See RFC-0011 "World format 0.9".
140
+
130
141
  IPC **0.16** adds the `upscaler` graphics key (`"fsr1"`, `"bilinear"` or `null` to
131
142
  inherit the preset) to `graphicsConfig`/`graphicsPatch`. Every 0.15 definition is
132
143
  otherwise unchanged; earlier schemas stay frozen. See RFC-0003/0008 amendments.
@@ -182,6 +193,16 @@ new `editor.gizmo` carries the tool 4 axis space, pivot and snapping. Error
182
193
  `data` may name the refusing placement `rule`. Every other 0.21 definition is
183
194
  unchanged. See the RFC-0011 amendment "P1 in IPC 0.22".
184
195
 
196
+ IPC **0.23** adds characters, paths and interactions (RFC-0011 P2): a required
197
+ `npcs` state key (motion setting and effective state, character budgets, the
198
+ path being drawn, the aimed character and the running interaction),
199
+ `character` and `accent` on object instances with path, activity and seat
200
+ values, `use`/`name`/`speed`/`stops` on editor paths, the reticle action
201
+ `interact` and the graphics key `npc_motion`. New methods
202
+ `npcs.spawn/bind/disable/remove` and `paths.set/remove/draw/finish`
203
+ (objects.control), `paths.list` (state.read) and `interaction.choose`
204
+ (world.control). Every other 0.22 definition is unchanged.
205
+
185
206
  ## Objects and libraries (RFC-0011)
186
207
 
187
208
  Object manifests (`object.json`) and library manifests (`library.json`) use the
@@ -0,0 +1,493 @@
1
+ {
2
+ "formatVersion": "0.9",
3
+ "id": "com.hyprune.example.courtyard",
4
+ "version": "0.1.0",
5
+ "name": "Courtyard",
6
+ "description": "Synthetic world 0.9 manifest: characters on routes, seats, interactions and keep-clear volumes. Referenced files are not supplied.",
7
+ "license": "CC-BY-4.0",
8
+ "scene": "scene.gltf",
9
+ "defaultSpawn": "arrival",
10
+ "spawns": [
11
+ {
12
+ "id": "arrival",
13
+ "pose": {
14
+ "position": [
15
+ 0,
16
+ 1,
17
+ 0
18
+ ],
19
+ "rotation": [
20
+ 0,
21
+ 0,
22
+ 0,
23
+ 1
24
+ ]
25
+ }
26
+ }
27
+ ],
28
+ "attribution": [
29
+ {
30
+ "path": ".",
31
+ "author": "Hyprune contributors",
32
+ "license": "CC-BY-4.0"
33
+ }
34
+ ],
35
+ "zones": [
36
+ {
37
+ "id": "work",
38
+ "name": "Work",
39
+ "bounds": {
40
+ "min": [
41
+ -4,
42
+ 0,
43
+ -4
44
+ ],
45
+ "max": [
46
+ 4,
47
+ 4,
48
+ 4
49
+ ]
50
+ }
51
+ }
52
+ ],
53
+ "anchors": [
54
+ {
55
+ "id": "desk",
56
+ "pose": {
57
+ "position": [
58
+ 0,
59
+ 1.4,
60
+ -3
61
+ ],
62
+ "rotation": [
63
+ 0,
64
+ 0,
65
+ 0,
66
+ 1
67
+ ]
68
+ },
69
+ "size": [
70
+ 1.6,
71
+ 0.9
72
+ ],
73
+ "screenType": "com.hyprune.window"
74
+ }
75
+ ],
76
+ "collision": [
77
+ {
78
+ "node": 0,
79
+ "shape": "mesh",
80
+ "layer": "static"
81
+ }
82
+ ],
83
+ "navigation": {
84
+ "kind": "mesh",
85
+ "node": 1,
86
+ "agentRadius": 0.3,
87
+ "agentHeight": 1.8
88
+ },
89
+ "lightmaps": [
90
+ {
91
+ "material": 0,
92
+ "texture": 1,
93
+ "texCoord": 1,
94
+ "encoding": "linear",
95
+ "intensity": 1
96
+ }
97
+ ],
98
+ "audio": [
99
+ {
100
+ "id": "air",
101
+ "path": "audio/air.ogg",
102
+ "position": [
103
+ 0,
104
+ 2,
105
+ 0
106
+ ],
107
+ "radius": 10,
108
+ "gain": 0.2,
109
+ "loop": true
110
+ }
111
+ ],
112
+ "objectAssets": [
113
+ {
114
+ "id": "resident",
115
+ "dir": "characters/resident-blue"
116
+ },
117
+ {
118
+ "id": "porter",
119
+ "library": "com.hyprune.starter@0.1.0",
120
+ "object": "porter"
121
+ },
122
+ {
123
+ "id": "guide",
124
+ "scene": "characters/guide.glb",
125
+ "traits": {
126
+ "character": {
127
+ "clips": {
128
+ "walk": {
129
+ "speed": 1.1
130
+ },
131
+ "idle": {},
132
+ "wave": {},
133
+ "nod": {},
134
+ "sit": {
135
+ "seatHeight": 0.46
136
+ },
137
+ "sit_idle": {}
138
+ },
139
+ "height": 1.72,
140
+ "radius": 0.3,
141
+ "accent": true,
142
+ "interactions": [
143
+ {
144
+ "id": "talk",
145
+ "label": "Talk",
146
+ "action": {
147
+ "type": "say",
148
+ "lines": [
149
+ "Welcome to the courtyard."
150
+ ]
151
+ }
152
+ }
153
+ ]
154
+ }
155
+ }
156
+ },
157
+ {
158
+ "id": "court-bench",
159
+ "scene": "objects/bench.glb",
160
+ "collision": {
161
+ "node": "proxy"
162
+ },
163
+ "traits": {
164
+ "movable": {},
165
+ "seat": {
166
+ "capacity": 2,
167
+ "anchors": [
168
+ {
169
+ "id": "left",
170
+ "position": [
171
+ -0.4,
172
+ 0,
173
+ 0.55
174
+ ],
175
+ "yaw": 0,
176
+ "height": 0.45
177
+ },
178
+ {
179
+ "id": "right",
180
+ "position": [
181
+ 0.4,
182
+ 0,
183
+ 0.55
184
+ ],
185
+ "yaw": 0,
186
+ "height": 0.45
187
+ }
188
+ ]
189
+ }
190
+ }
191
+ },
192
+ {
193
+ "id": "fountain",
194
+ "scene": "objects/fountain.glb",
195
+ "animations": [
196
+ {
197
+ "node": "spray",
198
+ "type": "spin",
199
+ "axis": [
200
+ 0,
201
+ 1,
202
+ 0
203
+ ],
204
+ "pivot": [
205
+ 0,
206
+ 0,
207
+ 0
208
+ ],
209
+ "period": 12
210
+ }
211
+ ],
212
+ "lighting": {
213
+ "mode": "probe"
214
+ }
215
+ }
216
+ ],
217
+ "objects": [
218
+ {
219
+ "id": "fountain-1",
220
+ "asset": "fountain",
221
+ "pose": {
222
+ "position": [
223
+ 1.5,
224
+ 0,
225
+ 0
226
+ ],
227
+ "rotation": [
228
+ 0,
229
+ 0,
230
+ 0,
231
+ 1
232
+ ]
233
+ }
234
+ },
235
+ {
236
+ "id": "bench-east",
237
+ "asset": "court-bench",
238
+ "pose": {
239
+ "position": [
240
+ 3.6,
241
+ 0,
242
+ -2
243
+ ],
244
+ "rotation": [
245
+ 0,
246
+ -0.7071068,
247
+ 0,
248
+ 0.7071068
249
+ ]
250
+ },
251
+ "locked": true
252
+ },
253
+ {
254
+ "id": "porter-1",
255
+ "asset": "porter",
256
+ "path": "court-loop",
257
+ "phase": 0.25,
258
+ "speed": 1,
259
+ "accent": [
260
+ 0.9,
261
+ 0.5,
262
+ 0.1
263
+ ],
264
+ "interactions": [
265
+ {
266
+ "id": "talk",
267
+ "label": "Talk",
268
+ "action": {
269
+ "type": "say",
270
+ "lines": [
271
+ "The desk is on the north side.",
272
+ "Mind the fountain."
273
+ ]
274
+ }
275
+ },
276
+ {
277
+ "id": "where",
278
+ "label": "Where is work?",
279
+ "prompt": "Mark it",
280
+ "action": {
281
+ "type": "waypoint",
282
+ "target": {
283
+ "zoneId": "work"
284
+ }
285
+ }
286
+ },
287
+ {
288
+ "id": "show-desk",
289
+ "label": "Show me the desk",
290
+ "prompt": "Follow me",
291
+ "action": {
292
+ "type": "guide",
293
+ "path": "to-desk"
294
+ }
295
+ },
296
+ {
297
+ "id": "map",
298
+ "label": "Open the map",
299
+ "action": {
300
+ "type": "panel",
301
+ "panel": "map"
302
+ }
303
+ }
304
+ ]
305
+ },
306
+ {
307
+ "id": "guide-1",
308
+ "asset": "guide",
309
+ "path": "court-loop",
310
+ "phase": 0.75,
311
+ "reverse": true,
312
+ "accent": [
313
+ 0.2,
314
+ 0.4,
315
+ 0.9
316
+ ]
317
+ },
318
+ {
319
+ "id": "reader",
320
+ "asset": "resident",
321
+ "pose": {
322
+ "position": [
323
+ 1.5,
324
+ 0,
325
+ 1.8
326
+ ],
327
+ "rotation": [
328
+ 0,
329
+ 1,
330
+ 0,
331
+ 0
332
+ ]
333
+ },
334
+ "seat": "fountain-ledge",
335
+ "interactions": [
336
+ {
337
+ "id": "fountain",
338
+ "label": "The fountain?",
339
+ "action": {
340
+ "type": "waypoint",
341
+ "target": {
342
+ "object": "fountain-1"
343
+ }
344
+ }
345
+ }
346
+ ]
347
+ }
348
+ ],
349
+ "paths": [
350
+ {
351
+ "id": "court-loop",
352
+ "name": "Court loop",
353
+ "use": "route",
354
+ "closed": true,
355
+ "speed": 1.1,
356
+ "points": [
357
+ {
358
+ "position": [
359
+ -3.5,
360
+ 0,
361
+ 3
362
+ ],
363
+ "type": "line"
364
+ },
365
+ {
366
+ "position": [
367
+ -3.5,
368
+ 0,
369
+ -2
370
+ ],
371
+ "type": "line"
372
+ },
373
+ {
374
+ "position": [
375
+ 3,
376
+ 0,
377
+ -2
378
+ ],
379
+ "type": "curve"
380
+ },
381
+ {
382
+ "position": [
383
+ 3,
384
+ 0,
385
+ 3
386
+ ],
387
+ "type": "arc"
388
+ }
389
+ ],
390
+ "stops": [
391
+ {
392
+ "point": 1,
393
+ "seconds": 3,
394
+ "clip": "look_around"
395
+ },
396
+ {
397
+ "point": 2,
398
+ "seconds": 20,
399
+ "seat": "bench-east/left"
400
+ },
401
+ {
402
+ "point": 3,
403
+ "seconds": 4,
404
+ "face": {
405
+ "anchor": "desk"
406
+ }
407
+ }
408
+ ]
409
+ },
410
+ {
411
+ "id": "to-desk",
412
+ "name": "To the desk",
413
+ "use": "route",
414
+ "points": [
415
+ {
416
+ "position": [
417
+ 0,
418
+ 0,
419
+ 3
420
+ ],
421
+ "type": "line"
422
+ },
423
+ {
424
+ "position": [
425
+ 0,
426
+ 0,
427
+ -2
428
+ ],
429
+ "type": "line"
430
+ }
431
+ ]
432
+ },
433
+ {
434
+ "id": "garden-walk",
435
+ "points": [
436
+ {
437
+ "position": [
438
+ -2,
439
+ 0,
440
+ 2
441
+ ],
442
+ "type": "line"
443
+ },
444
+ {
445
+ "position": [
446
+ 2,
447
+ 0,
448
+ 2
449
+ ],
450
+ "type": "curve"
451
+ }
452
+ ]
453
+ }
454
+ ],
455
+ "seats": [
456
+ {
457
+ "id": "fountain-ledge",
458
+ "pose": {
459
+ "position": [
460
+ 1.5,
461
+ 0,
462
+ 1.2
463
+ ],
464
+ "rotation": [
465
+ 0,
466
+ 1,
467
+ 0,
468
+ 0
469
+ ]
470
+ },
471
+ "height": 0.5,
472
+ "use": [
473
+ "sit"
474
+ ],
475
+ "approach": 0.6
476
+ }
477
+ ],
478
+ "keepClear": [
479
+ {
480
+ "id": "north-door",
481
+ "min": [
482
+ -0.8,
483
+ 0,
484
+ -4.2
485
+ ],
486
+ "max": [
487
+ 0.8,
488
+ 2.4,
489
+ -3.6
490
+ ]
491
+ }
492
+ ]
493
+ }
@@ -19,9 +19,17 @@ export interface ValidateOptions {
19
19
  /**
20
20
  * For kind `scene` from world 0.8: validate `value` as the glTF of this
21
21
  * `world.objectAssets[].id` (extension rules, animation and collision node
22
- * names, nesting) instead of the world's scene.gltf.
22
+ * names, nesting; from 0.9 also an inline character's skin and clips) instead
23
+ * of the world's scene.gltf.
23
24
  */
24
25
  asset?: string;
26
+ /**
27
+ * For kind `world` from 0.9: the parsed object.json of `dir` and `library` object
28
+ * assets, keyed by `objectAssets[].id`. Their traits make the character-only
29
+ * fields, seat anchor references, `locked` and the character limit checkable as
30
+ * for inline assets; without them those checks skip the asset.
31
+ */
32
+ assets?: Record<string, { id?: string; formatVersion?: string; traits?: Record<string, unknown> }>;
25
33
  /** Kind object: the parsed scene glTF (or a GLB's JSON chunk) for node, material, variant, clip, budget and bounds checks. */
26
34
  gltf?: unknown;
27
35
  /** Kind object: the directory name, which must equal the object id. */
@@ -60,5 +68,7 @@ export const contractVersions: readonly string[];
60
68
  export const objectFormats: readonly string[];
61
69
  /** RFC-0011 directory, asset and library limits the object and library checks apply. */
62
70
  export const objectLimits: Readonly<Record<string, number>>;
71
+ /** World 0.9 limits the world checks apply: character instances, characters per path, path points in total, minimum arc chord (m). */
72
+ export const worldLimits: Readonly<{ characters: number; charactersPerPath: number; pathPoints: number; arcChord: number }>;
63
73
  /** glTF extensions a scene may list in extensionsRequired for a world format. */
64
74
  export function sceneExtensions(version: string): string[];