@forgeax/engine-scene 0.1.2

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.
Files changed (90) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +55 -0
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/__tests__/asset-owner.integration.test.d.ts +2 -0
  5. package/dist/__tests__/asset-owner.integration.test.d.ts.map +1 -0
  6. package/dist/__tests__/components.unit.test.d.ts +2 -0
  7. package/dist/__tests__/components.unit.test.d.ts.map +1 -0
  8. package/dist/__tests__/diagnostic-type-surface.test-d.d.ts +3 -0
  9. package/dist/__tests__/diagnostic-type-surface.test-d.d.ts.map +1 -0
  10. package/dist/__tests__/direct-child-of-import.unit.test.d.ts +2 -0
  11. package/dist/__tests__/direct-child-of-import.unit.test.d.ts.map +1 -0
  12. package/dist/__tests__/fixtures/malformed-hierarchy-edge.d.ts +8 -0
  13. package/dist/__tests__/fixtures/malformed-hierarchy-edge.d.ts.map +1 -0
  14. package/dist/__tests__/hierarchy-projection-contract.unit.test.d.ts +2 -0
  15. package/dist/__tests__/hierarchy-projection-contract.unit.test.d.ts.map +1 -0
  16. package/dist/__tests__/hierarchy-projection.unit.test.d.ts +2 -0
  17. package/dist/__tests__/hierarchy-projection.unit.test.d.ts.map +1 -0
  18. package/dist/__tests__/plugin.integration.test.d.ts +2 -0
  19. package/dist/__tests__/plugin.integration.test.d.ts.map +1 -0
  20. package/dist/__tests__/propagation.unit.test.d.ts +2 -0
  21. package/dist/__tests__/propagation.unit.test.d.ts.map +1 -0
  22. package/dist/__tests__/transform-change-journal.unit.test.d.ts +2 -0
  23. package/dist/__tests__/transform-change-journal.unit.test.d.ts.map +1 -0
  24. package/dist/assets/instantiate-scene.d.ts +7 -0
  25. package/dist/assets/instantiate-scene.d.ts.map +1 -0
  26. package/dist/assets/publication-observer.d.ts +13 -0
  27. package/dist/assets/publication-observer.d.ts.map +1 -0
  28. package/dist/assets/scene-decoder.d.ts +8 -0
  29. package/dist/assets/scene-decoder.d.ts.map +1 -0
  30. package/dist/assets/scene-projection.d.ts +70 -0
  31. package/dist/assets/scene-projection.d.ts.map +1 -0
  32. package/dist/components/child-of.d.ts +31 -0
  33. package/dist/components/child-of.d.ts.map +1 -0
  34. package/dist/components/children.d.ts +48 -0
  35. package/dist/components/children.d.ts.map +1 -0
  36. package/dist/components/morph-weights.d.ts +5 -0
  37. package/dist/components/morph-weights.d.ts.map +1 -0
  38. package/dist/components/name.d.ts +4 -0
  39. package/dist/components/name.d.ts.map +1 -0
  40. package/dist/components/transform.d.ts +52 -0
  41. package/dist/components/transform.d.ts.map +1 -0
  42. package/dist/errors.d.ts +22 -0
  43. package/dist/errors.d.ts.map +1 -0
  44. package/dist/index.d.ts +15 -0
  45. package/dist/index.d.ts.map +1 -0
  46. package/dist/index.mjs +2167 -0
  47. package/dist/index.mjs.map +1 -0
  48. package/dist/instances/collect-profile.d.ts +7 -0
  49. package/dist/instances/collect-profile.d.ts.map +1 -0
  50. package/dist/instances/externalization.d.ts +14 -0
  51. package/dist/instances/externalization.d.ts.map +1 -0
  52. package/dist/instances/scene-instances.d.ts +349 -0
  53. package/dist/instances/scene-instances.d.ts.map +1 -0
  54. package/dist/plugin.d.ts +3 -0
  55. package/dist/plugin.d.ts.map +1 -0
  56. package/dist/systems/hierarchy-projection.d.ts +16 -0
  57. package/dist/systems/hierarchy-projection.d.ts.map +1 -0
  58. package/dist/systems/index.d.ts +3 -0
  59. package/dist/systems/index.d.ts.map +1 -0
  60. package/dist/systems/propagate-transforms.d.ts +15 -0
  61. package/dist/systems/propagate-transforms.d.ts.map +1 -0
  62. package/package.json +59 -0
  63. package/src/__tests__/asset-owner.integration.test.ts +245 -0
  64. package/src/__tests__/components.unit.test.ts +26 -0
  65. package/src/__tests__/diagnostic-type-surface.test-d.ts +11 -0
  66. package/src/__tests__/direct-child-of-import.unit.test.ts +13 -0
  67. package/src/__tests__/fixtures/malformed-hierarchy-edge.ts +15 -0
  68. package/src/__tests__/hierarchy-projection-contract.unit.test.ts +45 -0
  69. package/src/__tests__/hierarchy-projection.unit.test.ts +92 -0
  70. package/src/__tests__/plugin.integration.test.ts +23 -0
  71. package/src/__tests__/propagation.unit.test.ts +163 -0
  72. package/src/__tests__/transform-change-journal.unit.test.ts +105 -0
  73. package/src/assets/instantiate-scene.ts +14 -0
  74. package/src/assets/publication-observer.ts +24 -0
  75. package/src/assets/scene-decoder.ts +153 -0
  76. package/src/assets/scene-projection.ts +644 -0
  77. package/src/components/child-of.ts +90 -0
  78. package/src/components/children.ts +113 -0
  79. package/src/components/morph-weights.ts +6 -0
  80. package/src/components/name.ts +22 -0
  81. package/src/components/transform.ts +89 -0
  82. package/src/errors.ts +34 -0
  83. package/src/index.ts +78 -0
  84. package/src/instances/collect-profile.ts +10 -0
  85. package/src/instances/externalization.ts +137 -0
  86. package/src/instances/scene-instances.ts +1565 -0
  87. package/src/plugin.ts +28 -0
  88. package/src/systems/hierarchy-projection.ts +134 -0
  89. package/src/systems/index.ts +11 -0
  90. package/src/systems/propagate-transforms.ts +376 -0
@@ -0,0 +1,31 @@
1
+ export { ChildOf } from './children';
2
+ /**
3
+ * Hierarchy back-reference: pointer from child entity to its parent.
4
+ *
5
+ * Store the parent `Entity` handle (returned by `world.spawn(...).unwrap()`)
6
+ * in the `parent` field; `propagateTransforms` reads it each frame to
7
+ * compose the child's derived `Transform.world` mat4 (child.world =
8
+ * parent.world x child local). Despawning a child auto-detaches it from the
9
+ * parent's Children list (relationship `onRemove` hook). Despawning the
10
+ * parent does not auto-clean the child's ChildOf; the consumer removes the
11
+ * stale ChildOf (`world.removeComponent`) or checks `world.get(parent, Entity)` for liveness.
12
+ *
13
+ * Because ChildOf declares a `relationship` mirror, the engine keeps the
14
+ * parent's `Children.entities` reverse list consistent automatically: adding
15
+ * ChildOf appends the child to the parent's Children, removing it (or
16
+ * reparenting via the `exclusive` arm) prunes the stale entry. AI users no
17
+ * longer hand-maintain both sides (the prior OOS-10 contract is retired).
18
+ * Reparenting is a plain re-add: `world.addComponent(child, { component:
19
+ * ChildOf, data: { parent: newParent } })` on an entity that already carries
20
+ * ChildOf auto-reparents (exclusive arm), or use `world.reparent(child,
21
+ * newParent)`.
22
+ *
23
+ * @example Spawn a child entity referencing an already-spawned root:
24
+ * const root = world.spawn({ component: Transform, data: {...} }).unwrap();
25
+ * const child = world.spawn(
26
+ * { component: Transform, data: {...} },
27
+ * { component: ChildOf, data: { parent: root } },
28
+ * ).unwrap();
29
+ * // root now carries Children with [child] in its `entities` list.
30
+ */
31
+ //# sourceMappingURL=child-of.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"child-of.d.ts","sourceRoot":"","sources":["../../src/components/child-of.ts"],"names":[],"mappings":"AA2DA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Hierarchy forward-list of child entities.
3
+ *
4
+ * `entities` is a variable-length `array<entity>` field; each element is
5
+ * an `Entity` u32 the AI user pushed via
6
+ * `world.push(parent, Children, 'entities', child)`. The value returned by
7
+ * `world.get(parent, Children).unwrap().entities` is a read-only
8
+ * `Uint32Array` snapshot rematerialised fresh on every read (D-4 no-cache);
9
+ * the snapshot's `length` equals the live element count.
10
+ *
11
+ * Invariants:
12
+ * - Children is NOT consumed by `propagateTransforms` (which walks ChildOf
13
+ * upward, D-P2). The forward list is for AI-user traversal / debug /
14
+ * inspection.
15
+ * - Children <-> ChildOf consistency is maintained by the engine via the
16
+ * ChildOf `relationship` mirror hook (see ./child-of.ts): adding /
17
+ * removing / reparenting ChildOf on a child auto-updates the parent's
18
+ * `entities` list. AI users do not hand-sync the two sides for the
19
+ * hierarchy.
20
+ * - Stored entity u32s are NOT auto-cleared when the referenced entity is
21
+ * despawned (OOS-01 above); a `world.get(despawnedChild, ...)` call
22
+ * returns `Result.err(...)` so AI users discover the dangling state
23
+ * through the engine's structured-error channel.
24
+ *
25
+ * @example Spawn a parent and two children via ChildOf (engine maintains Children):
26
+ * const parent = world.spawn({ component: Transform, data: identityXf() }).unwrap();
27
+ * const a = world.spawn(
28
+ * { component: Transform, data: identityXf() },
29
+ * { component: ChildOf, data: { parent } },
30
+ * ).unwrap();
31
+ * const b = world.spawn(
32
+ * { component: Transform, data: identityXf() },
33
+ * { component: ChildOf, data: { parent } },
34
+ * ).unwrap();
35
+ * // Read back via the read-only snapshot - engine appended a, b:
36
+ * const snap = world.get(parent, Children).unwrap().entities;
37
+ * for (let i = 0; i < snap.length; i++) {
38
+ * const child = snap[i];
39
+ * // ... consume; world.get(child, ...) surfaces a structured error
40
+ * // if the child has been despawned (OOS-01 dangling-entity surface).
41
+ * }
42
+ */
43
+ export declare const ChildOf: import("@forgeax/engine-ecs").Component<"ChildOf", {
44
+ parent: "entity";
45
+ }>, Children: import("@forgeax/engine-ecs").RelationshipTargetComponent<import("@forgeax/engine-ecs").Component<"Children", {
46
+ entities: "array<entity>";
47
+ }>>;
48
+ //# sourceMappingURL=children.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"children.d.ts","sourceRoot":"","sources":["../../src/components/children.ts"],"names":[],"mappings":"AA+DA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,eAAO,MAAgB,OAAO;;IAAU,QAAQ;;GAO9C,CAAC"}
@@ -0,0 +1,5 @@
1
+ /** Per-entity morph weights; length is validated against the mesh target count. */
2
+ export declare const MorphWeights: import("@forgeax/engine-ecs").Component<"MorphWeights", {
3
+ readonly weights: "array<f32>";
4
+ }>;
5
+ //# sourceMappingURL=morph-weights.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"morph-weights.d.ts","sourceRoot":"","sources":["../../src/components/morph-weights.ts"],"names":[],"mappings":"AAEA,mFAAmF;AACnF,eAAO,MAAM,YAAY;;EAEvB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare const Name: import("@forgeax/engine-ecs").Component<"Name", {
2
+ readonly value: "string";
3
+ }>;
4
+ //# sourceMappingURL=name.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"name.d.ts","sourceRoot":"","sources":["../../src/components/name.ts"],"names":[],"mappings":"AAqBA,eAAO,MAAM,IAAI;;EAAyD,CAAC"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Transform: local position `pos` (xyz), rotation `quat` (quaternion,
3
+ * component order [x, y, z, w]), scale `scale` (xyz), plus the resolved
4
+ * `world` mat4 (column-major 16 floats).
5
+ *
6
+ * Local TRS is stored as three inline stride-N array<f32, N> columns. The
7
+ * propagate kernel composes each entity's local TRS into a mat4 and writes it
8
+ * into the `world` column (root: world = local; child: world = parent.world x
9
+ * local) using `@forgeax/engine-math` mat4 / vec3 / quat APIs (charter P4: do
10
+ * not reinvent math). MVP recomposes every frame; dirty-flag optimization is
11
+ * owned by feat-future-render-world.
12
+ *
13
+ * The `world` column is a fixed-capacity `array<f32, 16>` (feat-20260602):
14
+ * the 16 contiguous floats live inline in a stride-16 column -- no BufferPool
15
+ * slot. Read it via `world.get(e, Transform).world` which returns a live
16
+ * `Float32Array` aliasing the column buffer. The view is transient: it aliases
17
+ * the archetype column buffer and is valid only until the next structural
18
+ * change (spawn / despawn / addComponent / removeComponent). Re-fetch the view
19
+ * on every access; holding a view across a structural change is undefined
20
+ * behaviour (the backing `ArrayBuffer` is detached on column growth, and
21
+ * swap-remove at the same row index points to the wrong entity). All existing
22
+ * hot paths (propagate / render-extract / pick) already comply -- see
23
+ * `packages/ecs/README.md` Transient view contract section.
24
+ *
25
+ * All three local columns carry explicit layer-2 defaults (identity
26
+ * transform): `pos: [0, 0, 0]`, `quat: [0, 0, 0, 1]` (identity quaternion,
27
+ * [x, y, z, w]), `scale: [1, 1, 1]`. quat and scale MUST stay explicit: the
28
+ * layer-3 fallback for array<f32, N> is all-zero, which would land an invalid
29
+ * zero quaternion / zero scale. The `world` field defaults to the identity
30
+ * mat4. AI users spawn with `data: {}` or with only the fields they need to
31
+ * override.
32
+ *
33
+ * @example Minimal spawn (local defaulted to identity, world = identity mat4):
34
+ * world.spawn({ component: Transform, data: {} });
35
+ *
36
+ * @example Override only the position, leaving rotation/scale at identity:
37
+ * world.spawn({ component: Transform, data: { pos: [0, 6, 0] } });
38
+ *
39
+ * @example Full explicit local form (defaults are opt-in):
40
+ * world.spawn({ component: Transform, data: {
41
+ * pos: [1, 2, 3],
42
+ * quat: [0, 0, 0, 1], // [x, y, z, w]
43
+ * scale: [1, 1, 1],
44
+ * } });
45
+ */
46
+ export declare const Transform: import("@forgeax/engine-ecs").Component<"Transform", {
47
+ readonly pos: "array<f32, 3>";
48
+ readonly quat: "array<f32, 4>";
49
+ readonly scale: "array<f32, 3>";
50
+ readonly world: "array<f32, 16>";
51
+ }>;
52
+ //# sourceMappingURL=transform.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../src/components/transform.ts"],"names":[],"mappings":"AAiCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,eAAO,MAAM,SAAS;;;;;EAUpB,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { EntityHandle } from '@forgeax/engine-ecs';
2
+ export type SceneErrorCode = 'hierarchy-broken' | 'hierarchy-cycle';
3
+ /** Scene-instantiation failures owned by the scene package. */
4
+ export type SceneInstanceErrorCode = 'component-not-defined' | 'scene-override-type-mismatch';
5
+ export { ComponentNotDefinedError } from '@forgeax/engine-ecs/projection';
6
+ export interface SceneErrorDetail {
7
+ readonly entity: EntityHandle;
8
+ readonly parent: EntityHandle;
9
+ }
10
+ export declare class SceneError extends Error {
11
+ readonly code: SceneErrorCode;
12
+ readonly expected: string;
13
+ readonly hint: string;
14
+ readonly detail: SceneErrorDetail | undefined;
15
+ constructor(args: {
16
+ code: SceneErrorCode;
17
+ expected: string;
18
+ hint: string;
19
+ detail?: SceneErrorDetail;
20
+ });
21
+ }
22
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExD,MAAM,MAAM,cAAc,GAAG,kBAAkB,GAAG,iBAAiB,CAAC;AAEpE,+DAA+D;AAC/D,MAAM,MAAM,sBAAsB,GAAG,uBAAuB,GAAG,8BAA8B,CAAC;AAE9F,OAAO,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAE1E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;CAC/B;AAED,qBAAa,UAAW,SAAQ,KAAK;IACnC,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,gBAAgB,GAAG,SAAS,CAAC;gBAElC,IAAI,EAAE;QAChB,IAAI,EAAE,cAAc,CAAC;QACrB,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,CAAC,EAAE,gBAAgB,CAAC;KAC3B;CAQF"}
@@ -0,0 +1,15 @@
1
+ export { sceneAssetContribution, sceneAssetDecoder, sceneAssetKind, } from './assets/scene-decoder';
2
+ export { projectSceneAsset, SCENE_ASSET_MESH_DEFAULT_RESOLVER_RESOURCE_KEY, SCENE_ASSET_SKIN_RESOLVER_RESOURCE_KEY, type SceneAssetMeshDefaultResolver, type SceneAssetProjectionError, type SceneAssetReferenceLoader, type SceneAssetSkinResolver, } from './assets/scene-projection';
3
+ export { ChildOf } from './components/child-of';
4
+ export { Children } from './components/children';
5
+ export { MorphWeights } from './components/morph-weights';
6
+ export { Name } from './components/name';
7
+ export { Transform } from './components/transform';
8
+ export { ComponentNotDefinedError, SceneError, type SceneErrorCode, type SceneInstanceErrorCode, } from './errors';
9
+ export { SCENE_COLLECT_PROFILE, type SceneCollectProfile } from './instances/collect-profile';
10
+ export { type ExternalizedSceneAsset, externalizeSceneAsset, type SceneComponentSchemaResolver, type SceneExternalizationError, } from './instances/externalization';
11
+ export { type SceneAssetResolver, type SceneInstanceStatePayload, type SceneInstantiateDiagnostic, type SceneInstantiateFlatOk, type SceneInstantiateHook, type SceneInstantiateOk, type SceneMembersSpawn, worldApplyMountOverride, worldBuildSceneEntityComponentDatas, worldDespawnDescendants, worldDespawnScene, worldDetachSceneMember, worldGetSceneAssetForInstance, worldGetSceneAssetResolver, worldGetSceneInstanceState, worldInstantiateScene, worldInstantiateSceneAsset, worldInstantiateSceneAssetFlat, worldInstantiateSceneFlat, worldInstantiateSceneRec, worldMountOverridesToStateMap, worldReattachSceneMember, worldRemoveSceneOverride, worldResolveMountSource, worldResolveSceneAsset, worldResolveSceneInstanceStatePayload, worldSetSceneAssetResolver, worldSetSceneInstantiateHook, worldSetSceneOverride, worldSpawnMountEntity, worldSpawnSceneMembers, worldValidateMountOverrides, } from './instances/scene-instances';
12
+ export { scenePlugin } from './plugin';
13
+ export { projectHierarchy, type SceneHierarchyDiagnostic, type SceneHierarchySnapshot, } from './systems/hierarchy-projection';
14
+ export { PROPAGATE_TRANSFORMS_SYSTEM, propagateTransforms, registerPropagateTransforms, TransformSet, } from './systems/propagate-transforms';
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,cAAc,GACf,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,iBAAiB,EACjB,8CAA8C,EAC9C,sCAAsC,EACtC,KAAK,6BAA6B,EAClC,KAAK,yBAAyB,EAC9B,KAAK,yBAAyB,EAC9B,KAAK,sBAAsB,GAC5B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EACL,wBAAwB,EACxB,UAAU,EACV,KAAK,cAAc,EACnB,KAAK,sBAAsB,GAC5B,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,qBAAqB,EAAE,KAAK,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAC9F,OAAO,EACL,KAAK,sBAAsB,EAC3B,qBAAqB,EACrB,KAAK,4BAA4B,EACjC,KAAK,yBAAyB,GAC/B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,yBAAyB,EAC9B,KAAK,0BAA0B,EAC/B,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,uBAAuB,EACvB,mCAAmC,EACnC,uBAAuB,EACvB,iBAAiB,EACjB,sBAAsB,EACtB,6BAA6B,EAC7B,0BAA0B,EAC1B,0BAA0B,EAC1B,qBAAqB,EACrB,0BAA0B,EAC1B,8BAA8B,EAC9B,yBAAyB,EACzB,wBAAwB,EACxB,6BAA6B,EAC7B,wBAAwB,EACxB,wBAAwB,EACxB,uBAAuB,EACvB,sBAAsB,EACtB,qCAAqC,EACrC,0BAA0B,EAC1B,4BAA4B,EAC5B,qBAAqB,EACrB,qBAAqB,EACrB,sBAAsB,EACtB,2BAA2B,GAC5B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EACL,gBAAgB,EAChB,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,GAC5B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,2BAA2B,EAC3B,mBAAmB,EACnB,2BAA2B,EAC3B,YAAY,GACb,MAAM,gCAAgC,CAAC"}