babylon.quarks 0.28.0 → 0.29.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 (39) hide show
  1. package/CHANGELOG.md +160 -0
  2. package/dist/babylon.quarks.cjs +1 -1
  3. package/dist/babylon.quarks.cjs.map +1 -1
  4. package/dist/babylon.quarks.esm.js +1 -1
  5. package/dist/babylon.quarks.esm.js.map +1 -1
  6. package/dist/babylon.quarks.umd.min.js +1 -1
  7. package/dist/babylon.quarks.umd.min.js.map +1 -1
  8. package/dist/types/index.d.cts +602 -190
  9. package/dist/types/index.d.ts +602 -190
  10. package/package.json +1 -1
  11. package/src/BatchedRenderer.ts +13 -1
  12. package/src/EffectPool.ts +5 -4
  13. package/src/ParticleEmitter.ts +89 -24
  14. package/src/ParticleSystem.ts +213 -30
  15. package/src/QuarksLoader.ts +9 -0
  16. package/src/QuarksSerializer.ts +1 -1
  17. package/src/QuarksUtil.ts +24 -2
  18. package/src/SpriteBatch.ts +3 -0
  19. package/src/TrailBatch.ts +8 -1
  20. package/src/VFXBatch.ts +112 -0
  21. package/src/batchKey.ts +2 -0
  22. package/src/batchSettings.ts +2 -0
  23. package/src/index.ts +2 -0
  24. package/src/shaderProgram.ts +103 -0
  25. package/src/shaderVariants.ts +102 -5
  26. package/src/shaders/chunks/blend.ts +15 -7
  27. package/src/shaders/chunks/imageProcessing.ts +143 -0
  28. package/src/shaders/particle_frag.glsl.ts +2 -0
  29. package/src/shaders/particle_frag.wgsl.ts +2 -0
  30. package/src/shaders/particle_physics_frag.glsl.ts +2 -0
  31. package/src/shaders/particle_physics_frag.wgsl.ts +2 -0
  32. package/src/shaders/trail_frag.glsl.ts +2 -0
  33. package/src/shaders/trail_frag.wgsl.ts +2 -0
  34. package/src/system/EmissionController.ts +21 -16
  35. package/src/system/ParticleSpawner.ts +96 -19
  36. package/src/system/integrate.ts +61 -4
  37. package/src/system/normalize.ts +28 -1
  38. package/src/system/settingsSchema.ts +25 -7
  39. package/src/system/types.ts +83 -14
package/CHANGELOG.md CHANGED
@@ -4,6 +4,166 @@ All notable changes to the `babylon.quarks` package are documented here.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
5
5
  and the project follows the `quarks.core` 0.x version line.
6
6
 
7
+ ## [0.29.0] — 2026-10-24
8
+
9
+ Phase 7 of the road to 1.0: what still behaves differently from Unity is brought in line before
10
+ the API and the look of effects are frozen. Cones tilt and fill like Unity's and emit from their
11
+ volume, Scaling Mode has Unity's Local, Hierarchy and Shape, curves can be random between two,
12
+ Limit Velocity has Separate Axes, a system has a Stop Action and a Ring Buffer Mode, and the
13
+ particles take the scene's image processing as Babylon's own materials do.
14
+
15
+ ### Upgrading from 0.28
16
+
17
+ Effects in a scene without image processing, at scale 1 and without cones, look as before. Check
18
+ these, in this order:
19
+
20
+ 1. **Scenes with image processing** (tone mapping, exposure, contrast, a vignette or grading, also
21
+ when set up by `createDefaultEnvironment()` or a `DefaultRenderingPipeline`): the particles now
22
+ take it. Re-tune colours that were authored to look right without it, or set
23
+ `applyImageProcessing: false` on a system to keep the old look.
24
+ 2. **Scaled emitters or scaled parents:** the default Scaling Mode is now `'local'`. Set
25
+ `scalingMode: 'hierarchy'` where a parent's scale should reach the effect. Files saved before
26
+ 0.29 read as `'hierarchy'` and keep their look; save them again to write format 2.
27
+ 3. **Cones:** particles between the centre and the rim lean out more (Unity's tilt). Re-tune an
28
+ effect that relied on the narrower middle.
29
+ 4. **`autoDestroy`** still works but is deprecated: use `stopAction: 'destroy'`. Files are
30
+ written with `stopAction`, which a 0.28 runtime does not read.
31
+ 5. **TypeScript:** narrow `LimitSpeedOverLife.speed` before calling `genValue` on it
32
+ (`!(speed instanceof Vector3Function)`); a custom behavior reading `emitter.matrixWorld` gets
33
+ the matrix with the Scaling Mode's scale.
34
+ 6. **Files are format 2.** babylon.quarks 0.28 warns about them and reads their systems with its
35
+ own Scaling Mode. Install `babylon.quarks-editor` 0.29 with `babylon.quarks` 0.29, and export
36
+ from the Unity exporter 0.29 for this runtime.
37
+
38
+ ### Breaking
39
+
40
+ - `autoDestroy` gives way to `stopAction` (`'none'`, `'disable'` or `'destroy'`, Unity's Stop
41
+ Action). Files are written with `stopAction` and no longer with `autoDestroy`; reading
42
+ `autoDestroy: true` from an older file, or passing it to the constructor, still gives
43
+ `'destroy'`, and the `autoDestroy` property and `QuarksUtil.setAutoDestroy` remain as deprecated
44
+ aliases. An older runtime does not read `stopAction`.
45
+ - `LimitSpeedOverLife.speed` is typed `FunctionValueGenerator | ValueGenerator | Vector3Function`
46
+ (it was `FunctionValueGenerator`), for Separate Axes and constant limits. Code that reads it
47
+ with `genValue(memory, t)` narrows it first: `!(speed instanceof Vector3Function)`.
48
+ - **Cone particles between the centre and the rim tilt by `atan(r · tan(angle))`**, as Unity's
49
+ Cone, instead of `angle · r`. Each particle follows the cone's side line through its start
50
+ point, so the cone's far end is a disc of radius `radius + length · tan(angle)` filled as evenly
51
+ as its base. The rim and the centre are unchanged; particles in between lean out more than
52
+ before. Re-tune a cone effect that relied on the old, narrower middle. Cones in three.quarks
53
+ files tilt the new way too, so they lean out further in the middle than in three.quarks.
54
+ - **Scaling Mode works as Unity's, in world and local space, and defaults to `'local'`.** The
55
+ emitter's scale now reaches the shape, the particles' size and their motion in every mode except
56
+ where the mode leaves it out: `'local'` (new, the default) uses only the emitter's own `scaling`
57
+ and leaves its parents' out; `'hierarchy'` uses the whole world scale, as before; `'shape'` now
58
+ scales only the emission shape, leaving the particles' size and speed alone (it used to scale
59
+ their size too). Before, a local-space system took its emitter's whole world scale whatever the
60
+ mode. An effect whose emitter or its parents are scaled looks different unless it was
61
+ `'hierarchy'`: set `scalingMode: 'hierarchy'` to keep a parent's scale on it, or leave it at
62
+ `'local'` to keep the effect its own size under a scaled parent. Effects at scale 1 are
63
+ unchanged.
64
+ - **Files from before this release keep their look:** the format goes to 2, and a system in a
65
+ file of format 1 or without `quarksFormat` (older babylon.quarks, three.quarks, the Unity
66
+ exporter before 0.29) reads as `'hierarchy'`, which gives it the emitter's whole world scale
67
+ as before (except a world-space system's speed, which now scales too). Save it again to keep
68
+ that, or set the mode you want. A 0.28 loader warns about a format 2 file and reads its
69
+ systems as its own default.
70
+ - **`ParticleEmitter.matrixWorld` (`IEmitter.matrixWorld`) is the matrix the system simulates
71
+ and draws in:** the world matrix with each axis's length set by the mode. A custom behavior
72
+ that reads it gets that scale. `ParticleEmitter.shapeScale` is what `'shape'` gives the shape.
73
+ - **Negative scales mirror the start velocity as they mirror the position,** in every mode; a
74
+ world-space `'hierarchy'` system used to mirror the position only.
75
+ - **A sub emission's speed** takes its parent particle's frame, as its size did: it no longer
76
+ scales with the sub emitter's own scale in `'hierarchy'`.
77
+ - **The scene's image processing applies to the particles by default**, as it does to Babylon's
78
+ own `ParticleSystem` and its standard and PBR materials. A scene whose
79
+ `imageProcessingConfiguration` does nothing (Babylon's default) looks the same as before. One
80
+ that tone maps, sets exposure or contrast, grades, vignettes or dithers now does it to the
81
+ particles too, so they sit in the frame like the meshes around them. Under a
82
+ `DefaultRenderingPipeline` with image processing on (`applyByPostProcess`), the particles now
83
+ leave their colour in linear space for the post process, as Babylon's materials do; before they
84
+ were gamma-corrected twice and looked washed out. Set `applyImageProcessing: false` on a system
85
+ to keep the old look. Check effects in scenes set up by any of these, which turn image
86
+ processing on or hand it to a post process without saying so: `scene.createDefaultEnvironment()`
87
+ (tone mapping, exposure and contrast), a `DefaultRenderingPipeline` with
88
+ `imageProcessingEnabled` (its default), a `PrePassRenderer` (SSAO2, SSR, motion blur) and a
89
+ `ReflectionProbe` rendering in linear space.
90
+ Tone mapping clamps HDR particle colours, and a contrast below 1 or colour curves lift black,
91
+ which an additive particle then adds.
92
+
93
+ ### Added
94
+
95
+ - **Scene image processing** (`ParticleSystem.applyImageProcessing`, default true; JSON writes it
96
+ only when false): the scene's `imageProcessingConfiguration` (exposure, contrast, tone mapping,
97
+ vignette, colour curves, colour grading, dithering) is compiled into every render mode, in GLSL
98
+ and WGSL, through Babylon's own includes, bound on every draw, and switched in place, on
99
+ the same material, when the configuration changes what the shader needs. A post process that applies it gets the colour in
100
+ linear space. It runs on the straight colour after fog and before the blend resolve, so alpha
101
+ stays coverage; particles that multiply the frame (`ALPHA_MULTIPLY`) are a factor rather than
102
+ light and are not tone mapped. Systems that differ are batched apart. On WebGPU, a 2D colour
103
+ grading texture works through a WGSL port of Babylon's slice sampler, which Babylon's own WGSL
104
+ include lacks. The Image Processing demo compares a flame with and without it.
105
+
106
+ - **Cone Emit from Volume and Length** (Unity's Cone Volume): `ConeEmitter.emitFrom`
107
+ (`ConeEmitFrom.Base`, the default, or `ConeEmitFrom.Volume`) and `ConeEmitter.length` (5 by
108
+ default, as in Unity). In Volume, particles start anywhere on their side line from the base up
109
+ to `length` along z. The Unity exporter writes Cone Volume with its Length instead of warning,
110
+ and the editor's Shape module and wireframe show both.
111
+ - **Random Between Two Curves** (Unity's MinMaxCurve mode of the same name): `RandomBetweenCurves`
112
+ holds two `PiecewiseBezier` curves and rolls each particle a mix between them, kept for its
113
+ life, so every particle follows its own curve within the band. It goes wherever a curve does
114
+ (start values over the system's cycle, emission rates, every over-lifetime and by-speed
115
+ behavior, Noise) and reads and writes as `{type: 'RandomBetweenCurves', curve1, curve2}`. Where
116
+ a system-level setting takes it (emission over time or distance, a burst's count, a shape's
117
+ speed, Noise's scroll speed) the mix is rolled once per play, as a random range is there, rather
118
+ than at each emission step as in Unity. A bound that is missing or not a curve warns and reads as
119
+ a flat 0 curve. The Unity exporter writes it instead of the upper curve, and the editor offers it
120
+ in its value fields and in every module that edits a curve over life.
121
+ - **Grid sampling** (Niagara's Grid Location by particle index): `GridEmitter.sampling`
122
+ (`GridSampling.Random`, the default, or `GridSampling.Sequential`). Sequential fills the cells in
123
+ turn, row by row from −x, −y, so a burst of `row × column` particles puts one in every cell; a
124
+ restart starts over at the first cell. The editor's Shape module offers it.
125
+ - **Separate Axes for Limit Velocity over Lifetime** (Unity's option of the same name):
126
+ `LimitSpeedOverLife.speed` takes a `Vector3Function`, a limit per axis, and the new
127
+ `LimitSpeedOverLife.space` (`'local'`, the default, or `'world'`) says which axes they are
128
+ measured along. Each component of the velocity is limited on its own and keeps its sign; a world
129
+ limit is scaled by the system's `motionScale` in a world-space system. `space` is written only
130
+ when not `'local'`. One limit for the speed works as before. The editor's Limit Speed, Size over
131
+ Lifetime and Size by Speed modules get a Separate Axes switch, and the new Limit Velocity Axes
132
+ demo compares the two.
133
+ - **Stop Action** (Unity's option of the same name): `ParticleSystem.stopAction` says what a
134
+ finished system does: nothing (`'none'`, the default), disable its emitter node (`'disable'`,
135
+ once per finish), or dispose itself (`'destroy'`). Unity's Callback is the `finished` event,
136
+ which fires whatever the action. `ignoreStopAction`, runtime only, skips it for tools that replay
137
+ an effect; `EffectPool` and the editor set it, so pooled and previewed effects keep their
138
+ authored stop action. `QuarksUtil.setStopAction` sets it on a whole effect. As in Unity, the
139
+ action waits until the systems the system emits into have no particles left, and a sub emitter
140
+ target takes none of its own. `ParticleSystem.isAlive(withSubEmitters = true)` is Unity's
141
+ `IsAlive`. quarks.core's `IParticleSystem` gains `stopAction` (`autoDestroy` is deprecated),
142
+ `ringBufferActive`, and `hasPendingEmission(state?)` for a sub emission's state.
143
+ - **Ring Buffer Mode** (Unity's option of the same name): with `maxParticles`, a full system's
144
+ new particles replace the oldest instead of being dropped. `ringBufferMode: 'pauseUntilReplaced'`
145
+ freezes a particle at the end of its life until then (footprints, decals);
146
+ `'loopUntilReplaced'` replays the part of its life `ringBufferLoopRange` names (0 to 1 by
147
+ default); a range of no length holds the particle at that point. Particles of a ring buffer
148
+ never die by age, so the system keeps them, fires no Death sub emitter for them and never
149
+ finishes. Lowering `maxParticles` drops the oldest over the new limit. Every render mode but
150
+ Trail, whose particles always die. The Ring Buffer demo shows both.
151
+ - `EmitterFrame.fromSimulation`, the inverse of `toSimulation`, for behaviors that measure a
152
+ vector in their own space.
153
+
154
+ ### Fixed
155
+
156
+ - A **Death sub emitter** fired for the particles that died on a non-looping system's last step
157
+ queued its burst and never emitted it: the system counted itself finished first. A system now
158
+ finishes once the emissions its sub emitters run have nothing left to emit, so `finished` fires
159
+ after those bursts.
160
+ - A local-space force, orbit or per-axis speed limit under an emitter scaled to 0 on an axis read
161
+ a NaN rotation from it, and turned the velocity into NaN (forces) or stopped limiting
162
+ (limits). `EmitterFrame` rebuilds the rotation from the axes that remain.
163
+ - **Noise** rolls a random Frequency, Strength, Position or Rotation amount, or Remap (a range or
164
+ two curves) into every particle. Only the first particle got its own value; the others read a
165
+ missing one and their position became NaN.
166
+
7
167
  ## [0.28.0] — 2026-10-23
8
168
 
9
169
  The release after phase 6 of the audit and the 0.28 cleanup: alpha means coverage in every blend