@nayan-ui/engine 0.0.0-stage → 1.0.0-beta.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.
Files changed (189) hide show
  1. package/LICENSE +21 -0
  2. package/NayanEngine.podspec +28 -0
  3. package/README.md +210 -2
  4. package/lib/module/assets/AssetBytesCache.js +76 -0
  5. package/lib/module/assets/AssetCache.js +19 -0
  6. package/lib/module/assets/AssetLoader.js +52 -0
  7. package/lib/module/assets/CacheGeneration.js +7 -0
  8. package/lib/module/assets/IndexedDbCache.web.js +149 -0
  9. package/lib/module/assets/ProceduralCache.js +222 -0
  10. package/lib/module/assets/font.js +136 -0
  11. package/lib/module/assets/loft.js +142 -0
  12. package/lib/module/assets/model.js +74 -0
  13. package/lib/module/assets/modelling.js +254 -0
  14. package/lib/module/assets/shape.js +926 -0
  15. package/lib/module/assets/source.js +58 -0
  16. package/lib/module/assets/source.web.js +22 -0
  17. package/lib/module/assets/storage.js +4 -0
  18. package/lib/module/assets/storage.shared.js +36 -0
  19. package/lib/module/assets/storage.web.js +37 -0
  20. package/lib/module/assets/surface.js +47 -0
  21. package/lib/module/assets/texture.js +66 -0
  22. package/lib/module/drawing/DrawingCanvas.js +38 -0
  23. package/lib/module/drawing/DrawingCanvas.web.js +206 -0
  24. package/lib/module/drawing/DrawingDocument.js +256 -0
  25. package/lib/module/drawing/types.js +4 -0
  26. package/lib/module/globals.d.ts +12 -0
  27. package/lib/module/index.js +36 -0
  28. package/lib/module/input/Joystick.js +84 -0
  29. package/lib/module/input/Joystick.web.js +93 -0
  30. package/lib/module/input/keyboard.js +250 -0
  31. package/lib/module/media/audio-worklet.js +34 -0
  32. package/lib/module/media/audio.js +94 -0
  33. package/lib/module/media/haptics.js +82 -0
  34. package/lib/module/media/output.web.js +66 -0
  35. package/lib/module/native/BrowserEngine.js +551 -0
  36. package/lib/module/native/EngineBridge.js +4 -0
  37. package/lib/module/native/NativeNayanEngine.js +7 -0
  38. package/lib/module/native/NativeNayanEngine.web.js +62 -0
  39. package/lib/module/native/prepare.js +7 -0
  40. package/lib/module/native/prepare.web.js +17 -0
  41. package/lib/module/native/spec/NativeNayanEngine.js +17 -0
  42. package/lib/module/package.json +1 -0
  43. package/lib/module/render/GameView.js +249 -0
  44. package/lib/module/render/camera.js +34 -0
  45. package/lib/module/render/host.js +39 -0
  46. package/lib/module/render/host.web.js +104 -0
  47. package/lib/module/render/meshes.js +159 -0
  48. package/lib/module/render/quality.js +112 -0
  49. package/lib/module/render/responder.js +4 -0
  50. package/lib/module/render/responder.web.js +97 -0
  51. package/lib/module/render/touch.js +185 -0
  52. package/lib/module/types.js +30 -0
  53. package/lib/module/world/Scoreboard.js +143 -0
  54. package/lib/module/world/TransformBatch.js +126 -0
  55. package/lib/module/world/World.js +690 -0
  56. package/lib/module/world/desc.js +186 -0
  57. package/lib/module/world/effects.js +451 -0
  58. package/lib/module/world/quat.js +86 -0
  59. package/lib/module/world/types.js +4 -0
  60. package/lib/typescript/package.json +1 -0
  61. package/lib/typescript/src/assets/AssetBytesCache.d.ts +7 -0
  62. package/lib/typescript/src/assets/AssetCache.d.ts +9 -0
  63. package/lib/typescript/src/assets/AssetLoader.d.ts +11 -0
  64. package/lib/typescript/src/assets/CacheGeneration.d.ts +3 -0
  65. package/lib/typescript/src/assets/IndexedDbCache.web.d.ts +20 -0
  66. package/lib/typescript/src/assets/ProceduralCache.d.ts +33 -0
  67. package/lib/typescript/src/assets/font.d.ts +53 -0
  68. package/lib/typescript/src/assets/loft.d.ts +31 -0
  69. package/lib/typescript/src/assets/model.d.ts +48 -0
  70. package/lib/typescript/src/assets/modelling.d.ts +157 -0
  71. package/lib/typescript/src/assets/shape.d.ts +203 -0
  72. package/lib/typescript/src/assets/source.d.ts +10 -0
  73. package/lib/typescript/src/assets/source.web.d.ts +8 -0
  74. package/lib/typescript/src/assets/storage.d.ts +2 -0
  75. package/lib/typescript/src/assets/storage.shared.d.ts +7 -0
  76. package/lib/typescript/src/assets/storage.web.d.ts +7 -0
  77. package/lib/typescript/src/assets/surface.d.ts +17 -0
  78. package/lib/typescript/src/assets/texture.d.ts +30 -0
  79. package/lib/typescript/src/drawing/DrawingCanvas.d.ts +5 -0
  80. package/lib/typescript/src/drawing/DrawingCanvas.web.d.ts +4 -0
  81. package/lib/typescript/src/drawing/DrawingDocument.d.ts +210 -0
  82. package/lib/typescript/src/drawing/types.d.ts +12 -0
  83. package/lib/typescript/src/index.d.ts +42 -0
  84. package/lib/typescript/src/input/Joystick.d.ts +20 -0
  85. package/lib/typescript/src/input/Joystick.web.d.ts +13 -0
  86. package/lib/typescript/src/input/keyboard.d.ts +17 -0
  87. package/lib/typescript/src/media/audio.d.ts +46 -0
  88. package/lib/typescript/src/media/haptics.d.ts +22 -0
  89. package/lib/typescript/src/media/output.web.d.ts +4 -0
  90. package/lib/typescript/src/native/BrowserEngine.d.ts +8 -0
  91. package/lib/typescript/src/native/EngineBridge.d.ts +22 -0
  92. package/lib/typescript/src/native/NativeNayanEngine.d.ts +5 -0
  93. package/lib/typescript/src/native/NativeNayanEngine.web.d.ts +10 -0
  94. package/lib/typescript/src/native/prepare.d.ts +3 -0
  95. package/lib/typescript/src/native/prepare.web.d.ts +2 -0
  96. package/lib/typescript/src/native/spec/NativeNayanEngine.d.ts +182 -0
  97. package/lib/typescript/src/render/GameView.d.ts +95 -0
  98. package/lib/typescript/src/render/camera.d.ts +6 -0
  99. package/lib/typescript/src/render/host.d.ts +29 -0
  100. package/lib/typescript/src/render/host.web.d.ts +16 -0
  101. package/lib/typescript/src/render/meshes.d.ts +45 -0
  102. package/lib/typescript/src/render/quality.d.ts +46 -0
  103. package/lib/typescript/src/render/responder.d.ts +2 -0
  104. package/lib/typescript/src/render/responder.web.d.ts +40 -0
  105. package/lib/typescript/src/render/touch.d.ts +26 -0
  106. package/lib/typescript/src/types.d.ts +72 -0
  107. package/lib/typescript/src/world/Scoreboard.d.ts +65 -0
  108. package/lib/typescript/src/world/TransformBatch.d.ts +39 -0
  109. package/lib/typescript/src/world/World.d.ts +199 -0
  110. package/lib/typescript/src/world/desc.d.ts +17 -0
  111. package/lib/typescript/src/world/effects.d.ts +156 -0
  112. package/lib/typescript/src/world/quat.d.ts +31 -0
  113. package/lib/typescript/src/world/types.d.ts +233 -0
  114. package/lib/web/audio-worklet.js +29 -0
  115. package/lib/web/engine_core_bg.wasm +0 -0
  116. package/lib/web/index.js +7974 -0
  117. package/lib/web/types/src/assets/AssetBytesCache.d.ts +6 -0
  118. package/lib/web/types/src/assets/AssetCache.d.ts +8 -0
  119. package/lib/web/types/src/assets/AssetLoader.d.ts +10 -0
  120. package/lib/web/types/src/assets/CacheGeneration.d.ts +2 -0
  121. package/lib/web/types/src/assets/IndexedDbCache.d.ts +19 -0
  122. package/lib/web/types/src/assets/ProceduralCache.d.ts +32 -0
  123. package/lib/web/types/src/assets/font.d.ts +52 -0
  124. package/lib/web/types/src/assets/loft.d.ts +30 -0
  125. package/lib/web/types/src/assets/model.d.ts +47 -0
  126. package/lib/web/types/src/assets/modelling.d.ts +156 -0
  127. package/lib/web/types/src/assets/shape.d.ts +202 -0
  128. package/lib/web/types/src/assets/source.d.ts +7 -0
  129. package/lib/web/types/src/assets/storage.d.ts +6 -0
  130. package/lib/web/types/src/assets/storage.shared.d.ts +6 -0
  131. package/lib/web/types/src/assets/surface.d.ts +16 -0
  132. package/lib/web/types/src/assets/texture.d.ts +29 -0
  133. package/lib/web/types/src/drawing/DrawingCanvas.d.ts +3 -0
  134. package/lib/web/types/src/drawing/DrawingDocument.d.ts +209 -0
  135. package/lib/web/types/src/drawing/types.d.ts +11 -0
  136. package/lib/web/types/src/index.d.ts +41 -0
  137. package/lib/web/types/src/input/Joystick.d.ts +12 -0
  138. package/lib/web/types/src/input/keyboard.d.ts +16 -0
  139. package/lib/web/types/src/media/audio.d.ts +45 -0
  140. package/lib/web/types/src/media/haptics.d.ts +21 -0
  141. package/lib/web/types/src/media/output.d.ts +3 -0
  142. package/lib/web/types/src/native/BrowserEngine.d.ts +7 -0
  143. package/lib/web/types/src/native/EngineBridge.d.ts +21 -0
  144. package/lib/web/types/src/native/NativeNayanEngine.d.ts +9 -0
  145. package/lib/web/types/src/native/prepare.d.ts +1 -0
  146. package/lib/web/types/src/native/spec/NativeNayanEngine.d.ts +181 -0
  147. package/lib/web/types/src/render/GameView.d.ts +94 -0
  148. package/lib/web/types/src/render/camera.d.ts +5 -0
  149. package/lib/web/types/src/render/host.d.ts +15 -0
  150. package/lib/web/types/src/render/meshes.d.ts +44 -0
  151. package/lib/web/types/src/render/quality.d.ts +45 -0
  152. package/lib/web/types/src/render/responder.d.ts +39 -0
  153. package/lib/web/types/src/render/touch.d.ts +25 -0
  154. package/lib/web/types/src/types.d.ts +71 -0
  155. package/lib/web/types/src/world/Scoreboard.d.ts +64 -0
  156. package/lib/web/types/src/world/TransformBatch.d.ts +38 -0
  157. package/lib/web/types/src/world/World.d.ts +198 -0
  158. package/lib/web/types/src/world/desc.d.ts +16 -0
  159. package/lib/web/types/src/world/effects.d.ts +155 -0
  160. package/lib/web/types/src/world/quat.d.ts +30 -0
  161. package/lib/web/types/src/world/types.d.ts +232 -0
  162. package/native/android/CMakeLists.txt +34 -0
  163. package/native/android/NayanEngineSpec.h +15 -0
  164. package/native/android/build.gradle +26 -0
  165. package/native/android/codegen/CMakeLists.txt +3 -0
  166. package/native/android/proguard-rules.pro +2 -0
  167. package/native/android/src/main/java/com/nayanui/engine/EngineSurfaceView.java +234 -0
  168. package/native/android/src/main/java/com/nayanui/engine/EngineSurfaceViewManager.java +45 -0
  169. package/native/android/src/main/java/com/nayanui/engine/NayanEnginePackage.java +24 -0
  170. package/native/core/build/EngineCore.xcframework/Info.plist +43 -0
  171. package/native/core/build/EngineCore.xcframework/ios-arm64/libengine_core.a +0 -0
  172. package/native/core/build/EngineCore.xcframework/ios-arm64-simulator/libengine_core.a +0 -0
  173. package/native/core/build/android/arm64-v8a/libengine_core.a +0 -0
  174. package/native/core/build/android/armeabi-v7a/libengine_core.a +0 -0
  175. package/native/core/build/android/x86/libengine_core.a +0 -0
  176. package/native/core/build/android/x86_64/libengine_core.a +0 -0
  177. package/native/core/include/drawing-licenses.txt +58 -0
  178. package/native/core/include/engine_core.h +322 -0
  179. package/native/cpp/NayanEngineModule.cpp +827 -0
  180. package/native/cpp/NayanEngineModule.h +144 -0
  181. package/native/cpp/generated/NayanEngineSpecJSI.cpp +2 -0
  182. package/native/cpp/generated/NayanEngineSpecJSI.h +921 -0
  183. package/native/ios/NayanEngineProvider.h +5 -0
  184. package/native/ios/NayanEngineProvider.mm +21 -0
  185. package/native/ios/NayanEngineSurface.mm +223 -0
  186. package/native/scripts/check-package.mjs +39 -0
  187. package/package.json +162 -4
  188. package/react-native.config.js +18 -0
  189. package/src/native/spec/NativeNayanEngine.ts +226 -0
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+
3
+ // Encodes entity options into the flat layout the Rust core decodes (native/core/include/engine_core.h,
4
+ // native/core/src/world/desc.rs). One reusable Float64Array per world: spawning or changing an entity is
5
+ // a single native call, and doubles keep entity ids and layer bits exact.
6
+
7
+ export const DESC_LEN = 64;
8
+ const FLAG = {
9
+ MESH: 1 << 0,
10
+ POSITION: 1 << 1,
11
+ ROTATION: 1 << 2,
12
+ SCALE: 1 << 3,
13
+ COLOR: 1 << 4,
14
+ VELOCITY: 1 << 5,
15
+ GROUND_VELOCITY: 1 << 6,
16
+ SPIN: 1 << 7,
17
+ BOB: 1 << 8,
18
+ FOLLOW: 1 << 9,
19
+ LIFETIME: 1 << 10,
20
+ PARENT: 1 << 11,
21
+ PHYSICS: 1 << 12,
22
+ IMPACT: 1 << 13,
23
+ ACCELERATION: 1 << 14,
24
+ PICKABLE: 1 << 15,
25
+ REGION: 1 << 16
26
+ };
27
+ const SLOT = {
28
+ FLAGS: 0,
29
+ MESH: 1,
30
+ POSITION: 2,
31
+ ROTATION: 5,
32
+ SCALE: 9,
33
+ COLOR: 12,
34
+ VELOCITY: 16,
35
+ GROUND_VELOCITY: 19,
36
+ SPIN: 21,
37
+ BOB: 24,
38
+ FOLLOW: 29,
39
+ LIFETIME: 31,
40
+ PARENT: 32,
41
+ PHYSICS: 33,
42
+ IMPACT: 50,
43
+ ACCELERATION: 56,
44
+ PICKABLE: 59,
45
+ REGION: 60
46
+ };
47
+ const BODY_KIND = {
48
+ dynamic: 1,
49
+ kinematic: 2,
50
+ fixed: 3
51
+ };
52
+ const SHAPE = {
53
+ ball: 0,
54
+ box: 1,
55
+ fromMesh: 2,
56
+ cylinder: 3,
57
+ capsule: 4,
58
+ cone: 5
59
+ };
60
+ function encodePhysics(d, physics) {
61
+ const p = SLOT.PHYSICS;
62
+ const shape = physics.shape !== undefined ? SHAPE[physics.shape] : physics.size !== undefined ? SHAPE.box : physics.radius !== undefined ? SHAPE.ball : SHAPE.fromMesh;
63
+ // Sizes <= 0 tell the core to size the collider from the entity's mesh and scale.
64
+ const [sx, sy, sz] = shape === SHAPE.box ? physics.size ? [physics.size[0] / 2, physics.size[1] / 2, physics.size[2] / 2] : [0, 0, 0] : [physics.radius ?? 0, (physics.height ?? 0) / 2, 0];
65
+ d[p] = BODY_KIND[physics.type];
66
+ d[p + 1] = shape;
67
+ d[p + 2] = sx;
68
+ d[p + 3] = sy;
69
+ d[p + 4] = sz;
70
+ d[p + 5] = physics.layer ?? 1;
71
+ d[p + 6] = physics.mask ?? -1; // all layers
72
+ d[p + 7] = physics.sensor ? 1 : 0;
73
+ d[p + 8] = physics.friction ?? 0.5;
74
+ d[p + 9] = physics.bounce ?? 0;
75
+ d[p + 10] = physics.density ?? 1;
76
+ d[p + 11] = physics.drag ?? 0;
77
+ d[p + 12] = physics.angularDrag ?? 0.05;
78
+ d[p + 13] = physics.gravityScale ?? 1;
79
+ d[p + 14] = physics.upright ? 1 : 0;
80
+ d[p + 15] = physics.ccd ? 1 : 0;
81
+ d[p + 16] = physics.planar ? 1 : 0;
82
+ }
83
+
84
+ /** Writes `options` into `d`, with the mesh id already resolved. Only the fields present are flagged. */
85
+ export function encode(d, o, mesh) {
86
+ let flags = 0;
87
+ if (mesh !== undefined) {
88
+ flags |= FLAG.MESH;
89
+ d[SLOT.MESH] = mesh;
90
+ }
91
+ if (o.position) {
92
+ flags |= FLAG.POSITION;
93
+ d.set(o.position, SLOT.POSITION);
94
+ }
95
+ if (o.rotation) {
96
+ flags |= FLAG.ROTATION;
97
+ d.set(o.rotation, SLOT.ROTATION);
98
+ }
99
+ if (o.scale !== undefined) {
100
+ flags |= FLAG.SCALE;
101
+ if (typeof o.scale === 'number') d.fill(o.scale, SLOT.SCALE, SLOT.SCALE + 3);else d.set(o.scale, SLOT.SCALE);
102
+ }
103
+ if (o.color) {
104
+ flags |= FLAG.COLOR;
105
+ d[SLOT.COLOR] = o.color[0];
106
+ d[SLOT.COLOR + 1] = o.color[1];
107
+ d[SLOT.COLOR + 2] = o.color[2];
108
+ d[SLOT.COLOR + 3] = o.color[3] ?? 1;
109
+ }
110
+ if (o.velocity) {
111
+ flags |= FLAG.VELOCITY;
112
+ d.set(o.velocity, SLOT.VELOCITY);
113
+ }
114
+ if (o.groundVelocity) {
115
+ flags |= FLAG.GROUND_VELOCITY;
116
+ d.set(o.groundVelocity, SLOT.GROUND_VELOCITY);
117
+ }
118
+ if (o.spin) {
119
+ flags |= FLAG.SPIN;
120
+ d.set(o.spin, SLOT.SPIN);
121
+ }
122
+ if (o.bob !== undefined) {
123
+ flags |= FLAG.BOB;
124
+ d.set(o.bob?.amplitude ?? [0, 0, 0], SLOT.BOB);
125
+ d[SLOT.BOB + 3] = o.bob?.speed ?? 0;
126
+ d[SLOT.BOB + 4] = o.bob?.phase ?? 0;
127
+ }
128
+ if (o.follow !== undefined) {
129
+ flags |= FLAG.FOLLOW;
130
+ d[SLOT.FOLLOW] = o.follow?.target ?? -1;
131
+ d[SLOT.FOLLOW + 1] = o.follow?.speed ?? 0;
132
+ }
133
+ if (o.lifetime !== undefined) {
134
+ flags |= FLAG.LIFETIME;
135
+ d[SLOT.LIFETIME] = o.lifetime ?? 0;
136
+ }
137
+ if (o.parent !== undefined) {
138
+ flags |= FLAG.PARENT;
139
+ d[SLOT.PARENT] = o.parent ?? -1;
140
+ }
141
+ if (o.physics !== undefined) {
142
+ flags |= FLAG.PHYSICS;
143
+ if (o.physics === null) d[SLOT.PHYSICS] = 0;else encodePhysics(d, typeof o.physics === 'string' ? {
144
+ type: o.physics
145
+ } : o.physics);
146
+ }
147
+ if (o.impact !== undefined) {
148
+ flags |= FLAG.IMPACT;
149
+ const i = SLOT.IMPACT;
150
+ d[i] = o.impact ? 1 : 0;
151
+ d[i + 1] = o.impact?.sound ?? -1;
152
+ d[i + 2] = o.impact?.minSpeed ?? 1;
153
+ d[i + 3] = o.impact?.maxSpeed ?? 10;
154
+ d[i + 4] = o.impact?.volume ?? 1;
155
+ d[i + 5] = o.impact?.haptic ?? 0;
156
+ }
157
+ if (o.acceleration) {
158
+ flags |= FLAG.ACCELERATION;
159
+ d.set(o.acceleration, SLOT.ACCELERATION);
160
+ }
161
+ if (o.pickable !== undefined) {
162
+ flags |= FLAG.PICKABLE;
163
+ d[SLOT.PICKABLE] = o.pickable ? 1 : 0;
164
+ }
165
+ if (o.textureRegion) {
166
+ flags |= FLAG.REGION;
167
+ d.set(o.textureRegion, SLOT.REGION);
168
+ }
169
+ d[SLOT.FLAGS] = flags;
170
+ }
171
+
172
+ // ── Animations and bursts (layouts in native/core/include/engine_core.h) ─────────
173
+
174
+ export const ANIM_HEADER = 12;
175
+ export const ANIM_KEY_LEN = 23;
176
+ export const BURST_LEN = 36;
177
+ export const EASING = {
178
+ linear: 0,
179
+ easeIn: 1,
180
+ easeOut: 2,
181
+ easeInOut: 3,
182
+ back: 4,
183
+ bounce: 5,
184
+ elastic: 6
185
+ };
186
+ //# sourceMappingURL=desc.js.map
@@ -0,0 +1,451 @@
1
+ "use strict";
2
+
3
+ // Ready-made particle effects and the cleared-piece pop, built from `world.burst` and `world.animate`.
4
+ //
5
+ // A single burst gives every particle 50..100% of one top speed, so on its own it flies out as a
6
+ // hollow shell of same-sized bits that pop out of existence. These effects mix a few bursts instead:
7
+ // slow big pieces that fill the middle and fast small ones at the edge, an additive glow that flashes
8
+ // at the source (visible on dark scenes, harmless on light ones), and soft puffs that linger and fade.
9
+ // Every particle takes a world slot, out of the capacity shared with the game's own entities, so the
10
+ // counts stay close to what was passed in. Effects run entirely in the Rust core after one call each.
11
+
12
+ /** Shared options of the layered effects (confetti, sparkle, shatter, splash, sparks, explosion). */
13
+
14
+ /** A soft cloud of puffs that swell and fade: landing dust, kicked-up sand, sawdust, steam, muzzle smoke. */
15
+
16
+ /** One glow that swells and fades at a point: a hit, a strike, a muzzle flash. */
17
+
18
+ /** The cleared-piece pop: swell, flash white, settle, shrink away. */
19
+
20
+ const rgba = c => [c[0], c[1], c[2], c[3] ?? 1];
21
+ const list = colors => typeof colors[0] === 'number' ? [rgba(colors)] : colors.map(rgba);
22
+ const part = (count, share) => Math.max(1, Math.round(count * share));
23
+ const fade = c => [c[0], c[1], c[2], 0];
24
+
25
+ /** The colors' average. */
26
+ function mean(colors) {
27
+ const sum = [0, 0, 0, 0];
28
+ for (const c of colors) for (let i = 0; i < 4; i++) sum[i] += c[i];
29
+ return sum.map(v => v / colors.length);
30
+ }
31
+
32
+ /** The same hue, self-lit: its brightest channel lifted to `peak` (above 1 glows, through light, shadow and fog). */
33
+ function hot(c, peak = 2.2, alpha = c[3] ?? 1) {
34
+ const k = peak / Math.max(c[0], c[1], c[2], 0.25);
35
+ return [c[0] * k, c[1] * k, c[2] * k, alpha];
36
+ }
37
+
38
+ /** Part way (`t`, 0..1) to white, with `alpha`. */
39
+ function pale(c, t, alpha = c[3] ?? 1) {
40
+ return [c[0] + (1 - c[0]) * t, c[1] + (1 - c[1]) * t, c[2] + (1 - c[2]) * t, alpha];
41
+ }
42
+ function aim(e) {
43
+ return {
44
+ position: e.position,
45
+ direction: e.direction ?? [0, 1, 0],
46
+ spread: e.spread ?? Math.PI
47
+ };
48
+ }
49
+ function flash(world, o) {
50
+ return world.burst({
51
+ position: o.position,
52
+ count: o.count ?? 1,
53
+ mesh: o.mesh ?? 'flame',
54
+ size: o.size,
55
+ speed: o.speed ?? 0,
56
+ lifetime: o.lifetime ?? 0.22,
57
+ gravity: 0,
58
+ color: o.color,
59
+ endSize: o.endSize ?? 2.2,
60
+ endColor: o.endColor ?? fade(o.color)
61
+ });
62
+ }
63
+
64
+ /** A glow that swells and fades at the source, in the effect's own hue. */
65
+ function glowFlash(world, e, colors, size) {
66
+ flash(world, {
67
+ position: e.position,
68
+ color: hot(mean(colors), 2, 0.85),
69
+ size
70
+ });
71
+ }
72
+ function dust(world, o) {
73
+ const single = typeof o.color[0] === 'number';
74
+ return world.burst({
75
+ position: o.position,
76
+ count: o.count,
77
+ mesh: o.mesh ?? 'puff',
78
+ size: o.size,
79
+ speed: o.speed,
80
+ lifetime: o.lifetime,
81
+ gravity: o.gravity ?? 0,
82
+ direction: o.direction,
83
+ spread: o.spread,
84
+ color: o.color,
85
+ endSize: o.endSize ?? 2,
86
+ endColor: o.endColor ?? (single ? fade(o.color) : undefined)
87
+ });
88
+ }
89
+
90
+ /** Celebration confetti: tumbling paper in two layers, a few glinting sparkles, and a pop of light. */
91
+ function confetti(world, e) {
92
+ const colors = list(e.colors);
93
+ const g = (e.gravity ?? 0) * 0.65; // paper drifts down rather than dropping
94
+ const base = {
95
+ ...aim(e),
96
+ mesh: 'cube',
97
+ gravity: g,
98
+ color: colors,
99
+ endSize: 0.3
100
+ };
101
+ world.burst({
102
+ ...base,
103
+ count: part(e.count, 0.55),
104
+ size: e.size,
105
+ speed: e.speed,
106
+ lifetime: e.lifetime * 1.15
107
+ });
108
+ world.burst({
109
+ ...base,
110
+ count: part(e.count, 0.3),
111
+ size: e.size * 0.7,
112
+ speed: e.speed * 0.5,
113
+ lifetime: e.lifetime
114
+ });
115
+ const glint = colors.slice(0, 4).map(c => hot(pale(c, 0.5, 1), 2.4));
116
+ world.burst({
117
+ ...aim(e),
118
+ count: part(e.count, 0.15),
119
+ mesh: 'flame',
120
+ size: e.size * 1.1,
121
+ speed: e.speed * 0.8,
122
+ lifetime: e.lifetime * 0.8,
123
+ gravity: g * 0.5,
124
+ color: glint,
125
+ endSize: 0
126
+ });
127
+ if (e.flash !== false) glowFlash(world, e, [[1, 0.95, 0.8, 1]], e.size * 7);
128
+ }
129
+
130
+ /** Glitter for a reward: solid bright beads (seen on any background) with additive glints around them. */
131
+ function sparkle(world, e) {
132
+ const colors = list(e.colors);
133
+ const bright = colors.map(c => hot(c, 1.4));
134
+ const base = {
135
+ ...aim(e),
136
+ gravity: e.gravity ?? 0,
137
+ endSize: 0
138
+ };
139
+ world.burst({
140
+ ...base,
141
+ count: part(e.count, 0.35),
142
+ mesh: 'sphere',
143
+ size: e.size,
144
+ speed: e.speed,
145
+ lifetime: e.lifetime,
146
+ color: bright
147
+ });
148
+ world.burst({
149
+ ...base,
150
+ count: part(e.count, 0.25),
151
+ mesh: 'sphere',
152
+ size: e.size * 1.3,
153
+ speed: e.speed * 0.45,
154
+ lifetime: e.lifetime * 0.85,
155
+ color: bright
156
+ });
157
+ world.burst({
158
+ ...base,
159
+ count: part(e.count, 0.4),
160
+ mesh: 'flame',
161
+ size: e.size * 1.6,
162
+ speed: e.speed * 0.8,
163
+ lifetime: e.lifetime * 0.9,
164
+ color: colors.map(c => hot(pale(c, 0.35, 1), 2.4))
165
+ });
166
+ if (e.flash !== false) glowFlash(world, e, colors, e.size * 6);
167
+ }
168
+
169
+ /**
170
+ * Something breaking apart: big slow chunks, small fast crumbs, a glow at the break and a puff of
171
+ * its dust. `mesh` is the chunks' shape.
172
+ */
173
+ function shatter(world, e) {
174
+ const colors = list(e.colors);
175
+ const mesh = e.mesh ?? 'cube';
176
+ const base = {
177
+ ...aim(e),
178
+ gravity: e.gravity ?? 0,
179
+ color: colors
180
+ };
181
+ world.burst({
182
+ ...base,
183
+ count: part(e.count, 0.55),
184
+ mesh,
185
+ size: e.size * 1.1,
186
+ speed: e.speed * 0.65,
187
+ lifetime: e.lifetime,
188
+ endSize: 0.2
189
+ });
190
+ world.burst({
191
+ ...base,
192
+ count: part(e.count, 0.6),
193
+ mesh,
194
+ size: e.size * 0.5,
195
+ speed: e.speed * 1.1,
196
+ lifetime: e.lifetime * 0.85,
197
+ endSize: 0
198
+ });
199
+ if (e.flash !== false) glowFlash(world, e, colors, e.size * 3);
200
+ if (e.dust !== false) {
201
+ const c = pale(mean(colors), 0.45, 0.5);
202
+ world.burst({
203
+ ...aim(e),
204
+ count: 2,
205
+ mesh: 'puff',
206
+ size: e.size * 2,
207
+ speed: e.speed * 0.2,
208
+ lifetime: e.lifetime * 0.9,
209
+ gravity: 0,
210
+ color: c,
211
+ endSize: 2.4,
212
+ endColor: fade(c)
213
+ });
214
+ }
215
+ }
216
+
217
+ /** Liquid: droplets in two sizes thrown out of a fine mist of the same color. */
218
+ function splash(world, e) {
219
+ const colors = list(e.colors);
220
+ const base = {
221
+ ...aim(e),
222
+ mesh: 'sphere',
223
+ gravity: e.gravity ?? 0,
224
+ color: colors
225
+ };
226
+ world.burst({
227
+ ...base,
228
+ count: part(e.count, 0.6),
229
+ size: e.size,
230
+ speed: e.speed,
231
+ lifetime: e.lifetime,
232
+ endSize: 0.3
233
+ });
234
+ world.burst({
235
+ ...base,
236
+ count: part(e.count, 0.4),
237
+ size: e.size * 1.5,
238
+ speed: e.speed * 0.45,
239
+ lifetime: e.lifetime * 0.8,
240
+ endSize: 0.2
241
+ });
242
+ const mist = pale(mean(colors), 0.2, 0.55);
243
+ world.burst({
244
+ ...aim(e),
245
+ count: 3,
246
+ mesh: 'puff',
247
+ size: e.size * 3,
248
+ speed: e.speed * 0.25,
249
+ lifetime: e.lifetime * 0.7,
250
+ gravity: 0,
251
+ color: mist,
252
+ endSize: 2.2,
253
+ endColor: fade(mist)
254
+ });
255
+ if (e.flash !== false) glowFlash(world, e, colors, e.size * 4);
256
+ }
257
+
258
+ /** Hot metal sparks: additive streaks that burn out, with a few solid beads and a flash where they strike. */
259
+ function sparks(world, e) {
260
+ const colors = list(e.colors).map(c => hot(c, 2.6));
261
+ const base = {
262
+ ...aim(e),
263
+ gravity: e.gravity ?? 0,
264
+ color: colors,
265
+ endSize: 0
266
+ };
267
+ world.burst({
268
+ ...base,
269
+ count: part(e.count, 0.7),
270
+ mesh: 'flame',
271
+ size: e.size * 1.6,
272
+ speed: e.speed,
273
+ lifetime: e.lifetime
274
+ });
275
+ world.burst({
276
+ ...base,
277
+ count: part(e.count, 0.3),
278
+ mesh: 'sphere',
279
+ size: e.size * 0.6,
280
+ speed: e.speed * 1.1,
281
+ lifetime: e.lifetime * 0.8
282
+ });
283
+ if (e.flash !== false) glowFlash(world, e, colors, e.size * 5);
284
+ }
285
+ const FIRE = [[2.6, 2.4, 1.8, 1], [2.4, 1.5, 0.45, 0.95], [2.2, 0.8, 0.2, 0.85]];
286
+ const EMBERS = [[2.8, 2.2, 1, 1], [2.6, 1.3, 0.3, 1]];
287
+
288
+ /**
289
+ * A fiery blast: a white-hot flash, a fireball that cools into smoke, embers thrown out and, given
290
+ * `debris` colors, chunks of whatever blew up. `size` is the fireball's puff size; `colors` its fire.
291
+ * The fire and smoke swell every way; `direction`, `spread` and `gravity` aim the embers and debris.
292
+ */
293
+ function explosion(world, e) {
294
+ const fire = list(e.colors ?? FIRE);
295
+ const smoke = rgba(e.smoke ?? [0.28, 0.25, 0.24, 0.6]);
296
+ const g = e.gravity ?? 0;
297
+ const around = {
298
+ position: e.position,
299
+ spread: Math.PI,
300
+ gravity: 0
301
+ };
302
+ if (e.flash !== false) {
303
+ flash(world, {
304
+ position: e.position,
305
+ color: [3, 2.7, 2.1, 1],
306
+ size: e.size * 1.6,
307
+ lifetime: 0.2,
308
+ endSize: 2,
309
+ endColor: [2.4, 0.9, 0.2, 0]
310
+ });
311
+ }
312
+ world.burst({
313
+ ...around,
314
+ count: part(e.count, 0.5),
315
+ mesh: 'puff',
316
+ size: e.size,
317
+ speed: e.speed,
318
+ lifetime: e.lifetime,
319
+ color: fire,
320
+ endSize: 2.2,
321
+ endColor: [smoke[0], smoke[1], smoke[2], 0]
322
+ });
323
+ world.burst({
324
+ ...around,
325
+ count: part(e.count, 0.2),
326
+ mesh: 'flame',
327
+ size: e.size * 0.8,
328
+ speed: e.speed * 0.5,
329
+ lifetime: e.lifetime * 0.6,
330
+ color: fire,
331
+ endSize: 1.8,
332
+ endColor: [2, 0.5, 0.1, 0]
333
+ });
334
+ world.burst({
335
+ ...around,
336
+ count: part(e.count, 0.25),
337
+ mesh: 'puff',
338
+ size: e.size * 0.9,
339
+ speed: e.speed * 0.6,
340
+ lifetime: e.lifetime * 1.7,
341
+ color: smoke,
342
+ endSize: 2.8,
343
+ endColor: fade(smoke)
344
+ });
345
+ world.burst({
346
+ ...aim(e),
347
+ count: part(e.count, 0.4),
348
+ mesh: 'flame',
349
+ size: e.size * 0.12,
350
+ speed: e.speed * 2.4,
351
+ lifetime: e.lifetime * 0.9,
352
+ gravity: g,
353
+ color: EMBERS,
354
+ endSize: 0
355
+ });
356
+ if (e.debris) {
357
+ world.burst({
358
+ ...aim(e),
359
+ count: part(e.count, 0.5),
360
+ mesh: 'cube',
361
+ size: e.size * 0.16,
362
+ speed: e.speed * 1.8,
363
+ lifetime: e.lifetime * 1.2,
364
+ gravity: g,
365
+ color: e.debris,
366
+ endSize: 0.3
367
+ });
368
+ }
369
+ }
370
+ const WHITE_HOT = [2, 2, 2, 1]; // above 1 glows
371
+ const WHITE = [1, 1, 1, 1];
372
+ const POP_TIME = 0.5;
373
+ const times = (scale, k) => typeof scale === 'number' ? scale * k : [scale[0] * k, scale[1] * k, scale[2] * k];
374
+
375
+ /** The piece swells, flashes white, settles and shrinks away. Resolves when it's gone (despawning it is the caller's). */
376
+ function pop(world, entity, o) {
377
+ const delay = o.delay ?? 0;
378
+ const duration = o.duration ?? POP_TIME;
379
+ const flashFor = {
380
+ duration: duration * 0.3,
381
+ delay
382
+ };
383
+ world.stopAnimation(entity); // whatever it was doing (landing, falling, wobbling) gives way
384
+ if (o.color) world.animate(entity, [{
385
+ color: WHITE_HOT,
386
+ at: 0.33
387
+ }, {
388
+ color: o.color
389
+ }], flashFor);
390
+ if (o.flash?.length) world.animate(o.flash, [{
391
+ color: WHITE_HOT,
392
+ at: 0.33
393
+ }, {
394
+ color: WHITE
395
+ }], flashFor);
396
+ const s = o.scale;
397
+ return world.animate(entity, [{
398
+ scale: times(s, 1.35),
399
+ at: 0.15
400
+ }, {
401
+ scale: times(s, 0.9),
402
+ at: 0.25
403
+ }, {
404
+ scale: times(s, 1),
405
+ at: 0.35
406
+ }, {
407
+ scale: times(s, 0)
408
+ }], {
409
+ duration,
410
+ delay
411
+ });
412
+ }
413
+
414
+ /**
415
+ * Ready-made effects. Each is one call; particles then live, fall, shrink and recolor in Rust.
416
+ *
417
+ * ```ts
418
+ * effects.confetti(world, { position, colors: [RED, GOLD], size: 0.12, speed: 6, count: 40, lifetime: 1.2, gravity: -6 });
419
+ * effects.dust(world, { position: feet, color: [0.8, 0.75, 0.65, 0.6], size: 0.3, speed: 1.5, count: 6, lifetime: 0.5 });
420
+ * effects.flash(world, { position: hit, color: effects.hot(ORANGE), size: 0.8 });
421
+ * await effects.pop(world, candy, { scale: 1, color: RED });
422
+ * world.despawn(candy);
423
+ * ```
424
+ */
425
+ export const effects = {
426
+ /** Celebration: tumbling paper, glints and a pop of light (wins, level-ups). */
427
+ confetti,
428
+ /** Reward glitter: bright beads and glints (pickups, perfect moves). */
429
+ sparkle,
430
+ /** Breaking apart: chunks, crumbs, a glow and dust (bricks, crates, glass). `mesh` shapes the chunks. */
431
+ shatter,
432
+ /** Liquid: droplets and mist (water, juice, paint). */
433
+ splash,
434
+ /** Hot metal: additive streaks and beads (scrapes, strikes, electricity). */
435
+ sparks,
436
+ /** Fiery blast: flash, fireball cooling to smoke, embers and optional debris. */
437
+ explosion,
438
+ /** Soft swelling puffs: dust, sand, sawdust, steam, smoke. */
439
+ dust,
440
+ /** One swelling glow: hits, strikes, muzzle flashes. */
441
+ flash,
442
+ /** The cleared-piece animation: swell, flash white, settle, shrink to nothing. */
443
+ pop,
444
+ /** Default `pop` duration in seconds. */
445
+ POP_TIME,
446
+ /** The same hue made self-lit (brightest channel lifted to `peak`), for glows. */
447
+ hot,
448
+ /** Part way (`t`, 0..1) to white. */
449
+ pale
450
+ };
451
+ //# sourceMappingURL=effects.js.map
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+
3
+ /** A writable quaternion; pass one as `out` to reuse it instead of allocating. */
4
+
5
+ const result = (out, x, y, z, w) => {
6
+ if (!out) return [x, y, z, w];
7
+ out[0] = x;
8
+ out[1] = y;
9
+ out[2] = z;
10
+ out[3] = w;
11
+ return out;
12
+ };
13
+
14
+ /**
15
+ * Quaternion helpers for `rotation` options, keyframes and geometry parts ([x, y, z, w]). Every
16
+ * function takes an optional `out` so per-frame code can reuse one array instead of allocating.
17
+ *
18
+ * ```ts
19
+ * world.set(car, { rotation: quat.y(heading) });
20
+ * const spin = quat.multiply(quat.y(yaw), quat.x(pitch), scratch); // pitch first, then yaw
21
+ * ```
22
+ */
23
+ export const quat = {
24
+ /** No rotation. */
25
+ identity: Object.freeze([0, 0, 0, 1]),
26
+ /** Rotation by `angle` radians around the unit axis (x, y, z). */
27
+ axisAngle(x, y, z, angle, out) {
28
+ const s = Math.sin(angle / 2);
29
+ return result(out, x * s, y * s, z * s, Math.cos(angle / 2));
30
+ },
31
+ /** Rotation around the x axis (pitch). */
32
+ x(angle, out) {
33
+ return result(out, Math.sin(angle / 2), 0, 0, Math.cos(angle / 2));
34
+ },
35
+ /** Rotation around the y axis (yaw, heading). */
36
+ y(angle, out) {
37
+ return result(out, 0, Math.sin(angle / 2), 0, Math.cos(angle / 2));
38
+ },
39
+ /** Rotation around the z axis (roll; spin for 2D games looking down -z). */
40
+ z(angle, out) {
41
+ return result(out, 0, 0, Math.sin(angle / 2), Math.cos(angle / 2));
42
+ },
43
+ /** `a` after `b`: `b` turns first. `out` may be `a` or `b`. */
44
+ multiply(a, b, out) {
45
+ const [ax, ay, az, aw] = a;
46
+ const [bx, by, bz, bw] = b;
47
+ return result(out, aw * bx + ax * bw + ay * bz - az * by, aw * by - ax * bz + ay * bw + az * bx, aw * bz + ax * by - ay * bx + az * bw, aw * bw - ax * bx - ay * by - az * bz);
48
+ },
49
+ /** Turns around x, then y, then z (radians): the same as `multiply(z(z), multiply(y(y), x(x)))`. */
50
+ fromEuler(x, y, z, out) {
51
+ const sx = Math.sin(x / 2);
52
+ const cx = Math.cos(x / 2);
53
+ const sy = Math.sin(y / 2);
54
+ const cy = Math.cos(y / 2);
55
+ const sz = Math.sin(z / 2);
56
+ const cz = Math.cos(z / 2);
57
+ return result(out, sx * cy * cz - cx * sy * sz, cx * sy * cz + sx * cy * sz, cx * cy * sz - sx * sy * cz, cx * cy * cz + sx * sy * sz);
58
+ },
59
+ /** Shortest-path interpolation from `a` (t = 0) to `b` (t = 1). */
60
+ slerp(a, b, t, out) {
61
+ let [bx, by, bz, bw] = b;
62
+ let cos = a[0] * bx + a[1] * by + a[2] * bz + a[3] * bw;
63
+ if (cos < 0) {
64
+ cos = -cos;
65
+ bx = -bx;
66
+ by = -by;
67
+ bz = -bz;
68
+ bw = -bw;
69
+ }
70
+ let k0 = 1 - t;
71
+ let k1 = t;
72
+ if (cos < 0.9995) {
73
+ const angle = Math.acos(cos);
74
+ const sin = Math.sin(angle);
75
+ k0 = Math.sin(k0 * angle) / sin;
76
+ k1 = Math.sin(k1 * angle) / sin;
77
+ }
78
+ const x = k0 * a[0] + k1 * bx;
79
+ const y = k0 * a[1] + k1 * by;
80
+ const z = k0 * a[2] + k1 * bz;
81
+ const w = k0 * a[3] + k1 * bw;
82
+ const length = Math.hypot(x, y, z, w) || 1;
83
+ return result(out, x / length, y / length, z / length, w / length);
84
+ }
85
+ };
86
+ //# sourceMappingURL=quat.js.map