@chromatic-coherence/generative-engine 1.2.0 → 1.4.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/dist/world.d.ts CHANGED
@@ -91,6 +91,11 @@ export declare class World {
91
91
  private pFaceI;
92
92
  private pDepthI;
93
93
  private instanced;
94
+ /** W9 — the one wind that blows through every swaying instanced batch */
95
+ wind: {
96
+ dir: V3;
97
+ speed: number;
98
+ };
94
99
  private post;
95
100
  private ink;
96
101
  private bg;
@@ -243,7 +248,20 @@ export declare class World {
243
248
  /** W8 — GPU instancing: upload a Mesh ONCE and draw it at every given transform in a
244
249
  * single instanced call (scene + shadow pass alike). A forest is one draw. Instances
245
250
  * ride their group's fade / morph / transform like any other geometry. */
246
- meshInstanced(geo: Mesh, instances: (M4 | TransformSpec)[], o: FaceOpts): void;
251
+ meshInstanced(geo: Mesh, instances: (M4 | TransformSpec)[], o: FaceOpts & {
252
+ /** W9 GPU wind: per-instance sway computed in the vertex stage (shadows included).
253
+ * amp scales with vertex height; freq in rad/s; phases auto-scatter per instance. */
254
+ sway?: {
255
+ amp: number;
256
+ freq?: number;
257
+ };
258
+ /** W10 GPU flight: the batch IS a murmuration — per-bird orbit params generated
259
+ * here, positions evaluated in the vertex stage from time alone. The instance
260
+ * matrices become the shared flock frame (place / scale / steer the whole flock). */
261
+ flight?: boolean | {
262
+ lobes?: number;
263
+ };
264
+ }): void;
247
265
  grow(fn: GrowFn): void;
248
266
  drawLine(a: V3, b: V3, color: string, alpha: number, width?: number): void;
249
267
  drawPath(pts: {
package/dist/world.js CHANGED
@@ -34,6 +34,8 @@ export class World {
34
34
  }
35
35
  constructor(o) {
36
36
  this.instanced = [];
37
+ /** W9 — the one wind that blows through every swaying instanced batch */
38
+ this.wind = { dir: v3(1, 0, 0.35), speed: 1 };
37
39
  this.ink = false;
38
40
  this.bg = [0.024, 0.016, 0.055];
39
41
  this.transparent = false;
@@ -392,15 +394,31 @@ export class World {
392
394
  for (let i = 0; i < P.length; i += 9) {
393
395
  this.pushFace(store, v3(P[i], P[i + 1], P[i + 2]), v3(P[i + 3], P[i + 4], P[i + 5]), v3(P[i + 6], P[i + 7], P[i + 8]), o, v3(N[i], N[i + 1], N[i + 2]), v3(N[i + 3], N[i + 4], N[i + 5]), v3(N[i + 6], N[i + 7], N[i + 8]));
394
396
  }
395
- const mats = new Float32Array(instances.length * 16);
396
- instances.forEach((m, i) => mats.set(m instanceof Float32Array ? m : mCompose(m), i * 16));
397
+ const mats = new Float32Array(instances.length * 20); // mat4 + sway vec4, one stride
398
+ const lobes = typeof o.flight === "object" ? (o.flight.lobes ?? 3) : 3;
399
+ instances.forEach((m, i) => {
400
+ mats.set(m instanceof Float32Array ? m : mCompose(m), i * 20);
401
+ const ph = ((i * 2654435761) % 6283) / 1000; // scattered phase
402
+ if (o.flight) { // aIP = (a0, r0, ph, lobe)
403
+ mats[i * 20 + 16] = ((i * 40503) % 6283) / 1000;
404
+ mats[i * 20 + 17] = 40 + ((i * 9973) % 1000) / 5;
405
+ mats[i * 20 + 18] = ph;
406
+ mats[i * 20 + 19] = i % lobes;
407
+ }
408
+ else {
409
+ mats[i * 20 + 16] = ph;
410
+ mats[i * 20 + 17] = (o.sway?.freq ?? 1.3) * (0.85 + ((i * 97) % 30) / 100);
411
+ mats[i * 20 + 18] = (o.sway?.amp ?? 0) * 0.01;
412
+ mats[i * 20 + 19] = 0;
413
+ }
414
+ });
397
415
  const vbuf = gl.createBuffer();
398
416
  gl.bindBuffer(gl.ARRAY_BUFFER, vbuf);
399
417
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(store), gl.STATIC_DRAW);
400
418
  const ibuf = gl.createBuffer();
401
419
  gl.bindBuffer(gl.ARRAY_BUFFER, ibuf);
402
420
  gl.bufferData(gl.ARRAY_BUFFER, mats, gl.STATIC_DRAW);
403
- this.instanced.push({ vbuf, ibuf, verts: store.length / FACE_STRIDE, count: instances.length });
421
+ this.instanced.push({ vbuf, ibuf, verts: store.length / FACE_STRIDE, count: instances.length, flight: !!o.flight });
404
422
  }
405
423
  grow(fn) { this.hooks.push(fn); }
406
424
  // ── the living verbs (gathered per frame) ──
@@ -602,6 +620,7 @@ export class World {
602
620
  return;
603
621
  const gl = this.gl;
604
622
  for (const rec of this.instanced) {
623
+ gl.uniform1f(p.u("uFlight"), rec.flight ? 1 : 0);
605
624
  gl.bindBuffer(gl.ARRAY_BUFFER, rec.vbuf);
606
625
  this.attrib(p, "aPos", 3, FACE_STRIDE, 0);
607
626
  if (!depthOnly) {
@@ -615,12 +634,12 @@ export class World {
615
634
  this.attrib(p, "aNorm2", 3, FACE_STRIDE, 15);
616
635
  gl.bindBuffer(gl.ARRAY_BUFFER, rec.ibuf);
617
636
  const locs = [];
618
- for (let k = 0; k < 4; k++) {
619
- const loc = gl.getAttribLocation(p.prog, "aI" + k);
637
+ for (let k = 0; k < 5; k++) { // aI0..3 = the matrix, aIP = the sway params
638
+ const loc = gl.getAttribLocation(p.prog, k < 4 ? "aI" + k : "aIP");
620
639
  if (loc < 0)
621
640
  continue;
622
641
  gl.enableVertexAttribArray(loc);
623
- gl.vertexAttribPointer(loc, 4, gl.FLOAT, false, 64, k * 16);
642
+ gl.vertexAttribPointer(loc, 4, gl.FLOAT, false, 80, k * 16);
624
643
  gl.vertexAttribDivisor(loc, 1);
625
644
  locs.push(loc);
626
645
  }
@@ -716,6 +735,8 @@ export class World {
716
735
  if (this.instanced.length) {
717
736
  this.pDepthI.use();
718
737
  gl.uniformMatrix4fv(this.pDepthI.u("uVP"), false, this.svp);
738
+ gl.uniform1f(this.pDepthI.u("uT"), t * this.wind.speed);
739
+ gl.uniform3f(this.pDepthI.u("uWindDir"), this.wind.dir.x, this.wind.dir.y, this.wind.dir.z);
719
740
  this.setGroups(this.pDepthI);
720
741
  this.drawInstancedAll(this.pDepthI, true);
721
742
  }
@@ -747,6 +768,8 @@ export class World {
747
768
  this.pFaceI.use();
748
769
  this.setVP(this.pFaceI);
749
770
  this.setLights(this.pFaceI, fogK);
771
+ gl.uniform1f(this.pFaceI.u("uT"), t * this.wind.speed);
772
+ gl.uniform3f(this.pFaceI.u("uWindDir"), this.wind.dir.x, this.wind.dir.y, this.wind.dir.z);
750
773
  this.drawInstancedAll(this.pFaceI, false);
751
774
  }
752
775
  // the light — additive, depth-TESTED but not written (ink: normal alpha blend)
package/package.json CHANGED
@@ -1,44 +1,44 @@
1
- {
2
- "name": "@chromatic-coherence/generative-engine",
3
- "version": "1.2.0",
4
- "description": "THE THIRD ENGINE — a zero-dependency WebGL2 graphics engine grown from generative-charts-3d: HDR + bloom + SSAO post chain, hardware-PCF shadow maps, a geometry stdlib, ribbon strokes, group transforms and morph targets. The charts API rides on top unchanged.",
5
- "type": "module",
6
- "main": "./dist/index.js",
7
- "module": "./dist/index.js",
8
- "types": "./dist/index.d.ts",
9
- "exports": {
10
- ".": {
11
- "types": "./dist/index.d.ts",
12
- "import": "./dist/index.js"
13
- }
14
- },
15
- "files": [
16
- "dist",
17
- "README.md",
18
- "LICENSE"
19
- ],
20
- "sideEffects": false,
21
- "publishConfig": {
22
- "access": "public"
23
- },
24
- "scripts": {
25
- "build": "tsc -p tsconfig.json",
26
- "test": "node test/run.mjs",
27
- "prepublishOnly": "npm run build"
28
- },
29
- "keywords": [
30
- "3d",
31
- "webgl2",
32
- "engine",
33
- "graphics",
34
- "bloom",
35
- "ssao",
36
- "shadows",
37
- "zero-dependency"
38
- ],
39
- "author": "Chromatic Coherence",
40
- "license": "SEE LICENSE IN LICENSE",
41
- "devDependencies": {
42
- "typescript": "^5"
43
- }
44
- }
1
+ {
2
+ "name": "@chromatic-coherence/generative-engine",
3
+ "version": "1.4.0",
4
+ "description": "THE THIRD ENGINE — a zero-dependency WebGL2 graphics engine grown from generative-charts-3d: HDR + bloom + SSAO post chain, hardware-PCF shadow maps, a geometry stdlib, ribbon strokes, group transforms and morph targets. The charts API rides on top unchanged.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "README.md",
18
+ "LICENSE"
19
+ ],
20
+ "sideEffects": false,
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "scripts": {
25
+ "build": "tsc -p tsconfig.json",
26
+ "test": "node test/run.mjs",
27
+ "prepublishOnly": "npm run build"
28
+ },
29
+ "keywords": [
30
+ "3d",
31
+ "webgl2",
32
+ "engine",
33
+ "graphics",
34
+ "bloom",
35
+ "ssao",
36
+ "shadows",
37
+ "zero-dependency"
38
+ ],
39
+ "author": "Chromatic Coherence",
40
+ "license": "SEE LICENSE IN LICENSE",
41
+ "devDependencies": {
42
+ "typescript": "^5"
43
+ }
44
+ }