lecodes-sdk 2.4.10 → 2.5.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 (74) hide show
  1. package/dist/global.d.ts +35 -0
  2. package/dist/types/core/env.d.ts +25 -0
  3. package/dist/types/core/particlesConfig.d.ts +196 -0
  4. package/dist/types/g2/Font2D.d.ts +19 -0
  5. package/dist/types/g2/Material2D.d.ts +24 -0
  6. package/dist/types/g2/Node2D.d.ts +6 -5
  7. package/dist/types/g2/Particles2D.d.ts +169 -0
  8. package/dist/types/g2/Path2D.d.ts +95 -0
  9. package/dist/types/g2/Physics2D.d.ts +1 -1
  10. package/dist/types/g2/Scene2D.d.ts +15 -17
  11. package/dist/types/g2/Sprite.d.ts +12 -1
  12. package/dist/types/g2/SpriteSheet.d.ts +4 -1
  13. package/dist/types/g2/Text2D.d.ts +96 -0
  14. package/dist/types/g2/Tilemap.d.ts +8 -0
  15. package/dist/types/g2/defineScene2d.d.ts +69 -11
  16. package/dist/types/gl/Foliage.d.ts +0 -7
  17. package/dist/types/gl/Lightmap.d.ts +101 -2
  18. package/dist/types/gl/Material.d.ts +21 -15
  19. package/dist/types/gl/Model.d.ts +8 -3
  20. package/dist/types/gl/Particles.d.ts +3 -135
  21. package/dist/types/gl/Statics.d.ts +56 -0
  22. package/dist/types/gl/staticsFormat.d.ts +101 -0
  23. package/dist/types/inject.d.ts +11 -3
  24. package/dist/types/runtime/env.d.ts +10 -0
  25. package/dist/types/runtime/envValues.d.ts +8 -0
  26. package/dist/types/scene/defineScene.d.ts +17 -12
  27. package/dist/types/server/env.d.ts +14 -0
  28. package/dist/types/server/inject.d.ts +1 -0
  29. package/dist/types/ui/fonts.d.ts +4 -0
  30. package/dist/types/version.d.ts +1 -1
  31. package/dist/types.json +1 -1
  32. package/package.json +1 -1
  33. package/src/bridges/2d.d.ts +65 -5
  34. package/src/bridges/gl.d.ts +34 -15
  35. package/src/compile/bakeMacro.ts +3 -0
  36. package/src/compile/compileProject.ts +25 -4
  37. package/src/compile/envCompile.ts +74 -0
  38. package/src/compile/fontMacro.ts +11 -6
  39. package/src/compile/index.ts +6 -0
  40. package/src/compile/resourceSlots.ts +1 -0
  41. package/src/compile/serverSplit.ts +47 -4
  42. package/src/core/env.ts +47 -0
  43. package/src/core/particlesConfig.ts +422 -0
  44. package/src/g2/Font2D.ts +87 -0
  45. package/src/g2/Material2D.ts +64 -0
  46. package/src/g2/Node2D.ts +10 -6
  47. package/src/g2/Particles2D.ts +337 -0
  48. package/src/g2/Path2D.ts +215 -0
  49. package/src/g2/Physics2D.ts +1 -1
  50. package/src/g2/Scene2D.ts +16 -22
  51. package/src/g2/Sprite.ts +23 -4
  52. package/src/g2/SpriteSheet.ts +9 -5
  53. package/src/g2/Text2D.ts +178 -0
  54. package/src/g2/Tilemap.ts +10 -0
  55. package/src/g2/defineScene2d.ts +108 -21
  56. package/src/g2/groups2d.ts +2 -2
  57. package/src/gl/Foliage.ts +1 -16
  58. package/src/gl/Lightmap.ts +70 -26
  59. package/src/gl/Material.ts +51 -21
  60. package/src/gl/Model.ts +19 -5
  61. package/src/gl/Particles.ts +22 -361
  62. package/src/gl/Statics.ts +301 -0
  63. package/src/gl/nav/NavMesh.ts +4 -1
  64. package/src/gl/staticsFormat.ts +240 -0
  65. package/src/inject.ts +18 -3
  66. package/src/runtime/env.ts +13 -0
  67. package/src/runtime/envValues.ts +8 -0
  68. package/src/runtime/fetch.ts +18 -0
  69. package/src/scene/defineScene.ts +107 -27
  70. package/src/server/env.ts +25 -0
  71. package/src/server/host.ts +6 -0
  72. package/src/server/inject.ts +2 -1
  73. package/src/ui/fonts.ts +46 -0
  74. package/src/version.ts +1 -1
@@ -1,265 +1,38 @@
1
1
  // GPU particle system, as a Node. Draws with the default point-sprite material (Material.particles)
2
2
  // unless a custom one is passed; properties drive the native emitter.
3
3
  //
4
+ // The config vocabulary — the record tags, the curve()/colorCurve() builders, the emitter option
5
+ // types and the record writers — lives in core/particlesConfig.ts, shared with the 2D node
6
+ // (g2/Particles2D.ts): one simulation (creator-particles), one language. This file holds only what is
7
+ // 3D: the material, mesh mode, baked light (`lit`), the Filament render priority, and `Trail`.
4
8
  // All emitter/curve config crosses the bridge as ONE Float32Array of [tag, payloadLen, ...payload]
5
9
  // records (_creator.setParticleSystemConfig) — the constructor batches every option into a single
6
- // call, live setters send a one-record buffer. The tag values mirror CPART_TAG_* in
7
- // creator-particles/include/creator-particles/creator-particles.h (guarded by tests/gl/particles-tags.test.ts).
8
- //
9
- // Curves over a particle's lifetime are built with curve()/colorCurve() chains — see the builders
10
- // below. A builder's whole state is the flat `_data` array (the exact record payload), so the
11
- // chisel compiler can constant-fold literal chains into the buffer at compile time.
10
+ // call, live setters send a one-record buffer.
12
11
 
13
- import { Color, type ColorInput } from "../core/color"
14
- import { Vec3, cx, cy, cz, type Vec3Like } from "../math/vec"
12
+ import type { Vec3Like } from "../math/vec"
13
+ import { cx, cy, cz } from "../math/vec"
15
14
  import type { Geometry } from "./Geometry"
16
15
  import { Material, _sheetColsRows, type ParticlesMaterialOptions } from "./Material"
17
16
  import { Node } from "./Node"
17
+ import {
18
+ TAG_ACCELERATION, TAG_DRAG, TAG_INHERIT_VELOCITY, TAG_LIFETIME, TAG_LIT, TAG_NOISE, TAG_ORDER,
19
+ TAG_RATE, TAG_RATE_DISTANCE, TAG_RENDER_MODE, TAG_RIBBON_ORIENT, TAG_SEED, TAG_SMOOTH_PATH,
20
+ TAG_SPACE,
21
+ curve, lohi, pushAngularVelocity, pushColor, pushGround, pushMesh, pushParam, pushShape,
22
+ pushVelocity, pushVelocityLife,
23
+ type ParticleColor, type ParticleGround, type ParticleNoise as Noise, type ParticleShape as Shape,
24
+ type ParticleValue, type Range, type VelocityOverLife, type VelocityValue,
25
+ } from "../core/particlesConfig"
26
+
27
+ // What this module exported before the vocabulary moved to core/ — importers keep working.
28
+ export {
29
+ _particleTags, CurveBuilder, ColorCurveBuilder, curve, colorCurve,
30
+ type ParticleValue, type ParticleColor, type VelocityOverLife, type ParticleGround,
31
+ } from "../core/particlesConfig"
18
32
 
19
- type Range<T> = T | { min: T, max: T }
20
-
21
- // --- config record tags (keep in sync with CPART_TAG_* in creator-particles.h) ------------------
22
-
23
- const TAG_SHAPE = 1
24
- const TAG_LIFETIME = 2
25
- const TAG_RATE = 3
26
- const TAG_VELOCITY = 4
27
- const TAG_VELOCITY_RND = 5
28
- const TAG_ACCELERATION = 6
29
- const TAG_DRAG = 7
30
- const TAG_NOISE = 8
31
- const TAG_SEED = 9
32
- const TAG_PARAM_CURVE = 10
33
- const TAG_COLOR_CURVE = 11
34
- const TAG_SPACE = 12
35
- const TAG_INHERIT_VELOCITY = 13
36
- const TAG_RATE_DISTANCE = 14
37
- const TAG_RENDER_MODE = 15
38
- const TAG_MESH_GEOMETRY = 16
39
- const TAG_ANGULAR_VELOCITY = 17
40
- const TAG_GROUND = 18
41
- const TAG_VELOCITY_LIFE = 19
42
- const TAG_ORDER = 20
43
- const TAG_SMOOTH_PATH = 21
44
- const TAG_RIBBON_ORIENT = 22
45
- const TAG_LIT = 23
46
33
  /** `TrailOptions.orient` → the native axis code (0 = the camera-facing default). */
47
34
  const RIBBON_AXIS: Record<"camera" | "x" | "y" | "z", number> = { camera: 0, x: 1, y: 2, z: 3 }
48
35
 
49
- /** @internal — exported for the tag-sync test only. */
50
- export const _particleTags = {
51
- SHAPE: TAG_SHAPE, LIFETIME: TAG_LIFETIME, RATE: TAG_RATE, VELOCITY: TAG_VELOCITY,
52
- VELOCITY_RND: TAG_VELOCITY_RND, ACCELERATION: TAG_ACCELERATION, DRAG: TAG_DRAG,
53
- NOISE: TAG_NOISE, SEED: TAG_SEED, PARAM_CURVE: TAG_PARAM_CURVE, COLOR_CURVE: TAG_COLOR_CURVE,
54
- SPACE: TAG_SPACE, INHERIT_VELOCITY: TAG_INHERIT_VELOCITY, RATE_DISTANCE: TAG_RATE_DISTANCE,
55
- RENDER_MODE: TAG_RENDER_MODE, MESH_GEOMETRY: TAG_MESH_GEOMETRY,
56
- ANGULAR_VELOCITY: TAG_ANGULAR_VELOCITY, GROUND: TAG_GROUND, VELOCITY_LIFE: TAG_VELOCITY_LIFE,
57
- ORDER: TAG_ORDER, SMOOTH_PATH: TAG_SMOOTH_PATH, RIBBON_ORIENT: TAG_RIBBON_ORIENT,
58
- LIT: TAG_LIT,
59
- }
60
-
61
- // --- curve builders -----------------------------------------------------------------------------
62
-
63
- // A value curve reads as a journey over the particle's life:
64
- // curve(0.3).from(0).via(0.15, 1).via(0.6, 1).to(0) // fade in, hold, fade out — or:
65
- // curve(0.3).fade(0.15, 0.4)
66
- // The curve multiplies the base value (or adds to it with mode 'add'); the base and any stop can be
67
- // a { min, max } range, randomized per particle. With no `.from` the curve starts at the identity
68
- // (1 for multiply, 0 for add); with no `.to` it holds its last value to end of life.
69
- //
70
- // chisel constant-folds a literal chain into its `_data` buffer at compile time and validates it
71
- // (bad stop order, >8 stops, unparsable color → a build diagnostic): chisel-core/src/curve.rs mirrors
72
- // these method bodies op-for-op, against a verbatim copy of them in chisel's fixtures/curve-sdk/. Keep
73
- // the two in step — a change here means a change there (chisel's scripts/curve-exact.mjs compares the
74
- // fused payload against the real builder, buffer for buffer).
75
-
76
- const lohi = (v: Range<number>): [number, number] =>
77
- typeof v === "number" ? [ v, v ] : [ v.min, v.max ]
78
-
79
- export class CurveBuilder {
80
- private _kind: 0 | 1
81
- private _lo: number
82
- private _hi: number
83
- private _stops: number[] = [] // flat (t, lo, hi)
84
-
85
- constructor(base: Range<number>, mode: "multiply" | "add") {
86
- this._kind = mode === "add" ? 1 : 0
87
- ;[ this._lo, this._hi ] = lohi(base)
88
- }
89
-
90
- /** Curve value at birth (t = 0). Must come before any other stop. */
91
- from(v: Range<number>): this {
92
- if (this._stops.length > 0) throw new Error("curve: .from() must come first")
93
- return this.via(0, v)
94
- }
95
-
96
- /** Curve value at `t` (0..1 of the particle's life). Stops must be added in ascending t order. */
97
- via(t: number, v: Range<number>): this {
98
- const [ lo, hi ] = lohi(v)
99
- this._stops.push(t, lo, hi)
100
- return this
101
- }
102
-
103
- /** Curve value at death (t = 1). */
104
- to(v: Range<number>): this {
105
- return this.via(1, v)
106
- }
107
-
108
- /** The classic opacity envelope: rise over the first `fadeIn`, fall over the last `fadeOut`. */
109
- fade(fadeIn = 0.15, fadeOut = fadeIn): this {
110
- const up = Math.min(Math.max(fadeIn, 0), 1)
111
- const down = Math.min(Math.max(fadeOut, 0), 1 - up)
112
- if (up > 0) this.via(0, 0).via(up, 1)
113
- else this.via(0, 1)
114
- if (down > 0) {
115
- if (1 - down > up) this.via(1 - down, 1)
116
- this.via(1, 0)
117
- }
118
- return this
119
- }
120
-
121
- /** The PARAM_CURVE record payload (sans slot): [kind, baseLo, baseHi, n, (t, lo, hi)×n]. */
122
- get _data(): Float32Array {
123
- const stops = this._stops
124
- const prepend = stops.length > 0 && stops[0] > 0
125
- const n = stops.length / 3 + (prepend ? 1 : 0)
126
- const out = new Float32Array(4 + n * 3)
127
- out[0] = this._kind
128
- out[1] = this._lo
129
- out[2] = this._hi
130
- out[3] = n
131
- let o = 4
132
- if (prepend) {
133
- const identity = this._kind === 1 ? 0 : 1
134
- out[o + 1] = identity
135
- out[o + 2] = identity
136
- o += 3
137
- }
138
- out.set(stops, o)
139
- return out
140
- }
141
- }
142
-
143
- export class ColorCurveBuilder {
144
- private _lo: [number, number, number, number]
145
- private _hi: [number, number, number, number]
146
- private _stops: number[] = [] // flat (t, lo rgba, hi rgba)
147
-
148
- constructor(base: Range<ColorInput>) {
149
- if (isColorRange(base)) {
150
- this._lo = Color.toRgba01(base.min)
151
- this._hi = Color.toRgba01(base.max)
152
- } else {
153
- this._lo = Color.toRgba01(base)
154
- this._hi = this._lo
155
- }
156
- }
157
-
158
- /** Curve color at birth (t = 0). Must come first. The curve multiplies the base color. */
159
- from(c: Range<ColorInput>): this {
160
- if (this._stops.length > 0) throw new Error("colorCurve: .from() must come first")
161
- return this.via(0, c)
162
- }
163
-
164
- /** Curve color at `t` (0..1 of the particle's life), in ascending t order. */
165
- via(t: number, c: Range<ColorInput>): this {
166
- let lo: number[], hi: number[]
167
- if (isColorRange(c)) {
168
- lo = Color.toRgba01(c.min)
169
- hi = Color.toRgba01(c.max)
170
- } else {
171
- lo = hi = Color.toRgba01(c)
172
- }
173
- this._stops.push(t, ...lo, ...hi)
174
- return this
175
- }
176
-
177
- /** Curve color at death (t = 1). */
178
- to(c: Range<ColorInput>): this {
179
- return this.via(1, c)
180
- }
181
-
182
- /** The COLOR_CURVE record payload: [baseLo rgba, baseHi rgba, n, (t, lo rgba, hi rgba)×n]. */
183
- get _data(): Float32Array {
184
- const stops = this._stops
185
- const prepend = stops.length > 0 && stops[0] > 0
186
- const n = stops.length / 9 + (prepend ? 1 : 0)
187
- const out = new Float32Array(9 + n * 9)
188
- out.set(this._lo, 0)
189
- out.set(this._hi, 4)
190
- out[8] = n
191
- let o = 9
192
- if (prepend) {
193
- for (let i = 1; i < 9; i++) out[o + i] = 1 // identity multiplier: white, t = 0
194
- o += 9
195
- }
196
- out.set(stops, o)
197
- return out
198
- }
199
- }
200
-
201
- /** A value curve over each particle's lifetime. Default mode `multiply` (the curve scales the
202
- * base); `add` offsets it instead. */
203
- export const curve = (base: Range<number> = 1, mode: "multiply" | "add" = "multiply"): CurveBuilder =>
204
- new CurveBuilder(base, mode)
205
-
206
- /** A color curve over each particle's lifetime — always multiplies the base color. */
207
- export const colorCurve = (base: Range<ColorInput> = "#ffffff"): ColorCurveBuilder =>
208
- new ColorCurveBuilder(base)
209
-
210
- // --- option types -------------------------------------------------------------------------------
211
-
212
- export type ParticleValue = Range<number> | CurveBuilder | { _data: Float32Array }
213
- export type ParticleColor = ColorInput | { min: ColorInput, max: ColorInput } | ColorCurveBuilder | { _data: Float32Array }
214
-
215
- type VelocityValue = {
216
- speed?: Range<number>
217
- /** Cone half-angle in radians — jitter the launch direction uniformly within it. */
218
- spread?: number
219
- /** Asymmetric jitter: two angles (u, v — the x/y components) in radians. */
220
- randomizeAngle?: { min: Vec3Like, max: Vec3Like }
221
- } & ({ from: Vec3Like } | { to: Vec3Like } | { dir: Vec3Like } | {})
222
-
223
- /** Where particles are born, in emitter space. Sphere / hemisphere / cone have an axis of +Y (the
224
- * hemisphere is the +Y half, the cone opens along +Y from its base disc at `center`) — aim the
225
- * node with `lookAt(target, 'y')`. `thickness` 0 emits from the surface only, 1 (default) from the
226
- * whole volume. A sphere or cone also sets the LAUNCH DIRECTION (outward / from the cone's apex)
227
- * when `startVelocity` gives a speed but no direction, like Unity's shapes. */
228
- type Shape =
229
- | { type: "point", v: Vec3Like }
230
- | { type: "box", min: Vec3Like, max: Vec3Like }
231
- | { type: "circle", center: Vec3Like, radius: number }
232
- | { type: "sphere", center?: Vec3Like, radius: number, thickness?: number }
233
- | { type: "hemisphere", center?: Vec3Like, radius: number, thickness?: number }
234
- | { type: "cone", center?: Vec3Like, radius: number, /** half-angle, radians */ angle?: number, /** emit this far up the axis too */ length?: number, thickness?: number }
235
- /** Extra velocity over each particle's life — evaluated from the curves every frame and ADDED as a
236
- * displacement (not accumulated like `acceleration`): `radial` pushes outward along the particle's
237
- * birth direction (a burst that decays: `curve(4).to(0)`), `x`/`y`/`z` drift in the simulation
238
- * space (rising smoke: `y: curve(2).from(0).to(1)`). Unity's velocityOverLifetime. */
239
- export type VelocityOverLife = { radial?: ParticleValue, x?: ParticleValue, y?: ParticleValue, z?: ParticleValue }
240
- type Noise = {
241
- strength?: number, frequency?: number, speed?: number,
242
- /** How much of the displacement a particle earns with AGE (default 0 = all of it from birth).
243
- * The field is sampled by position, so at 0 every particle born at the same spot is pushed the
244
- * same way and a plume's root wanders off its emitter by up to `strength` metres; at 1 a particle
245
- * is born exactly where the emitter put it and drifts into the field over its life — what you
246
- * want whenever the source is visible (an exhaust pipe, a contact patch, a muzzle). */
247
- ramp?: number,
248
- }
249
-
250
- /** Ground plane for bouncing particles (all render modes). `height` is in the simulation space:
251
- * world y with `space: 'world'`, emitter-local y otherwise. */
252
- export type ParticleGround = {
253
- /** Plane height (default 0). */
254
- height?: number
255
- /** Contact radius — particles stop `radius` above the plane (a mesh's half-extent; default 0). */
256
- radius?: number
257
- /** Fraction of the vertical speed kept on impact, 0..1 (default 0.3). */
258
- bounce?: number
259
- /** Tangential damping while in contact, per second — like `drag` (default 8). */
260
- friction?: number
261
- }
262
-
263
36
  export type ParticlesOptions = ParticlesMaterialOptions & {
264
37
  /** Draw every particle as this mesh — lit, tumbling 3D debris (shell casings, rubble, leaves,
265
38
  * shrapnel) in one draw call. The system switches to the mesh render mode; the default
@@ -350,118 +123,6 @@ export type ParticlesOptions = ParticlesMaterialOptions & {
350
123
  seed?: number
351
124
  }
352
125
 
353
- // --- record assembly ----------------------------------------------------------------------------
354
-
355
- const isColorRange = (v: unknown): v is { min: ColorInput, max: ColorInput } =>
356
- typeof v === "object" && v !== null && !Array.isArray(v) && "min" in v
357
-
358
- const hasData = (v: unknown): v is { _data: Float32Array } =>
359
- typeof v === "object" && v !== null && "_data" in v
360
-
361
- const pushParam = (out: number[], slot: number, value: ParticleValue): void => {
362
- if (typeof value === "number") {
363
- out.push(TAG_PARAM_CURVE, 5, slot, 0, value, value, 0)
364
- } else if (hasData(value)) {
365
- const d = value._data
366
- out.push(TAG_PARAM_CURVE, d.length + 1, slot)
367
- for (let i = 0; i < d.length; i++) out.push(d[i])
368
- } else {
369
- out.push(TAG_PARAM_CURVE, 5, slot, 0, value.min, value.max, 0)
370
- }
371
- }
372
-
373
- const pushColor = (out: number[], value: ParticleColor): void => {
374
- let d: Float32Array
375
- if (hasData(value)) {
376
- d = value._data
377
- } else if (isColorRange(value)) {
378
- d = new ColorCurveBuilder(value)._data
379
- } else {
380
- d = new ColorCurveBuilder(value as ColorInput)._data
381
- }
382
- out.push(TAG_COLOR_CURVE, d.length)
383
- for (let i = 0; i < d.length; i++) out.push(d[i])
384
- }
385
-
386
- const pushMesh = (out: number[], g: Geometry): void => {
387
- const nv = g.vertices.length / 3
388
- const ni = g.indices.length
389
- out.push(TAG_MESH_GEOMETRY, 2 + nv * 8 + ni, nv, ni)
390
- for (let i = 0; i < nv * 3; i++) out.push(g.vertices[i])
391
- for (let i = 0; i < nv * 3; i++) out.push(g.normals[i])
392
- for (let i = 0; i < nv * 2; i++) out.push(g.uv[i])
393
- for (let i = 0; i < ni; i++) out.push(g.indices[i])
394
- }
395
-
396
- const pushAngularVelocity = (out: number[], v: Vec3Like | { min: Vec3Like, max: Vec3Like }): void => {
397
- const r = v as { min: Vec3Like, max: Vec3Like }
398
- if (typeof r === "object" && r !== null && !Array.isArray(r) && "min" in r && !(v instanceof Float32Array) && !(v instanceof Vec3)) {
399
- out.push(TAG_ANGULAR_VELOCITY, 6, cx(r.min), cy(r.min), cz(r.min), cx(r.max), cy(r.max), cz(r.max))
400
- } else {
401
- const a = v as Vec3Like
402
- out.push(TAG_ANGULAR_VELOCITY, 6, cx(a), cy(a), cz(a), cx(a), cy(a), cz(a))
403
- }
404
- }
405
-
406
- const pushGround = (out: number[], g: ParticleGround | null): void => {
407
- if (g === null) out.push(TAG_GROUND, 5, 0, 0, 0, 0, 0)
408
- else out.push(TAG_GROUND, 5, 1, g.height ?? 0, g.radius ?? 0, g.bounce ?? 0.3, g.friction ?? 8)
409
- }
410
-
411
- const pushShape = (out: number[], shape: Shape): void => {
412
- if (shape.type === "point") out.push(TAG_SHAPE, 4, 0, cx(shape.v), cy(shape.v), cz(shape.v))
413
- else if (shape.type === "box") out.push(TAG_SHAPE, 7, 1, cx(shape.min), cy(shape.min), cz(shape.min), cx(shape.max), cy(shape.max), cz(shape.max))
414
- else if (shape.type === "circle") out.push(TAG_SHAPE, 5, 2, cx(shape.center), cy(shape.center), cz(shape.center), shape.radius)
415
- else {
416
- const c = shape.center ?? [ 0, 0, 0 ]
417
- const thickness = shape.thickness ?? 1
418
- if (shape.type === "cone") out.push(TAG_SHAPE, 8, 5, cx(c), cy(c), cz(c), shape.radius, shape.angle ?? 0, shape.length ?? 0, thickness)
419
- else out.push(TAG_SHAPE, 6, shape.type === "sphere" ? 3 : 4, cx(c), cy(c), cz(c), shape.radius, thickness)
420
- }
421
- }
422
-
423
- const pushVelocityLife = (out: number[], v: VelocityOverLife): void => {
424
- const axes: Array<[number, ParticleValue | undefined]> = [ [ 0, v.radial ], [ 1, v.x ], [ 2, v.y ], [ 3, v.z ] ]
425
- for (const [ axis, value ] of axes) {
426
- if (value === undefined) continue
427
- if (typeof value === "number") out.push(TAG_VELOCITY_LIFE, 5, axis, 0, value, value, 0)
428
- else if (hasData(value)) {
429
- const d = value._data
430
- out.push(TAG_VELOCITY_LIFE, d.length + 1, axis)
431
- for (let i = 0; i < d.length; i++) out.push(d[i])
432
- } else out.push(TAG_VELOCITY_LIFE, 5, axis, 0, value.min, value.max, 0)
433
- }
434
- }
435
-
436
- const pushVelocity = (out: number[], val: Vec3Like | VelocityValue): void => {
437
- if (Array.isArray(val) || val instanceof Float32Array || val instanceof Vec3) {
438
- // a plain vector: launch along it, its length is the speed (native derives it)
439
- out.push(TAG_VELOCITY, 6, 1, cx(val), cy(val), cz(val), 0, 0)
440
- out.push(TAG_VELOCITY_RND, 5, 0, 0, 0, 0, 0)
441
- return
442
- }
443
- const v = val as VelocityValue
444
- let mode = 0
445
- let p: Vec3Like = [ 0, 0, 0 ]
446
- if ("dir" in v) { mode = 1; p = v.dir }
447
- else if ("from" in v) { mode = 2; p = v.from }
448
- else if ("to" in v) { mode = 3; p = v.to }
449
- let lo = 0, hi = 0
450
- if (v.speed !== undefined) {
451
- if (typeof v.speed === "number") lo = hi = v.speed
452
- else { lo = v.speed.min; hi = v.speed.max }
453
- }
454
- out.push(TAG_VELOCITY, 6, mode, cx(p), cy(p), cz(p), lo, hi)
455
- if (v.spread !== undefined) {
456
- out.push(TAG_VELOCITY_RND, 5, 1, -v.spread, -v.spread, v.spread, v.spread)
457
- } else if (v.randomizeAngle) {
458
- const a = v.randomizeAngle
459
- out.push(TAG_VELOCITY_RND, 5, 1, cx(a.min), cy(a.min), cx(a.max), cy(a.max))
460
- } else {
461
- out.push(TAG_VELOCITY_RND, 5, 0, 0, 0, 0, 0)
462
- }
463
- }
464
-
465
126
  // --- the node -----------------------------------------------------------------------------------
466
127
 
467
128
  export class Particles extends Node {