@sadhaka/loom-engine 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +344 -0
  3. package/dist/animation/animation-clip.d.ts +12 -0
  4. package/dist/animation/animation-clip.d.ts.map +1 -0
  5. package/dist/animation/animation-clip.js +85 -0
  6. package/dist/animation/animation-clip.js.map +1 -0
  7. package/dist/animation/animation-state-pool.d.ts +25 -0
  8. package/dist/animation/animation-state-pool.d.ts.map +1 -0
  9. package/dist/animation/animation-state-pool.js +113 -0
  10. package/dist/animation/animation-state-pool.js.map +1 -0
  11. package/dist/asset/sprite-sheet-loader.d.ts +41 -0
  12. package/dist/asset/sprite-sheet-loader.d.ts.map +1 -0
  13. package/dist/asset/sprite-sheet-loader.js +313 -0
  14. package/dist/asset/sprite-sheet-loader.js.map +1 -0
  15. package/dist/audio/audio-bus.d.ts +43 -0
  16. package/dist/audio/audio-bus.d.ts.map +1 -0
  17. package/dist/audio/audio-bus.js +258 -0
  18. package/dist/audio/audio-bus.js.map +1 -0
  19. package/dist/combat/mob-catalog.d.ts +29 -0
  20. package/dist/combat/mob-catalog.d.ts.map +1 -0
  21. package/dist/combat/mob-catalog.js +104 -0
  22. package/dist/combat/mob-catalog.js.map +1 -0
  23. package/dist/components/health.d.ts +28 -0
  24. package/dist/components/health.d.ts.map +1 -0
  25. package/dist/components/health.js +150 -0
  26. package/dist/components/health.js.map +1 -0
  27. package/dist/components/interactable.d.ts +30 -0
  28. package/dist/components/interactable.d.ts.map +1 -0
  29. package/dist/components/interactable.js +94 -0
  30. package/dist/components/interactable.js.map +1 -0
  31. package/dist/components/particle-emitter.d.ts +62 -0
  32. package/dist/components/particle-emitter.d.ts.map +1 -0
  33. package/dist/components/particle-emitter.js +193 -0
  34. package/dist/components/particle-emitter.js.map +1 -0
  35. package/dist/components/pursue.d.ts +23 -0
  36. package/dist/components/pursue.d.ts.map +1 -0
  37. package/dist/components/pursue.js +96 -0
  38. package/dist/components/pursue.js.map +1 -0
  39. package/dist/components/ranged-attack.d.ts +44 -0
  40. package/dist/components/ranged-attack.d.ts.map +1 -0
  41. package/dist/components/ranged-attack.js +120 -0
  42. package/dist/components/ranged-attack.js.map +1 -0
  43. package/dist/components/sprite.d.ts +27 -0
  44. package/dist/components/sprite.d.ts.map +1 -0
  45. package/dist/components/sprite.js +122 -0
  46. package/dist/components/sprite.js.map +1 -0
  47. package/dist/components/transform.d.ts +30 -0
  48. package/dist/components/transform.d.ts.map +1 -0
  49. package/dist/components/transform.js +150 -0
  50. package/dist/components/transform.js.map +1 -0
  51. package/dist/director/director-bridge.d.ts +22 -0
  52. package/dist/director/director-bridge.d.ts.map +1 -0
  53. package/dist/director/director-bridge.js +23 -0
  54. package/dist/director/director-bridge.js.map +1 -0
  55. package/dist/director/director-encounter-system.d.ts +21 -0
  56. package/dist/director/director-encounter-system.d.ts.map +1 -0
  57. package/dist/director/director-encounter-system.js +128 -0
  58. package/dist/director/director-encounter-system.js.map +1 -0
  59. package/dist/director/director-system.d.ts +19 -0
  60. package/dist/director/director-system.d.ts.map +1 -0
  61. package/dist/director/director-system.js +179 -0
  62. package/dist/director/director-system.js.map +1 -0
  63. package/dist/director/event-envelope.d.ts +144 -0
  64. package/dist/director/event-envelope.d.ts.map +1 -0
  65. package/dist/director/event-envelope.js +108 -0
  66. package/dist/director/event-envelope.js.map +1 -0
  67. package/dist/director/knot-context-resource.d.ts +25 -0
  68. package/dist/director/knot-context-resource.d.ts.map +1 -0
  69. package/dist/director/knot-context-resource.js +152 -0
  70. package/dist/director/knot-context-resource.js.map +1 -0
  71. package/dist/director/mock-director-bridge.d.ts +18 -0
  72. package/dist/director/mock-director-bridge.d.ts.map +1 -0
  73. package/dist/director/mock-director-bridge.js +75 -0
  74. package/dist/director/mock-director-bridge.js.map +1 -0
  75. package/dist/director/snapshot-recovery.d.ts +37 -0
  76. package/dist/director/snapshot-recovery.d.ts.map +1 -0
  77. package/dist/director/snapshot-recovery.js +180 -0
  78. package/dist/director/snapshot-recovery.js.map +1 -0
  79. package/dist/director/sse-director-bridge.d.ts +42 -0
  80. package/dist/director/sse-director-bridge.d.ts.map +1 -0
  81. package/dist/director/sse-director-bridge.js +280 -0
  82. package/dist/director/sse-director-bridge.js.map +1 -0
  83. package/dist/engine.d.ts +25 -0
  84. package/dist/engine.d.ts.map +1 -0
  85. package/dist/engine.js +166 -0
  86. package/dist/engine.js.map +1 -0
  87. package/dist/entity.d.ts +17 -0
  88. package/dist/entity.d.ts.map +1 -0
  89. package/dist/entity.js +77 -0
  90. package/dist/entity.js.map +1 -0
  91. package/dist/index.d.ts +85 -0
  92. package/dist/index.d.ts.map +1 -0
  93. package/dist/index.js +64 -0
  94. package/dist/index.js.map +1 -0
  95. package/dist/input/input-manager.d.ts +91 -0
  96. package/dist/input/input-manager.d.ts.map +1 -0
  97. package/dist/input/input-manager.js +349 -0
  98. package/dist/input/input-manager.js.map +1 -0
  99. package/dist/input/tap-to-walk.d.ts +27 -0
  100. package/dist/input/tap-to-walk.d.ts.map +1 -0
  101. package/dist/input/tap-to-walk.js +118 -0
  102. package/dist/input/tap-to-walk.js.map +1 -0
  103. package/dist/input/virtual-dpad.d.ts +34 -0
  104. package/dist/input/virtual-dpad.d.ts.map +1 -0
  105. package/dist/input/virtual-dpad.js +267 -0
  106. package/dist/input/virtual-dpad.js.map +1 -0
  107. package/dist/renderer/camera.d.ts +26 -0
  108. package/dist/renderer/camera.d.ts.map +1 -0
  109. package/dist/renderer/camera.js +39 -0
  110. package/dist/renderer/camera.js.map +1 -0
  111. package/dist/renderer/canvas2d-device.d.ts +26 -0
  112. package/dist/renderer/canvas2d-device.d.ts.map +1 -0
  113. package/dist/renderer/canvas2d-device.js +252 -0
  114. package/dist/renderer/canvas2d-device.js.map +1 -0
  115. package/dist/renderer/graphics-device.d.ts +36 -0
  116. package/dist/renderer/graphics-device.d.ts.map +1 -0
  117. package/dist/renderer/graphics-device.js +12 -0
  118. package/dist/renderer/graphics-device.js.map +1 -0
  119. package/dist/renderer/iso-projection.d.ts +11 -0
  120. package/dist/renderer/iso-projection.d.ts.map +1 -0
  121. package/dist/renderer/iso-projection.js +59 -0
  122. package/dist/renderer/iso-projection.js.map +1 -0
  123. package/dist/resources.d.ts +28 -0
  124. package/dist/resources.d.ts.map +1 -0
  125. package/dist/resources.js +53 -0
  126. package/dist/resources.js.map +1 -0
  127. package/dist/system.d.ts +14 -0
  128. package/dist/system.d.ts.map +1 -0
  129. package/dist/system.js +25 -0
  130. package/dist/system.js.map +1 -0
  131. package/dist/systems/animation-system.d.ts +8 -0
  132. package/dist/systems/animation-system.d.ts.map +1 -0
  133. package/dist/systems/animation-system.js +77 -0
  134. package/dist/systems/animation-system.js.map +1 -0
  135. package/dist/systems/attack-system.d.ts +17 -0
  136. package/dist/systems/attack-system.d.ts.map +1 -0
  137. package/dist/systems/attack-system.js +94 -0
  138. package/dist/systems/attack-system.js.map +1 -0
  139. package/dist/systems/damage-system.d.ts +18 -0
  140. package/dist/systems/damage-system.d.ts.map +1 -0
  141. package/dist/systems/damage-system.js +77 -0
  142. package/dist/systems/damage-system.js.map +1 -0
  143. package/dist/systems/input-system.d.ts +7 -0
  144. package/dist/systems/input-system.d.ts.map +1 -0
  145. package/dist/systems/input-system.js +27 -0
  146. package/dist/systems/input-system.js.map +1 -0
  147. package/dist/systems/interaction-system.d.ts +23 -0
  148. package/dist/systems/interaction-system.d.ts.map +1 -0
  149. package/dist/systems/interaction-system.js +120 -0
  150. package/dist/systems/interaction-system.js.map +1 -0
  151. package/dist/systems/particle-emitter-system.d.ts +8 -0
  152. package/dist/systems/particle-emitter-system.d.ts.map +1 -0
  153. package/dist/systems/particle-emitter-system.js +161 -0
  154. package/dist/systems/particle-emitter-system.js.map +1 -0
  155. package/dist/systems/particle-render-system.d.ts +7 -0
  156. package/dist/systems/particle-render-system.d.ts.map +1 -0
  157. package/dist/systems/particle-render-system.js +53 -0
  158. package/dist/systems/particle-render-system.js.map +1 -0
  159. package/dist/systems/particle-simulation-system.d.ts +8 -0
  160. package/dist/systems/particle-simulation-system.d.ts.map +1 -0
  161. package/dist/systems/particle-simulation-system.js +45 -0
  162. package/dist/systems/particle-simulation-system.js.map +1 -0
  163. package/dist/systems/projectile-render-system.d.ts +7 -0
  164. package/dist/systems/projectile-render-system.d.ts.map +1 -0
  165. package/dist/systems/projectile-render-system.js +35 -0
  166. package/dist/systems/projectile-render-system.js.map +1 -0
  167. package/dist/systems/projectile-system.d.ts +7 -0
  168. package/dist/systems/projectile-system.d.ts.map +1 -0
  169. package/dist/systems/projectile-system.js +114 -0
  170. package/dist/systems/projectile-system.js.map +1 -0
  171. package/dist/systems/pursue-system.d.ts +7 -0
  172. package/dist/systems/pursue-system.d.ts.map +1 -0
  173. package/dist/systems/pursue-system.js +83 -0
  174. package/dist/systems/pursue-system.js.map +1 -0
  175. package/dist/systems/ranged-attack-system.d.ts +7 -0
  176. package/dist/systems/ranged-attack-system.d.ts.map +1 -0
  177. package/dist/systems/ranged-attack-system.js +98 -0
  178. package/dist/systems/ranged-attack-system.js.map +1 -0
  179. package/dist/systems/sprite-render-system.d.ts +9 -0
  180. package/dist/systems/sprite-render-system.d.ts.map +1 -0
  181. package/dist/systems/sprite-render-system.js +108 -0
  182. package/dist/systems/sprite-render-system.js.map +1 -0
  183. package/dist/systems/veil-budget-system.d.ts +7 -0
  184. package/dist/systems/veil-budget-system.d.ts.map +1 -0
  185. package/dist/systems/veil-budget-system.js +37 -0
  186. package/dist/systems/veil-budget-system.js.map +1 -0
  187. package/dist/util/color.d.ts +19 -0
  188. package/dist/util/color.d.ts.map +1 -0
  189. package/dist/util/color.js +45 -0
  190. package/dist/util/color.js.map +1 -0
  191. package/dist/util/math.d.ts +26 -0
  192. package/dist/util/math.d.ts.map +1 -0
  193. package/dist/util/math.js +47 -0
  194. package/dist/util/math.js.map +1 -0
  195. package/dist/util/typed-arrays.d.ts +7 -0
  196. package/dist/util/typed-arrays.d.ts.map +1 -0
  197. package/dist/util/typed-arrays.js +42 -0
  198. package/dist/util/typed-arrays.js.map +1 -0
  199. package/dist/vfx/particle-pool.d.ts +61 -0
  200. package/dist/vfx/particle-pool.d.ts.map +1 -0
  201. package/dist/vfx/particle-pool.js +204 -0
  202. package/dist/vfx/particle-pool.js.map +1 -0
  203. package/dist/vfx/projectile-pool.d.ts +56 -0
  204. package/dist/vfx/projectile-pool.d.ts.map +1 -0
  205. package/dist/vfx/projectile-pool.js +157 -0
  206. package/dist/vfx/projectile-pool.js.map +1 -0
  207. package/dist/world.d.ts +23 -0
  208. package/dist/world.d.ts.map +1 -0
  209. package/dist/world.js +101 -0
  210. package/dist/world.js.map +1 -0
  211. package/dist/zone/zone-catalog.d.ts +17 -0
  212. package/dist/zone/zone-catalog.d.ts.map +1 -0
  213. package/dist/zone/zone-catalog.js +116 -0
  214. package/dist/zone/zone-catalog.js.map +1 -0
  215. package/dist/zone/zone-state.d.ts +18 -0
  216. package/dist/zone/zone-state.d.ts.map +1 -0
  217. package/dist/zone/zone-state.js +52 -0
  218. package/dist/zone/zone-state.js.map +1 -0
  219. package/package.json +56 -0
@@ -0,0 +1,122 @@
1
+ // SpritePool - per-entity sprite appearance data.
2
+ //
3
+ // Companion to TransformPool: an entity that has both Transform
4
+ // (position) and Sprite (atlas + frame + tint) gets rendered by
5
+ // the SpriteRenderSystem.
6
+ //
7
+ // Stored as parallel arrays indexed by entity index, mirroring
8
+ // TransformPool's structure-of-arrays layout. Atlas + frame are
9
+ // tightly packed. Tint is split into rgba arrays so iteration
10
+ // stays cache-friendly.
11
+ import { growF32, growI32, growU8, nextPow2 } from '../util/typed-arrays.js';
12
+ import { entityIndex } from '../entity.js';
13
+ export const SPRITE_FLAG_ACTIVE = 1 << 0;
14
+ export const SPRITE_FLAG_TINTED = 1 << 1;
15
+ export class SpritePool {
16
+ // Hot data
17
+ atlas; // -1 = no sprite assigned (pair with flags ACTIVE bit)
18
+ frame;
19
+ tintR;
20
+ tintG;
21
+ tintB;
22
+ tintA;
23
+ // Cold data
24
+ flags;
25
+ highWaterMark = 0;
26
+ capacity = 0;
27
+ constructor(initialCapacity = 64) {
28
+ this.capacity = nextPow2(initialCapacity);
29
+ this.atlas = new Int32Array(this.capacity).fill(-1);
30
+ this.frame = new Int32Array(this.capacity);
31
+ this.tintR = new Float32Array(this.capacity);
32
+ this.tintG = new Float32Array(this.capacity);
33
+ this.tintB = new Float32Array(this.capacity);
34
+ this.tintA = new Float32Array(this.capacity);
35
+ this.flags = new Uint8Array(this.capacity);
36
+ }
37
+ ensureCapacity(neededIndex) {
38
+ if (neededIndex < this.capacity)
39
+ return;
40
+ const next = nextPow2(neededIndex + 1);
41
+ const newAtlas = new Int32Array(next).fill(-1);
42
+ newAtlas.set(this.atlas);
43
+ this.atlas = newAtlas;
44
+ this.frame = growI32(this.frame, next);
45
+ this.tintR = growF32(this.tintR, next);
46
+ this.tintG = growF32(this.tintG, next);
47
+ this.tintB = growF32(this.tintB, next);
48
+ this.tintA = growF32(this.tintA, next);
49
+ this.flags = growU8(this.flags, next);
50
+ this.capacity = next;
51
+ }
52
+ attach(e, atlas, frame = 0, tint) {
53
+ const i = entityIndex(e);
54
+ this.ensureCapacity(i);
55
+ this.atlas[i] = atlas;
56
+ this.frame[i] = frame;
57
+ if (tint) {
58
+ this.tintR[i] = tint.r;
59
+ this.tintG[i] = tint.g;
60
+ this.tintB[i] = tint.b;
61
+ this.tintA[i] = tint.a;
62
+ this.flags[i] = SPRITE_FLAG_ACTIVE | SPRITE_FLAG_TINTED;
63
+ }
64
+ else {
65
+ this.tintR[i] = 1;
66
+ this.tintG[i] = 1;
67
+ this.tintB[i] = 1;
68
+ this.tintA[i] = 1;
69
+ this.flags[i] = SPRITE_FLAG_ACTIVE;
70
+ }
71
+ if (i >= this.highWaterMark)
72
+ this.highWaterMark = i + 1;
73
+ }
74
+ detach(e) {
75
+ const i = entityIndex(e);
76
+ if (i >= this.capacity)
77
+ return;
78
+ this.atlas[i] = -1;
79
+ this.flags[i] = 0;
80
+ }
81
+ setFrame(e, frame) {
82
+ const i = entityIndex(e);
83
+ if (i >= this.capacity)
84
+ return;
85
+ this.frame[i] = frame;
86
+ }
87
+ setTint(e, tint) {
88
+ const i = entityIndex(e);
89
+ if (i >= this.capacity)
90
+ return;
91
+ this.tintR[i] = tint.r;
92
+ this.tintG[i] = tint.g;
93
+ this.tintB[i] = tint.b;
94
+ this.tintA[i] = tint.a;
95
+ const f = this.flags[i] ?? 0;
96
+ this.flags[i] = f | SPRITE_FLAG_TINTED;
97
+ }
98
+ clearTint(e) {
99
+ const i = entityIndex(e);
100
+ if (i >= this.capacity)
101
+ return;
102
+ this.tintR[i] = 1;
103
+ this.tintG[i] = 1;
104
+ this.tintB[i] = 1;
105
+ this.tintA[i] = 1;
106
+ const f = this.flags[i] ?? 0;
107
+ this.flags[i] = f & ~SPRITE_FLAG_TINTED;
108
+ }
109
+ isActive(e) {
110
+ const i = entityIndex(e);
111
+ if (i >= this.capacity)
112
+ return false;
113
+ return ((this.flags[i] ?? 0) & SPRITE_FLAG_ACTIVE) !== 0;
114
+ }
115
+ getHighWaterMark() {
116
+ return this.highWaterMark;
117
+ }
118
+ getCapacity() {
119
+ return this.capacity;
120
+ }
121
+ }
122
+ //# sourceMappingURL=sprite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sprite.js","sourceRoot":"","sources":["../../src/components/sprite.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { type EntityId } from '../entity.js';
2
+ export declare const TRANSFORM_FLAG_DIRTY: number;
3
+ export declare const TRANSFORM_FLAG_VISIBLE: number;
4
+ export declare const TRANSFORM_FLAG_STATIC: number;
5
+ export declare const TRANSFORM_FLAG_HAS_PARENT: number;
6
+ export declare class TransformPool {
7
+ x: Float32Array;
8
+ y: Float32Array;
9
+ z: Float32Array;
10
+ rotation: Float32Array;
11
+ scaleX: Float32Array;
12
+ scaleY: Float32Array;
13
+ parent: Int32Array;
14
+ flags: Uint8Array;
15
+ private highWaterMark;
16
+ private capacity;
17
+ constructor(initialCapacity?: number);
18
+ ensureCapacity(neededIndex: number): void;
19
+ attach(e: EntityId, x?: number, y?: number, z?: number): void;
20
+ detach(e: EntityId): void;
21
+ setPosition(e: EntityId, x: number, y: number, z?: number): void;
22
+ setScale(e: EntityId, sx: number, sy: number): void;
23
+ setRotation(e: EntityId, radians: number): void;
24
+ isVisible(e: EntityId): boolean;
25
+ setVisible(e: EntityId, visible: boolean): void;
26
+ getHighWaterMark(): number;
27
+ getCapacity(): number;
28
+ clearDirtyAt(index: number): void;
29
+ }
30
+ //# sourceMappingURL=transform.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../src/components/transform.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,KAAK,QAAQ,EAAe,MAAM,cAAc,CAAC;AAG1D,eAAO,MAAM,oBAAoB,QAAS,CAAC;AAC3C,eAAO,MAAM,sBAAsB,QAAS,CAAC;AAC7C,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAC5C,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAEhD,qBAAa,aAAa;IAExB,CAAC,EAAE,YAAY,CAAC;IAChB,CAAC,EAAE,YAAY,CAAC;IAChB,CAAC,EAAE,YAAY,CAAC;IAChB,QAAQ,EAAE,YAAY,CAAC;IACvB,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,YAAY,CAAC;IAGrB,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,UAAU,CAAC;IAKlB,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAa;gBAEjB,eAAe,GAAE,MAAW;IAYxC,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAsBzC,MAAM,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAE,MAAU,EAAE,CAAC,GAAE,MAAU,EAAE,CAAC,GAAE,MAAU,GAAG,IAAI;IActE,MAAM,CAAC,CAAC,EAAE,QAAQ,GAAG,IAAI;IASzB,WAAW,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,GAAE,MAAU,GAAG,IAAI;IAUnE,QAAQ,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IASnD,WAAW,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAQ/C,SAAS,CAAC,CAAC,EAAE,QAAQ,GAAG,OAAO;IAM/B,UAAU,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAO/C,gBAAgB,IAAI,MAAM;IAI1B,WAAW,IAAI,MAAM;IAOrB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;CAKlC"}
@@ -0,0 +1,150 @@
1
+ // TransformPool - the hot component for the Loom Engine ECS.
2
+ //
3
+ // Structure-of-arrays storage: x, y, z, rotation, scaleX, scaleY in
4
+ // separate Float32Arrays so iteration sweeps a contiguous block.
5
+ // Cold metadata (parent, flags) in their own arrays.
6
+ //
7
+ // Inspired by Mike Acton's CppCon 2014 "Data-Oriented Design" talk
8
+ // (see PRIOR-ART.md). The premise: a 10k-entity sort step iterates
9
+ // through ~80kB of contiguous Float32Array memory rather than
10
+ // chasing 10k object pointers.
11
+ //
12
+ // Capacity grows by 2x on demand. Initial capacity is small to
13
+ // keep startup cost tiny; first scene with > 64 entities pays for
14
+ // one grow, after that pow-2 sizing absorbs further growth cheaply.
15
+ import { growF32, growU8, nextPow2 } from '../util/typed-arrays.js';
16
+ import { entityIndex } from '../entity.js';
17
+ // Bitflags packed into the cold flags array.
18
+ export const TRANSFORM_FLAG_DIRTY = 1 << 0; // world matrix needs recompute
19
+ export const TRANSFORM_FLAG_VISIBLE = 1 << 1; // skip render if cleared
20
+ export const TRANSFORM_FLAG_STATIC = 1 << 2; // never moves; cache aggressively
21
+ export const TRANSFORM_FLAG_HAS_PARENT = 1 << 3; // parent slot is meaningful
22
+ export class TransformPool {
23
+ // Hot data - touched every frame by render + sort systems.
24
+ x;
25
+ y;
26
+ z;
27
+ rotation;
28
+ scaleX;
29
+ scaleY;
30
+ // Cold data - rarely touched per-frame.
31
+ parent; // -1 for root, otherwise parent entity index
32
+ flags;
33
+ // High-water mark of active indices. Iteration goes up to this,
34
+ // not capacity, so a sparsely-populated pool doesn't waste cycles
35
+ // on empty slots above the live set.
36
+ highWaterMark = 0;
37
+ capacity = 0;
38
+ constructor(initialCapacity = 64) {
39
+ this.capacity = nextPow2(initialCapacity);
40
+ this.x = new Float32Array(this.capacity);
41
+ this.y = new Float32Array(this.capacity);
42
+ this.z = new Float32Array(this.capacity);
43
+ this.rotation = new Float32Array(this.capacity);
44
+ this.scaleX = new Float32Array(this.capacity);
45
+ this.scaleY = new Float32Array(this.capacity);
46
+ this.parent = new Int32Array(this.capacity).fill(-1);
47
+ this.flags = new Uint8Array(this.capacity);
48
+ }
49
+ ensureCapacity(neededIndex) {
50
+ if (neededIndex < this.capacity)
51
+ return;
52
+ const next = nextPow2(neededIndex + 1);
53
+ this.x = growF32(this.x, next);
54
+ this.y = growF32(this.y, next);
55
+ this.z = growF32(this.z, next);
56
+ this.rotation = growF32(this.rotation, next);
57
+ this.scaleX = growF32(this.scaleX, next);
58
+ this.scaleY = growF32(this.scaleY, next);
59
+ // -1 is the parent sentinel for "no parent" - new slots default
60
+ // to that.
61
+ const oldParent = this.parent;
62
+ const newParent = new Int32Array(next).fill(-1);
63
+ newParent.set(oldParent);
64
+ this.parent = newParent;
65
+ this.flags = growU8(this.flags, next);
66
+ this.capacity = next;
67
+ }
68
+ // Attach a transform to an entity. Sets sane defaults: scale = 1,
69
+ // visible = true, dirty = true. The dirty flag tells the transform
70
+ // system to recompute any cached world matrix on the next commit.
71
+ attach(e, x = 0, y = 0, z = 0) {
72
+ const i = entityIndex(e);
73
+ this.ensureCapacity(i);
74
+ this.x[i] = x;
75
+ this.y[i] = y;
76
+ this.z[i] = z;
77
+ this.rotation[i] = 0;
78
+ this.scaleX[i] = 1;
79
+ this.scaleY[i] = 1;
80
+ this.parent[i] = -1;
81
+ this.flags[i] = TRANSFORM_FLAG_DIRTY | TRANSFORM_FLAG_VISIBLE;
82
+ if (i >= this.highWaterMark)
83
+ this.highWaterMark = i + 1;
84
+ }
85
+ detach(e) {
86
+ const i = entityIndex(e);
87
+ if (i >= this.capacity)
88
+ return;
89
+ this.flags[i] = 0;
90
+ // We don't shrink highWaterMark on detach - the slot is just
91
+ // marked invisible. A future tighten() pass could compact, but
92
+ // v1 keeps it simple.
93
+ }
94
+ setPosition(e, x, y, z = 0) {
95
+ const i = entityIndex(e);
96
+ if (i >= this.capacity)
97
+ return;
98
+ this.x[i] = x;
99
+ this.y[i] = y;
100
+ this.z[i] = z;
101
+ const f = this.flags[i] ?? 0;
102
+ this.flags[i] = f | TRANSFORM_FLAG_DIRTY;
103
+ }
104
+ setScale(e, sx, sy) {
105
+ const i = entityIndex(e);
106
+ if (i >= this.capacity)
107
+ return;
108
+ this.scaleX[i] = sx;
109
+ this.scaleY[i] = sy;
110
+ const f = this.flags[i] ?? 0;
111
+ this.flags[i] = f | TRANSFORM_FLAG_DIRTY;
112
+ }
113
+ setRotation(e, radians) {
114
+ const i = entityIndex(e);
115
+ if (i >= this.capacity)
116
+ return;
117
+ this.rotation[i] = radians;
118
+ const f = this.flags[i] ?? 0;
119
+ this.flags[i] = f | TRANSFORM_FLAG_DIRTY;
120
+ }
121
+ isVisible(e) {
122
+ const i = entityIndex(e);
123
+ if (i >= this.capacity)
124
+ return false;
125
+ return ((this.flags[i] ?? 0) & TRANSFORM_FLAG_VISIBLE) !== 0;
126
+ }
127
+ setVisible(e, visible) {
128
+ const i = entityIndex(e);
129
+ if (i >= this.capacity)
130
+ return;
131
+ const f = this.flags[i] ?? 0;
132
+ this.flags[i] = visible ? f | TRANSFORM_FLAG_VISIBLE : f & ~TRANSFORM_FLAG_VISIBLE;
133
+ }
134
+ getHighWaterMark() {
135
+ return this.highWaterMark;
136
+ }
137
+ getCapacity() {
138
+ return this.capacity;
139
+ }
140
+ // Clear the dirty bit after the transform-system commit pass. The
141
+ // commit pass walks all dirty entries, recomputes derived state,
142
+ // then calls this.
143
+ clearDirtyAt(index) {
144
+ if (index >= this.capacity)
145
+ return;
146
+ const f = this.flags[index] ?? 0;
147
+ this.flags[index] = f & ~TRANSFORM_FLAG_DIRTY;
148
+ }
149
+ }
150
+ //# sourceMappingURL=transform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform.js","sourceRoot":"","sources":["../../src/components/transform.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { DirectorEvent } from './event-envelope.js';
2
+ export type DirectorBridgeStatus = 'idle' | 'connecting' | 'connected' | 'reconnecting' | 'snapshot-required' | 'closed';
3
+ export interface DirectorBridgeStats {
4
+ eventsReceived: number;
5
+ reconnects: number;
6
+ lastEventId: number;
7
+ outOfOrderEvents: number;
8
+ serverDropsP1: number;
9
+ serverDropsP2: number;
10
+ }
11
+ export interface IDirectorBridge {
12
+ start(): void;
13
+ stop(): void;
14
+ status(): DirectorBridgeStatus;
15
+ isConnected(): boolean;
16
+ getLastEventId(): number;
17
+ pollEvents(): DirectorEvent[];
18
+ stats(): Readonly<DirectorBridgeStats>;
19
+ }
20
+ export declare const RESOURCE_DIRECTOR_BRIDGE = "director_bridge";
21
+ export declare const RESOURCE_KNOT_CONTEXT = "knot_context";
22
+ //# sourceMappingURL=director-bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"director-bridge.d.ts","sourceRoot":"","sources":["../../src/director/director-bridge.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,MAAM,MAAM,oBAAoB,GAC5B,MAAM,GACN,YAAY,GACZ,WAAW,GACX,cAAc,GACd,mBAAmB,GACnB,QAAQ,CAAC;AAEb,MAAM,WAAW,mBAAmB;IAElC,cAAc,EAAE,MAAM,CAAC;IAEvB,UAAU,EAAE,MAAM,CAAC;IAEnB,WAAW,EAAE,MAAM,CAAC;IAEpB,gBAAgB,EAAE,MAAM,CAAC;IAEzB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,IAAI,IAAI,CAAC;IACd,IAAI,IAAI,IAAI,CAAC;IACb,MAAM,IAAI,oBAAoB,CAAC;IAC/B,WAAW,IAAI,OAAO,CAAC;IACvB,cAAc,IAAI,MAAM,CAAC;IACzB,UAAU,IAAI,aAAa,EAAE,CAAC;IAC9B,KAAK,IAAI,QAAQ,CAAC,mBAAmB,CAAC,CAAC;CACxC;AAGD,eAAO,MAAM,wBAAwB,oBAAoB,CAAC;AAC1D,eAAO,MAAM,qBAAqB,iBAAiB,CAAC"}
@@ -0,0 +1,23 @@
1
+ // IDirectorBridge - abstraction over the event source.
2
+ //
3
+ // Concrete implementations:
4
+ // MockDirectorBridge - synthetic event injection. Used in tests +
5
+ // offline demo. Does not touch the network.
6
+ // SSEDirectorBridge - real EventSource subscription against the
7
+ // backend's /api/v1/loom/director/events route.
8
+ // Browser-only; throws in Node test runs.
9
+ //
10
+ // The DirectorSystem (PHASE_INPUT) calls pollEvents() once per tick
11
+ // to drain queued events. Bridges buffer events between polls so the
12
+ // system's per-tick read is bounded.
13
+ //
14
+ // Connection lifecycle:
15
+ // start() - begin subscription / open EventSource
16
+ // stop() - close and stop reconnecting
17
+ // isConnected() - true when the underlying transport is open
18
+ // getLastEventId() - highest id observed; used for reconnect Last-Event-ID
19
+ // pollEvents() - drain and return all queued events since last poll
20
+ // Resource keys.
21
+ export const RESOURCE_DIRECTOR_BRIDGE = 'director_bridge';
22
+ export const RESOURCE_KNOT_CONTEXT = 'knot_context';
23
+ //# sourceMappingURL=director-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"director-bridge.js","sourceRoot":"","sources":["../../src/director/director-bridge.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,EAAE;AACF,4BAA4B;AAC5B,qEAAqE;AACrE,oEAAoE;AACpE,oEAAoE;AACpE,wEAAwE;AACxE,kEAAkE;AAClE,EAAE;AACF,oEAAoE;AACpE,qEAAqE;AACrE,qCAAqC;AACrC,EAAE;AACF,wBAAwB;AACxB,+DAA+D;AAC/D,qDAAqD;AACrD,oEAAoE;AACpE,+EAA+E;AAC/E,4EAA4E;AAoC5E,iBAAiB;AACjB,MAAM,CAAC,MAAM,wBAAwB,GAAG,iBAAiB,CAAC;AAC1D,MAAM,CAAC,MAAM,qBAAqB,GAAG,cAAc,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { System } from '../system.js';
2
+ import type { World } from '../world.js';
3
+ import type { AtlasHandle } from '../renderer/graphics-device.js';
4
+ import type { EntityId } from '../entity.js';
5
+ export interface DirectorEncounterSystemOptions {
6
+ player: EntityId;
7
+ mobAtlas: AtlasHandle;
8
+ onEncounterStarted?: (encounterId: string, mobCount: number, narratorLine: string | null) => void;
9
+ }
10
+ export declare class DirectorEncounterSystem implements System {
11
+ readonly name: string;
12
+ private handled;
13
+ private opts;
14
+ constructor(opts: DirectorEncounterSystemOptions);
15
+ update(world: World, _dt: number): void;
16
+ private spawnEncounter;
17
+ private spawnOne;
18
+ clearHandled(): void;
19
+ hasHandled(encounterId: string): boolean;
20
+ }
21
+ //# sourceMappingURL=director-encounter-system.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"director-encounter-system.d.ts","sourceRoot":"","sources":["../../src/director/director-encounter-system.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAWzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAsB7C,MAAM,WAAW,8BAA8B;IAE7C,MAAM,EAAE,QAAQ,CAAC;IAKjB,QAAQ,EAAE,WAAW,CAAC;IAItB,kBAAkB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CACnG;AAED,qBAAa,uBAAwB,YAAW,MAAM;IACpD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAwB;IAI7C,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,IAAI,CAAiC;gBAEjC,IAAI,EAAE,8BAA8B;IAIhD,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IA2BvC,OAAO,CAAC,cAAc;IA6BtB,OAAO,CAAC,QAAQ;IAyBhB,YAAY,IAAI,IAAI;IAIpB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;CAGzC"}
@@ -0,0 +1,128 @@
1
+ // DirectorEncounterSystem - subscribes to encounter.spawn events
2
+ // from the DirectorEventLog and spawns mobs into the world.
3
+ //
4
+ // Works in tandem with DirectorSystem:
5
+ // 1. DirectorSystem (PHASE_INPUT) drains the bridge and applies
6
+ // events to KnotContext / VeilBudget / DirectorEventLog
7
+ // 2. DirectorEncounterSystem (PHASE_LOGIC) re-reads the most
8
+ // recent events from the log, spawns mobs from any new
9
+ // encounter.spawn event, and tracks handled encounter ids so
10
+ // replay / duplicate events don't double-spawn
11
+ //
12
+ // Per spec §3.1 the encounter.spawn payload includes:
13
+ // - mobs: ReadonlyArray<MobSpec> with type, position_hint, etc.
14
+ // - boss: BossSpec | null
15
+ // - knot, level, zone_id, narrator_line
16
+ //
17
+ // The renderer never decides composition (spec §5.1, §6.5). It just
18
+ // applies what the Director said.
19
+ //
20
+ // Mob type mapping: the spec's `type` field is a string the Director
21
+ // chose. We map known strings to MobArchetype values; unknown strings
22
+ // fall back to 'skel_warrior' so the encounter still produces
23
+ // something visible.
24
+ import { RESOURCE_DIRECTOR_LOG, } from './director-system.js';
25
+ import { spawnMob, MOB_CATALOG, } from '../combat/mob-catalog.js';
26
+ // String -> MobArchetype map. The Director can emit any string in
27
+ // the type field (spec doesn't enumerate); the engine validates +
28
+ // falls back. New mob types added in subsequent phases just extend
29
+ // this map.
30
+ const TYPE_MAP = {
31
+ skel_warrior: 'skel_warrior',
32
+ skel_archer: 'skel_archer',
33
+ skel_caster: 'skel_caster',
34
+ // Aliases / legacy names from the existing Survivor that map to
35
+ // catalog archetypes.
36
+ skeleton_iron: 'skel_warrior',
37
+ skeleton_warrior: 'skel_warrior',
38
+ skeleton_archer: 'skel_archer',
39
+ skeleton_caster: 'skel_caster',
40
+ };
41
+ function resolveMobArchetype(typeStr) {
42
+ return TYPE_MAP[typeStr] ?? 'skel_warrior';
43
+ }
44
+ export class DirectorEncounterSystem {
45
+ name = 'director-encounter';
46
+ // Set of encounter_ids we've already spawned. Prevents duplicate
47
+ // spawn on event replay (spec §9.3 dual-delivery dedupe).
48
+ handled = new Set();
49
+ opts;
50
+ constructor(opts) {
51
+ this.opts = opts;
52
+ }
53
+ update(world, _dt) {
54
+ const log = world.resources.get(RESOURCE_DIRECTOR_LOG);
55
+ if (!log)
56
+ return;
57
+ // Walk recent events from the log. recent is newest-first and
58
+ // capped at 32 (per DirectorSystem ring buffer). Iterate from
59
+ // oldest-to-newest so multi-encounter ticks spawn in order.
60
+ for (let i = log.recent.length - 1; i >= 0; i--) {
61
+ const ev = log.recent[i];
62
+ if (!ev || ev.type !== 'encounter.spawn')
63
+ continue;
64
+ const spawn = ev;
65
+ const id = spawn.data.encounter_id;
66
+ if (!id || this.handled.has(id))
67
+ continue;
68
+ this.spawnEncounter(world, spawn.data);
69
+ this.handled.add(id);
70
+ }
71
+ // On encounter.end events, free up the encounter id so a future
72
+ // re-emission (e.g. retry) can spawn again.
73
+ for (let i = log.recent.length - 1; i >= 0; i--) {
74
+ const ev = log.recent[i];
75
+ if (!ev || ev.type !== 'encounter.end')
76
+ continue;
77
+ const id = ev.encounter_id;
78
+ if (id)
79
+ this.handled.delete(id);
80
+ }
81
+ }
82
+ spawnEncounter(world, data) {
83
+ let totalSpawned = 0;
84
+ for (const mob of data.mobs) {
85
+ totalSpawned += this.spawnOne(world, mob);
86
+ }
87
+ // Boss spawn (if present).
88
+ if (data.boss) {
89
+ // Bosses use the same spawnMob factory in v1; future work
90
+ // adds a spawnBoss with bigger HP / unique behaviour.
91
+ const archetype = resolveMobArchetype(data.boss.type);
92
+ // Verify the catalog has the entry before spawning - prevents
93
+ // a typo on the Director side from crashing the renderer.
94
+ if (MOB_CATALOG[archetype]) {
95
+ spawnMob(world, archetype, data.boss.position_hint.x, data.boss.position_hint.y, this.opts.player, this.opts.mobAtlas);
96
+ totalSpawned++;
97
+ }
98
+ }
99
+ if (this.opts.onEncounterStarted) {
100
+ this.opts.onEncounterStarted(data.encounter_id, totalSpawned, data.narrator_line);
101
+ }
102
+ }
103
+ spawnOne(world, mob) {
104
+ const archetype = resolveMobArchetype(mob.type);
105
+ if (!MOB_CATALOG[archetype])
106
+ return 0;
107
+ const baseX = mob.position_hint.x;
108
+ const baseY = mob.position_hint.y;
109
+ // count > 1 spawns multiple instances at slightly varied
110
+ // positions (small radius around the position_hint).
111
+ for (let i = 0; i < mob.count; i++) {
112
+ const angle = (i / Math.max(1, mob.count)) * Math.PI * 2;
113
+ const spread = mob.count > 1 ? 0.5 : 0;
114
+ spawnMob(world, archetype, baseX + Math.cos(angle) * spread, baseY + Math.sin(angle) * spread, this.opts.player, this.opts.mobAtlas);
115
+ }
116
+ return mob.count;
117
+ }
118
+ // Test / debug helper: clear the handled-id cache. Used by demo
119
+ // code when transitioning zones so a fresh encounter.spawn for a
120
+ // re-entered zone re-spawns mobs.
121
+ clearHandled() {
122
+ this.handled.clear();
123
+ }
124
+ hasHandled(encounterId) {
125
+ return this.handled.has(encounterId);
126
+ }
127
+ }
128
+ //# sourceMappingURL=director-encounter-system.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"director-encounter-system.js","sourceRoot":"","sources":["../../src/director/director-encounter-system.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { System } from '../system.js';
2
+ import type { World } from '../world.js';
3
+ import type { DirectorEvent, VeilTier } from './event-envelope.js';
4
+ export interface DirectorEventLog {
5
+ recent: DirectorEvent[];
6
+ lastNarratorLine: string | null;
7
+ lastNarratorTtlMs: number;
8
+ lastKnot: string | null;
9
+ activeEncounterId: string | null;
10
+ lastTier: VeilTier;
11
+ eventsApplied: number;
12
+ }
13
+ export declare const RESOURCE_DIRECTOR_LOG = "director_log";
14
+ export declare function createDirectorEventLog(): DirectorEventLog;
15
+ export declare class DirectorSystem implements System {
16
+ readonly name: string;
17
+ update(world: World, _dt: number): void;
18
+ }
19
+ //# sourceMappingURL=director-system.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"director-system.d.ts","sourceRoot":"","sources":["../../src/director/director-system.ts"],"names":[],"mappings":"AA6CA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAazC,OAAO,KAAK,EACV,aAAa,EACb,QAAQ,EACT,MAAM,qBAAqB,CAAC;AAG7B,MAAM,WAAW,gBAAgB;IAE/B,MAAM,EAAE,aAAa,EAAE,CAAC;IAExB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,iBAAiB,EAAE,MAAM,CAAC;IAG1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAExB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IAEjC,QAAQ,EAAE,QAAQ,CAAC;IAEnB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,eAAO,MAAM,qBAAqB,iBAAiB,CAAC;AAIpD,wBAAgB,sBAAsB,IAAI,gBAAgB,CAUzD;AAwBD,qBAAa,cAAe,YAAW,MAAM;IAC3C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAc;IAEnC,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;CAwBxC"}