@plasius/scene-object 0.1.2 → 0.1.3
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 +5 -0
- package/dist/index.cjs +321 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +30 -1
- package/dist/index.d.ts +30 -1
- package/dist/index.js +316 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,6 +13,7 @@ npm install @plasius/scene-object
|
|
|
13
13
|
This package is controlled by a site-owned feature flag:
|
|
14
14
|
|
|
15
15
|
- `scene.object.runtime.enabled`
|
|
16
|
+
- Player System interface extensions inherit `isekai.player-system.interface.enabled`
|
|
16
17
|
|
|
17
18
|
## Package exports
|
|
18
19
|
|
|
@@ -20,6 +21,8 @@ This package is controlled by a site-owned feature flag:
|
|
|
20
21
|
- deterministic object validation and manifest creation helpers
|
|
21
22
|
- attachment and attachment-point helpers
|
|
22
23
|
- state lookup helpers
|
|
24
|
+
- Player System extension contracts for target anchors, focus-pane screens, and localized alert markers
|
|
25
|
+
- `validateSceneObjectPlayerSystemManifest()` plus focus/anchor lookup helpers
|
|
23
26
|
|
|
24
27
|
## Development
|
|
25
28
|
|
|
@@ -38,3 +41,5 @@ npm run pack:check
|
|
|
38
41
|
- transforms and bounds must be finite numbers with valid units
|
|
39
42
|
- attachment points and links must reference existing objects/points
|
|
40
43
|
- state visibility and object references must be structurally valid
|
|
44
|
+
- Player System anchors must reference exported object attachment points
|
|
45
|
+
- focus screens must bind to `focus-pane` anchors and declare a bounded presentation variant
|
package/dist/index.cjs
CHANGED
|
@@ -20,14 +20,18 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
SCENE_OBJECT_PLAYER_SYSTEM_INTERFACE_FLAG_ID: () => SCENE_OBJECT_PLAYER_SYSTEM_INTERFACE_FLAG_ID,
|
|
23
24
|
SCENE_OBJECT_RUNTIME_FLAG_ID: () => SCENE_OBJECT_RUNTIME_FLAG_ID,
|
|
24
25
|
SCENE_OBJECT_SCHEMA_VERSION: () => SCENE_OBJECT_SCHEMA_VERSION,
|
|
25
26
|
createSceneObjectManifest: () => createSceneObjectManifest,
|
|
27
|
+
resolveSceneObjectAnchorById: () => resolveSceneObjectAnchorById,
|
|
26
28
|
resolveSceneObjectById: () => resolveSceneObjectById,
|
|
29
|
+
resolveSceneObjectFocusScreenById: () => resolveSceneObjectFocusScreenById,
|
|
27
30
|
resolveSceneObjectReferences: () => resolveSceneObjectReferences,
|
|
28
31
|
resolveSceneObjectState: () => resolveSceneObjectState,
|
|
29
32
|
validateSceneObjectManifest: () => validateSceneObjectManifest,
|
|
30
|
-
validateSceneObjectObjectState: () => validateSceneObjectObjectState
|
|
33
|
+
validateSceneObjectObjectState: () => validateSceneObjectObjectState,
|
|
34
|
+
validateSceneObjectPlayerSystemManifest: () => validateSceneObjectPlayerSystemManifest
|
|
31
35
|
});
|
|
32
36
|
module.exports = __toCommonJS(index_exports);
|
|
33
37
|
|
|
@@ -436,6 +440,317 @@ function resolveSceneObjectById(requestOrManifest, objectId) {
|
|
|
436
440
|
return result.value.objects.find((object) => object.id === request.objectId);
|
|
437
441
|
}
|
|
438
442
|
|
|
443
|
+
// src/player-system.ts
|
|
444
|
+
var SCENE_OBJECT_PLAYER_SYSTEM_INTERFACE_FLAG_ID = "isekai.player-system.interface.enabled";
|
|
445
|
+
var ID_PATTERN2 = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
446
|
+
var ANCHOR_KINDS = /* @__PURE__ */ new Set([
|
|
447
|
+
"target",
|
|
448
|
+
"focus-pane",
|
|
449
|
+
"localized-alert",
|
|
450
|
+
"line-of-sight-popup"
|
|
451
|
+
]);
|
|
452
|
+
var ANCHOR_VISIBILITIES = /* @__PURE__ */ new Set([
|
|
453
|
+
"always",
|
|
454
|
+
"combat-safe",
|
|
455
|
+
"focused-only",
|
|
456
|
+
"line-of-sight"
|
|
457
|
+
]);
|
|
458
|
+
var FOCUS_SCREEN_VARIANTS = /* @__PURE__ */ new Set([
|
|
459
|
+
"single-pane",
|
|
460
|
+
"multi-pane",
|
|
461
|
+
"combat-safe"
|
|
462
|
+
]);
|
|
463
|
+
function pushIssue2(issues, issue) {
|
|
464
|
+
issues.push(issue);
|
|
465
|
+
}
|
|
466
|
+
function isFiniteNumber2(value) {
|
|
467
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
468
|
+
}
|
|
469
|
+
function isKebabId(value) {
|
|
470
|
+
return typeof value === "string" && ID_PATTERN2.test(value);
|
|
471
|
+
}
|
|
472
|
+
function validateKebabId2(value, path, issues) {
|
|
473
|
+
if (typeof value !== "string") {
|
|
474
|
+
pushIssue2(issues, {
|
|
475
|
+
code: "invalid-type",
|
|
476
|
+
path,
|
|
477
|
+
message: "Expected a string identifier."
|
|
478
|
+
});
|
|
479
|
+
return false;
|
|
480
|
+
}
|
|
481
|
+
if (!ID_PATTERN2.test(value)) {
|
|
482
|
+
pushIssue2(issues, {
|
|
483
|
+
code: "invalid-id",
|
|
484
|
+
path,
|
|
485
|
+
message: "Identifiers must be kebab-case tokens."
|
|
486
|
+
});
|
|
487
|
+
return false;
|
|
488
|
+
}
|
|
489
|
+
return true;
|
|
490
|
+
}
|
|
491
|
+
function findObjectPoint(object, pointId) {
|
|
492
|
+
return object?.attachmentPoints?.find((point) => point.id === pointId);
|
|
493
|
+
}
|
|
494
|
+
function validateAnchorDefinition(anchor, path, issues, objectsById, anchorIds) {
|
|
495
|
+
if (!anchor || typeof anchor !== "object") {
|
|
496
|
+
pushIssue2(issues, {
|
|
497
|
+
code: "required",
|
|
498
|
+
path,
|
|
499
|
+
message: "Expected anchor definition object."
|
|
500
|
+
});
|
|
501
|
+
return false;
|
|
502
|
+
}
|
|
503
|
+
const value = anchor;
|
|
504
|
+
let valid = true;
|
|
505
|
+
if (!validateKebabId2(value.id, `${path}.id`, issues)) {
|
|
506
|
+
valid = false;
|
|
507
|
+
} else if (anchorIds.has(value.id)) {
|
|
508
|
+
pushIssue2(issues, {
|
|
509
|
+
code: "duplicate-id",
|
|
510
|
+
path: `${path}.id`,
|
|
511
|
+
message: "Anchor identifiers must be unique."
|
|
512
|
+
});
|
|
513
|
+
valid = false;
|
|
514
|
+
} else {
|
|
515
|
+
anchorIds.add(value.id);
|
|
516
|
+
}
|
|
517
|
+
if (!validateKebabId2(value.objectId, `${path}.objectId`, issues)) {
|
|
518
|
+
valid = false;
|
|
519
|
+
}
|
|
520
|
+
if (!validateKebabId2(value.pointId, `${path}.pointId`, issues)) {
|
|
521
|
+
valid = false;
|
|
522
|
+
}
|
|
523
|
+
if (!ANCHOR_KINDS.has(value.kind)) {
|
|
524
|
+
pushIssue2(issues, {
|
|
525
|
+
code: "invalid-value",
|
|
526
|
+
path: `${path}.kind`,
|
|
527
|
+
message: "Anchor kind must be target, focus-pane, localized-alert, or line-of-sight-popup."
|
|
528
|
+
});
|
|
529
|
+
valid = false;
|
|
530
|
+
}
|
|
531
|
+
if (!ANCHOR_VISIBILITIES.has(value.visibility)) {
|
|
532
|
+
pushIssue2(issues, {
|
|
533
|
+
code: "invalid-value",
|
|
534
|
+
path: `${path}.visibility`,
|
|
535
|
+
message: "Anchor visibility must be always, combat-safe, focused-only, or line-of-sight."
|
|
536
|
+
});
|
|
537
|
+
valid = false;
|
|
538
|
+
}
|
|
539
|
+
const object = typeof value.objectId === "string" ? objectsById.get(value.objectId) : void 0;
|
|
540
|
+
if (!object) {
|
|
541
|
+
pushIssue2(issues, {
|
|
542
|
+
code: "missing-reference",
|
|
543
|
+
path: `${path}.objectId`,
|
|
544
|
+
message: "Anchor objectId must reference an existing scene object."
|
|
545
|
+
});
|
|
546
|
+
valid = false;
|
|
547
|
+
} else if (typeof value.pointId === "string" && !findObjectPoint(object, value.pointId)) {
|
|
548
|
+
pushIssue2(issues, {
|
|
549
|
+
code: "missing-reference",
|
|
550
|
+
path: `${path}.pointId`,
|
|
551
|
+
message: "Anchor pointId must reference an attachment point on the target object."
|
|
552
|
+
});
|
|
553
|
+
valid = false;
|
|
554
|
+
}
|
|
555
|
+
if (value.kind === "localized-alert") {
|
|
556
|
+
if (typeof value.localeKey !== "string" || value.localeKey.trim().length === 0) {
|
|
557
|
+
pushIssue2(issues, {
|
|
558
|
+
code: "required",
|
|
559
|
+
path: `${path}.localeKey`,
|
|
560
|
+
message: "localized-alert anchors require a localeKey."
|
|
561
|
+
});
|
|
562
|
+
valid = false;
|
|
563
|
+
}
|
|
564
|
+
} else if (value.localeKey !== void 0 && (typeof value.localeKey !== "string" || value.localeKey.trim().length === 0)) {
|
|
565
|
+
pushIssue2(issues, {
|
|
566
|
+
code: "invalid-type",
|
|
567
|
+
path: `${path}.localeKey`,
|
|
568
|
+
message: "localeKey must be a non-empty string when present."
|
|
569
|
+
});
|
|
570
|
+
valid = false;
|
|
571
|
+
}
|
|
572
|
+
if (value.offset !== void 0) {
|
|
573
|
+
if (!value.offset || typeof value.offset !== "object") {
|
|
574
|
+
pushIssue2(issues, {
|
|
575
|
+
code: "invalid-type",
|
|
576
|
+
path: `${path}.offset`,
|
|
577
|
+
message: "offset must be a finite x/y/z vector when present."
|
|
578
|
+
});
|
|
579
|
+
valid = false;
|
|
580
|
+
} else {
|
|
581
|
+
for (const axis of ["x", "y", "z"]) {
|
|
582
|
+
if (!isFiniteNumber2(value.offset[axis])) {
|
|
583
|
+
pushIssue2(issues, {
|
|
584
|
+
code: "invalid-type",
|
|
585
|
+
path: `${path}.offset.${axis}`,
|
|
586
|
+
message: "offset axes must be finite numbers."
|
|
587
|
+
});
|
|
588
|
+
valid = false;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
if (value.tags !== void 0) {
|
|
594
|
+
if (!Array.isArray(value.tags) || value.tags.some((tag) => typeof tag !== "string" || tag.trim().length === 0)) {
|
|
595
|
+
pushIssue2(issues, {
|
|
596
|
+
code: "invalid-type",
|
|
597
|
+
path: `${path}.tags`,
|
|
598
|
+
message: "tags must be an array of non-empty strings when present."
|
|
599
|
+
});
|
|
600
|
+
valid = false;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
return valid;
|
|
604
|
+
}
|
|
605
|
+
function validateFocusScreenDefinition(focusScreen, path, issues, objectsById, anchorsById, focusScreenIds) {
|
|
606
|
+
if (!focusScreen || typeof focusScreen !== "object") {
|
|
607
|
+
pushIssue2(issues, {
|
|
608
|
+
code: "required",
|
|
609
|
+
path,
|
|
610
|
+
message: "Expected focus-screen definition object."
|
|
611
|
+
});
|
|
612
|
+
return false;
|
|
613
|
+
}
|
|
614
|
+
const value = focusScreen;
|
|
615
|
+
let valid = true;
|
|
616
|
+
if (!validateKebabId2(value.id, `${path}.id`, issues)) {
|
|
617
|
+
valid = false;
|
|
618
|
+
} else if (focusScreenIds.has(value.id)) {
|
|
619
|
+
pushIssue2(issues, {
|
|
620
|
+
code: "duplicate-id",
|
|
621
|
+
path: `${path}.id`,
|
|
622
|
+
message: "Focus-screen identifiers must be unique."
|
|
623
|
+
});
|
|
624
|
+
valid = false;
|
|
625
|
+
} else {
|
|
626
|
+
focusScreenIds.add(value.id);
|
|
627
|
+
}
|
|
628
|
+
if (!validateKebabId2(value.objectId, `${path}.objectId`, issues)) {
|
|
629
|
+
valid = false;
|
|
630
|
+
} else if (!objectsById.has(value.objectId)) {
|
|
631
|
+
pushIssue2(issues, {
|
|
632
|
+
code: "missing-reference",
|
|
633
|
+
path: `${path}.objectId`,
|
|
634
|
+
message: "Focus-screen objectId must reference an existing scene object."
|
|
635
|
+
});
|
|
636
|
+
valid = false;
|
|
637
|
+
}
|
|
638
|
+
if (!validateKebabId2(value.anchorId, `${path}.anchorId`, issues)) {
|
|
639
|
+
valid = false;
|
|
640
|
+
} else {
|
|
641
|
+
const anchor = anchorsById.get(value.anchorId);
|
|
642
|
+
if (!anchor) {
|
|
643
|
+
pushIssue2(issues, {
|
|
644
|
+
code: "missing-reference",
|
|
645
|
+
path: `${path}.anchorId`,
|
|
646
|
+
message: "Focus-screen anchorId must reference an exported anchor."
|
|
647
|
+
});
|
|
648
|
+
valid = false;
|
|
649
|
+
} else if (anchor.kind !== "focus-pane") {
|
|
650
|
+
pushIssue2(issues, {
|
|
651
|
+
code: "invalid-reference",
|
|
652
|
+
path: `${path}.anchorId`,
|
|
653
|
+
message: "Focus screens must bind to focus-pane anchors."
|
|
654
|
+
});
|
|
655
|
+
valid = false;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
if (!validateKebabId2(value.paneId, `${path}.paneId`, issues)) {
|
|
659
|
+
valid = false;
|
|
660
|
+
}
|
|
661
|
+
if (!FOCUS_SCREEN_VARIANTS.has(value.variant)) {
|
|
662
|
+
pushIssue2(issues, {
|
|
663
|
+
code: "invalid-value",
|
|
664
|
+
path: `${path}.variant`,
|
|
665
|
+
message: "Focus-screen variant must be single-pane, multi-pane, or combat-safe."
|
|
666
|
+
});
|
|
667
|
+
valid = false;
|
|
668
|
+
}
|
|
669
|
+
if (value.headingKey !== void 0 && (typeof value.headingKey !== "string" || value.headingKey.trim().length === 0)) {
|
|
670
|
+
pushIssue2(issues, {
|
|
671
|
+
code: "invalid-type",
|
|
672
|
+
path: `${path}.headingKey`,
|
|
673
|
+
message: "headingKey must be a non-empty string when present."
|
|
674
|
+
});
|
|
675
|
+
valid = false;
|
|
676
|
+
}
|
|
677
|
+
return valid;
|
|
678
|
+
}
|
|
679
|
+
function validateSceneObjectPlayerSystemManifest(manifest) {
|
|
680
|
+
const base = validateSceneObjectManifest(manifest);
|
|
681
|
+
if (!base.valid || !base.value) {
|
|
682
|
+
return base;
|
|
683
|
+
}
|
|
684
|
+
const issues = [...base.issues];
|
|
685
|
+
const value = manifest;
|
|
686
|
+
const objectsById = new Map(
|
|
687
|
+
base.value.objects.map((object) => [object.id, object])
|
|
688
|
+
);
|
|
689
|
+
const anchorIds = /* @__PURE__ */ new Set();
|
|
690
|
+
const anchorsById = /* @__PURE__ */ new Map();
|
|
691
|
+
const focusScreenIds = /* @__PURE__ */ new Set();
|
|
692
|
+
let valid = true;
|
|
693
|
+
if (value.anchors !== void 0) {
|
|
694
|
+
if (!Array.isArray(value.anchors)) {
|
|
695
|
+
pushIssue2(issues, {
|
|
696
|
+
code: "invalid-type",
|
|
697
|
+
path: "$.anchors",
|
|
698
|
+
message: "anchors must be an array when present."
|
|
699
|
+
});
|
|
700
|
+
valid = false;
|
|
701
|
+
} else {
|
|
702
|
+
value.anchors.forEach((anchor, index) => {
|
|
703
|
+
const path = `$.anchors[${index}]`;
|
|
704
|
+
if (validateAnchorDefinition(anchor, path, issues, objectsById, anchorIds)) {
|
|
705
|
+
anchorsById.set(anchor.id, anchor);
|
|
706
|
+
} else {
|
|
707
|
+
valid = false;
|
|
708
|
+
}
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
if (value.focusScreens !== void 0) {
|
|
713
|
+
if (!Array.isArray(value.focusScreens)) {
|
|
714
|
+
pushIssue2(issues, {
|
|
715
|
+
code: "invalid-type",
|
|
716
|
+
path: "$.focusScreens",
|
|
717
|
+
message: "focusScreens must be an array when present."
|
|
718
|
+
});
|
|
719
|
+
valid = false;
|
|
720
|
+
} else {
|
|
721
|
+
value.focusScreens.forEach((focusScreen, index) => {
|
|
722
|
+
if (!validateFocusScreenDefinition(
|
|
723
|
+
focusScreen,
|
|
724
|
+
`$.focusScreens[${index}]`,
|
|
725
|
+
issues,
|
|
726
|
+
objectsById,
|
|
727
|
+
anchorsById,
|
|
728
|
+
focusScreenIds
|
|
729
|
+
)) {
|
|
730
|
+
valid = false;
|
|
731
|
+
}
|
|
732
|
+
});
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
return {
|
|
736
|
+
valid,
|
|
737
|
+
issues,
|
|
738
|
+
value: valid ? value : void 0
|
|
739
|
+
};
|
|
740
|
+
}
|
|
741
|
+
function resolveSceneObjectAnchorById(manifest, anchorId) {
|
|
742
|
+
if (!isKebabId(anchorId)) {
|
|
743
|
+
return void 0;
|
|
744
|
+
}
|
|
745
|
+
return manifest.anchors?.find((anchor) => anchor.id === anchorId);
|
|
746
|
+
}
|
|
747
|
+
function resolveSceneObjectFocusScreenById(manifest, focusScreenId) {
|
|
748
|
+
if (!isKebabId(focusScreenId)) {
|
|
749
|
+
return void 0;
|
|
750
|
+
}
|
|
751
|
+
return manifest.focusScreens?.find((focusScreen) => focusScreen.id === focusScreenId);
|
|
752
|
+
}
|
|
753
|
+
|
|
439
754
|
// src/resolve.ts
|
|
440
755
|
function resolveSceneObjectState(manifest, objectId) {
|
|
441
756
|
if (!manifest.stateSnapshots || !Array.isArray(manifest.stateSnapshots)) {
|
|
@@ -447,13 +762,17 @@ function resolveSceneObjectState(manifest, objectId) {
|
|
|
447
762
|
}
|
|
448
763
|
// Annotate the CommonJS export names for ESM import in node:
|
|
449
764
|
0 && (module.exports = {
|
|
765
|
+
SCENE_OBJECT_PLAYER_SYSTEM_INTERFACE_FLAG_ID,
|
|
450
766
|
SCENE_OBJECT_RUNTIME_FLAG_ID,
|
|
451
767
|
SCENE_OBJECT_SCHEMA_VERSION,
|
|
452
768
|
createSceneObjectManifest,
|
|
769
|
+
resolveSceneObjectAnchorById,
|
|
453
770
|
resolveSceneObjectById,
|
|
771
|
+
resolveSceneObjectFocusScreenById,
|
|
454
772
|
resolveSceneObjectReferences,
|
|
455
773
|
resolveSceneObjectState,
|
|
456
774
|
validateSceneObjectManifest,
|
|
457
|
-
validateSceneObjectObjectState
|
|
775
|
+
validateSceneObjectObjectState,
|
|
776
|
+
validateSceneObjectPlayerSystemManifest
|
|
458
777
|
});
|
|
459
778
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/types.ts","../src/validation.ts","../src/resolve.ts"],"sourcesContent":["export {\n SCENE_OBJECT_RUNTIME_FLAG_ID,\n SCENE_OBJECT_SCHEMA_VERSION,\n type SceneObjectAttachment,\n type SceneObjectAttachmentPoint,\n type SceneObjectBounds,\n type SceneObjectManifest,\n type SceneObjectObjectState,\n type SceneObjectPoint,\n type SceneObjectReference,\n type SceneObjectResolutionRequest,\n type SceneObjectResolutionResult,\n type SceneObjectStateKind,\n type SceneObjectTransform,\n type SceneObjectValidationIssue,\n type SceneObjectValidationResult,\n type SceneObjectVector3,\n} from \"./types.js\";\nexport {\n createSceneObjectManifest,\n resolveSceneObjectById,\n resolveSceneObjectReferences,\n validateSceneObjectManifest,\n validateSceneObjectObjectState,\n} from \"./validation.js\";\nexport { resolveSceneObjectState } from \"./resolve.js\";\n","export const SCENE_OBJECT_SCHEMA_VERSION = \"1.0.0\";\nexport const SCENE_OBJECT_RUNTIME_FLAG_ID = \"scene.object.runtime.enabled\";\n\nexport type SceneObjectStateKind = \"idle\" | \"visible\" | \"hidden\" | \"disabled\";\n\nexport type SceneObjectCoordinateSpace =\n | \"normalized-viewport\"\n | \"pixel-viewport\"\n | \"world\"\n | \"local\";\n\nexport type SceneObjectUnits = \"ratio\" | \"pixels\";\n\nexport interface SceneObjectVector3 {\n x: number;\n y: number;\n z: number;\n}\n\nexport interface SceneObjectTransform {\n translate: SceneObjectVector3;\n rotate: SceneObjectVector3;\n scale: SceneObjectVector3;\n}\n\nexport interface SceneObjectBounds {\n rect: {\n x: number;\n y: number;\n width: number;\n height: number;\n unit: SceneObjectUnits;\n };\n depth?: number;\n coordinateSpace: SceneObjectCoordinateSpace;\n}\n\nexport interface SceneObjectPoint {\n id: string;\n x: number;\n y: number;\n z?: number;\n}\n\nexport interface SceneObjectAttachment {\n id: string;\n sourceObjectId: string;\n sourcePointId: string;\n targetObjectId: string;\n targetPointId: string;\n offset?: SceneObjectVector3;\n}\n\nexport type SceneObjectAttachmentPoint = SceneObjectPoint;\n\nexport interface SceneObjectObjectState {\n objectId: string;\n visible: boolean;\n tags?: string[];\n metadata?: Record<string, unknown>;\n}\n\nexport interface SceneObjectReference {\n objectId: string;\n pointId: string;\n}\n\nexport interface SceneObjectManifest {\n schemaVersion: string;\n objects: SceneObjectDefinition[];\n stateSnapshots?: SceneObjectObjectState[];\n}\n\nexport interface SceneObjectDefinition {\n id: string;\n name?: string;\n transform: SceneObjectTransform;\n bounds: SceneObjectBounds;\n attachmentPoints?: SceneObjectPoint[];\n attachments?: SceneObjectAttachment[];\n}\n\nexport type SceneObjectValidationCode =\n | \"required\"\n | \"invalid-type\"\n | \"invalid-value\"\n | \"invalid-id\"\n | \"duplicate-id\"\n | \"invalid-reference\"\n | \"missing-reference\";\n\nexport interface SceneObjectValidationIssue {\n code: SceneObjectValidationCode;\n path: string;\n message: string;\n}\n\nexport interface SceneObjectValidationResult<T> {\n valid: boolean;\n issues: SceneObjectValidationIssue[];\n value?: T;\n}\n\nexport interface SceneObjectResolutionRequest {\n manifest: SceneObjectManifest;\n objectId: string;\n}\n\nexport interface SceneObjectResolutionResult {\n manifest: SceneObjectManifest;\n object: SceneObjectDefinition;\n}\n","import {\n SCENE_OBJECT_SCHEMA_VERSION,\n type SceneObjectBounds,\n type SceneObjectCoordinateSpace,\n type SceneObjectManifest,\n type SceneObjectObjectState,\n type SceneObjectPoint,\n type SceneObjectValidationIssue,\n type SceneObjectValidationResult,\n type SceneObjectDefinition,\n type SceneObjectAttachment,\n type SceneObjectResolutionRequest,\n type SceneObjectTransform,\n} from \"./types.js\";\n\nconst ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\nconst COORDINATE_SPACES = new Set<SceneObjectCoordinateSpace>([\n \"normalized-viewport\",\n \"pixel-viewport\",\n \"world\",\n \"local\",\n]);\nconst UNITS = new Set([\"ratio\", \"pixels\"]);\n\nfunction pushIssue(\n issues: SceneObjectValidationIssue[],\n issue: SceneObjectValidationIssue,\n): void {\n issues.push(issue);\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\nfunction validateKebabId(\n value: unknown,\n path: string,\n issues: SceneObjectValidationIssue[],\n): value is string {\n if (typeof value !== \"string\") {\n pushIssue(issues, {\n code: \"invalid-type\",\n path,\n message: \"Expected a string identifier.\",\n });\n return false;\n }\n\n if (!ID_PATTERN.test(value)) {\n pushIssue(issues, {\n code: \"invalid-id\",\n path,\n message: \"Identifiers must be kebab-case tokens.\",\n });\n return false;\n }\n\n return true;\n}\n\nfunction validateTransform(\n value: SceneObjectTransform,\n path: string,\n issues: SceneObjectValidationIssue[],\n): boolean {\n const vectorChecks = [\"translate\", \"rotate\", \"scale\"] as const;\n let valid = true;\n\n for (const field of vectorChecks) {\n const vector = value[field];\n if (!vector || typeof vector !== \"object\") {\n pushIssue(issues, {\n code: \"required\",\n path: `${path}.${field}`,\n message: `Expected a ${field} vector.`,\n });\n valid = false;\n continue;\n }\n\n for (const axis of [\"x\", \"y\", \"z\"] as const) {\n const raw = vector[axis];\n if (!isFiniteNumber(raw)) {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.${field}.${axis}`,\n message: `Vector ${axis} must be finite.`,\n });\n valid = false;\n }\n }\n }\n\n return valid;\n}\n\nfunction validatePoint(point: SceneObjectPoint, path: string, issues: SceneObjectValidationIssue[]): boolean {\n let valid = true;\n\n if (!validateKebabId(point.id, `${path}.id`, issues)) {\n valid = false;\n }\n\n for (const field of [\"x\", \"y\", \"z\"] as const) {\n const value = point[field];\n if (field === \"z\" && value === undefined) {\n continue;\n }\n if (!isFiniteNumber(value)) {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.${field}`,\n message: \"Attachment point axis must be finite.\",\n });\n valid = false;\n }\n }\n\n return valid;\n}\n\nfunction validateBounds(bounds: SceneObjectBounds, path: string, issues: SceneObjectValidationIssue[]): boolean {\n if (!bounds || typeof bounds !== \"object\") {\n pushIssue(issues, { code: \"required\", path, message: \"Expected bounds block.\" });\n return false;\n }\n\n if (!COORDINATE_SPACES.has(bounds.coordinateSpace as SceneObjectCoordinateSpace)) {\n pushIssue(issues, {\n code: \"invalid-value\",\n path: `${path}.coordinateSpace`,\n message: \"coordinateSpace must be normalized-viewport, pixel-viewport, world, or local.\",\n });\n return false;\n }\n\n const rect = bounds.rect;\n if (!rect || typeof rect !== \"object\") {\n pushIssue(issues, { code: \"required\", path: `${path}.rect`, message: \"Expected rect bounds.\" });\n return false;\n }\n\n if (!UNITS.has(rect.unit as string)) {\n pushIssue(issues, {\n code: \"invalid-value\",\n path: `${path}.rect.unit`,\n message: \"unit must be 'ratio' or 'pixels'.\",\n });\n return false;\n }\n\n let valid = true;\n for (const field of [\"x\", \"y\", \"width\", \"height\"] as const) {\n const value = rect[field];\n if (!isFiniteNumber(value) || value < 0) {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.rect.${field}`,\n message: \"Rect fields must be finite non-negative numbers.\",\n });\n valid = false;\n }\n }\n\n if (rect.width === 0 || rect.height === 0) {\n pushIssue(issues, {\n code: \"invalid-value\",\n path: `${path}.rect`,\n message: \"Rect width and height must be positive.\",\n });\n valid = false;\n }\n\n if (bounds.depth !== undefined && (!isFiniteNumber(bounds.depth) || bounds.depth < 0)) {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.depth`,\n message: \"depth must be a non-negative number.\",\n });\n valid = false;\n }\n\n return valid && isFiniteNumber(bounds.rect.width) && isFiniteNumber(bounds.rect.height);\n}\n\nfunction validateAttachmentTarget(\n attachment: {\n id: string;\n sourceObjectId: string;\n sourcePointId: string;\n targetObjectId: string;\n targetPointId: string;\n },\n path: string,\n issues: SceneObjectValidationIssue[],\n seenPoints: Map<string, Set<string>>,\n): boolean {\n let valid = true;\n if (!validateKebabId(attachment.id, `${path}.id`, issues)) {\n valid = false;\n }\n\n if (!validateKebabId(attachment.sourceObjectId, `${path}.sourceObjectId`, issues)) {\n valid = false;\n }\n\n if (!validateKebabId(attachment.targetObjectId, `${path}.targetObjectId`, issues)) {\n valid = false;\n }\n\n if (!validateKebabId(attachment.sourcePointId, `${path}.sourcePointId`, issues)) {\n valid = false;\n }\n\n if (!validateKebabId(attachment.targetPointId, `${path}.targetPointId`, issues)) {\n valid = false;\n }\n\n const sourcePoints = seenPoints.get(attachment.sourceObjectId);\n const targetPoints = seenPoints.get(attachment.targetObjectId);\n\n if (sourcePoints && !sourcePoints.has(attachment.sourcePointId)) {\n pushIssue(issues, {\n code: \"invalid-reference\",\n path: `${path}.sourcePointId`,\n message: \"sourcePointId does not exist on source object.\",\n });\n valid = false;\n }\n\n if (targetPoints && !targetPoints.has(attachment.targetPointId)) {\n pushIssue(issues, {\n code: \"invalid-reference\",\n path: `${path}.targetPointId`,\n message: \"targetPointId does not exist on target object.\",\n });\n valid = false;\n }\n\n return valid;\n}\n\nexport function validateSceneObjectManifest(\n manifest: unknown,\n): SceneObjectValidationResult<SceneObjectManifest> {\n const issues: SceneObjectValidationIssue[] = [];\n\n if (!manifest || typeof manifest !== \"object\") {\n return {\n valid: false,\n issues: [{ code: \"required\", path: \"$\", message: \"Expected a scene object manifest object.\" }],\n };\n }\n\n const value = manifest as Record<string, unknown>;\n let valid = true;\n\n if (value.schemaVersion !== SCENE_OBJECT_SCHEMA_VERSION) {\n pushIssue(issues, {\n code: \"invalid-value\",\n path: \"$.schemaVersion\",\n message: `schemaVersion must equal ${SCENE_OBJECT_SCHEMA_VERSION}.`,\n });\n valid = false;\n }\n\n if (!Array.isArray(value.objects) || value.objects.length === 0) {\n pushIssue(issues, {\n code: \"required\",\n path: \"$.objects\",\n message: \"Manifest must contain at least one object.\",\n });\n return { valid: false, issues };\n }\n\n const objects = value.objects as SceneObjectDefinition[];\n const seenObjects = new Set<string>();\n const pointsByObject = new Map<string, Set<string>>();\n\n for (const [index, object] of objects.entries()) {\n const path = `$.objects[${index}]`;\n\n if (!object || typeof object !== \"object\") {\n pushIssue(issues, { code: \"required\", path, message: \"Expected object definition.\" });\n valid = false;\n continue;\n }\n\n if (!validateKebabId(object.id, `${path}.id`, issues)) {\n valid = false;\n }\n\n if (seenObjects.has(object.id)) {\n pushIssue(issues, {\n code: \"duplicate-id\",\n path: `${path}.id`,\n message: `Duplicate object id '${object.id}' is not allowed.`,\n });\n valid = false;\n }\n seenObjects.add(object.id);\n\n if (!object.transform || typeof object.transform !== \"object\" || !validateTransform(object.transform as SceneObjectTransform, `${path}.transform`, issues)) {\n pushIssue(issues, {\n code: \"required\",\n path: `${path}.transform`,\n message: \"Object must define a transform.\",\n });\n valid = false;\n }\n\n if (!object.bounds) {\n pushIssue(issues, {\n code: \"required\",\n path: `${path}.bounds`,\n message: \"Object must define bounds.\",\n });\n valid = false;\n } else if (!validateBounds(object.bounds, `${path}.bounds`, issues)) {\n valid = false;\n }\n\n const attachmentPointIds = new Set<string>();\n const rawPoints = Array.isArray(object.attachmentPoints)\n ? object.attachmentPoints\n : [];\n for (const [pointIndex, point] of rawPoints.entries()) {\n if (!point || typeof point !== \"object\") {\n pushIssue(issues, {\n code: \"required\",\n path: `${path}.attachmentPoints[${pointIndex}]`,\n message: \"Expected attachment point definition.\",\n });\n valid = false;\n continue;\n }\n\n if (!validatePoint(point as SceneObjectPoint, `${path}.attachmentPoints[${pointIndex}]`, issues)) {\n valid = false;\n continue;\n }\n\n const pointId = (point as SceneObjectPoint).id;\n if (attachmentPointIds.has(pointId)) {\n pushIssue(issues, {\n code: \"duplicate-id\",\n path: `${path}.attachmentPoints[${pointIndex}].id`,\n message: `Duplicate attachment point '${pointId}' within object.`,\n });\n valid = false;\n }\n attachmentPointIds.add(pointId);\n }\n\n if (rawPoints.length > 0) {\n pointsByObject.set(object.id, attachmentPointIds);\n }\n\n if (Array.isArray(object.attachments)) {\n const attachmentIds = new Set<string>();\n for (const [attachmentIndex, attachment] of object.attachments.entries()) {\n if (!attachment || typeof attachment !== \"object\") {\n pushIssue(issues, {\n code: \"required\",\n path: `${path}.attachments[${attachmentIndex}]`,\n message: \"Expected attachment definition.\",\n });\n valid = false;\n continue;\n }\n\n if (!validateKebabId((attachment as SceneObjectAttachment).sourceObjectId, `${path}.attachments[${attachmentIndex}].sourceObjectId`, issues)) {\n valid = false;\n }\n\n if (!attachmentIds.has((attachment as { id?: string }).id ?? \"\")) {\n attachmentIds.add((attachment as { id?: string }).id ?? \"\");\n } else {\n pushIssue(issues, {\n code: \"duplicate-id\",\n path: `${path}.attachments[${attachmentIndex}].id`,\n message: \"Duplicate attachment id.\",\n });\n valid = false;\n }\n\n if (\n !validateAttachmentTarget(\n attachment as {\n id: string;\n sourceObjectId: string;\n sourcePointId: string;\n targetObjectId: string;\n targetPointId: string;\n },\n `${path}.attachments[${attachmentIndex}]`,\n issues,\n pointsByObject,\n )\n ) {\n valid = false;\n }\n }\n }\n }\n\n const objectIds = new Set(\n objects\n .filter((candidate): candidate is SceneObjectDefinition => Boolean(candidate && typeof candidate === \"object\"))\n .map((candidate) => candidate.id),\n );\n if (Array.isArray(value.stateSnapshots)) {\n for (const [stateIndex, state] of value.stateSnapshots.entries()) {\n const stateValue = state as SceneObjectObjectState;\n const path = `$.stateSnapshots[${stateIndex}]`;\n\n if (!stateValue || typeof stateValue !== \"object\") {\n pushIssue(issues, {\n code: \"required\",\n path,\n message: \"Expected object state definition.\",\n });\n valid = false;\n continue;\n }\n\n if (!validateKebabId(stateValue.objectId, `${path}.objectId`, issues)) {\n valid = false;\n }\n\n if (!objectIds.has(stateValue.objectId)) {\n pushIssue(issues, {\n code: \"missing-reference\",\n path: `${path}.objectId`,\n message: \"objectId does not reference an object in objects.\",\n });\n valid = false;\n }\n\n if (typeof stateValue.visible !== \"boolean\") {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.visible`,\n message: \"visible must be a boolean.\",\n });\n valid = false;\n }\n }\n }\n\n return valid\n ? { valid: true, issues, value: manifest as SceneObjectManifest }\n : { valid: false, issues };\n}\n\nexport function createSceneObjectManifest(manifest: SceneObjectManifest): SceneObjectManifest {\n const result = validateSceneObjectManifest(manifest);\n if (!result.valid || !result.value) {\n const summary = result.issues.map((issue) => `${issue.path}: ${issue.message}`).join(\"; \");\n throw new Error(`Invalid scene object manifest. ${summary}`);\n }\n\n return result.value;\n}\n\nexport function validateSceneObjectObjectState(state: unknown): SceneObjectValidationResult<SceneObjectObjectState> {\n if (!state || typeof state !== \"object\") {\n return {\n valid: false,\n issues: [{\n code: \"required\",\n path: \"$\",\n message: \"Expected an object state.\",\n }],\n };\n }\n\n const value = state as Record<string, unknown>;\n const issues: SceneObjectValidationIssue[] = [];\n let valid = true;\n\n if (!validateKebabId(value.objectId, \"$.objectId\", issues)) {\n valid = false;\n }\n\n if (typeof value.visible !== \"boolean\") {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: \"$.visible\",\n message: \"visible must be a boolean.\",\n });\n valid = false;\n }\n\n return valid\n ? { valid: true, issues, value: state as SceneObjectObjectState }\n : { valid: false, issues };\n}\n\nexport function resolveSceneObjectReferences(\n manifest: SceneObjectManifest,\n): SceneObjectValidationResult<SceneObjectManifest> {\n const result = validateSceneObjectManifest(manifest);\n if (!result.valid || !result.value) {\n return { valid: false, issues: result.issues };\n }\n\n return { valid: true, issues: [], value: result.value };\n}\n\nexport function resolveSceneObjectById(\n requestOrManifest:\n | SceneObjectResolutionRequest\n | SceneObjectManifest,\n objectId?: string,\n): SceneObjectDefinition | undefined {\n const request: SceneObjectResolutionRequest = typeof objectId === \"string\"\n ? {\n manifest: requestOrManifest as SceneObjectManifest,\n objectId,\n }\n : requestOrManifest as SceneObjectResolutionRequest;\n\n const result = validateSceneObjectManifest(request.manifest);\n if (!result.valid || !result.value) {\n return undefined;\n }\n\n return result.value.objects.find((object) => object.id === request.objectId);\n}\n","import {\n SceneObjectManifest,\n SceneObjectObjectState,\n SceneObjectDefinition,\n} from \"./types.js\";\n\nexport function resolveSceneObjectState(\n manifest: SceneObjectManifest,\n objectId: string,\n): SceneObjectObjectState | undefined {\n if (!manifest.stateSnapshots || !Array.isArray(manifest.stateSnapshots)) {\n return undefined;\n }\n\n return manifest.stateSnapshots.find(\n (snapshot) => snapshot.objectId === objectId,\n );\n}\n\nexport function resolveSceneObjectById(\n manifest: SceneObjectManifest,\n objectId: string,\n): SceneObjectDefinition | undefined {\n return manifest.objects.find((object) => object.id === objectId);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAO,IAAM,8BAA8B;AACpC,IAAM,+BAA+B;;;ACc5C,IAAM,aAAa;AACnB,IAAM,oBAAoB,oBAAI,IAAgC;AAAA,EAC5D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AACD,IAAM,QAAQ,oBAAI,IAAI,CAAC,SAAS,QAAQ,CAAC;AAEzC,SAAS,UACP,QACA,OACM;AACN,SAAO,KAAK,KAAK;AACnB;AAEA,SAAS,eAAe,OAAiC;AACvD,SAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK;AAC3D;AAEA,SAAS,gBACP,OACA,MACA,QACiB;AACjB,MAAI,OAAO,UAAU,UAAU;AAC7B,cAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN;AAAA,MACA,SAAS;AAAA,IACX,CAAC;AACD,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,WAAW,KAAK,KAAK,GAAG;AAC3B,cAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN;AAAA,MACA,SAAS;AAAA,IACX,CAAC;AACD,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,kBACP,OACA,MACA,QACS;AACT,QAAM,eAAe,CAAC,aAAa,UAAU,OAAO;AACpD,MAAI,QAAQ;AAEZ,aAAW,SAAS,cAAc;AAChC,UAAM,SAAS,MAAM,KAAK;AAC1B,QAAI,CAAC,UAAU,OAAO,WAAW,UAAU;AACzC,gBAAU,QAAQ;AAAA,QAChB,MAAM;AAAA,QACN,MAAM,GAAG,IAAI,IAAI,KAAK;AAAA,QACtB,SAAS,cAAc,KAAK;AAAA,MAC9B,CAAC;AACD,cAAQ;AACR;AAAA,IACF;AAEA,eAAW,QAAQ,CAAC,KAAK,KAAK,GAAG,GAAY;AAC3C,YAAM,MAAM,OAAO,IAAI;AACvB,UAAI,CAAC,eAAe,GAAG,GAAG;AACxB,kBAAU,QAAQ;AAAA,UAChB,MAAM;AAAA,UACN,MAAM,GAAG,IAAI,IAAI,KAAK,IAAI,IAAI;AAAA,UAC9B,SAAS,UAAU,IAAI;AAAA,QACzB,CAAC;AACD,gBAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,cAAc,OAAyB,MAAc,QAA+C;AAC3G,MAAI,QAAQ;AAEZ,MAAI,CAAC,gBAAgB,MAAM,IAAI,GAAG,IAAI,OAAO,MAAM,GAAG;AACpD,YAAQ;AAAA,EACV;AAEA,aAAW,SAAS,CAAC,KAAK,KAAK,GAAG,GAAY;AAC5C,UAAM,QAAQ,MAAM,KAAK;AACzB,QAAI,UAAU,OAAO,UAAU,QAAW;AACxC;AAAA,IACF;AACA,QAAI,CAAC,eAAe,KAAK,GAAG;AAC1B,gBAAU,QAAQ;AAAA,QAChB,MAAM;AAAA,QACN,MAAM,GAAG,IAAI,IAAI,KAAK;AAAA,QACtB,SAAS;AAAA,MACX,CAAC;AACD,cAAQ;AAAA,IACV;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,eAAe,QAA2B,MAAc,QAA+C;AAC9G,MAAI,CAAC,UAAU,OAAO,WAAW,UAAU;AACzC,cAAU,QAAQ,EAAE,MAAM,YAAY,MAAM,SAAS,yBAAyB,CAAC;AAC/E,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,kBAAkB,IAAI,OAAO,eAA6C,GAAG;AAChF,cAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,MAAM,GAAG,IAAI;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AACD,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,OAAO;AACpB,MAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,cAAU,QAAQ,EAAE,MAAM,YAAY,MAAM,GAAG,IAAI,SAAS,SAAS,wBAAwB,CAAC;AAC9F,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,MAAM,IAAI,KAAK,IAAc,GAAG;AACnC,cAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,MAAM,GAAG,IAAI;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AACD,WAAO;AAAA,EACT;AAEA,MAAI,QAAQ;AACZ,aAAW,SAAS,CAAC,KAAK,KAAK,SAAS,QAAQ,GAAY;AAC1D,UAAM,QAAQ,KAAK,KAAK;AACxB,QAAI,CAAC,eAAe,KAAK,KAAK,QAAQ,GAAG;AACvC,gBAAU,QAAQ;AAAA,QAChB,MAAM;AAAA,QACN,MAAM,GAAG,IAAI,SAAS,KAAK;AAAA,QAC3B,SAAS;AAAA,MACX,CAAC;AACD,cAAQ;AAAA,IACV;AAAA,EACF;AAEA,MAAI,KAAK,UAAU,KAAK,KAAK,WAAW,GAAG;AACzC,cAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,MAAM,GAAG,IAAI;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AACD,YAAQ;AAAA,EACV;AAEA,MAAI,OAAO,UAAU,WAAc,CAAC,eAAe,OAAO,KAAK,KAAK,OAAO,QAAQ,IAAI;AACrF,cAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,MAAM,GAAG,IAAI;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AACD,YAAQ;AAAA,EACV;AAEA,SAAO,SAAS,eAAe,OAAO,KAAK,KAAK,KAAK,eAAe,OAAO,KAAK,MAAM;AACxF;AAEA,SAAS,yBACP,YAOA,MACA,QACA,YACS;AACT,MAAI,QAAQ;AACZ,MAAI,CAAC,gBAAgB,WAAW,IAAI,GAAG,IAAI,OAAO,MAAM,GAAG;AACzD,YAAQ;AAAA,EACV;AAEA,MAAI,CAAC,gBAAgB,WAAW,gBAAgB,GAAG,IAAI,mBAAmB,MAAM,GAAG;AACjF,YAAQ;AAAA,EACV;AAEA,MAAI,CAAC,gBAAgB,WAAW,gBAAgB,GAAG,IAAI,mBAAmB,MAAM,GAAG;AACjF,YAAQ;AAAA,EACV;AAEA,MAAI,CAAC,gBAAgB,WAAW,eAAe,GAAG,IAAI,kBAAkB,MAAM,GAAG;AAC/E,YAAQ;AAAA,EACV;AAEA,MAAI,CAAC,gBAAgB,WAAW,eAAe,GAAG,IAAI,kBAAkB,MAAM,GAAG;AAC/E,YAAQ;AAAA,EACV;AAEA,QAAM,eAAe,WAAW,IAAI,WAAW,cAAc;AAC7D,QAAM,eAAe,WAAW,IAAI,WAAW,cAAc;AAE7D,MAAI,gBAAgB,CAAC,aAAa,IAAI,WAAW,aAAa,GAAG;AAC/D,cAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,MAAM,GAAG,IAAI;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AACD,YAAQ;AAAA,EACV;AAEA,MAAI,gBAAgB,CAAC,aAAa,IAAI,WAAW,aAAa,GAAG;AAC/D,cAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,MAAM,GAAG,IAAI;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AACD,YAAQ;AAAA,EACV;AAEA,SAAO;AACT;AAEO,SAAS,4BACd,UACkD;AAClD,QAAM,SAAuC,CAAC;AAE9C,MAAI,CAAC,YAAY,OAAO,aAAa,UAAU;AAC7C,WAAO;AAAA,MACL,OAAO;AAAA,MACP,QAAQ,CAAC,EAAE,MAAM,YAAY,MAAM,KAAK,SAAS,2CAA2C,CAAC;AAAA,IAC/F;AAAA,EACF;AAEA,QAAM,QAAQ;AACd,MAAI,QAAQ;AAEZ,MAAI,MAAM,kBAAkB,6BAA6B;AACvD,cAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,4BAA4B,2BAA2B;AAAA,IAClE,CAAC;AACD,YAAQ;AAAA,EACV;AAEA,MAAI,CAAC,MAAM,QAAQ,MAAM,OAAO,KAAK,MAAM,QAAQ,WAAW,GAAG;AAC/D,cAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,IACX,CAAC;AACD,WAAO,EAAE,OAAO,OAAO,OAAO;AAAA,EAChC;AAEA,QAAM,UAAU,MAAM;AACtB,QAAM,cAAc,oBAAI,IAAY;AACpC,QAAM,iBAAiB,oBAAI,IAAyB;AAEpD,aAAW,CAAC,OAAO,MAAM,KAAK,QAAQ,QAAQ,GAAG;AAC/C,UAAM,OAAO,aAAa,KAAK;AAE/B,QAAI,CAAC,UAAU,OAAO,WAAW,UAAU;AACzC,gBAAU,QAAQ,EAAE,MAAM,YAAY,MAAM,SAAS,8BAA8B,CAAC;AACpF,cAAQ;AACR;AAAA,IACF;AAEA,QAAI,CAAC,gBAAgB,OAAO,IAAI,GAAG,IAAI,OAAO,MAAM,GAAG;AACrD,cAAQ;AAAA,IACV;AAEA,QAAI,YAAY,IAAI,OAAO,EAAE,GAAG;AAC9B,gBAAU,QAAQ;AAAA,QAChB,MAAM;AAAA,QACN,MAAM,GAAG,IAAI;AAAA,QACb,SAAS,wBAAwB,OAAO,EAAE;AAAA,MAC5C,CAAC;AACD,cAAQ;AAAA,IACV;AACA,gBAAY,IAAI,OAAO,EAAE;AAEzB,QAAI,CAAC,OAAO,aAAa,OAAO,OAAO,cAAc,YAAY,CAAC,kBAAkB,OAAO,WAAmC,GAAG,IAAI,cAAc,MAAM,GAAG;AAC1J,gBAAU,QAAQ;AAAA,QAChB,MAAM;AAAA,QACN,MAAM,GAAG,IAAI;AAAA,QACb,SAAS;AAAA,MACX,CAAC;AACD,cAAQ;AAAA,IACV;AAEA,QAAI,CAAC,OAAO,QAAQ;AAClB,gBAAU,QAAQ;AAAA,QAChB,MAAM;AAAA,QACN,MAAM,GAAG,IAAI;AAAA,QACb,SAAS;AAAA,MACX,CAAC;AACD,cAAQ;AAAA,IACV,WAAW,CAAC,eAAe,OAAO,QAAQ,GAAG,IAAI,WAAW,MAAM,GAAG;AACnE,cAAQ;AAAA,IACV;AAEA,UAAM,qBAAqB,oBAAI,IAAY;AAC3C,UAAM,YAAY,MAAM,QAAQ,OAAO,gBAAgB,IACnD,OAAO,mBACP,CAAC;AACL,eAAW,CAAC,YAAY,KAAK,KAAK,UAAU,QAAQ,GAAG;AACrD,UAAI,CAAC,SAAS,OAAO,UAAU,UAAU;AACvC,kBAAU,QAAQ;AAAA,UAChB,MAAM;AAAA,UACN,MAAM,GAAG,IAAI,qBAAqB,UAAU;AAAA,UAC5C,SAAS;AAAA,QACX,CAAC;AACD,gBAAQ;AACR;AAAA,MACF;AAEA,UAAI,CAAC,cAAc,OAA2B,GAAG,IAAI,qBAAqB,UAAU,KAAK,MAAM,GAAG;AAChG,gBAAQ;AACR;AAAA,MACF;AAEA,YAAM,UAAW,MAA2B;AAC5C,UAAI,mBAAmB,IAAI,OAAO,GAAG;AACnC,kBAAU,QAAQ;AAAA,UAChB,MAAM;AAAA,UACN,MAAM,GAAG,IAAI,qBAAqB,UAAU;AAAA,UAC5C,SAAS,+BAA+B,OAAO;AAAA,QACjD,CAAC;AACD,gBAAQ;AAAA,MACV;AACA,yBAAmB,IAAI,OAAO;AAAA,IAChC;AAEA,QAAI,UAAU,SAAS,GAAG;AACxB,qBAAe,IAAI,OAAO,IAAI,kBAAkB;AAAA,IAClD;AAEA,QAAI,MAAM,QAAQ,OAAO,WAAW,GAAG;AACrC,YAAM,gBAAgB,oBAAI,IAAY;AACtC,iBAAW,CAAC,iBAAiB,UAAU,KAAK,OAAO,YAAY,QAAQ,GAAG;AACxE,YAAI,CAAC,cAAc,OAAO,eAAe,UAAU;AACjD,oBAAU,QAAQ;AAAA,YAChB,MAAM;AAAA,YACN,MAAM,GAAG,IAAI,gBAAgB,eAAe;AAAA,YAC5C,SAAS;AAAA,UACX,CAAC;AACD,kBAAQ;AACR;AAAA,QACF;AAEA,YAAI,CAAC,gBAAiB,WAAqC,gBAAgB,GAAG,IAAI,gBAAgB,eAAe,oBAAoB,MAAM,GAAG;AAC5I,kBAAQ;AAAA,QACV;AAEA,YAAI,CAAC,cAAc,IAAK,WAA+B,MAAM,EAAE,GAAG;AAChE,wBAAc,IAAK,WAA+B,MAAM,EAAE;AAAA,QAC5D,OAAO;AACL,oBAAU,QAAQ;AAAA,YAChB,MAAM;AAAA,YACN,MAAM,GAAG,IAAI,gBAAgB,eAAe;AAAA,YAC5C,SAAS;AAAA,UACX,CAAC;AACD,kBAAQ;AAAA,QACV;AAEA,YACE,CAAC;AAAA,UACC;AAAA,UAOA,GAAG,IAAI,gBAAgB,eAAe;AAAA,UACtC;AAAA,UACA;AAAA,QACF,GACA;AACA,kBAAQ;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,YAAY,IAAI;AAAA,IACpB,QACG,OAAO,CAAC,cAAkD,QAAQ,aAAa,OAAO,cAAc,QAAQ,CAAC,EAC7G,IAAI,CAAC,cAAc,UAAU,EAAE;AAAA,EACpC;AACA,MAAI,MAAM,QAAQ,MAAM,cAAc,GAAG;AACvC,eAAW,CAAC,YAAY,KAAK,KAAK,MAAM,eAAe,QAAQ,GAAG;AAChE,YAAM,aAAa;AACnB,YAAM,OAAO,oBAAoB,UAAU;AAE3C,UAAI,CAAC,cAAc,OAAO,eAAe,UAAU;AACjD,kBAAU,QAAQ;AAAA,UAChB,MAAM;AAAA,UACN;AAAA,UACA,SAAS;AAAA,QACX,CAAC;AACD,gBAAQ;AACR;AAAA,MACF;AAEA,UAAI,CAAC,gBAAgB,WAAW,UAAU,GAAG,IAAI,aAAa,MAAM,GAAG;AACrE,gBAAQ;AAAA,MACV;AAEA,UAAI,CAAC,UAAU,IAAI,WAAW,QAAQ,GAAG;AACvC,kBAAU,QAAQ;AAAA,UAChB,MAAM;AAAA,UACN,MAAM,GAAG,IAAI;AAAA,UACb,SAAS;AAAA,QACX,CAAC;AACD,gBAAQ;AAAA,MACV;AAEA,UAAI,OAAO,WAAW,YAAY,WAAW;AAC3C,kBAAU,QAAQ;AAAA,UAChB,MAAM;AAAA,UACN,MAAM,GAAG,IAAI;AAAA,UACb,SAAS;AAAA,QACX,CAAC;AACD,gBAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAEA,SAAO,QACH,EAAE,OAAO,MAAM,QAAQ,OAAO,SAAgC,IAC9D,EAAE,OAAO,OAAO,OAAO;AAC7B;AAEO,SAAS,0BAA0B,UAAoD;AAC5F,QAAM,SAAS,4BAA4B,QAAQ;AACnD,MAAI,CAAC,OAAO,SAAS,CAAC,OAAO,OAAO;AAClC,UAAM,UAAU,OAAO,OAAO,IAAI,CAAC,UAAU,GAAG,MAAM,IAAI,KAAK,MAAM,OAAO,EAAE,EAAE,KAAK,IAAI;AACzF,UAAM,IAAI,MAAM,kCAAkC,OAAO,EAAE;AAAA,EAC7D;AAEA,SAAO,OAAO;AAChB;AAEO,SAAS,+BAA+B,OAAqE;AAClH,MAAI,CAAC,SAAS,OAAO,UAAU,UAAU;AACvC,WAAO;AAAA,MACL,OAAO;AAAA,MACP,QAAQ,CAAC;AAAA,QACP,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,QAAQ;AACd,QAAM,SAAuC,CAAC;AAC9C,MAAI,QAAQ;AAEZ,MAAI,CAAC,gBAAgB,MAAM,UAAU,cAAc,MAAM,GAAG;AAC1D,YAAQ;AAAA,EACV;AAEA,MAAI,OAAO,MAAM,YAAY,WAAW;AACtC,cAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,IACX,CAAC;AACD,YAAQ;AAAA,EACV;AAEA,SAAO,QACH,EAAE,OAAO,MAAM,QAAQ,OAAO,MAAgC,IAC9D,EAAE,OAAO,OAAO,OAAO;AAC7B;AAEO,SAAS,6BACd,UACkD;AAClD,QAAM,SAAS,4BAA4B,QAAQ;AACnD,MAAI,CAAC,OAAO,SAAS,CAAC,OAAO,OAAO;AAClC,WAAO,EAAE,OAAO,OAAO,QAAQ,OAAO,OAAO;AAAA,EAC/C;AAEA,SAAO,EAAE,OAAO,MAAM,QAAQ,CAAC,GAAG,OAAO,OAAO,MAAM;AACxD;AAEO,SAAS,uBACd,mBAGA,UACmC;AACnC,QAAM,UAAwC,OAAO,aAAa,WAC9D;AAAA,IACA,UAAU;AAAA,IACV;AAAA,EACF,IACE;AAEJ,QAAM,SAAS,4BAA4B,QAAQ,QAAQ;AAC3D,MAAI,CAAC,OAAO,SAAS,CAAC,OAAO,OAAO;AAClC,WAAO;AAAA,EACT;AAEA,SAAO,OAAO,MAAM,QAAQ,KAAK,CAAC,WAAW,OAAO,OAAO,QAAQ,QAAQ;AAC7E;;;AC5gBO,SAAS,wBACd,UACA,UACoC;AACpC,MAAI,CAAC,SAAS,kBAAkB,CAAC,MAAM,QAAQ,SAAS,cAAc,GAAG;AACvE,WAAO;AAAA,EACT;AAEA,SAAO,SAAS,eAAe;AAAA,IAC7B,CAAC,aAAa,SAAS,aAAa;AAAA,EACtC;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/types.ts","../src/validation.ts","../src/player-system.ts","../src/resolve.ts"],"sourcesContent":["export {\n SCENE_OBJECT_RUNTIME_FLAG_ID,\n SCENE_OBJECT_SCHEMA_VERSION,\n type SceneObjectAttachment,\n type SceneObjectAttachmentPoint,\n type SceneObjectBounds,\n type SceneObjectManifest,\n type SceneObjectObjectState,\n type SceneObjectPoint,\n type SceneObjectReference,\n type SceneObjectResolutionRequest,\n type SceneObjectResolutionResult,\n type SceneObjectStateKind,\n type SceneObjectTransform,\n type SceneObjectValidationIssue,\n type SceneObjectValidationResult,\n type SceneObjectVector3,\n} from \"./types.js\";\nexport {\n SCENE_OBJECT_PLAYER_SYSTEM_INTERFACE_FLAG_ID,\n type SceneObjectAnchorDefinition,\n type SceneObjectAnchorKind,\n type SceneObjectAnchorVisibility,\n type SceneObjectFocusScreenDefinition,\n type SceneObjectPlayerSystemManifest,\n resolveSceneObjectAnchorById,\n resolveSceneObjectFocusScreenById,\n validateSceneObjectPlayerSystemManifest,\n} from \"./player-system.js\";\nexport {\n createSceneObjectManifest,\n resolveSceneObjectById,\n resolveSceneObjectReferences,\n validateSceneObjectManifest,\n validateSceneObjectObjectState,\n} from \"./validation.js\";\nexport { resolveSceneObjectState } from \"./resolve.js\";\n","export const SCENE_OBJECT_SCHEMA_VERSION = \"1.0.0\";\nexport const SCENE_OBJECT_RUNTIME_FLAG_ID = \"scene.object.runtime.enabled\";\n\nexport type SceneObjectStateKind = \"idle\" | \"visible\" | \"hidden\" | \"disabled\";\n\nexport type SceneObjectCoordinateSpace =\n | \"normalized-viewport\"\n | \"pixel-viewport\"\n | \"world\"\n | \"local\";\n\nexport type SceneObjectUnits = \"ratio\" | \"pixels\";\n\nexport interface SceneObjectVector3 {\n x: number;\n y: number;\n z: number;\n}\n\nexport interface SceneObjectTransform {\n translate: SceneObjectVector3;\n rotate: SceneObjectVector3;\n scale: SceneObjectVector3;\n}\n\nexport interface SceneObjectBounds {\n rect: {\n x: number;\n y: number;\n width: number;\n height: number;\n unit: SceneObjectUnits;\n };\n depth?: number;\n coordinateSpace: SceneObjectCoordinateSpace;\n}\n\nexport interface SceneObjectPoint {\n id: string;\n x: number;\n y: number;\n z?: number;\n}\n\nexport interface SceneObjectAttachment {\n id: string;\n sourceObjectId: string;\n sourcePointId: string;\n targetObjectId: string;\n targetPointId: string;\n offset?: SceneObjectVector3;\n}\n\nexport type SceneObjectAttachmentPoint = SceneObjectPoint;\n\nexport interface SceneObjectObjectState {\n objectId: string;\n visible: boolean;\n tags?: string[];\n metadata?: Record<string, unknown>;\n}\n\nexport interface SceneObjectReference {\n objectId: string;\n pointId: string;\n}\n\nexport interface SceneObjectManifest {\n schemaVersion: string;\n objects: SceneObjectDefinition[];\n stateSnapshots?: SceneObjectObjectState[];\n}\n\nexport interface SceneObjectDefinition {\n id: string;\n name?: string;\n transform: SceneObjectTransform;\n bounds: SceneObjectBounds;\n attachmentPoints?: SceneObjectPoint[];\n attachments?: SceneObjectAttachment[];\n}\n\nexport type SceneObjectValidationCode =\n | \"required\"\n | \"invalid-type\"\n | \"invalid-value\"\n | \"invalid-id\"\n | \"duplicate-id\"\n | \"invalid-reference\"\n | \"missing-reference\";\n\nexport interface SceneObjectValidationIssue {\n code: SceneObjectValidationCode;\n path: string;\n message: string;\n}\n\nexport interface SceneObjectValidationResult<T> {\n valid: boolean;\n issues: SceneObjectValidationIssue[];\n value?: T;\n}\n\nexport interface SceneObjectResolutionRequest {\n manifest: SceneObjectManifest;\n objectId: string;\n}\n\nexport interface SceneObjectResolutionResult {\n manifest: SceneObjectManifest;\n object: SceneObjectDefinition;\n}\n","import {\n SCENE_OBJECT_SCHEMA_VERSION,\n type SceneObjectBounds,\n type SceneObjectCoordinateSpace,\n type SceneObjectManifest,\n type SceneObjectObjectState,\n type SceneObjectPoint,\n type SceneObjectValidationIssue,\n type SceneObjectValidationResult,\n type SceneObjectDefinition,\n type SceneObjectAttachment,\n type SceneObjectResolutionRequest,\n type SceneObjectTransform,\n} from \"./types.js\";\n\nconst ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\nconst COORDINATE_SPACES = new Set<SceneObjectCoordinateSpace>([\n \"normalized-viewport\",\n \"pixel-viewport\",\n \"world\",\n \"local\",\n]);\nconst UNITS = new Set([\"ratio\", \"pixels\"]);\n\nfunction pushIssue(\n issues: SceneObjectValidationIssue[],\n issue: SceneObjectValidationIssue,\n): void {\n issues.push(issue);\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\nfunction validateKebabId(\n value: unknown,\n path: string,\n issues: SceneObjectValidationIssue[],\n): value is string {\n if (typeof value !== \"string\") {\n pushIssue(issues, {\n code: \"invalid-type\",\n path,\n message: \"Expected a string identifier.\",\n });\n return false;\n }\n\n if (!ID_PATTERN.test(value)) {\n pushIssue(issues, {\n code: \"invalid-id\",\n path,\n message: \"Identifiers must be kebab-case tokens.\",\n });\n return false;\n }\n\n return true;\n}\n\nfunction validateTransform(\n value: SceneObjectTransform,\n path: string,\n issues: SceneObjectValidationIssue[],\n): boolean {\n const vectorChecks = [\"translate\", \"rotate\", \"scale\"] as const;\n let valid = true;\n\n for (const field of vectorChecks) {\n const vector = value[field];\n if (!vector || typeof vector !== \"object\") {\n pushIssue(issues, {\n code: \"required\",\n path: `${path}.${field}`,\n message: `Expected a ${field} vector.`,\n });\n valid = false;\n continue;\n }\n\n for (const axis of [\"x\", \"y\", \"z\"] as const) {\n const raw = vector[axis];\n if (!isFiniteNumber(raw)) {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.${field}.${axis}`,\n message: `Vector ${axis} must be finite.`,\n });\n valid = false;\n }\n }\n }\n\n return valid;\n}\n\nfunction validatePoint(point: SceneObjectPoint, path: string, issues: SceneObjectValidationIssue[]): boolean {\n let valid = true;\n\n if (!validateKebabId(point.id, `${path}.id`, issues)) {\n valid = false;\n }\n\n for (const field of [\"x\", \"y\", \"z\"] as const) {\n const value = point[field];\n if (field === \"z\" && value === undefined) {\n continue;\n }\n if (!isFiniteNumber(value)) {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.${field}`,\n message: \"Attachment point axis must be finite.\",\n });\n valid = false;\n }\n }\n\n return valid;\n}\n\nfunction validateBounds(bounds: SceneObjectBounds, path: string, issues: SceneObjectValidationIssue[]): boolean {\n if (!bounds || typeof bounds !== \"object\") {\n pushIssue(issues, { code: \"required\", path, message: \"Expected bounds block.\" });\n return false;\n }\n\n if (!COORDINATE_SPACES.has(bounds.coordinateSpace as SceneObjectCoordinateSpace)) {\n pushIssue(issues, {\n code: \"invalid-value\",\n path: `${path}.coordinateSpace`,\n message: \"coordinateSpace must be normalized-viewport, pixel-viewport, world, or local.\",\n });\n return false;\n }\n\n const rect = bounds.rect;\n if (!rect || typeof rect !== \"object\") {\n pushIssue(issues, { code: \"required\", path: `${path}.rect`, message: \"Expected rect bounds.\" });\n return false;\n }\n\n if (!UNITS.has(rect.unit as string)) {\n pushIssue(issues, {\n code: \"invalid-value\",\n path: `${path}.rect.unit`,\n message: \"unit must be 'ratio' or 'pixels'.\",\n });\n return false;\n }\n\n let valid = true;\n for (const field of [\"x\", \"y\", \"width\", \"height\"] as const) {\n const value = rect[field];\n if (!isFiniteNumber(value) || value < 0) {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.rect.${field}`,\n message: \"Rect fields must be finite non-negative numbers.\",\n });\n valid = false;\n }\n }\n\n if (rect.width === 0 || rect.height === 0) {\n pushIssue(issues, {\n code: \"invalid-value\",\n path: `${path}.rect`,\n message: \"Rect width and height must be positive.\",\n });\n valid = false;\n }\n\n if (bounds.depth !== undefined && (!isFiniteNumber(bounds.depth) || bounds.depth < 0)) {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.depth`,\n message: \"depth must be a non-negative number.\",\n });\n valid = false;\n }\n\n return valid && isFiniteNumber(bounds.rect.width) && isFiniteNumber(bounds.rect.height);\n}\n\nfunction validateAttachmentTarget(\n attachment: {\n id: string;\n sourceObjectId: string;\n sourcePointId: string;\n targetObjectId: string;\n targetPointId: string;\n },\n path: string,\n issues: SceneObjectValidationIssue[],\n seenPoints: Map<string, Set<string>>,\n): boolean {\n let valid = true;\n if (!validateKebabId(attachment.id, `${path}.id`, issues)) {\n valid = false;\n }\n\n if (!validateKebabId(attachment.sourceObjectId, `${path}.sourceObjectId`, issues)) {\n valid = false;\n }\n\n if (!validateKebabId(attachment.targetObjectId, `${path}.targetObjectId`, issues)) {\n valid = false;\n }\n\n if (!validateKebabId(attachment.sourcePointId, `${path}.sourcePointId`, issues)) {\n valid = false;\n }\n\n if (!validateKebabId(attachment.targetPointId, `${path}.targetPointId`, issues)) {\n valid = false;\n }\n\n const sourcePoints = seenPoints.get(attachment.sourceObjectId);\n const targetPoints = seenPoints.get(attachment.targetObjectId);\n\n if (sourcePoints && !sourcePoints.has(attachment.sourcePointId)) {\n pushIssue(issues, {\n code: \"invalid-reference\",\n path: `${path}.sourcePointId`,\n message: \"sourcePointId does not exist on source object.\",\n });\n valid = false;\n }\n\n if (targetPoints && !targetPoints.has(attachment.targetPointId)) {\n pushIssue(issues, {\n code: \"invalid-reference\",\n path: `${path}.targetPointId`,\n message: \"targetPointId does not exist on target object.\",\n });\n valid = false;\n }\n\n return valid;\n}\n\nexport function validateSceneObjectManifest(\n manifest: unknown,\n): SceneObjectValidationResult<SceneObjectManifest> {\n const issues: SceneObjectValidationIssue[] = [];\n\n if (!manifest || typeof manifest !== \"object\") {\n return {\n valid: false,\n issues: [{ code: \"required\", path: \"$\", message: \"Expected a scene object manifest object.\" }],\n };\n }\n\n const value = manifest as Record<string, unknown>;\n let valid = true;\n\n if (value.schemaVersion !== SCENE_OBJECT_SCHEMA_VERSION) {\n pushIssue(issues, {\n code: \"invalid-value\",\n path: \"$.schemaVersion\",\n message: `schemaVersion must equal ${SCENE_OBJECT_SCHEMA_VERSION}.`,\n });\n valid = false;\n }\n\n if (!Array.isArray(value.objects) || value.objects.length === 0) {\n pushIssue(issues, {\n code: \"required\",\n path: \"$.objects\",\n message: \"Manifest must contain at least one object.\",\n });\n return { valid: false, issues };\n }\n\n const objects = value.objects as SceneObjectDefinition[];\n const seenObjects = new Set<string>();\n const pointsByObject = new Map<string, Set<string>>();\n\n for (const [index, object] of objects.entries()) {\n const path = `$.objects[${index}]`;\n\n if (!object || typeof object !== \"object\") {\n pushIssue(issues, { code: \"required\", path, message: \"Expected object definition.\" });\n valid = false;\n continue;\n }\n\n if (!validateKebabId(object.id, `${path}.id`, issues)) {\n valid = false;\n }\n\n if (seenObjects.has(object.id)) {\n pushIssue(issues, {\n code: \"duplicate-id\",\n path: `${path}.id`,\n message: `Duplicate object id '${object.id}' is not allowed.`,\n });\n valid = false;\n }\n seenObjects.add(object.id);\n\n if (!object.transform || typeof object.transform !== \"object\" || !validateTransform(object.transform as SceneObjectTransform, `${path}.transform`, issues)) {\n pushIssue(issues, {\n code: \"required\",\n path: `${path}.transform`,\n message: \"Object must define a transform.\",\n });\n valid = false;\n }\n\n if (!object.bounds) {\n pushIssue(issues, {\n code: \"required\",\n path: `${path}.bounds`,\n message: \"Object must define bounds.\",\n });\n valid = false;\n } else if (!validateBounds(object.bounds, `${path}.bounds`, issues)) {\n valid = false;\n }\n\n const attachmentPointIds = new Set<string>();\n const rawPoints = Array.isArray(object.attachmentPoints)\n ? object.attachmentPoints\n : [];\n for (const [pointIndex, point] of rawPoints.entries()) {\n if (!point || typeof point !== \"object\") {\n pushIssue(issues, {\n code: \"required\",\n path: `${path}.attachmentPoints[${pointIndex}]`,\n message: \"Expected attachment point definition.\",\n });\n valid = false;\n continue;\n }\n\n if (!validatePoint(point as SceneObjectPoint, `${path}.attachmentPoints[${pointIndex}]`, issues)) {\n valid = false;\n continue;\n }\n\n const pointId = (point as SceneObjectPoint).id;\n if (attachmentPointIds.has(pointId)) {\n pushIssue(issues, {\n code: \"duplicate-id\",\n path: `${path}.attachmentPoints[${pointIndex}].id`,\n message: `Duplicate attachment point '${pointId}' within object.`,\n });\n valid = false;\n }\n attachmentPointIds.add(pointId);\n }\n\n if (rawPoints.length > 0) {\n pointsByObject.set(object.id, attachmentPointIds);\n }\n\n if (Array.isArray(object.attachments)) {\n const attachmentIds = new Set<string>();\n for (const [attachmentIndex, attachment] of object.attachments.entries()) {\n if (!attachment || typeof attachment !== \"object\") {\n pushIssue(issues, {\n code: \"required\",\n path: `${path}.attachments[${attachmentIndex}]`,\n message: \"Expected attachment definition.\",\n });\n valid = false;\n continue;\n }\n\n if (!validateKebabId((attachment as SceneObjectAttachment).sourceObjectId, `${path}.attachments[${attachmentIndex}].sourceObjectId`, issues)) {\n valid = false;\n }\n\n if (!attachmentIds.has((attachment as { id?: string }).id ?? \"\")) {\n attachmentIds.add((attachment as { id?: string }).id ?? \"\");\n } else {\n pushIssue(issues, {\n code: \"duplicate-id\",\n path: `${path}.attachments[${attachmentIndex}].id`,\n message: \"Duplicate attachment id.\",\n });\n valid = false;\n }\n\n if (\n !validateAttachmentTarget(\n attachment as {\n id: string;\n sourceObjectId: string;\n sourcePointId: string;\n targetObjectId: string;\n targetPointId: string;\n },\n `${path}.attachments[${attachmentIndex}]`,\n issues,\n pointsByObject,\n )\n ) {\n valid = false;\n }\n }\n }\n }\n\n const objectIds = new Set(\n objects\n .filter((candidate): candidate is SceneObjectDefinition => Boolean(candidate && typeof candidate === \"object\"))\n .map((candidate) => candidate.id),\n );\n if (Array.isArray(value.stateSnapshots)) {\n for (const [stateIndex, state] of value.stateSnapshots.entries()) {\n const stateValue = state as SceneObjectObjectState;\n const path = `$.stateSnapshots[${stateIndex}]`;\n\n if (!stateValue || typeof stateValue !== \"object\") {\n pushIssue(issues, {\n code: \"required\",\n path,\n message: \"Expected object state definition.\",\n });\n valid = false;\n continue;\n }\n\n if (!validateKebabId(stateValue.objectId, `${path}.objectId`, issues)) {\n valid = false;\n }\n\n if (!objectIds.has(stateValue.objectId)) {\n pushIssue(issues, {\n code: \"missing-reference\",\n path: `${path}.objectId`,\n message: \"objectId does not reference an object in objects.\",\n });\n valid = false;\n }\n\n if (typeof stateValue.visible !== \"boolean\") {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.visible`,\n message: \"visible must be a boolean.\",\n });\n valid = false;\n }\n }\n }\n\n return valid\n ? { valid: true, issues, value: manifest as SceneObjectManifest }\n : { valid: false, issues };\n}\n\nexport function createSceneObjectManifest(manifest: SceneObjectManifest): SceneObjectManifest {\n const result = validateSceneObjectManifest(manifest);\n if (!result.valid || !result.value) {\n const summary = result.issues.map((issue) => `${issue.path}: ${issue.message}`).join(\"; \");\n throw new Error(`Invalid scene object manifest. ${summary}`);\n }\n\n return result.value;\n}\n\nexport function validateSceneObjectObjectState(state: unknown): SceneObjectValidationResult<SceneObjectObjectState> {\n if (!state || typeof state !== \"object\") {\n return {\n valid: false,\n issues: [{\n code: \"required\",\n path: \"$\",\n message: \"Expected an object state.\",\n }],\n };\n }\n\n const value = state as Record<string, unknown>;\n const issues: SceneObjectValidationIssue[] = [];\n let valid = true;\n\n if (!validateKebabId(value.objectId, \"$.objectId\", issues)) {\n valid = false;\n }\n\n if (typeof value.visible !== \"boolean\") {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: \"$.visible\",\n message: \"visible must be a boolean.\",\n });\n valid = false;\n }\n\n return valid\n ? { valid: true, issues, value: state as SceneObjectObjectState }\n : { valid: false, issues };\n}\n\nexport function resolveSceneObjectReferences(\n manifest: SceneObjectManifest,\n): SceneObjectValidationResult<SceneObjectManifest> {\n const result = validateSceneObjectManifest(manifest);\n if (!result.valid || !result.value) {\n return { valid: false, issues: result.issues };\n }\n\n return { valid: true, issues: [], value: result.value };\n}\n\nexport function resolveSceneObjectById(\n requestOrManifest:\n | SceneObjectResolutionRequest\n | SceneObjectManifest,\n objectId?: string,\n): SceneObjectDefinition | undefined {\n const request: SceneObjectResolutionRequest = typeof objectId === \"string\"\n ? {\n manifest: requestOrManifest as SceneObjectManifest,\n objectId,\n }\n : requestOrManifest as SceneObjectResolutionRequest;\n\n const result = validateSceneObjectManifest(request.manifest);\n if (!result.valid || !result.value) {\n return undefined;\n }\n\n return result.value.objects.find((object) => object.id === request.objectId);\n}\n","import { type SceneObjectDefinition,\n type SceneObjectManifest,\n type SceneObjectPoint,\n type SceneObjectValidationIssue,\n type SceneObjectValidationResult,\n type SceneObjectVector3,\n} from \"./types.js\";\nimport { validateSceneObjectManifest } from \"./validation.js\";\n\nexport const SCENE_OBJECT_PLAYER_SYSTEM_INTERFACE_FLAG_ID =\n \"isekai.player-system.interface.enabled\";\n\nexport type SceneObjectAnchorKind =\n | \"target\"\n | \"focus-pane\"\n | \"localized-alert\"\n | \"line-of-sight-popup\";\n\nexport type SceneObjectAnchorVisibility =\n | \"always\"\n | \"combat-safe\"\n | \"focused-only\"\n | \"line-of-sight\";\n\nexport interface SceneObjectAnchorDefinition {\n id: string;\n kind: SceneObjectAnchorKind;\n objectId: string;\n pointId: string;\n visibility: SceneObjectAnchorVisibility;\n localeKey?: string;\n offset?: SceneObjectVector3;\n tags?: string[];\n}\n\nexport interface SceneObjectFocusScreenDefinition {\n id: string;\n objectId: string;\n anchorId: string;\n paneId: string;\n variant: \"single-pane\" | \"multi-pane\" | \"combat-safe\";\n headingKey?: string;\n}\n\nexport interface SceneObjectPlayerSystemManifest extends SceneObjectManifest {\n anchors?: SceneObjectAnchorDefinition[];\n focusScreens?: SceneObjectFocusScreenDefinition[];\n}\n\nconst ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\nconst ANCHOR_KINDS = new Set<SceneObjectAnchorKind>([\n \"target\",\n \"focus-pane\",\n \"localized-alert\",\n \"line-of-sight-popup\",\n]);\nconst ANCHOR_VISIBILITIES = new Set<SceneObjectAnchorVisibility>([\n \"always\",\n \"combat-safe\",\n \"focused-only\",\n \"line-of-sight\",\n]);\nconst FOCUS_SCREEN_VARIANTS = new Set<SceneObjectFocusScreenDefinition[\"variant\"]>([\n \"single-pane\",\n \"multi-pane\",\n \"combat-safe\",\n]);\n\nfunction pushIssue(\n issues: SceneObjectValidationIssue[],\n issue: SceneObjectValidationIssue,\n): void {\n issues.push(issue);\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\nfunction isKebabId(value: unknown): value is string {\n return typeof value === \"string\" && ID_PATTERN.test(value);\n}\n\nfunction validateKebabId(\n value: unknown,\n path: string,\n issues: SceneObjectValidationIssue[],\n): value is string {\n if (typeof value !== \"string\") {\n pushIssue(issues, {\n code: \"invalid-type\",\n path,\n message: \"Expected a string identifier.\",\n });\n return false;\n }\n\n if (!ID_PATTERN.test(value)) {\n pushIssue(issues, {\n code: \"invalid-id\",\n path,\n message: \"Identifiers must be kebab-case tokens.\",\n });\n return false;\n }\n\n return true;\n}\n\nfunction findObjectPoint(\n object: SceneObjectDefinition | undefined,\n pointId: string,\n): SceneObjectPoint | undefined {\n return object?.attachmentPoints?.find((point) => point.id === pointId);\n}\n\nfunction validateAnchorDefinition(\n anchor: unknown,\n path: string,\n issues: SceneObjectValidationIssue[],\n objectsById: Map<string, SceneObjectDefinition>,\n anchorIds: Set<string>,\n): anchor is SceneObjectAnchorDefinition {\n if (!anchor || typeof anchor !== \"object\") {\n pushIssue(issues, {\n code: \"required\",\n path,\n message: \"Expected anchor definition object.\",\n });\n return false;\n }\n\n const value = anchor as Record<string, unknown>;\n let valid = true;\n\n if (!validateKebabId(value.id, `${path}.id`, issues)) {\n valid = false;\n } else if (anchorIds.has(value.id)) {\n pushIssue(issues, {\n code: \"duplicate-id\",\n path: `${path}.id`,\n message: \"Anchor identifiers must be unique.\",\n });\n valid = false;\n } else {\n anchorIds.add(value.id);\n }\n\n if (!validateKebabId(value.objectId, `${path}.objectId`, issues)) {\n valid = false;\n }\n\n if (!validateKebabId(value.pointId, `${path}.pointId`, issues)) {\n valid = false;\n }\n\n if (!ANCHOR_KINDS.has(value.kind as SceneObjectAnchorKind)) {\n pushIssue(issues, {\n code: \"invalid-value\",\n path: `${path}.kind`,\n message:\n \"Anchor kind must be target, focus-pane, localized-alert, or line-of-sight-popup.\",\n });\n valid = false;\n }\n\n if (!ANCHOR_VISIBILITIES.has(value.visibility as SceneObjectAnchorVisibility)) {\n pushIssue(issues, {\n code: \"invalid-value\",\n path: `${path}.visibility`,\n message:\n \"Anchor visibility must be always, combat-safe, focused-only, or line-of-sight.\",\n });\n valid = false;\n }\n\n const object =\n typeof value.objectId === \"string\"\n ? objectsById.get(value.objectId)\n : undefined;\n if (!object) {\n pushIssue(issues, {\n code: \"missing-reference\",\n path: `${path}.objectId`,\n message: \"Anchor objectId must reference an existing scene object.\",\n });\n valid = false;\n } else if (\n typeof value.pointId === \"string\" &&\n !findObjectPoint(object, value.pointId)\n ) {\n pushIssue(issues, {\n code: \"missing-reference\",\n path: `${path}.pointId`,\n message:\n \"Anchor pointId must reference an attachment point on the target object.\",\n });\n valid = false;\n }\n\n if (value.kind === \"localized-alert\") {\n if (typeof value.localeKey !== \"string\" || value.localeKey.trim().length === 0) {\n pushIssue(issues, {\n code: \"required\",\n path: `${path}.localeKey`,\n message: \"localized-alert anchors require a localeKey.\",\n });\n valid = false;\n }\n } else if (\n value.localeKey !== undefined &&\n (typeof value.localeKey !== \"string\" || value.localeKey.trim().length === 0)\n ) {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.localeKey`,\n message: \"localeKey must be a non-empty string when present.\",\n });\n valid = false;\n }\n\n if (value.offset !== undefined) {\n if (!value.offset || typeof value.offset !== \"object\") {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.offset`,\n message: \"offset must be a finite x/y/z vector when present.\",\n });\n valid = false;\n } else {\n for (const axis of [\"x\", \"y\", \"z\"] as const) {\n if (!isFiniteNumber((value.offset as Record<string, unknown>)[axis])) {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.offset.${axis}`,\n message: \"offset axes must be finite numbers.\",\n });\n valid = false;\n }\n }\n }\n }\n\n if (value.tags !== undefined) {\n if (\n !Array.isArray(value.tags) ||\n value.tags.some((tag) => typeof tag !== \"string\" || tag.trim().length === 0)\n ) {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.tags`,\n message: \"tags must be an array of non-empty strings when present.\",\n });\n valid = false;\n }\n }\n\n return valid;\n}\n\nfunction validateFocusScreenDefinition(\n focusScreen: unknown,\n path: string,\n issues: SceneObjectValidationIssue[],\n objectsById: Map<string, SceneObjectDefinition>,\n anchorsById: Map<string, SceneObjectAnchorDefinition>,\n focusScreenIds: Set<string>,\n): focusScreen is SceneObjectFocusScreenDefinition {\n if (!focusScreen || typeof focusScreen !== \"object\") {\n pushIssue(issues, {\n code: \"required\",\n path,\n message: \"Expected focus-screen definition object.\",\n });\n return false;\n }\n\n const value = focusScreen as Record<string, unknown>;\n let valid = true;\n\n if (!validateKebabId(value.id, `${path}.id`, issues)) {\n valid = false;\n } else if (focusScreenIds.has(value.id)) {\n pushIssue(issues, {\n code: \"duplicate-id\",\n path: `${path}.id`,\n message: \"Focus-screen identifiers must be unique.\",\n });\n valid = false;\n } else {\n focusScreenIds.add(value.id);\n }\n\n if (!validateKebabId(value.objectId, `${path}.objectId`, issues)) {\n valid = false;\n } else if (!objectsById.has(value.objectId)) {\n pushIssue(issues, {\n code: \"missing-reference\",\n path: `${path}.objectId`,\n message: \"Focus-screen objectId must reference an existing scene object.\",\n });\n valid = false;\n }\n\n if (!validateKebabId(value.anchorId, `${path}.anchorId`, issues)) {\n valid = false;\n } else {\n const anchor = anchorsById.get(value.anchorId);\n if (!anchor) {\n pushIssue(issues, {\n code: \"missing-reference\",\n path: `${path}.anchorId`,\n message: \"Focus-screen anchorId must reference an exported anchor.\",\n });\n valid = false;\n } else if (anchor.kind !== \"focus-pane\") {\n pushIssue(issues, {\n code: \"invalid-reference\",\n path: `${path}.anchorId`,\n message: \"Focus screens must bind to focus-pane anchors.\",\n });\n valid = false;\n }\n }\n\n if (!validateKebabId(value.paneId, `${path}.paneId`, issues)) {\n valid = false;\n }\n\n if (!FOCUS_SCREEN_VARIANTS.has(value.variant as SceneObjectFocusScreenDefinition[\"variant\"])) {\n pushIssue(issues, {\n code: \"invalid-value\",\n path: `${path}.variant`,\n message: \"Focus-screen variant must be single-pane, multi-pane, or combat-safe.\",\n });\n valid = false;\n }\n\n if (\n value.headingKey !== undefined &&\n (typeof value.headingKey !== \"string\" || value.headingKey.trim().length === 0)\n ) {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.headingKey`,\n message: \"headingKey must be a non-empty string when present.\",\n });\n valid = false;\n }\n\n return valid;\n}\n\nexport function validateSceneObjectPlayerSystemManifest(\n manifest: unknown,\n): SceneObjectValidationResult<SceneObjectPlayerSystemManifest> {\n const base = validateSceneObjectManifest(manifest);\n if (!base.valid || !base.value) {\n return base as SceneObjectValidationResult<SceneObjectPlayerSystemManifest>;\n }\n\n const issues = [...base.issues];\n const value = manifest as SceneObjectPlayerSystemManifest;\n const objectsById = new Map(\n base.value.objects.map((object) => [object.id, object] as const),\n );\n const anchorIds = new Set<string>();\n const anchorsById = new Map<string, SceneObjectAnchorDefinition>();\n const focusScreenIds = new Set<string>();\n let valid = true;\n\n if (value.anchors !== undefined) {\n if (!Array.isArray(value.anchors)) {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: \"$.anchors\",\n message: \"anchors must be an array when present.\",\n });\n valid = false;\n } else {\n value.anchors.forEach((anchor, index) => {\n const path = `$.anchors[${index}]`;\n if (\n validateAnchorDefinition(anchor, path, issues, objectsById, anchorIds)\n ) {\n anchorsById.set(anchor.id, anchor);\n } else {\n valid = false;\n }\n });\n }\n }\n\n if (value.focusScreens !== undefined) {\n if (!Array.isArray(value.focusScreens)) {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: \"$.focusScreens\",\n message: \"focusScreens must be an array when present.\",\n });\n valid = false;\n } else {\n value.focusScreens.forEach((focusScreen, index) => {\n if (\n !validateFocusScreenDefinition(\n focusScreen,\n `$.focusScreens[${index}]`,\n issues,\n objectsById,\n anchorsById,\n focusScreenIds,\n )\n ) {\n valid = false;\n }\n });\n }\n }\n\n return {\n valid,\n issues,\n value: valid ? value : undefined,\n };\n}\n\nexport function resolveSceneObjectAnchorById(\n manifest: SceneObjectPlayerSystemManifest,\n anchorId: string,\n): SceneObjectAnchorDefinition | undefined {\n if (!isKebabId(anchorId)) {\n return undefined;\n }\n\n return manifest.anchors?.find((anchor) => anchor.id === anchorId);\n}\n\nexport function resolveSceneObjectFocusScreenById(\n manifest: SceneObjectPlayerSystemManifest,\n focusScreenId: string,\n): SceneObjectFocusScreenDefinition | undefined {\n if (!isKebabId(focusScreenId)) {\n return undefined;\n }\n\n return manifest.focusScreens?.find((focusScreen) => focusScreen.id === focusScreenId);\n}\n","import {\n SceneObjectManifest,\n SceneObjectObjectState,\n SceneObjectDefinition,\n} from \"./types.js\";\n\nexport function resolveSceneObjectState(\n manifest: SceneObjectManifest,\n objectId: string,\n): SceneObjectObjectState | undefined {\n if (!manifest.stateSnapshots || !Array.isArray(manifest.stateSnapshots)) {\n return undefined;\n }\n\n return manifest.stateSnapshots.find(\n (snapshot) => snapshot.objectId === objectId,\n );\n}\n\nexport function resolveSceneObjectById(\n manifest: SceneObjectManifest,\n objectId: string,\n): SceneObjectDefinition | undefined {\n return manifest.objects.find((object) => object.id === objectId);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAO,IAAM,8BAA8B;AACpC,IAAM,+BAA+B;;;ACc5C,IAAM,aAAa;AACnB,IAAM,oBAAoB,oBAAI,IAAgC;AAAA,EAC5D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AACD,IAAM,QAAQ,oBAAI,IAAI,CAAC,SAAS,QAAQ,CAAC;AAEzC,SAAS,UACP,QACA,OACM;AACN,SAAO,KAAK,KAAK;AACnB;AAEA,SAAS,eAAe,OAAiC;AACvD,SAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK;AAC3D;AAEA,SAAS,gBACP,OACA,MACA,QACiB;AACjB,MAAI,OAAO,UAAU,UAAU;AAC7B,cAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN;AAAA,MACA,SAAS;AAAA,IACX,CAAC;AACD,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,WAAW,KAAK,KAAK,GAAG;AAC3B,cAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN;AAAA,MACA,SAAS;AAAA,IACX,CAAC;AACD,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,kBACP,OACA,MACA,QACS;AACT,QAAM,eAAe,CAAC,aAAa,UAAU,OAAO;AACpD,MAAI,QAAQ;AAEZ,aAAW,SAAS,cAAc;AAChC,UAAM,SAAS,MAAM,KAAK;AAC1B,QAAI,CAAC,UAAU,OAAO,WAAW,UAAU;AACzC,gBAAU,QAAQ;AAAA,QAChB,MAAM;AAAA,QACN,MAAM,GAAG,IAAI,IAAI,KAAK;AAAA,QACtB,SAAS,cAAc,KAAK;AAAA,MAC9B,CAAC;AACD,cAAQ;AACR;AAAA,IACF;AAEA,eAAW,QAAQ,CAAC,KAAK,KAAK,GAAG,GAAY;AAC3C,YAAM,MAAM,OAAO,IAAI;AACvB,UAAI,CAAC,eAAe,GAAG,GAAG;AACxB,kBAAU,QAAQ;AAAA,UAChB,MAAM;AAAA,UACN,MAAM,GAAG,IAAI,IAAI,KAAK,IAAI,IAAI;AAAA,UAC9B,SAAS,UAAU,IAAI;AAAA,QACzB,CAAC;AACD,gBAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,cAAc,OAAyB,MAAc,QAA+C;AAC3G,MAAI,QAAQ;AAEZ,MAAI,CAAC,gBAAgB,MAAM,IAAI,GAAG,IAAI,OAAO,MAAM,GAAG;AACpD,YAAQ;AAAA,EACV;AAEA,aAAW,SAAS,CAAC,KAAK,KAAK,GAAG,GAAY;AAC5C,UAAM,QAAQ,MAAM,KAAK;AACzB,QAAI,UAAU,OAAO,UAAU,QAAW;AACxC;AAAA,IACF;AACA,QAAI,CAAC,eAAe,KAAK,GAAG;AAC1B,gBAAU,QAAQ;AAAA,QAChB,MAAM;AAAA,QACN,MAAM,GAAG,IAAI,IAAI,KAAK;AAAA,QACtB,SAAS;AAAA,MACX,CAAC;AACD,cAAQ;AAAA,IACV;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,eAAe,QAA2B,MAAc,QAA+C;AAC9G,MAAI,CAAC,UAAU,OAAO,WAAW,UAAU;AACzC,cAAU,QAAQ,EAAE,MAAM,YAAY,MAAM,SAAS,yBAAyB,CAAC;AAC/E,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,kBAAkB,IAAI,OAAO,eAA6C,GAAG;AAChF,cAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,MAAM,GAAG,IAAI;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AACD,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,OAAO;AACpB,MAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,cAAU,QAAQ,EAAE,MAAM,YAAY,MAAM,GAAG,IAAI,SAAS,SAAS,wBAAwB,CAAC;AAC9F,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,MAAM,IAAI,KAAK,IAAc,GAAG;AACnC,cAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,MAAM,GAAG,IAAI;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AACD,WAAO;AAAA,EACT;AAEA,MAAI,QAAQ;AACZ,aAAW,SAAS,CAAC,KAAK,KAAK,SAAS,QAAQ,GAAY;AAC1D,UAAM,QAAQ,KAAK,KAAK;AACxB,QAAI,CAAC,eAAe,KAAK,KAAK,QAAQ,GAAG;AACvC,gBAAU,QAAQ;AAAA,QAChB,MAAM;AAAA,QACN,MAAM,GAAG,IAAI,SAAS,KAAK;AAAA,QAC3B,SAAS;AAAA,MACX,CAAC;AACD,cAAQ;AAAA,IACV;AAAA,EACF;AAEA,MAAI,KAAK,UAAU,KAAK,KAAK,WAAW,GAAG;AACzC,cAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,MAAM,GAAG,IAAI;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AACD,YAAQ;AAAA,EACV;AAEA,MAAI,OAAO,UAAU,WAAc,CAAC,eAAe,OAAO,KAAK,KAAK,OAAO,QAAQ,IAAI;AACrF,cAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,MAAM,GAAG,IAAI;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AACD,YAAQ;AAAA,EACV;AAEA,SAAO,SAAS,eAAe,OAAO,KAAK,KAAK,KAAK,eAAe,OAAO,KAAK,MAAM;AACxF;AAEA,SAAS,yBACP,YAOA,MACA,QACA,YACS;AACT,MAAI,QAAQ;AACZ,MAAI,CAAC,gBAAgB,WAAW,IAAI,GAAG,IAAI,OAAO,MAAM,GAAG;AACzD,YAAQ;AAAA,EACV;AAEA,MAAI,CAAC,gBAAgB,WAAW,gBAAgB,GAAG,IAAI,mBAAmB,MAAM,GAAG;AACjF,YAAQ;AAAA,EACV;AAEA,MAAI,CAAC,gBAAgB,WAAW,gBAAgB,GAAG,IAAI,mBAAmB,MAAM,GAAG;AACjF,YAAQ;AAAA,EACV;AAEA,MAAI,CAAC,gBAAgB,WAAW,eAAe,GAAG,IAAI,kBAAkB,MAAM,GAAG;AAC/E,YAAQ;AAAA,EACV;AAEA,MAAI,CAAC,gBAAgB,WAAW,eAAe,GAAG,IAAI,kBAAkB,MAAM,GAAG;AAC/E,YAAQ;AAAA,EACV;AAEA,QAAM,eAAe,WAAW,IAAI,WAAW,cAAc;AAC7D,QAAM,eAAe,WAAW,IAAI,WAAW,cAAc;AAE7D,MAAI,gBAAgB,CAAC,aAAa,IAAI,WAAW,aAAa,GAAG;AAC/D,cAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,MAAM,GAAG,IAAI;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AACD,YAAQ;AAAA,EACV;AAEA,MAAI,gBAAgB,CAAC,aAAa,IAAI,WAAW,aAAa,GAAG;AAC/D,cAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,MAAM,GAAG,IAAI;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AACD,YAAQ;AAAA,EACV;AAEA,SAAO;AACT;AAEO,SAAS,4BACd,UACkD;AAClD,QAAM,SAAuC,CAAC;AAE9C,MAAI,CAAC,YAAY,OAAO,aAAa,UAAU;AAC7C,WAAO;AAAA,MACL,OAAO;AAAA,MACP,QAAQ,CAAC,EAAE,MAAM,YAAY,MAAM,KAAK,SAAS,2CAA2C,CAAC;AAAA,IAC/F;AAAA,EACF;AAEA,QAAM,QAAQ;AACd,MAAI,QAAQ;AAEZ,MAAI,MAAM,kBAAkB,6BAA6B;AACvD,cAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,4BAA4B,2BAA2B;AAAA,IAClE,CAAC;AACD,YAAQ;AAAA,EACV;AAEA,MAAI,CAAC,MAAM,QAAQ,MAAM,OAAO,KAAK,MAAM,QAAQ,WAAW,GAAG;AAC/D,cAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,IACX,CAAC;AACD,WAAO,EAAE,OAAO,OAAO,OAAO;AAAA,EAChC;AAEA,QAAM,UAAU,MAAM;AACtB,QAAM,cAAc,oBAAI,IAAY;AACpC,QAAM,iBAAiB,oBAAI,IAAyB;AAEpD,aAAW,CAAC,OAAO,MAAM,KAAK,QAAQ,QAAQ,GAAG;AAC/C,UAAM,OAAO,aAAa,KAAK;AAE/B,QAAI,CAAC,UAAU,OAAO,WAAW,UAAU;AACzC,gBAAU,QAAQ,EAAE,MAAM,YAAY,MAAM,SAAS,8BAA8B,CAAC;AACpF,cAAQ;AACR;AAAA,IACF;AAEA,QAAI,CAAC,gBAAgB,OAAO,IAAI,GAAG,IAAI,OAAO,MAAM,GAAG;AACrD,cAAQ;AAAA,IACV;AAEA,QAAI,YAAY,IAAI,OAAO,EAAE,GAAG;AAC9B,gBAAU,QAAQ;AAAA,QAChB,MAAM;AAAA,QACN,MAAM,GAAG,IAAI;AAAA,QACb,SAAS,wBAAwB,OAAO,EAAE;AAAA,MAC5C,CAAC;AACD,cAAQ;AAAA,IACV;AACA,gBAAY,IAAI,OAAO,EAAE;AAEzB,QAAI,CAAC,OAAO,aAAa,OAAO,OAAO,cAAc,YAAY,CAAC,kBAAkB,OAAO,WAAmC,GAAG,IAAI,cAAc,MAAM,GAAG;AAC1J,gBAAU,QAAQ;AAAA,QAChB,MAAM;AAAA,QACN,MAAM,GAAG,IAAI;AAAA,QACb,SAAS;AAAA,MACX,CAAC;AACD,cAAQ;AAAA,IACV;AAEA,QAAI,CAAC,OAAO,QAAQ;AAClB,gBAAU,QAAQ;AAAA,QAChB,MAAM;AAAA,QACN,MAAM,GAAG,IAAI;AAAA,QACb,SAAS;AAAA,MACX,CAAC;AACD,cAAQ;AAAA,IACV,WAAW,CAAC,eAAe,OAAO,QAAQ,GAAG,IAAI,WAAW,MAAM,GAAG;AACnE,cAAQ;AAAA,IACV;AAEA,UAAM,qBAAqB,oBAAI,IAAY;AAC3C,UAAM,YAAY,MAAM,QAAQ,OAAO,gBAAgB,IACnD,OAAO,mBACP,CAAC;AACL,eAAW,CAAC,YAAY,KAAK,KAAK,UAAU,QAAQ,GAAG;AACrD,UAAI,CAAC,SAAS,OAAO,UAAU,UAAU;AACvC,kBAAU,QAAQ;AAAA,UAChB,MAAM;AAAA,UACN,MAAM,GAAG,IAAI,qBAAqB,UAAU;AAAA,UAC5C,SAAS;AAAA,QACX,CAAC;AACD,gBAAQ;AACR;AAAA,MACF;AAEA,UAAI,CAAC,cAAc,OAA2B,GAAG,IAAI,qBAAqB,UAAU,KAAK,MAAM,GAAG;AAChG,gBAAQ;AACR;AAAA,MACF;AAEA,YAAM,UAAW,MAA2B;AAC5C,UAAI,mBAAmB,IAAI,OAAO,GAAG;AACnC,kBAAU,QAAQ;AAAA,UAChB,MAAM;AAAA,UACN,MAAM,GAAG,IAAI,qBAAqB,UAAU;AAAA,UAC5C,SAAS,+BAA+B,OAAO;AAAA,QACjD,CAAC;AACD,gBAAQ;AAAA,MACV;AACA,yBAAmB,IAAI,OAAO;AAAA,IAChC;AAEA,QAAI,UAAU,SAAS,GAAG;AACxB,qBAAe,IAAI,OAAO,IAAI,kBAAkB;AAAA,IAClD;AAEA,QAAI,MAAM,QAAQ,OAAO,WAAW,GAAG;AACrC,YAAM,gBAAgB,oBAAI,IAAY;AACtC,iBAAW,CAAC,iBAAiB,UAAU,KAAK,OAAO,YAAY,QAAQ,GAAG;AACxE,YAAI,CAAC,cAAc,OAAO,eAAe,UAAU;AACjD,oBAAU,QAAQ;AAAA,YAChB,MAAM;AAAA,YACN,MAAM,GAAG,IAAI,gBAAgB,eAAe;AAAA,YAC5C,SAAS;AAAA,UACX,CAAC;AACD,kBAAQ;AACR;AAAA,QACF;AAEA,YAAI,CAAC,gBAAiB,WAAqC,gBAAgB,GAAG,IAAI,gBAAgB,eAAe,oBAAoB,MAAM,GAAG;AAC5I,kBAAQ;AAAA,QACV;AAEA,YAAI,CAAC,cAAc,IAAK,WAA+B,MAAM,EAAE,GAAG;AAChE,wBAAc,IAAK,WAA+B,MAAM,EAAE;AAAA,QAC5D,OAAO;AACL,oBAAU,QAAQ;AAAA,YAChB,MAAM;AAAA,YACN,MAAM,GAAG,IAAI,gBAAgB,eAAe;AAAA,YAC5C,SAAS;AAAA,UACX,CAAC;AACD,kBAAQ;AAAA,QACV;AAEA,YACE,CAAC;AAAA,UACC;AAAA,UAOA,GAAG,IAAI,gBAAgB,eAAe;AAAA,UACtC;AAAA,UACA;AAAA,QACF,GACA;AACA,kBAAQ;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,YAAY,IAAI;AAAA,IACpB,QACG,OAAO,CAAC,cAAkD,QAAQ,aAAa,OAAO,cAAc,QAAQ,CAAC,EAC7G,IAAI,CAAC,cAAc,UAAU,EAAE;AAAA,EACpC;AACA,MAAI,MAAM,QAAQ,MAAM,cAAc,GAAG;AACvC,eAAW,CAAC,YAAY,KAAK,KAAK,MAAM,eAAe,QAAQ,GAAG;AAChE,YAAM,aAAa;AACnB,YAAM,OAAO,oBAAoB,UAAU;AAE3C,UAAI,CAAC,cAAc,OAAO,eAAe,UAAU;AACjD,kBAAU,QAAQ;AAAA,UAChB,MAAM;AAAA,UACN;AAAA,UACA,SAAS;AAAA,QACX,CAAC;AACD,gBAAQ;AACR;AAAA,MACF;AAEA,UAAI,CAAC,gBAAgB,WAAW,UAAU,GAAG,IAAI,aAAa,MAAM,GAAG;AACrE,gBAAQ;AAAA,MACV;AAEA,UAAI,CAAC,UAAU,IAAI,WAAW,QAAQ,GAAG;AACvC,kBAAU,QAAQ;AAAA,UAChB,MAAM;AAAA,UACN,MAAM,GAAG,IAAI;AAAA,UACb,SAAS;AAAA,QACX,CAAC;AACD,gBAAQ;AAAA,MACV;AAEA,UAAI,OAAO,WAAW,YAAY,WAAW;AAC3C,kBAAU,QAAQ;AAAA,UAChB,MAAM;AAAA,UACN,MAAM,GAAG,IAAI;AAAA,UACb,SAAS;AAAA,QACX,CAAC;AACD,gBAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAEA,SAAO,QACH,EAAE,OAAO,MAAM,QAAQ,OAAO,SAAgC,IAC9D,EAAE,OAAO,OAAO,OAAO;AAC7B;AAEO,SAAS,0BAA0B,UAAoD;AAC5F,QAAM,SAAS,4BAA4B,QAAQ;AACnD,MAAI,CAAC,OAAO,SAAS,CAAC,OAAO,OAAO;AAClC,UAAM,UAAU,OAAO,OAAO,IAAI,CAAC,UAAU,GAAG,MAAM,IAAI,KAAK,MAAM,OAAO,EAAE,EAAE,KAAK,IAAI;AACzF,UAAM,IAAI,MAAM,kCAAkC,OAAO,EAAE;AAAA,EAC7D;AAEA,SAAO,OAAO;AAChB;AAEO,SAAS,+BAA+B,OAAqE;AAClH,MAAI,CAAC,SAAS,OAAO,UAAU,UAAU;AACvC,WAAO;AAAA,MACL,OAAO;AAAA,MACP,QAAQ,CAAC;AAAA,QACP,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,QAAQ;AACd,QAAM,SAAuC,CAAC;AAC9C,MAAI,QAAQ;AAEZ,MAAI,CAAC,gBAAgB,MAAM,UAAU,cAAc,MAAM,GAAG;AAC1D,YAAQ;AAAA,EACV;AAEA,MAAI,OAAO,MAAM,YAAY,WAAW;AACtC,cAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,IACX,CAAC;AACD,YAAQ;AAAA,EACV;AAEA,SAAO,QACH,EAAE,OAAO,MAAM,QAAQ,OAAO,MAAgC,IAC9D,EAAE,OAAO,OAAO,OAAO;AAC7B;AAEO,SAAS,6BACd,UACkD;AAClD,QAAM,SAAS,4BAA4B,QAAQ;AACnD,MAAI,CAAC,OAAO,SAAS,CAAC,OAAO,OAAO;AAClC,WAAO,EAAE,OAAO,OAAO,QAAQ,OAAO,OAAO;AAAA,EAC/C;AAEA,SAAO,EAAE,OAAO,MAAM,QAAQ,CAAC,GAAG,OAAO,OAAO,MAAM;AACxD;AAEO,SAAS,uBACd,mBAGA,UACmC;AACnC,QAAM,UAAwC,OAAO,aAAa,WAC9D;AAAA,IACA,UAAU;AAAA,IACV;AAAA,EACF,IACE;AAEJ,QAAM,SAAS,4BAA4B,QAAQ,QAAQ;AAC3D,MAAI,CAAC,OAAO,SAAS,CAAC,OAAO,OAAO;AAClC,WAAO;AAAA,EACT;AAEA,SAAO,OAAO,MAAM,QAAQ,KAAK,CAAC,WAAW,OAAO,OAAO,QAAQ,QAAQ;AAC7E;;;ACzgBO,IAAM,+CACX;AAuCF,IAAMA,cAAa;AACnB,IAAM,eAAe,oBAAI,IAA2B;AAAA,EAClD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AACD,IAAM,sBAAsB,oBAAI,IAAiC;AAAA,EAC/D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AACD,IAAM,wBAAwB,oBAAI,IAAiD;AAAA,EACjF;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,SAASC,WACP,QACA,OACM;AACN,SAAO,KAAK,KAAK;AACnB;AAEA,SAASC,gBAAe,OAAiC;AACvD,SAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK;AAC3D;AAEA,SAAS,UAAU,OAAiC;AAClD,SAAO,OAAO,UAAU,YAAYF,YAAW,KAAK,KAAK;AAC3D;AAEA,SAASG,iBACP,OACA,MACA,QACiB;AACjB,MAAI,OAAO,UAAU,UAAU;AAC7B,IAAAF,WAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN;AAAA,MACA,SAAS;AAAA,IACX,CAAC;AACD,WAAO;AAAA,EACT;AAEA,MAAI,CAACD,YAAW,KAAK,KAAK,GAAG;AAC3B,IAAAC,WAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN;AAAA,MACA,SAAS;AAAA,IACX,CAAC;AACD,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,gBACP,QACA,SAC8B;AAC9B,SAAO,QAAQ,kBAAkB,KAAK,CAAC,UAAU,MAAM,OAAO,OAAO;AACvE;AAEA,SAAS,yBACP,QACA,MACA,QACA,aACA,WACuC;AACvC,MAAI,CAAC,UAAU,OAAO,WAAW,UAAU;AACzC,IAAAA,WAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN;AAAA,MACA,SAAS;AAAA,IACX,CAAC;AACD,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ;AACd,MAAI,QAAQ;AAEZ,MAAI,CAACE,iBAAgB,MAAM,IAAI,GAAG,IAAI,OAAO,MAAM,GAAG;AACpD,YAAQ;AAAA,EACV,WAAW,UAAU,IAAI,MAAM,EAAE,GAAG;AAClC,IAAAF,WAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,MAAM,GAAG,IAAI;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AACD,YAAQ;AAAA,EACV,OAAO;AACL,cAAU,IAAI,MAAM,EAAE;AAAA,EACxB;AAEA,MAAI,CAACE,iBAAgB,MAAM,UAAU,GAAG,IAAI,aAAa,MAAM,GAAG;AAChE,YAAQ;AAAA,EACV;AAEA,MAAI,CAACA,iBAAgB,MAAM,SAAS,GAAG,IAAI,YAAY,MAAM,GAAG;AAC9D,YAAQ;AAAA,EACV;AAEA,MAAI,CAAC,aAAa,IAAI,MAAM,IAA6B,GAAG;AAC1D,IAAAF,WAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,MAAM,GAAG,IAAI;AAAA,MACb,SACE;AAAA,IACJ,CAAC;AACD,YAAQ;AAAA,EACV;AAEA,MAAI,CAAC,oBAAoB,IAAI,MAAM,UAAyC,GAAG;AAC7E,IAAAA,WAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,MAAM,GAAG,IAAI;AAAA,MACb,SACE;AAAA,IACJ,CAAC;AACD,YAAQ;AAAA,EACV;AAEA,QAAM,SACJ,OAAO,MAAM,aAAa,WACtB,YAAY,IAAI,MAAM,QAAQ,IAC9B;AACN,MAAI,CAAC,QAAQ;AACX,IAAAA,WAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,MAAM,GAAG,IAAI;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AACD,YAAQ;AAAA,EACV,WACE,OAAO,MAAM,YAAY,YACzB,CAAC,gBAAgB,QAAQ,MAAM,OAAO,GACtC;AACA,IAAAA,WAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,MAAM,GAAG,IAAI;AAAA,MACb,SACE;AAAA,IACJ,CAAC;AACD,YAAQ;AAAA,EACV;AAEA,MAAI,MAAM,SAAS,mBAAmB;AACpC,QAAI,OAAO,MAAM,cAAc,YAAY,MAAM,UAAU,KAAK,EAAE,WAAW,GAAG;AAC9E,MAAAA,WAAU,QAAQ;AAAA,QAChB,MAAM;AAAA,QACN,MAAM,GAAG,IAAI;AAAA,QACb,SAAS;AAAA,MACX,CAAC;AACD,cAAQ;AAAA,IACV;AAAA,EACF,WACE,MAAM,cAAc,WACnB,OAAO,MAAM,cAAc,YAAY,MAAM,UAAU,KAAK,EAAE,WAAW,IAC1E;AACA,IAAAA,WAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,MAAM,GAAG,IAAI;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AACD,YAAQ;AAAA,EACV;AAEA,MAAI,MAAM,WAAW,QAAW;AAC9B,QAAI,CAAC,MAAM,UAAU,OAAO,MAAM,WAAW,UAAU;AACrD,MAAAA,WAAU,QAAQ;AAAA,QAChB,MAAM;AAAA,QACN,MAAM,GAAG,IAAI;AAAA,QACb,SAAS;AAAA,MACX,CAAC;AACD,cAAQ;AAAA,IACV,OAAO;AACL,iBAAW,QAAQ,CAAC,KAAK,KAAK,GAAG,GAAY;AAC3C,YAAI,CAACC,gBAAgB,MAAM,OAAmC,IAAI,CAAC,GAAG;AACpE,UAAAD,WAAU,QAAQ;AAAA,YAChB,MAAM;AAAA,YACN,MAAM,GAAG,IAAI,WAAW,IAAI;AAAA,YAC5B,SAAS;AAAA,UACX,CAAC;AACD,kBAAQ;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,MAAM,SAAS,QAAW;AAC5B,QACE,CAAC,MAAM,QAAQ,MAAM,IAAI,KACzB,MAAM,KAAK,KAAK,CAAC,QAAQ,OAAO,QAAQ,YAAY,IAAI,KAAK,EAAE,WAAW,CAAC,GAC3E;AACA,MAAAA,WAAU,QAAQ;AAAA,QAChB,MAAM;AAAA,QACN,MAAM,GAAG,IAAI;AAAA,QACb,SAAS;AAAA,MACX,CAAC;AACD,cAAQ;AAAA,IACV;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,8BACP,aACA,MACA,QACA,aACA,aACA,gBACiD;AACjD,MAAI,CAAC,eAAe,OAAO,gBAAgB,UAAU;AACnD,IAAAA,WAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN;AAAA,MACA,SAAS;AAAA,IACX,CAAC;AACD,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ;AACd,MAAI,QAAQ;AAEZ,MAAI,CAACE,iBAAgB,MAAM,IAAI,GAAG,IAAI,OAAO,MAAM,GAAG;AACpD,YAAQ;AAAA,EACV,WAAW,eAAe,IAAI,MAAM,EAAE,GAAG;AACvC,IAAAF,WAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,MAAM,GAAG,IAAI;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AACD,YAAQ;AAAA,EACV,OAAO;AACL,mBAAe,IAAI,MAAM,EAAE;AAAA,EAC7B;AAEA,MAAI,CAACE,iBAAgB,MAAM,UAAU,GAAG,IAAI,aAAa,MAAM,GAAG;AAChE,YAAQ;AAAA,EACV,WAAW,CAAC,YAAY,IAAI,MAAM,QAAQ,GAAG;AAC3C,IAAAF,WAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,MAAM,GAAG,IAAI;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AACD,YAAQ;AAAA,EACV;AAEA,MAAI,CAACE,iBAAgB,MAAM,UAAU,GAAG,IAAI,aAAa,MAAM,GAAG;AAChE,YAAQ;AAAA,EACV,OAAO;AACL,UAAM,SAAS,YAAY,IAAI,MAAM,QAAQ;AAC7C,QAAI,CAAC,QAAQ;AACX,MAAAF,WAAU,QAAQ;AAAA,QAChB,MAAM;AAAA,QACN,MAAM,GAAG,IAAI;AAAA,QACb,SAAS;AAAA,MACX,CAAC;AACD,cAAQ;AAAA,IACV,WAAW,OAAO,SAAS,cAAc;AACvC,MAAAA,WAAU,QAAQ;AAAA,QAChB,MAAM;AAAA,QACN,MAAM,GAAG,IAAI;AAAA,QACb,SAAS;AAAA,MACX,CAAC;AACD,cAAQ;AAAA,IACV;AAAA,EACF;AAEA,MAAI,CAACE,iBAAgB,MAAM,QAAQ,GAAG,IAAI,WAAW,MAAM,GAAG;AAC5D,YAAQ;AAAA,EACV;AAEA,MAAI,CAAC,sBAAsB,IAAI,MAAM,OAAsD,GAAG;AAC5F,IAAAF,WAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,MAAM,GAAG,IAAI;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AACD,YAAQ;AAAA,EACV;AAEA,MACE,MAAM,eAAe,WACpB,OAAO,MAAM,eAAe,YAAY,MAAM,WAAW,KAAK,EAAE,WAAW,IAC5E;AACA,IAAAA,WAAU,QAAQ;AAAA,MAChB,MAAM;AAAA,MACN,MAAM,GAAG,IAAI;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AACD,YAAQ;AAAA,EACV;AAEA,SAAO;AACT;AAEO,SAAS,wCACd,UAC8D;AAC9D,QAAM,OAAO,4BAA4B,QAAQ;AACjD,MAAI,CAAC,KAAK,SAAS,CAAC,KAAK,OAAO;AAC9B,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,CAAC,GAAG,KAAK,MAAM;AAC9B,QAAM,QAAQ;AACd,QAAM,cAAc,IAAI;AAAA,IACtB,KAAK,MAAM,QAAQ,IAAI,CAAC,WAAW,CAAC,OAAO,IAAI,MAAM,CAAU;AAAA,EACjE;AACA,QAAM,YAAY,oBAAI,IAAY;AAClC,QAAM,cAAc,oBAAI,IAAyC;AACjE,QAAM,iBAAiB,oBAAI,IAAY;AACvC,MAAI,QAAQ;AAEZ,MAAI,MAAM,YAAY,QAAW;AAC/B,QAAI,CAAC,MAAM,QAAQ,MAAM,OAAO,GAAG;AACjC,MAAAA,WAAU,QAAQ;AAAA,QAChB,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AACD,cAAQ;AAAA,IACV,OAAO;AACL,YAAM,QAAQ,QAAQ,CAAC,QAAQ,UAAU;AACvC,cAAM,OAAO,aAAa,KAAK;AAC/B,YACE,yBAAyB,QAAQ,MAAM,QAAQ,aAAa,SAAS,GACrE;AACA,sBAAY,IAAI,OAAO,IAAI,MAAM;AAAA,QACnC,OAAO;AACL,kBAAQ;AAAA,QACV;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAEA,MAAI,MAAM,iBAAiB,QAAW;AACpC,QAAI,CAAC,MAAM,QAAQ,MAAM,YAAY,GAAG;AACtC,MAAAA,WAAU,QAAQ;AAAA,QAChB,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AACD,cAAQ;AAAA,IACV,OAAO;AACL,YAAM,aAAa,QAAQ,CAAC,aAAa,UAAU;AACjD,YACE,CAAC;AAAA,UACC;AAAA,UACA,kBAAkB,KAAK;AAAA,UACvB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,GACA;AACA,kBAAQ;AAAA,QACV;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,OAAO,QAAQ,QAAQ;AAAA,EACzB;AACF;AAEO,SAAS,6BACd,UACA,UACyC;AACzC,MAAI,CAAC,UAAU,QAAQ,GAAG;AACxB,WAAO;AAAA,EACT;AAEA,SAAO,SAAS,SAAS,KAAK,CAAC,WAAW,OAAO,OAAO,QAAQ;AAClE;AAEO,SAAS,kCACd,UACA,eAC8C;AAC9C,MAAI,CAAC,UAAU,aAAa,GAAG;AAC7B,WAAO;AAAA,EACT;AAEA,SAAO,SAAS,cAAc,KAAK,CAAC,gBAAgB,YAAY,OAAO,aAAa;AACtF;;;ACxbO,SAAS,wBACd,UACA,UACoC;AACpC,MAAI,CAAC,SAAS,kBAAkB,CAAC,MAAM,QAAQ,SAAS,cAAc,GAAG;AACvE,WAAO;AAAA,EACT;AAEA,SAAO,SAAS,eAAe;AAAA,IAC7B,CAAC,aAAa,SAAS,aAAa;AAAA,EACtC;AACF;","names":["ID_PATTERN","pushIssue","isFiniteNumber","validateKebabId"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -82,6 +82,35 @@ interface SceneObjectResolutionResult {
|
|
|
82
82
|
object: SceneObjectDefinition;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
declare const SCENE_OBJECT_PLAYER_SYSTEM_INTERFACE_FLAG_ID = "isekai.player-system.interface.enabled";
|
|
86
|
+
type SceneObjectAnchorKind = "target" | "focus-pane" | "localized-alert" | "line-of-sight-popup";
|
|
87
|
+
type SceneObjectAnchorVisibility = "always" | "combat-safe" | "focused-only" | "line-of-sight";
|
|
88
|
+
interface SceneObjectAnchorDefinition {
|
|
89
|
+
id: string;
|
|
90
|
+
kind: SceneObjectAnchorKind;
|
|
91
|
+
objectId: string;
|
|
92
|
+
pointId: string;
|
|
93
|
+
visibility: SceneObjectAnchorVisibility;
|
|
94
|
+
localeKey?: string;
|
|
95
|
+
offset?: SceneObjectVector3;
|
|
96
|
+
tags?: string[];
|
|
97
|
+
}
|
|
98
|
+
interface SceneObjectFocusScreenDefinition {
|
|
99
|
+
id: string;
|
|
100
|
+
objectId: string;
|
|
101
|
+
anchorId: string;
|
|
102
|
+
paneId: string;
|
|
103
|
+
variant: "single-pane" | "multi-pane" | "combat-safe";
|
|
104
|
+
headingKey?: string;
|
|
105
|
+
}
|
|
106
|
+
interface SceneObjectPlayerSystemManifest extends SceneObjectManifest {
|
|
107
|
+
anchors?: SceneObjectAnchorDefinition[];
|
|
108
|
+
focusScreens?: SceneObjectFocusScreenDefinition[];
|
|
109
|
+
}
|
|
110
|
+
declare function validateSceneObjectPlayerSystemManifest(manifest: unknown): SceneObjectValidationResult<SceneObjectPlayerSystemManifest>;
|
|
111
|
+
declare function resolveSceneObjectAnchorById(manifest: SceneObjectPlayerSystemManifest, anchorId: string): SceneObjectAnchorDefinition | undefined;
|
|
112
|
+
declare function resolveSceneObjectFocusScreenById(manifest: SceneObjectPlayerSystemManifest, focusScreenId: string): SceneObjectFocusScreenDefinition | undefined;
|
|
113
|
+
|
|
85
114
|
declare function validateSceneObjectManifest(manifest: unknown): SceneObjectValidationResult<SceneObjectManifest>;
|
|
86
115
|
declare function createSceneObjectManifest(manifest: SceneObjectManifest): SceneObjectManifest;
|
|
87
116
|
declare function validateSceneObjectObjectState(state: unknown): SceneObjectValidationResult<SceneObjectObjectState>;
|
|
@@ -90,4 +119,4 @@ declare function resolveSceneObjectById(requestOrManifest: SceneObjectResolution
|
|
|
90
119
|
|
|
91
120
|
declare function resolveSceneObjectState(manifest: SceneObjectManifest, objectId: string): SceneObjectObjectState | undefined;
|
|
92
121
|
|
|
93
|
-
export { SCENE_OBJECT_RUNTIME_FLAG_ID, SCENE_OBJECT_SCHEMA_VERSION, type SceneObjectAttachment, type SceneObjectAttachmentPoint, type SceneObjectBounds, type SceneObjectManifest, type SceneObjectObjectState, type SceneObjectPoint, type SceneObjectReference, type SceneObjectResolutionRequest, type SceneObjectResolutionResult, type SceneObjectStateKind, type SceneObjectTransform, type SceneObjectValidationIssue, type SceneObjectValidationResult, type SceneObjectVector3, createSceneObjectManifest, resolveSceneObjectById, resolveSceneObjectReferences, resolveSceneObjectState, validateSceneObjectManifest, validateSceneObjectObjectState };
|
|
122
|
+
export { SCENE_OBJECT_PLAYER_SYSTEM_INTERFACE_FLAG_ID, SCENE_OBJECT_RUNTIME_FLAG_ID, SCENE_OBJECT_SCHEMA_VERSION, type SceneObjectAnchorDefinition, type SceneObjectAnchorKind, type SceneObjectAnchorVisibility, type SceneObjectAttachment, type SceneObjectAttachmentPoint, type SceneObjectBounds, type SceneObjectFocusScreenDefinition, type SceneObjectManifest, type SceneObjectObjectState, type SceneObjectPlayerSystemManifest, type SceneObjectPoint, type SceneObjectReference, type SceneObjectResolutionRequest, type SceneObjectResolutionResult, type SceneObjectStateKind, type SceneObjectTransform, type SceneObjectValidationIssue, type SceneObjectValidationResult, type SceneObjectVector3, createSceneObjectManifest, resolveSceneObjectAnchorById, resolveSceneObjectById, resolveSceneObjectFocusScreenById, resolveSceneObjectReferences, resolveSceneObjectState, validateSceneObjectManifest, validateSceneObjectObjectState, validateSceneObjectPlayerSystemManifest };
|
package/dist/index.d.ts
CHANGED
|
@@ -82,6 +82,35 @@ interface SceneObjectResolutionResult {
|
|
|
82
82
|
object: SceneObjectDefinition;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
declare const SCENE_OBJECT_PLAYER_SYSTEM_INTERFACE_FLAG_ID = "isekai.player-system.interface.enabled";
|
|
86
|
+
type SceneObjectAnchorKind = "target" | "focus-pane" | "localized-alert" | "line-of-sight-popup";
|
|
87
|
+
type SceneObjectAnchorVisibility = "always" | "combat-safe" | "focused-only" | "line-of-sight";
|
|
88
|
+
interface SceneObjectAnchorDefinition {
|
|
89
|
+
id: string;
|
|
90
|
+
kind: SceneObjectAnchorKind;
|
|
91
|
+
objectId: string;
|
|
92
|
+
pointId: string;
|
|
93
|
+
visibility: SceneObjectAnchorVisibility;
|
|
94
|
+
localeKey?: string;
|
|
95
|
+
offset?: SceneObjectVector3;
|
|
96
|
+
tags?: string[];
|
|
97
|
+
}
|
|
98
|
+
interface SceneObjectFocusScreenDefinition {
|
|
99
|
+
id: string;
|
|
100
|
+
objectId: string;
|
|
101
|
+
anchorId: string;
|
|
102
|
+
paneId: string;
|
|
103
|
+
variant: "single-pane" | "multi-pane" | "combat-safe";
|
|
104
|
+
headingKey?: string;
|
|
105
|
+
}
|
|
106
|
+
interface SceneObjectPlayerSystemManifest extends SceneObjectManifest {
|
|
107
|
+
anchors?: SceneObjectAnchorDefinition[];
|
|
108
|
+
focusScreens?: SceneObjectFocusScreenDefinition[];
|
|
109
|
+
}
|
|
110
|
+
declare function validateSceneObjectPlayerSystemManifest(manifest: unknown): SceneObjectValidationResult<SceneObjectPlayerSystemManifest>;
|
|
111
|
+
declare function resolveSceneObjectAnchorById(manifest: SceneObjectPlayerSystemManifest, anchorId: string): SceneObjectAnchorDefinition | undefined;
|
|
112
|
+
declare function resolveSceneObjectFocusScreenById(manifest: SceneObjectPlayerSystemManifest, focusScreenId: string): SceneObjectFocusScreenDefinition | undefined;
|
|
113
|
+
|
|
85
114
|
declare function validateSceneObjectManifest(manifest: unknown): SceneObjectValidationResult<SceneObjectManifest>;
|
|
86
115
|
declare function createSceneObjectManifest(manifest: SceneObjectManifest): SceneObjectManifest;
|
|
87
116
|
declare function validateSceneObjectObjectState(state: unknown): SceneObjectValidationResult<SceneObjectObjectState>;
|
|
@@ -90,4 +119,4 @@ declare function resolveSceneObjectById(requestOrManifest: SceneObjectResolution
|
|
|
90
119
|
|
|
91
120
|
declare function resolveSceneObjectState(manifest: SceneObjectManifest, objectId: string): SceneObjectObjectState | undefined;
|
|
92
121
|
|
|
93
|
-
export { SCENE_OBJECT_RUNTIME_FLAG_ID, SCENE_OBJECT_SCHEMA_VERSION, type SceneObjectAttachment, type SceneObjectAttachmentPoint, type SceneObjectBounds, type SceneObjectManifest, type SceneObjectObjectState, type SceneObjectPoint, type SceneObjectReference, type SceneObjectResolutionRequest, type SceneObjectResolutionResult, type SceneObjectStateKind, type SceneObjectTransform, type SceneObjectValidationIssue, type SceneObjectValidationResult, type SceneObjectVector3, createSceneObjectManifest, resolveSceneObjectById, resolveSceneObjectReferences, resolveSceneObjectState, validateSceneObjectManifest, validateSceneObjectObjectState };
|
|
122
|
+
export { SCENE_OBJECT_PLAYER_SYSTEM_INTERFACE_FLAG_ID, SCENE_OBJECT_RUNTIME_FLAG_ID, SCENE_OBJECT_SCHEMA_VERSION, type SceneObjectAnchorDefinition, type SceneObjectAnchorKind, type SceneObjectAnchorVisibility, type SceneObjectAttachment, type SceneObjectAttachmentPoint, type SceneObjectBounds, type SceneObjectFocusScreenDefinition, type SceneObjectManifest, type SceneObjectObjectState, type SceneObjectPlayerSystemManifest, type SceneObjectPoint, type SceneObjectReference, type SceneObjectResolutionRequest, type SceneObjectResolutionResult, type SceneObjectStateKind, type SceneObjectTransform, type SceneObjectValidationIssue, type SceneObjectValidationResult, type SceneObjectVector3, createSceneObjectManifest, resolveSceneObjectAnchorById, resolveSceneObjectById, resolveSceneObjectFocusScreenById, resolveSceneObjectReferences, resolveSceneObjectState, validateSceneObjectManifest, validateSceneObjectObjectState, validateSceneObjectPlayerSystemManifest };
|
package/dist/index.js
CHANGED
|
@@ -403,6 +403,317 @@ function resolveSceneObjectById(requestOrManifest, objectId) {
|
|
|
403
403
|
return result.value.objects.find((object) => object.id === request.objectId);
|
|
404
404
|
}
|
|
405
405
|
|
|
406
|
+
// src/player-system.ts
|
|
407
|
+
var SCENE_OBJECT_PLAYER_SYSTEM_INTERFACE_FLAG_ID = "isekai.player-system.interface.enabled";
|
|
408
|
+
var ID_PATTERN2 = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
409
|
+
var ANCHOR_KINDS = /* @__PURE__ */ new Set([
|
|
410
|
+
"target",
|
|
411
|
+
"focus-pane",
|
|
412
|
+
"localized-alert",
|
|
413
|
+
"line-of-sight-popup"
|
|
414
|
+
]);
|
|
415
|
+
var ANCHOR_VISIBILITIES = /* @__PURE__ */ new Set([
|
|
416
|
+
"always",
|
|
417
|
+
"combat-safe",
|
|
418
|
+
"focused-only",
|
|
419
|
+
"line-of-sight"
|
|
420
|
+
]);
|
|
421
|
+
var FOCUS_SCREEN_VARIANTS = /* @__PURE__ */ new Set([
|
|
422
|
+
"single-pane",
|
|
423
|
+
"multi-pane",
|
|
424
|
+
"combat-safe"
|
|
425
|
+
]);
|
|
426
|
+
function pushIssue2(issues, issue) {
|
|
427
|
+
issues.push(issue);
|
|
428
|
+
}
|
|
429
|
+
function isFiniteNumber2(value) {
|
|
430
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
431
|
+
}
|
|
432
|
+
function isKebabId(value) {
|
|
433
|
+
return typeof value === "string" && ID_PATTERN2.test(value);
|
|
434
|
+
}
|
|
435
|
+
function validateKebabId2(value, path, issues) {
|
|
436
|
+
if (typeof value !== "string") {
|
|
437
|
+
pushIssue2(issues, {
|
|
438
|
+
code: "invalid-type",
|
|
439
|
+
path,
|
|
440
|
+
message: "Expected a string identifier."
|
|
441
|
+
});
|
|
442
|
+
return false;
|
|
443
|
+
}
|
|
444
|
+
if (!ID_PATTERN2.test(value)) {
|
|
445
|
+
pushIssue2(issues, {
|
|
446
|
+
code: "invalid-id",
|
|
447
|
+
path,
|
|
448
|
+
message: "Identifiers must be kebab-case tokens."
|
|
449
|
+
});
|
|
450
|
+
return false;
|
|
451
|
+
}
|
|
452
|
+
return true;
|
|
453
|
+
}
|
|
454
|
+
function findObjectPoint(object, pointId) {
|
|
455
|
+
return object?.attachmentPoints?.find((point) => point.id === pointId);
|
|
456
|
+
}
|
|
457
|
+
function validateAnchorDefinition(anchor, path, issues, objectsById, anchorIds) {
|
|
458
|
+
if (!anchor || typeof anchor !== "object") {
|
|
459
|
+
pushIssue2(issues, {
|
|
460
|
+
code: "required",
|
|
461
|
+
path,
|
|
462
|
+
message: "Expected anchor definition object."
|
|
463
|
+
});
|
|
464
|
+
return false;
|
|
465
|
+
}
|
|
466
|
+
const value = anchor;
|
|
467
|
+
let valid = true;
|
|
468
|
+
if (!validateKebabId2(value.id, `${path}.id`, issues)) {
|
|
469
|
+
valid = false;
|
|
470
|
+
} else if (anchorIds.has(value.id)) {
|
|
471
|
+
pushIssue2(issues, {
|
|
472
|
+
code: "duplicate-id",
|
|
473
|
+
path: `${path}.id`,
|
|
474
|
+
message: "Anchor identifiers must be unique."
|
|
475
|
+
});
|
|
476
|
+
valid = false;
|
|
477
|
+
} else {
|
|
478
|
+
anchorIds.add(value.id);
|
|
479
|
+
}
|
|
480
|
+
if (!validateKebabId2(value.objectId, `${path}.objectId`, issues)) {
|
|
481
|
+
valid = false;
|
|
482
|
+
}
|
|
483
|
+
if (!validateKebabId2(value.pointId, `${path}.pointId`, issues)) {
|
|
484
|
+
valid = false;
|
|
485
|
+
}
|
|
486
|
+
if (!ANCHOR_KINDS.has(value.kind)) {
|
|
487
|
+
pushIssue2(issues, {
|
|
488
|
+
code: "invalid-value",
|
|
489
|
+
path: `${path}.kind`,
|
|
490
|
+
message: "Anchor kind must be target, focus-pane, localized-alert, or line-of-sight-popup."
|
|
491
|
+
});
|
|
492
|
+
valid = false;
|
|
493
|
+
}
|
|
494
|
+
if (!ANCHOR_VISIBILITIES.has(value.visibility)) {
|
|
495
|
+
pushIssue2(issues, {
|
|
496
|
+
code: "invalid-value",
|
|
497
|
+
path: `${path}.visibility`,
|
|
498
|
+
message: "Anchor visibility must be always, combat-safe, focused-only, or line-of-sight."
|
|
499
|
+
});
|
|
500
|
+
valid = false;
|
|
501
|
+
}
|
|
502
|
+
const object = typeof value.objectId === "string" ? objectsById.get(value.objectId) : void 0;
|
|
503
|
+
if (!object) {
|
|
504
|
+
pushIssue2(issues, {
|
|
505
|
+
code: "missing-reference",
|
|
506
|
+
path: `${path}.objectId`,
|
|
507
|
+
message: "Anchor objectId must reference an existing scene object."
|
|
508
|
+
});
|
|
509
|
+
valid = false;
|
|
510
|
+
} else if (typeof value.pointId === "string" && !findObjectPoint(object, value.pointId)) {
|
|
511
|
+
pushIssue2(issues, {
|
|
512
|
+
code: "missing-reference",
|
|
513
|
+
path: `${path}.pointId`,
|
|
514
|
+
message: "Anchor pointId must reference an attachment point on the target object."
|
|
515
|
+
});
|
|
516
|
+
valid = false;
|
|
517
|
+
}
|
|
518
|
+
if (value.kind === "localized-alert") {
|
|
519
|
+
if (typeof value.localeKey !== "string" || value.localeKey.trim().length === 0) {
|
|
520
|
+
pushIssue2(issues, {
|
|
521
|
+
code: "required",
|
|
522
|
+
path: `${path}.localeKey`,
|
|
523
|
+
message: "localized-alert anchors require a localeKey."
|
|
524
|
+
});
|
|
525
|
+
valid = false;
|
|
526
|
+
}
|
|
527
|
+
} else if (value.localeKey !== void 0 && (typeof value.localeKey !== "string" || value.localeKey.trim().length === 0)) {
|
|
528
|
+
pushIssue2(issues, {
|
|
529
|
+
code: "invalid-type",
|
|
530
|
+
path: `${path}.localeKey`,
|
|
531
|
+
message: "localeKey must be a non-empty string when present."
|
|
532
|
+
});
|
|
533
|
+
valid = false;
|
|
534
|
+
}
|
|
535
|
+
if (value.offset !== void 0) {
|
|
536
|
+
if (!value.offset || typeof value.offset !== "object") {
|
|
537
|
+
pushIssue2(issues, {
|
|
538
|
+
code: "invalid-type",
|
|
539
|
+
path: `${path}.offset`,
|
|
540
|
+
message: "offset must be a finite x/y/z vector when present."
|
|
541
|
+
});
|
|
542
|
+
valid = false;
|
|
543
|
+
} else {
|
|
544
|
+
for (const axis of ["x", "y", "z"]) {
|
|
545
|
+
if (!isFiniteNumber2(value.offset[axis])) {
|
|
546
|
+
pushIssue2(issues, {
|
|
547
|
+
code: "invalid-type",
|
|
548
|
+
path: `${path}.offset.${axis}`,
|
|
549
|
+
message: "offset axes must be finite numbers."
|
|
550
|
+
});
|
|
551
|
+
valid = false;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
if (value.tags !== void 0) {
|
|
557
|
+
if (!Array.isArray(value.tags) || value.tags.some((tag) => typeof tag !== "string" || tag.trim().length === 0)) {
|
|
558
|
+
pushIssue2(issues, {
|
|
559
|
+
code: "invalid-type",
|
|
560
|
+
path: `${path}.tags`,
|
|
561
|
+
message: "tags must be an array of non-empty strings when present."
|
|
562
|
+
});
|
|
563
|
+
valid = false;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
return valid;
|
|
567
|
+
}
|
|
568
|
+
function validateFocusScreenDefinition(focusScreen, path, issues, objectsById, anchorsById, focusScreenIds) {
|
|
569
|
+
if (!focusScreen || typeof focusScreen !== "object") {
|
|
570
|
+
pushIssue2(issues, {
|
|
571
|
+
code: "required",
|
|
572
|
+
path,
|
|
573
|
+
message: "Expected focus-screen definition object."
|
|
574
|
+
});
|
|
575
|
+
return false;
|
|
576
|
+
}
|
|
577
|
+
const value = focusScreen;
|
|
578
|
+
let valid = true;
|
|
579
|
+
if (!validateKebabId2(value.id, `${path}.id`, issues)) {
|
|
580
|
+
valid = false;
|
|
581
|
+
} else if (focusScreenIds.has(value.id)) {
|
|
582
|
+
pushIssue2(issues, {
|
|
583
|
+
code: "duplicate-id",
|
|
584
|
+
path: `${path}.id`,
|
|
585
|
+
message: "Focus-screen identifiers must be unique."
|
|
586
|
+
});
|
|
587
|
+
valid = false;
|
|
588
|
+
} else {
|
|
589
|
+
focusScreenIds.add(value.id);
|
|
590
|
+
}
|
|
591
|
+
if (!validateKebabId2(value.objectId, `${path}.objectId`, issues)) {
|
|
592
|
+
valid = false;
|
|
593
|
+
} else if (!objectsById.has(value.objectId)) {
|
|
594
|
+
pushIssue2(issues, {
|
|
595
|
+
code: "missing-reference",
|
|
596
|
+
path: `${path}.objectId`,
|
|
597
|
+
message: "Focus-screen objectId must reference an existing scene object."
|
|
598
|
+
});
|
|
599
|
+
valid = false;
|
|
600
|
+
}
|
|
601
|
+
if (!validateKebabId2(value.anchorId, `${path}.anchorId`, issues)) {
|
|
602
|
+
valid = false;
|
|
603
|
+
} else {
|
|
604
|
+
const anchor = anchorsById.get(value.anchorId);
|
|
605
|
+
if (!anchor) {
|
|
606
|
+
pushIssue2(issues, {
|
|
607
|
+
code: "missing-reference",
|
|
608
|
+
path: `${path}.anchorId`,
|
|
609
|
+
message: "Focus-screen anchorId must reference an exported anchor."
|
|
610
|
+
});
|
|
611
|
+
valid = false;
|
|
612
|
+
} else if (anchor.kind !== "focus-pane") {
|
|
613
|
+
pushIssue2(issues, {
|
|
614
|
+
code: "invalid-reference",
|
|
615
|
+
path: `${path}.anchorId`,
|
|
616
|
+
message: "Focus screens must bind to focus-pane anchors."
|
|
617
|
+
});
|
|
618
|
+
valid = false;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
if (!validateKebabId2(value.paneId, `${path}.paneId`, issues)) {
|
|
622
|
+
valid = false;
|
|
623
|
+
}
|
|
624
|
+
if (!FOCUS_SCREEN_VARIANTS.has(value.variant)) {
|
|
625
|
+
pushIssue2(issues, {
|
|
626
|
+
code: "invalid-value",
|
|
627
|
+
path: `${path}.variant`,
|
|
628
|
+
message: "Focus-screen variant must be single-pane, multi-pane, or combat-safe."
|
|
629
|
+
});
|
|
630
|
+
valid = false;
|
|
631
|
+
}
|
|
632
|
+
if (value.headingKey !== void 0 && (typeof value.headingKey !== "string" || value.headingKey.trim().length === 0)) {
|
|
633
|
+
pushIssue2(issues, {
|
|
634
|
+
code: "invalid-type",
|
|
635
|
+
path: `${path}.headingKey`,
|
|
636
|
+
message: "headingKey must be a non-empty string when present."
|
|
637
|
+
});
|
|
638
|
+
valid = false;
|
|
639
|
+
}
|
|
640
|
+
return valid;
|
|
641
|
+
}
|
|
642
|
+
function validateSceneObjectPlayerSystemManifest(manifest) {
|
|
643
|
+
const base = validateSceneObjectManifest(manifest);
|
|
644
|
+
if (!base.valid || !base.value) {
|
|
645
|
+
return base;
|
|
646
|
+
}
|
|
647
|
+
const issues = [...base.issues];
|
|
648
|
+
const value = manifest;
|
|
649
|
+
const objectsById = new Map(
|
|
650
|
+
base.value.objects.map((object) => [object.id, object])
|
|
651
|
+
);
|
|
652
|
+
const anchorIds = /* @__PURE__ */ new Set();
|
|
653
|
+
const anchorsById = /* @__PURE__ */ new Map();
|
|
654
|
+
const focusScreenIds = /* @__PURE__ */ new Set();
|
|
655
|
+
let valid = true;
|
|
656
|
+
if (value.anchors !== void 0) {
|
|
657
|
+
if (!Array.isArray(value.anchors)) {
|
|
658
|
+
pushIssue2(issues, {
|
|
659
|
+
code: "invalid-type",
|
|
660
|
+
path: "$.anchors",
|
|
661
|
+
message: "anchors must be an array when present."
|
|
662
|
+
});
|
|
663
|
+
valid = false;
|
|
664
|
+
} else {
|
|
665
|
+
value.anchors.forEach((anchor, index) => {
|
|
666
|
+
const path = `$.anchors[${index}]`;
|
|
667
|
+
if (validateAnchorDefinition(anchor, path, issues, objectsById, anchorIds)) {
|
|
668
|
+
anchorsById.set(anchor.id, anchor);
|
|
669
|
+
} else {
|
|
670
|
+
valid = false;
|
|
671
|
+
}
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
if (value.focusScreens !== void 0) {
|
|
676
|
+
if (!Array.isArray(value.focusScreens)) {
|
|
677
|
+
pushIssue2(issues, {
|
|
678
|
+
code: "invalid-type",
|
|
679
|
+
path: "$.focusScreens",
|
|
680
|
+
message: "focusScreens must be an array when present."
|
|
681
|
+
});
|
|
682
|
+
valid = false;
|
|
683
|
+
} else {
|
|
684
|
+
value.focusScreens.forEach((focusScreen, index) => {
|
|
685
|
+
if (!validateFocusScreenDefinition(
|
|
686
|
+
focusScreen,
|
|
687
|
+
`$.focusScreens[${index}]`,
|
|
688
|
+
issues,
|
|
689
|
+
objectsById,
|
|
690
|
+
anchorsById,
|
|
691
|
+
focusScreenIds
|
|
692
|
+
)) {
|
|
693
|
+
valid = false;
|
|
694
|
+
}
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
return {
|
|
699
|
+
valid,
|
|
700
|
+
issues,
|
|
701
|
+
value: valid ? value : void 0
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
function resolveSceneObjectAnchorById(manifest, anchorId) {
|
|
705
|
+
if (!isKebabId(anchorId)) {
|
|
706
|
+
return void 0;
|
|
707
|
+
}
|
|
708
|
+
return manifest.anchors?.find((anchor) => anchor.id === anchorId);
|
|
709
|
+
}
|
|
710
|
+
function resolveSceneObjectFocusScreenById(manifest, focusScreenId) {
|
|
711
|
+
if (!isKebabId(focusScreenId)) {
|
|
712
|
+
return void 0;
|
|
713
|
+
}
|
|
714
|
+
return manifest.focusScreens?.find((focusScreen) => focusScreen.id === focusScreenId);
|
|
715
|
+
}
|
|
716
|
+
|
|
406
717
|
// src/resolve.ts
|
|
407
718
|
function resolveSceneObjectState(manifest, objectId) {
|
|
408
719
|
if (!manifest.stateSnapshots || !Array.isArray(manifest.stateSnapshots)) {
|
|
@@ -413,13 +724,17 @@ function resolveSceneObjectState(manifest, objectId) {
|
|
|
413
724
|
);
|
|
414
725
|
}
|
|
415
726
|
export {
|
|
727
|
+
SCENE_OBJECT_PLAYER_SYSTEM_INTERFACE_FLAG_ID,
|
|
416
728
|
SCENE_OBJECT_RUNTIME_FLAG_ID,
|
|
417
729
|
SCENE_OBJECT_SCHEMA_VERSION,
|
|
418
730
|
createSceneObjectManifest,
|
|
731
|
+
resolveSceneObjectAnchorById,
|
|
419
732
|
resolveSceneObjectById,
|
|
733
|
+
resolveSceneObjectFocusScreenById,
|
|
420
734
|
resolveSceneObjectReferences,
|
|
421
735
|
resolveSceneObjectState,
|
|
422
736
|
validateSceneObjectManifest,
|
|
423
|
-
validateSceneObjectObjectState
|
|
737
|
+
validateSceneObjectObjectState,
|
|
738
|
+
validateSceneObjectPlayerSystemManifest
|
|
424
739
|
};
|
|
425
740
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts","../src/validation.ts","../src/resolve.ts"],"sourcesContent":["export const SCENE_OBJECT_SCHEMA_VERSION = \"1.0.0\";\nexport const SCENE_OBJECT_RUNTIME_FLAG_ID = \"scene.object.runtime.enabled\";\n\nexport type SceneObjectStateKind = \"idle\" | \"visible\" | \"hidden\" | \"disabled\";\n\nexport type SceneObjectCoordinateSpace =\n | \"normalized-viewport\"\n | \"pixel-viewport\"\n | \"world\"\n | \"local\";\n\nexport type SceneObjectUnits = \"ratio\" | \"pixels\";\n\nexport interface SceneObjectVector3 {\n x: number;\n y: number;\n z: number;\n}\n\nexport interface SceneObjectTransform {\n translate: SceneObjectVector3;\n rotate: SceneObjectVector3;\n scale: SceneObjectVector3;\n}\n\nexport interface SceneObjectBounds {\n rect: {\n x: number;\n y: number;\n width: number;\n height: number;\n unit: SceneObjectUnits;\n };\n depth?: number;\n coordinateSpace: SceneObjectCoordinateSpace;\n}\n\nexport interface SceneObjectPoint {\n id: string;\n x: number;\n y: number;\n z?: number;\n}\n\nexport interface SceneObjectAttachment {\n id: string;\n sourceObjectId: string;\n sourcePointId: string;\n targetObjectId: string;\n targetPointId: string;\n offset?: SceneObjectVector3;\n}\n\nexport type SceneObjectAttachmentPoint = SceneObjectPoint;\n\nexport interface SceneObjectObjectState {\n objectId: string;\n visible: boolean;\n tags?: string[];\n metadata?: Record<string, unknown>;\n}\n\nexport interface SceneObjectReference {\n objectId: string;\n pointId: string;\n}\n\nexport interface SceneObjectManifest {\n schemaVersion: string;\n objects: SceneObjectDefinition[];\n stateSnapshots?: SceneObjectObjectState[];\n}\n\nexport interface SceneObjectDefinition {\n id: string;\n name?: string;\n transform: SceneObjectTransform;\n bounds: SceneObjectBounds;\n attachmentPoints?: SceneObjectPoint[];\n attachments?: SceneObjectAttachment[];\n}\n\nexport type SceneObjectValidationCode =\n | \"required\"\n | \"invalid-type\"\n | \"invalid-value\"\n | \"invalid-id\"\n | \"duplicate-id\"\n | \"invalid-reference\"\n | \"missing-reference\";\n\nexport interface SceneObjectValidationIssue {\n code: SceneObjectValidationCode;\n path: string;\n message: string;\n}\n\nexport interface SceneObjectValidationResult<T> {\n valid: boolean;\n issues: SceneObjectValidationIssue[];\n value?: T;\n}\n\nexport interface SceneObjectResolutionRequest {\n manifest: SceneObjectManifest;\n objectId: string;\n}\n\nexport interface SceneObjectResolutionResult {\n manifest: SceneObjectManifest;\n object: SceneObjectDefinition;\n}\n","import {\n SCENE_OBJECT_SCHEMA_VERSION,\n type SceneObjectBounds,\n type SceneObjectCoordinateSpace,\n type SceneObjectManifest,\n type SceneObjectObjectState,\n type SceneObjectPoint,\n type SceneObjectValidationIssue,\n type SceneObjectValidationResult,\n type SceneObjectDefinition,\n type SceneObjectAttachment,\n type SceneObjectResolutionRequest,\n type SceneObjectTransform,\n} from \"./types.js\";\n\nconst ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\nconst COORDINATE_SPACES = new Set<SceneObjectCoordinateSpace>([\n \"normalized-viewport\",\n \"pixel-viewport\",\n \"world\",\n \"local\",\n]);\nconst UNITS = new Set([\"ratio\", \"pixels\"]);\n\nfunction pushIssue(\n issues: SceneObjectValidationIssue[],\n issue: SceneObjectValidationIssue,\n): void {\n issues.push(issue);\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\nfunction validateKebabId(\n value: unknown,\n path: string,\n issues: SceneObjectValidationIssue[],\n): value is string {\n if (typeof value !== \"string\") {\n pushIssue(issues, {\n code: \"invalid-type\",\n path,\n message: \"Expected a string identifier.\",\n });\n return false;\n }\n\n if (!ID_PATTERN.test(value)) {\n pushIssue(issues, {\n code: \"invalid-id\",\n path,\n message: \"Identifiers must be kebab-case tokens.\",\n });\n return false;\n }\n\n return true;\n}\n\nfunction validateTransform(\n value: SceneObjectTransform,\n path: string,\n issues: SceneObjectValidationIssue[],\n): boolean {\n const vectorChecks = [\"translate\", \"rotate\", \"scale\"] as const;\n let valid = true;\n\n for (const field of vectorChecks) {\n const vector = value[field];\n if (!vector || typeof vector !== \"object\") {\n pushIssue(issues, {\n code: \"required\",\n path: `${path}.${field}`,\n message: `Expected a ${field} vector.`,\n });\n valid = false;\n continue;\n }\n\n for (const axis of [\"x\", \"y\", \"z\"] as const) {\n const raw = vector[axis];\n if (!isFiniteNumber(raw)) {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.${field}.${axis}`,\n message: `Vector ${axis} must be finite.`,\n });\n valid = false;\n }\n }\n }\n\n return valid;\n}\n\nfunction validatePoint(point: SceneObjectPoint, path: string, issues: SceneObjectValidationIssue[]): boolean {\n let valid = true;\n\n if (!validateKebabId(point.id, `${path}.id`, issues)) {\n valid = false;\n }\n\n for (const field of [\"x\", \"y\", \"z\"] as const) {\n const value = point[field];\n if (field === \"z\" && value === undefined) {\n continue;\n }\n if (!isFiniteNumber(value)) {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.${field}`,\n message: \"Attachment point axis must be finite.\",\n });\n valid = false;\n }\n }\n\n return valid;\n}\n\nfunction validateBounds(bounds: SceneObjectBounds, path: string, issues: SceneObjectValidationIssue[]): boolean {\n if (!bounds || typeof bounds !== \"object\") {\n pushIssue(issues, { code: \"required\", path, message: \"Expected bounds block.\" });\n return false;\n }\n\n if (!COORDINATE_SPACES.has(bounds.coordinateSpace as SceneObjectCoordinateSpace)) {\n pushIssue(issues, {\n code: \"invalid-value\",\n path: `${path}.coordinateSpace`,\n message: \"coordinateSpace must be normalized-viewport, pixel-viewport, world, or local.\",\n });\n return false;\n }\n\n const rect = bounds.rect;\n if (!rect || typeof rect !== \"object\") {\n pushIssue(issues, { code: \"required\", path: `${path}.rect`, message: \"Expected rect bounds.\" });\n return false;\n }\n\n if (!UNITS.has(rect.unit as string)) {\n pushIssue(issues, {\n code: \"invalid-value\",\n path: `${path}.rect.unit`,\n message: \"unit must be 'ratio' or 'pixels'.\",\n });\n return false;\n }\n\n let valid = true;\n for (const field of [\"x\", \"y\", \"width\", \"height\"] as const) {\n const value = rect[field];\n if (!isFiniteNumber(value) || value < 0) {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.rect.${field}`,\n message: \"Rect fields must be finite non-negative numbers.\",\n });\n valid = false;\n }\n }\n\n if (rect.width === 0 || rect.height === 0) {\n pushIssue(issues, {\n code: \"invalid-value\",\n path: `${path}.rect`,\n message: \"Rect width and height must be positive.\",\n });\n valid = false;\n }\n\n if (bounds.depth !== undefined && (!isFiniteNumber(bounds.depth) || bounds.depth < 0)) {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.depth`,\n message: \"depth must be a non-negative number.\",\n });\n valid = false;\n }\n\n return valid && isFiniteNumber(bounds.rect.width) && isFiniteNumber(bounds.rect.height);\n}\n\nfunction validateAttachmentTarget(\n attachment: {\n id: string;\n sourceObjectId: string;\n sourcePointId: string;\n targetObjectId: string;\n targetPointId: string;\n },\n path: string,\n issues: SceneObjectValidationIssue[],\n seenPoints: Map<string, Set<string>>,\n): boolean {\n let valid = true;\n if (!validateKebabId(attachment.id, `${path}.id`, issues)) {\n valid = false;\n }\n\n if (!validateKebabId(attachment.sourceObjectId, `${path}.sourceObjectId`, issues)) {\n valid = false;\n }\n\n if (!validateKebabId(attachment.targetObjectId, `${path}.targetObjectId`, issues)) {\n valid = false;\n }\n\n if (!validateKebabId(attachment.sourcePointId, `${path}.sourcePointId`, issues)) {\n valid = false;\n }\n\n if (!validateKebabId(attachment.targetPointId, `${path}.targetPointId`, issues)) {\n valid = false;\n }\n\n const sourcePoints = seenPoints.get(attachment.sourceObjectId);\n const targetPoints = seenPoints.get(attachment.targetObjectId);\n\n if (sourcePoints && !sourcePoints.has(attachment.sourcePointId)) {\n pushIssue(issues, {\n code: \"invalid-reference\",\n path: `${path}.sourcePointId`,\n message: \"sourcePointId does not exist on source object.\",\n });\n valid = false;\n }\n\n if (targetPoints && !targetPoints.has(attachment.targetPointId)) {\n pushIssue(issues, {\n code: \"invalid-reference\",\n path: `${path}.targetPointId`,\n message: \"targetPointId does not exist on target object.\",\n });\n valid = false;\n }\n\n return valid;\n}\n\nexport function validateSceneObjectManifest(\n manifest: unknown,\n): SceneObjectValidationResult<SceneObjectManifest> {\n const issues: SceneObjectValidationIssue[] = [];\n\n if (!manifest || typeof manifest !== \"object\") {\n return {\n valid: false,\n issues: [{ code: \"required\", path: \"$\", message: \"Expected a scene object manifest object.\" }],\n };\n }\n\n const value = manifest as Record<string, unknown>;\n let valid = true;\n\n if (value.schemaVersion !== SCENE_OBJECT_SCHEMA_VERSION) {\n pushIssue(issues, {\n code: \"invalid-value\",\n path: \"$.schemaVersion\",\n message: `schemaVersion must equal ${SCENE_OBJECT_SCHEMA_VERSION}.`,\n });\n valid = false;\n }\n\n if (!Array.isArray(value.objects) || value.objects.length === 0) {\n pushIssue(issues, {\n code: \"required\",\n path: \"$.objects\",\n message: \"Manifest must contain at least one object.\",\n });\n return { valid: false, issues };\n }\n\n const objects = value.objects as SceneObjectDefinition[];\n const seenObjects = new Set<string>();\n const pointsByObject = new Map<string, Set<string>>();\n\n for (const [index, object] of objects.entries()) {\n const path = `$.objects[${index}]`;\n\n if (!object || typeof object !== \"object\") {\n pushIssue(issues, { code: \"required\", path, message: \"Expected object definition.\" });\n valid = false;\n continue;\n }\n\n if (!validateKebabId(object.id, `${path}.id`, issues)) {\n valid = false;\n }\n\n if (seenObjects.has(object.id)) {\n pushIssue(issues, {\n code: \"duplicate-id\",\n path: `${path}.id`,\n message: `Duplicate object id '${object.id}' is not allowed.`,\n });\n valid = false;\n }\n seenObjects.add(object.id);\n\n if (!object.transform || typeof object.transform !== \"object\" || !validateTransform(object.transform as SceneObjectTransform, `${path}.transform`, issues)) {\n pushIssue(issues, {\n code: \"required\",\n path: `${path}.transform`,\n message: \"Object must define a transform.\",\n });\n valid = false;\n }\n\n if (!object.bounds) {\n pushIssue(issues, {\n code: \"required\",\n path: `${path}.bounds`,\n message: \"Object must define bounds.\",\n });\n valid = false;\n } else if (!validateBounds(object.bounds, `${path}.bounds`, issues)) {\n valid = false;\n }\n\n const attachmentPointIds = new Set<string>();\n const rawPoints = Array.isArray(object.attachmentPoints)\n ? object.attachmentPoints\n : [];\n for (const [pointIndex, point] of rawPoints.entries()) {\n if (!point || typeof point !== \"object\") {\n pushIssue(issues, {\n code: \"required\",\n path: `${path}.attachmentPoints[${pointIndex}]`,\n message: \"Expected attachment point definition.\",\n });\n valid = false;\n continue;\n }\n\n if (!validatePoint(point as SceneObjectPoint, `${path}.attachmentPoints[${pointIndex}]`, issues)) {\n valid = false;\n continue;\n }\n\n const pointId = (point as SceneObjectPoint).id;\n if (attachmentPointIds.has(pointId)) {\n pushIssue(issues, {\n code: \"duplicate-id\",\n path: `${path}.attachmentPoints[${pointIndex}].id`,\n message: `Duplicate attachment point '${pointId}' within object.`,\n });\n valid = false;\n }\n attachmentPointIds.add(pointId);\n }\n\n if (rawPoints.length > 0) {\n pointsByObject.set(object.id, attachmentPointIds);\n }\n\n if (Array.isArray(object.attachments)) {\n const attachmentIds = new Set<string>();\n for (const [attachmentIndex, attachment] of object.attachments.entries()) {\n if (!attachment || typeof attachment !== \"object\") {\n pushIssue(issues, {\n code: \"required\",\n path: `${path}.attachments[${attachmentIndex}]`,\n message: \"Expected attachment definition.\",\n });\n valid = false;\n continue;\n }\n\n if (!validateKebabId((attachment as SceneObjectAttachment).sourceObjectId, `${path}.attachments[${attachmentIndex}].sourceObjectId`, issues)) {\n valid = false;\n }\n\n if (!attachmentIds.has((attachment as { id?: string }).id ?? \"\")) {\n attachmentIds.add((attachment as { id?: string }).id ?? \"\");\n } else {\n pushIssue(issues, {\n code: \"duplicate-id\",\n path: `${path}.attachments[${attachmentIndex}].id`,\n message: \"Duplicate attachment id.\",\n });\n valid = false;\n }\n\n if (\n !validateAttachmentTarget(\n attachment as {\n id: string;\n sourceObjectId: string;\n sourcePointId: string;\n targetObjectId: string;\n targetPointId: string;\n },\n `${path}.attachments[${attachmentIndex}]`,\n issues,\n pointsByObject,\n )\n ) {\n valid = false;\n }\n }\n }\n }\n\n const objectIds = new Set(\n objects\n .filter((candidate): candidate is SceneObjectDefinition => Boolean(candidate && typeof candidate === \"object\"))\n .map((candidate) => candidate.id),\n );\n if (Array.isArray(value.stateSnapshots)) {\n for (const [stateIndex, state] of value.stateSnapshots.entries()) {\n const stateValue = state as SceneObjectObjectState;\n const path = `$.stateSnapshots[${stateIndex}]`;\n\n if (!stateValue || typeof stateValue !== \"object\") {\n pushIssue(issues, {\n code: \"required\",\n path,\n message: \"Expected object state definition.\",\n });\n valid = false;\n continue;\n }\n\n if (!validateKebabId(stateValue.objectId, `${path}.objectId`, issues)) {\n valid = false;\n }\n\n if (!objectIds.has(stateValue.objectId)) {\n pushIssue(issues, {\n code: \"missing-reference\",\n path: `${path}.objectId`,\n message: \"objectId does not reference an object in objects.\",\n });\n valid = false;\n }\n\n if (typeof stateValue.visible !== \"boolean\") {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.visible`,\n message: \"visible must be a boolean.\",\n });\n valid = false;\n }\n }\n }\n\n return valid\n ? { valid: true, issues, value: manifest as SceneObjectManifest }\n : { valid: false, issues };\n}\n\nexport function createSceneObjectManifest(manifest: SceneObjectManifest): SceneObjectManifest {\n const result = validateSceneObjectManifest(manifest);\n if (!result.valid || !result.value) {\n const summary = result.issues.map((issue) => `${issue.path}: ${issue.message}`).join(\"; \");\n throw new Error(`Invalid scene object manifest. ${summary}`);\n }\n\n return result.value;\n}\n\nexport function validateSceneObjectObjectState(state: unknown): SceneObjectValidationResult<SceneObjectObjectState> {\n if (!state || typeof state !== \"object\") {\n return {\n valid: false,\n issues: [{\n code: \"required\",\n path: \"$\",\n message: \"Expected an object state.\",\n }],\n };\n }\n\n const value = state as Record<string, unknown>;\n const issues: SceneObjectValidationIssue[] = [];\n let valid = true;\n\n if (!validateKebabId(value.objectId, \"$.objectId\", issues)) {\n valid = false;\n }\n\n if (typeof value.visible !== \"boolean\") {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: \"$.visible\",\n message: \"visible must be a boolean.\",\n });\n valid = false;\n }\n\n return valid\n ? { valid: true, issues, value: state as SceneObjectObjectState }\n : { valid: false, issues };\n}\n\nexport function resolveSceneObjectReferences(\n manifest: SceneObjectManifest,\n): SceneObjectValidationResult<SceneObjectManifest> {\n const result = validateSceneObjectManifest(manifest);\n if (!result.valid || !result.value) {\n return { valid: false, issues: result.issues };\n }\n\n return { valid: true, issues: [], value: result.value };\n}\n\nexport function resolveSceneObjectById(\n requestOrManifest:\n | SceneObjectResolutionRequest\n | SceneObjectManifest,\n objectId?: string,\n): SceneObjectDefinition | undefined {\n const request: SceneObjectResolutionRequest = typeof objectId === \"string\"\n ? {\n manifest: requestOrManifest as SceneObjectManifest,\n objectId,\n }\n : requestOrManifest as SceneObjectResolutionRequest;\n\n const result = validateSceneObjectManifest(request.manifest);\n if (!result.valid || !result.value) {\n return undefined;\n }\n\n return result.value.objects.find((object) => object.id === request.objectId);\n}\n","import {\n SceneObjectManifest,\n SceneObjectObjectState,\n SceneObjectDefinition,\n} from \"./types.js\";\n\nexport function resolveSceneObjectState(\n manifest: SceneObjectManifest,\n objectId: string,\n): SceneObjectObjectState | undefined {\n if (!manifest.stateSnapshots || !Array.isArray(manifest.stateSnapshots)) {\n return undefined;\n }\n\n return manifest.stateSnapshots.find(\n (snapshot) => snapshot.objectId === objectId,\n );\n}\n\nexport function resolveSceneObjectById(\n manifest: SceneObjectManifest,\n objectId: string,\n): SceneObjectDefinition | undefined {\n return manifest.objects.find((object) => object.id === objectId);\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/validation.ts","../src/player-system.ts","../src/resolve.ts"],"sourcesContent":["export const SCENE_OBJECT_SCHEMA_VERSION = \"1.0.0\";\nexport const SCENE_OBJECT_RUNTIME_FLAG_ID = \"scene.object.runtime.enabled\";\n\nexport type SceneObjectStateKind = \"idle\" | \"visible\" | \"hidden\" | \"disabled\";\n\nexport type SceneObjectCoordinateSpace =\n | \"normalized-viewport\"\n | \"pixel-viewport\"\n | \"world\"\n | \"local\";\n\nexport type SceneObjectUnits = \"ratio\" | \"pixels\";\n\nexport interface SceneObjectVector3 {\n x: number;\n y: number;\n z: number;\n}\n\nexport interface SceneObjectTransform {\n translate: SceneObjectVector3;\n rotate: SceneObjectVector3;\n scale: SceneObjectVector3;\n}\n\nexport interface SceneObjectBounds {\n rect: {\n x: number;\n y: number;\n width: number;\n height: number;\n unit: SceneObjectUnits;\n };\n depth?: number;\n coordinateSpace: SceneObjectCoordinateSpace;\n}\n\nexport interface SceneObjectPoint {\n id: string;\n x: number;\n y: number;\n z?: number;\n}\n\nexport interface SceneObjectAttachment {\n id: string;\n sourceObjectId: string;\n sourcePointId: string;\n targetObjectId: string;\n targetPointId: string;\n offset?: SceneObjectVector3;\n}\n\nexport type SceneObjectAttachmentPoint = SceneObjectPoint;\n\nexport interface SceneObjectObjectState {\n objectId: string;\n visible: boolean;\n tags?: string[];\n metadata?: Record<string, unknown>;\n}\n\nexport interface SceneObjectReference {\n objectId: string;\n pointId: string;\n}\n\nexport interface SceneObjectManifest {\n schemaVersion: string;\n objects: SceneObjectDefinition[];\n stateSnapshots?: SceneObjectObjectState[];\n}\n\nexport interface SceneObjectDefinition {\n id: string;\n name?: string;\n transform: SceneObjectTransform;\n bounds: SceneObjectBounds;\n attachmentPoints?: SceneObjectPoint[];\n attachments?: SceneObjectAttachment[];\n}\n\nexport type SceneObjectValidationCode =\n | \"required\"\n | \"invalid-type\"\n | \"invalid-value\"\n | \"invalid-id\"\n | \"duplicate-id\"\n | \"invalid-reference\"\n | \"missing-reference\";\n\nexport interface SceneObjectValidationIssue {\n code: SceneObjectValidationCode;\n path: string;\n message: string;\n}\n\nexport interface SceneObjectValidationResult<T> {\n valid: boolean;\n issues: SceneObjectValidationIssue[];\n value?: T;\n}\n\nexport interface SceneObjectResolutionRequest {\n manifest: SceneObjectManifest;\n objectId: string;\n}\n\nexport interface SceneObjectResolutionResult {\n manifest: SceneObjectManifest;\n object: SceneObjectDefinition;\n}\n","import {\n SCENE_OBJECT_SCHEMA_VERSION,\n type SceneObjectBounds,\n type SceneObjectCoordinateSpace,\n type SceneObjectManifest,\n type SceneObjectObjectState,\n type SceneObjectPoint,\n type SceneObjectValidationIssue,\n type SceneObjectValidationResult,\n type SceneObjectDefinition,\n type SceneObjectAttachment,\n type SceneObjectResolutionRequest,\n type SceneObjectTransform,\n} from \"./types.js\";\n\nconst ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\nconst COORDINATE_SPACES = new Set<SceneObjectCoordinateSpace>([\n \"normalized-viewport\",\n \"pixel-viewport\",\n \"world\",\n \"local\",\n]);\nconst UNITS = new Set([\"ratio\", \"pixels\"]);\n\nfunction pushIssue(\n issues: SceneObjectValidationIssue[],\n issue: SceneObjectValidationIssue,\n): void {\n issues.push(issue);\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\nfunction validateKebabId(\n value: unknown,\n path: string,\n issues: SceneObjectValidationIssue[],\n): value is string {\n if (typeof value !== \"string\") {\n pushIssue(issues, {\n code: \"invalid-type\",\n path,\n message: \"Expected a string identifier.\",\n });\n return false;\n }\n\n if (!ID_PATTERN.test(value)) {\n pushIssue(issues, {\n code: \"invalid-id\",\n path,\n message: \"Identifiers must be kebab-case tokens.\",\n });\n return false;\n }\n\n return true;\n}\n\nfunction validateTransform(\n value: SceneObjectTransform,\n path: string,\n issues: SceneObjectValidationIssue[],\n): boolean {\n const vectorChecks = [\"translate\", \"rotate\", \"scale\"] as const;\n let valid = true;\n\n for (const field of vectorChecks) {\n const vector = value[field];\n if (!vector || typeof vector !== \"object\") {\n pushIssue(issues, {\n code: \"required\",\n path: `${path}.${field}`,\n message: `Expected a ${field} vector.`,\n });\n valid = false;\n continue;\n }\n\n for (const axis of [\"x\", \"y\", \"z\"] as const) {\n const raw = vector[axis];\n if (!isFiniteNumber(raw)) {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.${field}.${axis}`,\n message: `Vector ${axis} must be finite.`,\n });\n valid = false;\n }\n }\n }\n\n return valid;\n}\n\nfunction validatePoint(point: SceneObjectPoint, path: string, issues: SceneObjectValidationIssue[]): boolean {\n let valid = true;\n\n if (!validateKebabId(point.id, `${path}.id`, issues)) {\n valid = false;\n }\n\n for (const field of [\"x\", \"y\", \"z\"] as const) {\n const value = point[field];\n if (field === \"z\" && value === undefined) {\n continue;\n }\n if (!isFiniteNumber(value)) {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.${field}`,\n message: \"Attachment point axis must be finite.\",\n });\n valid = false;\n }\n }\n\n return valid;\n}\n\nfunction validateBounds(bounds: SceneObjectBounds, path: string, issues: SceneObjectValidationIssue[]): boolean {\n if (!bounds || typeof bounds !== \"object\") {\n pushIssue(issues, { code: \"required\", path, message: \"Expected bounds block.\" });\n return false;\n }\n\n if (!COORDINATE_SPACES.has(bounds.coordinateSpace as SceneObjectCoordinateSpace)) {\n pushIssue(issues, {\n code: \"invalid-value\",\n path: `${path}.coordinateSpace`,\n message: \"coordinateSpace must be normalized-viewport, pixel-viewport, world, or local.\",\n });\n return false;\n }\n\n const rect = bounds.rect;\n if (!rect || typeof rect !== \"object\") {\n pushIssue(issues, { code: \"required\", path: `${path}.rect`, message: \"Expected rect bounds.\" });\n return false;\n }\n\n if (!UNITS.has(rect.unit as string)) {\n pushIssue(issues, {\n code: \"invalid-value\",\n path: `${path}.rect.unit`,\n message: \"unit must be 'ratio' or 'pixels'.\",\n });\n return false;\n }\n\n let valid = true;\n for (const field of [\"x\", \"y\", \"width\", \"height\"] as const) {\n const value = rect[field];\n if (!isFiniteNumber(value) || value < 0) {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.rect.${field}`,\n message: \"Rect fields must be finite non-negative numbers.\",\n });\n valid = false;\n }\n }\n\n if (rect.width === 0 || rect.height === 0) {\n pushIssue(issues, {\n code: \"invalid-value\",\n path: `${path}.rect`,\n message: \"Rect width and height must be positive.\",\n });\n valid = false;\n }\n\n if (bounds.depth !== undefined && (!isFiniteNumber(bounds.depth) || bounds.depth < 0)) {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.depth`,\n message: \"depth must be a non-negative number.\",\n });\n valid = false;\n }\n\n return valid && isFiniteNumber(bounds.rect.width) && isFiniteNumber(bounds.rect.height);\n}\n\nfunction validateAttachmentTarget(\n attachment: {\n id: string;\n sourceObjectId: string;\n sourcePointId: string;\n targetObjectId: string;\n targetPointId: string;\n },\n path: string,\n issues: SceneObjectValidationIssue[],\n seenPoints: Map<string, Set<string>>,\n): boolean {\n let valid = true;\n if (!validateKebabId(attachment.id, `${path}.id`, issues)) {\n valid = false;\n }\n\n if (!validateKebabId(attachment.sourceObjectId, `${path}.sourceObjectId`, issues)) {\n valid = false;\n }\n\n if (!validateKebabId(attachment.targetObjectId, `${path}.targetObjectId`, issues)) {\n valid = false;\n }\n\n if (!validateKebabId(attachment.sourcePointId, `${path}.sourcePointId`, issues)) {\n valid = false;\n }\n\n if (!validateKebabId(attachment.targetPointId, `${path}.targetPointId`, issues)) {\n valid = false;\n }\n\n const sourcePoints = seenPoints.get(attachment.sourceObjectId);\n const targetPoints = seenPoints.get(attachment.targetObjectId);\n\n if (sourcePoints && !sourcePoints.has(attachment.sourcePointId)) {\n pushIssue(issues, {\n code: \"invalid-reference\",\n path: `${path}.sourcePointId`,\n message: \"sourcePointId does not exist on source object.\",\n });\n valid = false;\n }\n\n if (targetPoints && !targetPoints.has(attachment.targetPointId)) {\n pushIssue(issues, {\n code: \"invalid-reference\",\n path: `${path}.targetPointId`,\n message: \"targetPointId does not exist on target object.\",\n });\n valid = false;\n }\n\n return valid;\n}\n\nexport function validateSceneObjectManifest(\n manifest: unknown,\n): SceneObjectValidationResult<SceneObjectManifest> {\n const issues: SceneObjectValidationIssue[] = [];\n\n if (!manifest || typeof manifest !== \"object\") {\n return {\n valid: false,\n issues: [{ code: \"required\", path: \"$\", message: \"Expected a scene object manifest object.\" }],\n };\n }\n\n const value = manifest as Record<string, unknown>;\n let valid = true;\n\n if (value.schemaVersion !== SCENE_OBJECT_SCHEMA_VERSION) {\n pushIssue(issues, {\n code: \"invalid-value\",\n path: \"$.schemaVersion\",\n message: `schemaVersion must equal ${SCENE_OBJECT_SCHEMA_VERSION}.`,\n });\n valid = false;\n }\n\n if (!Array.isArray(value.objects) || value.objects.length === 0) {\n pushIssue(issues, {\n code: \"required\",\n path: \"$.objects\",\n message: \"Manifest must contain at least one object.\",\n });\n return { valid: false, issues };\n }\n\n const objects = value.objects as SceneObjectDefinition[];\n const seenObjects = new Set<string>();\n const pointsByObject = new Map<string, Set<string>>();\n\n for (const [index, object] of objects.entries()) {\n const path = `$.objects[${index}]`;\n\n if (!object || typeof object !== \"object\") {\n pushIssue(issues, { code: \"required\", path, message: \"Expected object definition.\" });\n valid = false;\n continue;\n }\n\n if (!validateKebabId(object.id, `${path}.id`, issues)) {\n valid = false;\n }\n\n if (seenObjects.has(object.id)) {\n pushIssue(issues, {\n code: \"duplicate-id\",\n path: `${path}.id`,\n message: `Duplicate object id '${object.id}' is not allowed.`,\n });\n valid = false;\n }\n seenObjects.add(object.id);\n\n if (!object.transform || typeof object.transform !== \"object\" || !validateTransform(object.transform as SceneObjectTransform, `${path}.transform`, issues)) {\n pushIssue(issues, {\n code: \"required\",\n path: `${path}.transform`,\n message: \"Object must define a transform.\",\n });\n valid = false;\n }\n\n if (!object.bounds) {\n pushIssue(issues, {\n code: \"required\",\n path: `${path}.bounds`,\n message: \"Object must define bounds.\",\n });\n valid = false;\n } else if (!validateBounds(object.bounds, `${path}.bounds`, issues)) {\n valid = false;\n }\n\n const attachmentPointIds = new Set<string>();\n const rawPoints = Array.isArray(object.attachmentPoints)\n ? object.attachmentPoints\n : [];\n for (const [pointIndex, point] of rawPoints.entries()) {\n if (!point || typeof point !== \"object\") {\n pushIssue(issues, {\n code: \"required\",\n path: `${path}.attachmentPoints[${pointIndex}]`,\n message: \"Expected attachment point definition.\",\n });\n valid = false;\n continue;\n }\n\n if (!validatePoint(point as SceneObjectPoint, `${path}.attachmentPoints[${pointIndex}]`, issues)) {\n valid = false;\n continue;\n }\n\n const pointId = (point as SceneObjectPoint).id;\n if (attachmentPointIds.has(pointId)) {\n pushIssue(issues, {\n code: \"duplicate-id\",\n path: `${path}.attachmentPoints[${pointIndex}].id`,\n message: `Duplicate attachment point '${pointId}' within object.`,\n });\n valid = false;\n }\n attachmentPointIds.add(pointId);\n }\n\n if (rawPoints.length > 0) {\n pointsByObject.set(object.id, attachmentPointIds);\n }\n\n if (Array.isArray(object.attachments)) {\n const attachmentIds = new Set<string>();\n for (const [attachmentIndex, attachment] of object.attachments.entries()) {\n if (!attachment || typeof attachment !== \"object\") {\n pushIssue(issues, {\n code: \"required\",\n path: `${path}.attachments[${attachmentIndex}]`,\n message: \"Expected attachment definition.\",\n });\n valid = false;\n continue;\n }\n\n if (!validateKebabId((attachment as SceneObjectAttachment).sourceObjectId, `${path}.attachments[${attachmentIndex}].sourceObjectId`, issues)) {\n valid = false;\n }\n\n if (!attachmentIds.has((attachment as { id?: string }).id ?? \"\")) {\n attachmentIds.add((attachment as { id?: string }).id ?? \"\");\n } else {\n pushIssue(issues, {\n code: \"duplicate-id\",\n path: `${path}.attachments[${attachmentIndex}].id`,\n message: \"Duplicate attachment id.\",\n });\n valid = false;\n }\n\n if (\n !validateAttachmentTarget(\n attachment as {\n id: string;\n sourceObjectId: string;\n sourcePointId: string;\n targetObjectId: string;\n targetPointId: string;\n },\n `${path}.attachments[${attachmentIndex}]`,\n issues,\n pointsByObject,\n )\n ) {\n valid = false;\n }\n }\n }\n }\n\n const objectIds = new Set(\n objects\n .filter((candidate): candidate is SceneObjectDefinition => Boolean(candidate && typeof candidate === \"object\"))\n .map((candidate) => candidate.id),\n );\n if (Array.isArray(value.stateSnapshots)) {\n for (const [stateIndex, state] of value.stateSnapshots.entries()) {\n const stateValue = state as SceneObjectObjectState;\n const path = `$.stateSnapshots[${stateIndex}]`;\n\n if (!stateValue || typeof stateValue !== \"object\") {\n pushIssue(issues, {\n code: \"required\",\n path,\n message: \"Expected object state definition.\",\n });\n valid = false;\n continue;\n }\n\n if (!validateKebabId(stateValue.objectId, `${path}.objectId`, issues)) {\n valid = false;\n }\n\n if (!objectIds.has(stateValue.objectId)) {\n pushIssue(issues, {\n code: \"missing-reference\",\n path: `${path}.objectId`,\n message: \"objectId does not reference an object in objects.\",\n });\n valid = false;\n }\n\n if (typeof stateValue.visible !== \"boolean\") {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.visible`,\n message: \"visible must be a boolean.\",\n });\n valid = false;\n }\n }\n }\n\n return valid\n ? { valid: true, issues, value: manifest as SceneObjectManifest }\n : { valid: false, issues };\n}\n\nexport function createSceneObjectManifest(manifest: SceneObjectManifest): SceneObjectManifest {\n const result = validateSceneObjectManifest(manifest);\n if (!result.valid || !result.value) {\n const summary = result.issues.map((issue) => `${issue.path}: ${issue.message}`).join(\"; \");\n throw new Error(`Invalid scene object manifest. ${summary}`);\n }\n\n return result.value;\n}\n\nexport function validateSceneObjectObjectState(state: unknown): SceneObjectValidationResult<SceneObjectObjectState> {\n if (!state || typeof state !== \"object\") {\n return {\n valid: false,\n issues: [{\n code: \"required\",\n path: \"$\",\n message: \"Expected an object state.\",\n }],\n };\n }\n\n const value = state as Record<string, unknown>;\n const issues: SceneObjectValidationIssue[] = [];\n let valid = true;\n\n if (!validateKebabId(value.objectId, \"$.objectId\", issues)) {\n valid = false;\n }\n\n if (typeof value.visible !== \"boolean\") {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: \"$.visible\",\n message: \"visible must be a boolean.\",\n });\n valid = false;\n }\n\n return valid\n ? { valid: true, issues, value: state as SceneObjectObjectState }\n : { valid: false, issues };\n}\n\nexport function resolveSceneObjectReferences(\n manifest: SceneObjectManifest,\n): SceneObjectValidationResult<SceneObjectManifest> {\n const result = validateSceneObjectManifest(manifest);\n if (!result.valid || !result.value) {\n return { valid: false, issues: result.issues };\n }\n\n return { valid: true, issues: [], value: result.value };\n}\n\nexport function resolveSceneObjectById(\n requestOrManifest:\n | SceneObjectResolutionRequest\n | SceneObjectManifest,\n objectId?: string,\n): SceneObjectDefinition | undefined {\n const request: SceneObjectResolutionRequest = typeof objectId === \"string\"\n ? {\n manifest: requestOrManifest as SceneObjectManifest,\n objectId,\n }\n : requestOrManifest as SceneObjectResolutionRequest;\n\n const result = validateSceneObjectManifest(request.manifest);\n if (!result.valid || !result.value) {\n return undefined;\n }\n\n return result.value.objects.find((object) => object.id === request.objectId);\n}\n","import { type SceneObjectDefinition,\n type SceneObjectManifest,\n type SceneObjectPoint,\n type SceneObjectValidationIssue,\n type SceneObjectValidationResult,\n type SceneObjectVector3,\n} from \"./types.js\";\nimport { validateSceneObjectManifest } from \"./validation.js\";\n\nexport const SCENE_OBJECT_PLAYER_SYSTEM_INTERFACE_FLAG_ID =\n \"isekai.player-system.interface.enabled\";\n\nexport type SceneObjectAnchorKind =\n | \"target\"\n | \"focus-pane\"\n | \"localized-alert\"\n | \"line-of-sight-popup\";\n\nexport type SceneObjectAnchorVisibility =\n | \"always\"\n | \"combat-safe\"\n | \"focused-only\"\n | \"line-of-sight\";\n\nexport interface SceneObjectAnchorDefinition {\n id: string;\n kind: SceneObjectAnchorKind;\n objectId: string;\n pointId: string;\n visibility: SceneObjectAnchorVisibility;\n localeKey?: string;\n offset?: SceneObjectVector3;\n tags?: string[];\n}\n\nexport interface SceneObjectFocusScreenDefinition {\n id: string;\n objectId: string;\n anchorId: string;\n paneId: string;\n variant: \"single-pane\" | \"multi-pane\" | \"combat-safe\";\n headingKey?: string;\n}\n\nexport interface SceneObjectPlayerSystemManifest extends SceneObjectManifest {\n anchors?: SceneObjectAnchorDefinition[];\n focusScreens?: SceneObjectFocusScreenDefinition[];\n}\n\nconst ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\nconst ANCHOR_KINDS = new Set<SceneObjectAnchorKind>([\n \"target\",\n \"focus-pane\",\n \"localized-alert\",\n \"line-of-sight-popup\",\n]);\nconst ANCHOR_VISIBILITIES = new Set<SceneObjectAnchorVisibility>([\n \"always\",\n \"combat-safe\",\n \"focused-only\",\n \"line-of-sight\",\n]);\nconst FOCUS_SCREEN_VARIANTS = new Set<SceneObjectFocusScreenDefinition[\"variant\"]>([\n \"single-pane\",\n \"multi-pane\",\n \"combat-safe\",\n]);\n\nfunction pushIssue(\n issues: SceneObjectValidationIssue[],\n issue: SceneObjectValidationIssue,\n): void {\n issues.push(issue);\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\nfunction isKebabId(value: unknown): value is string {\n return typeof value === \"string\" && ID_PATTERN.test(value);\n}\n\nfunction validateKebabId(\n value: unknown,\n path: string,\n issues: SceneObjectValidationIssue[],\n): value is string {\n if (typeof value !== \"string\") {\n pushIssue(issues, {\n code: \"invalid-type\",\n path,\n message: \"Expected a string identifier.\",\n });\n return false;\n }\n\n if (!ID_PATTERN.test(value)) {\n pushIssue(issues, {\n code: \"invalid-id\",\n path,\n message: \"Identifiers must be kebab-case tokens.\",\n });\n return false;\n }\n\n return true;\n}\n\nfunction findObjectPoint(\n object: SceneObjectDefinition | undefined,\n pointId: string,\n): SceneObjectPoint | undefined {\n return object?.attachmentPoints?.find((point) => point.id === pointId);\n}\n\nfunction validateAnchorDefinition(\n anchor: unknown,\n path: string,\n issues: SceneObjectValidationIssue[],\n objectsById: Map<string, SceneObjectDefinition>,\n anchorIds: Set<string>,\n): anchor is SceneObjectAnchorDefinition {\n if (!anchor || typeof anchor !== \"object\") {\n pushIssue(issues, {\n code: \"required\",\n path,\n message: \"Expected anchor definition object.\",\n });\n return false;\n }\n\n const value = anchor as Record<string, unknown>;\n let valid = true;\n\n if (!validateKebabId(value.id, `${path}.id`, issues)) {\n valid = false;\n } else if (anchorIds.has(value.id)) {\n pushIssue(issues, {\n code: \"duplicate-id\",\n path: `${path}.id`,\n message: \"Anchor identifiers must be unique.\",\n });\n valid = false;\n } else {\n anchorIds.add(value.id);\n }\n\n if (!validateKebabId(value.objectId, `${path}.objectId`, issues)) {\n valid = false;\n }\n\n if (!validateKebabId(value.pointId, `${path}.pointId`, issues)) {\n valid = false;\n }\n\n if (!ANCHOR_KINDS.has(value.kind as SceneObjectAnchorKind)) {\n pushIssue(issues, {\n code: \"invalid-value\",\n path: `${path}.kind`,\n message:\n \"Anchor kind must be target, focus-pane, localized-alert, or line-of-sight-popup.\",\n });\n valid = false;\n }\n\n if (!ANCHOR_VISIBILITIES.has(value.visibility as SceneObjectAnchorVisibility)) {\n pushIssue(issues, {\n code: \"invalid-value\",\n path: `${path}.visibility`,\n message:\n \"Anchor visibility must be always, combat-safe, focused-only, or line-of-sight.\",\n });\n valid = false;\n }\n\n const object =\n typeof value.objectId === \"string\"\n ? objectsById.get(value.objectId)\n : undefined;\n if (!object) {\n pushIssue(issues, {\n code: \"missing-reference\",\n path: `${path}.objectId`,\n message: \"Anchor objectId must reference an existing scene object.\",\n });\n valid = false;\n } else if (\n typeof value.pointId === \"string\" &&\n !findObjectPoint(object, value.pointId)\n ) {\n pushIssue(issues, {\n code: \"missing-reference\",\n path: `${path}.pointId`,\n message:\n \"Anchor pointId must reference an attachment point on the target object.\",\n });\n valid = false;\n }\n\n if (value.kind === \"localized-alert\") {\n if (typeof value.localeKey !== \"string\" || value.localeKey.trim().length === 0) {\n pushIssue(issues, {\n code: \"required\",\n path: `${path}.localeKey`,\n message: \"localized-alert anchors require a localeKey.\",\n });\n valid = false;\n }\n } else if (\n value.localeKey !== undefined &&\n (typeof value.localeKey !== \"string\" || value.localeKey.trim().length === 0)\n ) {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.localeKey`,\n message: \"localeKey must be a non-empty string when present.\",\n });\n valid = false;\n }\n\n if (value.offset !== undefined) {\n if (!value.offset || typeof value.offset !== \"object\") {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.offset`,\n message: \"offset must be a finite x/y/z vector when present.\",\n });\n valid = false;\n } else {\n for (const axis of [\"x\", \"y\", \"z\"] as const) {\n if (!isFiniteNumber((value.offset as Record<string, unknown>)[axis])) {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.offset.${axis}`,\n message: \"offset axes must be finite numbers.\",\n });\n valid = false;\n }\n }\n }\n }\n\n if (value.tags !== undefined) {\n if (\n !Array.isArray(value.tags) ||\n value.tags.some((tag) => typeof tag !== \"string\" || tag.trim().length === 0)\n ) {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.tags`,\n message: \"tags must be an array of non-empty strings when present.\",\n });\n valid = false;\n }\n }\n\n return valid;\n}\n\nfunction validateFocusScreenDefinition(\n focusScreen: unknown,\n path: string,\n issues: SceneObjectValidationIssue[],\n objectsById: Map<string, SceneObjectDefinition>,\n anchorsById: Map<string, SceneObjectAnchorDefinition>,\n focusScreenIds: Set<string>,\n): focusScreen is SceneObjectFocusScreenDefinition {\n if (!focusScreen || typeof focusScreen !== \"object\") {\n pushIssue(issues, {\n code: \"required\",\n path,\n message: \"Expected focus-screen definition object.\",\n });\n return false;\n }\n\n const value = focusScreen as Record<string, unknown>;\n let valid = true;\n\n if (!validateKebabId(value.id, `${path}.id`, issues)) {\n valid = false;\n } else if (focusScreenIds.has(value.id)) {\n pushIssue(issues, {\n code: \"duplicate-id\",\n path: `${path}.id`,\n message: \"Focus-screen identifiers must be unique.\",\n });\n valid = false;\n } else {\n focusScreenIds.add(value.id);\n }\n\n if (!validateKebabId(value.objectId, `${path}.objectId`, issues)) {\n valid = false;\n } else if (!objectsById.has(value.objectId)) {\n pushIssue(issues, {\n code: \"missing-reference\",\n path: `${path}.objectId`,\n message: \"Focus-screen objectId must reference an existing scene object.\",\n });\n valid = false;\n }\n\n if (!validateKebabId(value.anchorId, `${path}.anchorId`, issues)) {\n valid = false;\n } else {\n const anchor = anchorsById.get(value.anchorId);\n if (!anchor) {\n pushIssue(issues, {\n code: \"missing-reference\",\n path: `${path}.anchorId`,\n message: \"Focus-screen anchorId must reference an exported anchor.\",\n });\n valid = false;\n } else if (anchor.kind !== \"focus-pane\") {\n pushIssue(issues, {\n code: \"invalid-reference\",\n path: `${path}.anchorId`,\n message: \"Focus screens must bind to focus-pane anchors.\",\n });\n valid = false;\n }\n }\n\n if (!validateKebabId(value.paneId, `${path}.paneId`, issues)) {\n valid = false;\n }\n\n if (!FOCUS_SCREEN_VARIANTS.has(value.variant as SceneObjectFocusScreenDefinition[\"variant\"])) {\n pushIssue(issues, {\n code: \"invalid-value\",\n path: `${path}.variant`,\n message: \"Focus-screen variant must be single-pane, multi-pane, or combat-safe.\",\n });\n valid = false;\n }\n\n if (\n value.headingKey !== undefined &&\n (typeof value.headingKey !== \"string\" || value.headingKey.trim().length === 0)\n ) {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: `${path}.headingKey`,\n message: \"headingKey must be a non-empty string when present.\",\n });\n valid = false;\n }\n\n return valid;\n}\n\nexport function validateSceneObjectPlayerSystemManifest(\n manifest: unknown,\n): SceneObjectValidationResult<SceneObjectPlayerSystemManifest> {\n const base = validateSceneObjectManifest(manifest);\n if (!base.valid || !base.value) {\n return base as SceneObjectValidationResult<SceneObjectPlayerSystemManifest>;\n }\n\n const issues = [...base.issues];\n const value = manifest as SceneObjectPlayerSystemManifest;\n const objectsById = new Map(\n base.value.objects.map((object) => [object.id, object] as const),\n );\n const anchorIds = new Set<string>();\n const anchorsById = new Map<string, SceneObjectAnchorDefinition>();\n const focusScreenIds = new Set<string>();\n let valid = true;\n\n if (value.anchors !== undefined) {\n if (!Array.isArray(value.anchors)) {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: \"$.anchors\",\n message: \"anchors must be an array when present.\",\n });\n valid = false;\n } else {\n value.anchors.forEach((anchor, index) => {\n const path = `$.anchors[${index}]`;\n if (\n validateAnchorDefinition(anchor, path, issues, objectsById, anchorIds)\n ) {\n anchorsById.set(anchor.id, anchor);\n } else {\n valid = false;\n }\n });\n }\n }\n\n if (value.focusScreens !== undefined) {\n if (!Array.isArray(value.focusScreens)) {\n pushIssue(issues, {\n code: \"invalid-type\",\n path: \"$.focusScreens\",\n message: \"focusScreens must be an array when present.\",\n });\n valid = false;\n } else {\n value.focusScreens.forEach((focusScreen, index) => {\n if (\n !validateFocusScreenDefinition(\n focusScreen,\n `$.focusScreens[${index}]`,\n issues,\n objectsById,\n anchorsById,\n focusScreenIds,\n )\n ) {\n valid = false;\n }\n });\n }\n }\n\n return {\n valid,\n issues,\n value: valid ? value : undefined,\n };\n}\n\nexport function resolveSceneObjectAnchorById(\n manifest: SceneObjectPlayerSystemManifest,\n anchorId: string,\n): SceneObjectAnchorDefinition | undefined {\n if (!isKebabId(anchorId)) {\n return undefined;\n }\n\n return manifest.anchors?.find((anchor) => anchor.id === anchorId);\n}\n\nexport function resolveSceneObjectFocusScreenById(\n manifest: SceneObjectPlayerSystemManifest,\n focusScreenId: string,\n): SceneObjectFocusScreenDefinition | undefined {\n if (!isKebabId(focusScreenId)) {\n return undefined;\n }\n\n return manifest.focusScreens?.find((focusScreen) => focusScreen.id === focusScreenId);\n}\n","import {\n SceneObjectManifest,\n SceneObjectObjectState,\n SceneObjectDefinition,\n} from \"./types.js\";\n\nexport function resolveSceneObjectState(\n manifest: SceneObjectManifest,\n objectId: string,\n): SceneObjectObjectState | undefined {\n if (!manifest.stateSnapshots || !Array.isArray(manifest.stateSnapshots)) {\n return undefined;\n }\n\n return manifest.stateSnapshots.find(\n (snapshot) => snapshot.objectId === objectId,\n );\n}\n\nexport function resolveSceneObjectById(\n manifest: SceneObjectManifest,\n objectId: string,\n): SceneObjectDefinition | undefined {\n return manifest.objects.find((object) => object.id === objectId);\n}\n"],"mappings":"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","names":["ID_PATTERN","pushIssue","isFiniteNumber","validateKebabId"]}
|