@hyprune/schema 0.6.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.
@@ -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
+ }
@@ -1,12 +1,16 @@
1
1
  // Type declarations for lib/validate.mjs.
2
2
 
3
3
  /** Schema kinds `validate` accepts; `scene` checks a scene.gltf against its world format. */
4
- export type ContractKind = 'world' | 'extension' | 'screen-type' | 'ipc' | 'scene';
4
+ export type ContractKind = 'world' | 'extension' | 'screen-type' | 'ipc' | 'scene' | 'object' | 'library' | 'library-releases';
5
5
 
6
6
  export interface ValidationResult {
7
7
  valid: boolean;
8
8
  /** JSON-pointer-prefixed messages; empty when valid. */
9
9
  errors: string[];
10
+ /** Kinds object, library and library-releases: advisory messages (never make a document invalid). */
11
+ warnings?: string[];
12
+ /** Kind object with a glTF: triangles drawn by the scene. */
13
+ triangles?: number;
10
14
  }
11
15
 
12
16
  export interface ValidateOptions {
@@ -15,9 +19,29 @@ export interface ValidateOptions {
15
19
  /**
16
20
  * For kind `scene` from world 0.8: validate `value` as the glTF of this
17
21
  * `world.objectAssets[].id` (extension rules, animation and collision node
18
- * 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.
19
24
  */
20
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> }>;
33
+ /** Kind object: the parsed scene glTF (or a GLB's JSON chunk) for node, material, variant, clip, budget and bounds checks. */
34
+ gltf?: unknown;
35
+ /** Kind object: the directory name, which must equal the object id. */
36
+ directory?: string;
37
+ /** Kind object: every file of the object directory (attribution coverage and limits); kind library: every file of the library. */
38
+ files?: ReadonlyArray<{ path: string; size: number }>;
39
+ /** Kind object: the thumbnail PNG's size. */
40
+ thumbnail?: { width: number; height: number; bytes: number };
41
+ /** Kind object: values that need decoded geometry or images. */
42
+ measured?: { bounds?: { min: number[]; max: number[] }; maxTextureSize?: number; gpuBytes?: number };
43
+ /** Kind library: each listed object's parsed object.json, keyed by directory name. */
44
+ objects?: Record<string, { id?: string; formatVersion?: string }>;
21
45
  }
22
46
 
23
47
  /**
@@ -25,7 +49,8 @@ export interface ValidateOptions {
25
49
  * @param kind contract kind
26
50
  * @param value parsed document (world.json, extension.json, an IPC frame, scene.gltf)
27
51
  * @param method IPC only: the outstanding request's method, to validate a response's result
28
- * @param version world format or IPC version, e.g. '0.7' or '0.19' (default '0.1')
52
+ * @param version world format or IPC version, e.g. '0.7' or '0.19' (default '0.1'); for objects and
53
+ * libraries the object format (default: the document's formatVersion)
29
54
  * @throws on an unknown kind, version or method (usage errors, not validation failures)
30
55
  */
31
56
  export function validate(kind: ContractKind, value: unknown, method?: string, version?: string, options?: ValidateOptions): ValidationResult;
@@ -39,5 +64,11 @@ export const worldFormats: readonly string[];
39
64
  export const ipcProtocols: readonly string[];
40
65
  /** Every contract version directory, oldest first. */
41
66
  export const contractVersions: readonly string[];
67
+ /** Object manifest formats with a published schema (RFC-0011; world format numbering from 0.9). */
68
+ export const objectFormats: readonly string[];
69
+ /** RFC-0011 directory, asset and library limits the object and library checks apply. */
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 }>;
42
73
  /** glTF extensions a scene may list in extensionsRequired for a world format. */
43
74
  export function sceneExtensions(version: string): string[];