babylon.quarks 0.20.0 → 0.23.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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,111 @@ 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.23.0] — 2026-10-18
8
+
9
+ ### Changed
10
+
11
+ - CPU simulation and batch upload rewritten to work on the `ParticleStore` columns instead of
12
+ walking particle objects. Scalar attributes (`rotation`, `angularVelocity`, `uvTile`, `flip`,
13
+ `startSpeed`) and mesh quaternion rotations now live in store columns; the sprite batch copies
14
+ them as ranges and only visits particle objects for sub-emitted systems. Compiled behavior passes
15
+ (now built for single behaviors too) read and write the columns, interpolate sampled curves and
16
+ gradients inline and take per-particle random samples from a mirrored memory column, so a step
17
+ no longer touches the particle object for the built-in behaviors. Snapshots of size and colour
18
+ for the renderer are only kept when a behavior can change them, and the step's integration,
19
+ newborn fix-up and compaction run in one pass. Trail ribbons transform each recorded sample
20
+ once, upload indices straight to the GPU buffer (no per-frame sub mesh rebuild) and recompute
21
+ the emitter matrix only when its transform changed. `Noise` and `TurbulenceField` evaluate
22
+ constant generators once per frame and update through the columns. Measured on 50k particles:
23
+ billboards 2.1–2.9x faster per frame, trails 1.5x, noise/turbulence 1.2x.
24
+ - Assigning a `Quaternion` to a sprite particle's `rotation` or `angularVelocity` copies it into
25
+ the particle's store row; reading the property back returns a view of that row rather than the
26
+ assigned object. `RandomQuatGenerator` stores its sample as four numbers in the particle's
27
+ memory instead of a `Quaternion`. `TrailParticle.previous` (deprecated) is created on first use.
28
+
29
+ ## [0.22.0] — 2026-10-17
30
+
31
+ ### Added
32
+
33
+ - Mesh particle lighting modes: `ParticleSystem.lighting` (constructor option `lighting`, saved
34
+ as `lighting` on the effect's `QuarksMaterial` and read back by `QuarksLoader`) is `'fixed'`
35
+ (default — exactly the light mesh particles had before), `'unlit'` (the lighting term is
36
+ compiled out with `MESH_UNLIT`: texture × particle colour, for emissive meshes) or `'scene'`
37
+ (the scene's first enabled `DirectionalLight` / `HemisphericLight`, re-read every frame:
38
+ direction, diffuse × intensity, `scene.ambientColor`, plus a hemispheric light's ground colour
39
+ in the ambient; falls back to the fixed light when the scene has neither). Systems with
40
+ different lighting are batched apart. The default is not written to JSON.
41
+ - `BatchedRenderer.setMeshLighting({direction, color, ambient})` (Babylon `Vector3` / `Color3`,
42
+ any subset) sets the `'fixed'` light for every mesh batch of the renderer, including later ones;
43
+ `getMeshLighting()` returns a copy, `defaultMeshLighting()` the built-in values
44
+ (`(0.4, -1, 0.6)`, white, `0.35` grey). Exposed in the editor's Renderer module as "Lighting".
45
+ - Mesh particle rim (Fresnel) term: `ParticleSystem.rim` (constructor option `rim`, saved as
46
+ `rim` on the effect's `QuarksMaterial`) — `{color: [r, g, b], power, strength, mode}` with
47
+ defaults `[1, 1, 1]`, `2`, `1`, `'add'`; any field may be left out. The edge term is
48
+ `pow(1 - |N·V|, power) * strength`; `'add'` adds `color` (glowing edge), `'mix'` blends toward it
49
+ (outline). Compiled in only when set (`MESH_RIM` / `MESH_RIM_MIX`), batched by value, written to
50
+ JSON only when set, and exposed in the editor's Renderer module. `normalizeMeshRim` /
51
+ `meshRimEqual` are exported.
52
+
53
+ ### Changed
54
+
55
+ - **Behaviour change:** quarks.core `WidthOverLength` (Width over Trail) now reads its curve as a
56
+ multiplier on the width each trail sample was recorded with (the particle's `size.x` at that
57
+ moment), the way Unity's Width over Trail works, and gives the head sample the curve's value at
58
+ 0, so a trail no longer flares out behind its head or steps at the tip. A new `absolute` flag
59
+ (`new WidthOverLength(curve, absolute = false)`, JSON field `absolute`) keeps the old reading —
60
+ the curve as the width in world units, the head at the particle's size. `toJSON` always writes
61
+ the flag; JSON without it (everything written by 0.21 and earlier, including the Unity
62
+ exporter's output) loads as `absolute: true`, so authored effects keep their look. Code that
63
+ builds `new WidthOverLength(curve)` gets the new multiplier behaviour: divide an absolute curve
64
+ by the start size, or pass `true`. `TrailParticle` gains `historyBaseSizes` (the unscaled
65
+ recorded widths) and `headWidthScale`.
66
+
67
+ ### Fixed
68
+
69
+ - Burst `cycle` / `interval` are honoured: a burst fires `cycle` waves, `interval` seconds apart,
70
+ each rolling `probability` on its own. Repeats past the system's `duration` are dropped (a
71
+ looping system starts them over every loop), a `cycle` below 1 fires once, and a zero interval
72
+ fires every wave at once. Previously every burst fired a single wave.
73
+ - Emission over distance spreads the particles it owes along the path the emitter travelled
74
+ this step, each at its own metre mark (the spacing carries across steps), instead of spawning
75
+ all of them at the emitter's current position — a fast world-space emitter now leaves a
76
+ continuous trail rather than one clump per frame. Only the position is interpolated (rotation
77
+ and scale are the emitter's current ones) and the particles start at age 0. Local-space
78
+ systems, whose particles move with the emitter, are unchanged.
79
+ - A sub emitter whose target uuid is not in the effect no longer throws on every frame.
80
+ `QuarksLoader` unlinks it (`subParticleSystem = undefined`) with one `console.warn` naming the
81
+ emitter and the uuid — also when the uuid names a node that is not a particle emitter — and
82
+ quarks.core `EmitSubParticleSystem` skips any value that is not a resolved emitter. An
83
+ unresolved uuid string is written back unchanged by `toJSON`.
84
+ - quarks.core `RotationOverLife` turns mesh particles too: a quaternion rotation is turned about
85
+ the particle's local Z axis (the axis a number `startRotation` uses, and what Unity's Rotation
86
+ over Lifetime without separate axes does to meshes), in its own pass and in the fused pass, and
87
+ the step is kept for the renderer's in-between-step interpolation. It used to do nothing on
88
+ meshes, silently. `Rotation3DOverLife` remains the behavior for any other axis.
89
+
90
+ ## [0.21.0] — 2026-10-16
91
+
92
+ ### Added
93
+
94
+ - `QuarksResourceResolver` on `QuarksLoaderOptions` (`resolve` / `fetchJson`) so File pickers,
95
+ CDN layouts and virtual FS backends can resolve relative texture and geometry links without
96
+ calling `resolveExternalGeometries` by hand.
97
+ - `loadFromJSON(json, baseUrl?)` — same pipeline as `load(url)` when the effect document is
98
+ already in memory; `resolveResources` / static `resolveLinkedResources` for prepare-only.
99
+ - `loadAll(urls)` and `loadFromJSONAll(entries)` for battle / level preload: fetch effect docs
100
+ (optional `concurrency`), resolve every linked geometry/image across the pack so shared asset
101
+ urls hit a per-scene fetch cache once, then parse. `continueOnError` and `onProgress` (once per
102
+ settled effect) supported; without `continueOnError` the return type is `TransformNode[]`.
103
+ - `QuarksLoader.joinUrl` for portable baseUrl joining (data/blob/absolute urls left alone).
104
+
105
+ ### Changed
106
+
107
+ - `load(url)` goes through `loadFromJSON` after fetching the effect JSON. Geometry JSON fetches
108
+ are deduped per scene; inlined array fields are copied so cached documents are not aliased
109
+ across effects. Prefer `load` / `loadFromJSON` / `resolveResources` over
110
+ `resolveExternalGeometries` (kept for compatibility).
111
+
7
112
  ## [0.20.0] — 2026-10-16
8
113
 
9
114
  ### Added
package/README.md CHANGED
@@ -170,6 +170,8 @@ import {BatchedRenderer, QuarksLoader, QuarksUtil} from 'babylon.quarks';
170
170
  const batchRenderer = new BatchedRenderer('particles', scene);
171
171
  const loader = new QuarksLoader(scene);
172
172
  const effect = await loader.load('effects/explosion.json');
173
+ // Or preload a battle pack — shared textures/geometries fetch once:
174
+ // const roots = await loader.loadAll(['fx/hit.json', 'fx/explosion.json'], { concurrency: 6 });
173
175
  QuarksUtil.addToBatchRenderer(effect, batchRenderer);
174
176
  QuarksUtil.play(effect);
175
177
  ```