@driftengine/core 4.2.1 → 4.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.
Files changed (215) hide show
  1. package/CHANGELOG.json +272 -0
  2. package/README.md +1 -1
  3. package/dist/cinematic/cameraPath.d.ts +53 -0
  4. package/dist/cinematic/cameraPath.js +118 -0
  5. package/dist/environment/daylight.d.ts +77 -0
  6. package/dist/environment/daylight.js +77 -0
  7. package/dist/geometry/meshConcat.d.ts +9 -0
  8. package/dist/geometry/meshConcat.js +101 -0
  9. package/dist/index.d.ts +12 -2
  10. package/dist/index.js +14 -1
  11. package/dist/render/backend/createRenderer.d.ts +13 -1
  12. package/dist/render/backend/createRenderer.js +6 -5
  13. package/dist/render/backend/webgl2/renderer.d.ts +166 -1
  14. package/dist/render/backend/webgl2/renderer.js +424 -23
  15. package/dist/render/backend/webgpu/buffers.js +46 -8
  16. package/dist/render/backend/webgpu/depthPass.d.ts +81 -3
  17. package/dist/render/backend/webgpu/depthPass.js +75 -14
  18. package/dist/render/backend/webgpu/exposurePass.d.ts +39 -0
  19. package/dist/render/backend/webgpu/exposurePass.js +190 -0
  20. package/dist/render/backend/webgpu/fieldCompose.d.ts +11 -0
  21. package/dist/render/backend/webgpu/fieldCompose.js +13 -0
  22. package/dist/render/backend/webgpu/flatPass.d.ts +3 -1
  23. package/dist/render/backend/webgpu/flatPass.js +12 -5
  24. package/dist/render/backend/webgpu/particlePass.d.ts +8 -0
  25. package/dist/render/backend/webgpu/particlePass.js +1 -0
  26. package/dist/render/backend/webgpu/postPass.d.ts +12 -2
  27. package/dist/render/backend/webgpu/probeBake.d.ts +59 -3
  28. package/dist/render/backend/webgpu/probeBake.js +97 -7
  29. package/dist/render/backend/webgpu/probeTargets.d.ts +65 -0
  30. package/dist/render/backend/webgpu/probeTargets.js +180 -0
  31. package/dist/render/backend/webgpu/renderer.d.ts +176 -11
  32. package/dist/render/backend/webgpu/renderer.js +680 -250
  33. package/dist/render/backend/webgpu/scatterPass.js +7 -7
  34. package/dist/render/backend/webgpu/shaders/clusterBin.wgsl.d.ts +1 -1
  35. package/dist/render/backend/webgpu/skinPaletteRing.d.ts +4 -0
  36. package/dist/render/backend/webgpu/skinPaletteRing.js +9 -0
  37. package/dist/render/backend/webgpu/skyPass.js +5 -1
  38. package/dist/render/backend/webgpu/uniformRing.d.ts +31 -1
  39. package/dist/render/backend/webgpu/uniformRing.js +53 -3
  40. package/dist/render/bloomChain.d.ts +6 -0
  41. package/dist/render/bloomChain.js +8 -0
  42. package/dist/render/clusteredLights.d.ts +19 -11
  43. package/dist/render/clusteredLights.js +96 -45
  44. package/dist/render/cutoutCaster.d.ts +23 -0
  45. package/dist/render/cutoutCaster.js +20 -0
  46. package/dist/render/driftLight/bake.d.ts +34 -0
  47. package/dist/render/driftLight/bake.js +95 -0
  48. package/dist/render/driftLight/falloff.d.ts +16 -0
  49. package/dist/render/driftLight/falloff.js +23 -0
  50. package/dist/render/driftLight/layout.d.ts +59 -0
  51. package/dist/render/driftLight/layout.js +138 -0
  52. package/dist/render/driftLight/lightField.d.ts +108 -0
  53. package/dist/render/driftLight/lightField.js +179 -0
  54. package/dist/render/driftLight/uniforms.d.ts +28 -0
  55. package/dist/render/driftLight/uniforms.js +41 -0
  56. package/dist/render/driftLight/visibility.d.ts +18 -0
  57. package/dist/render/driftLight/visibility.js +47 -0
  58. package/dist/render/emptyTexture.d.ts +6 -0
  59. package/dist/render/emptyTexture.js +19 -0
  60. package/dist/render/exposurePass.d.ts +48 -0
  61. package/dist/render/exposurePass.js +172 -0
  62. package/dist/render/flameLight.d.ts +71 -0
  63. package/dist/render/flameLight.js +63 -0
  64. package/dist/render/gi/bounceLights.d.ts +34 -0
  65. package/dist/render/gi/bounceLights.js +66 -0
  66. package/dist/render/gi/fieldReach.d.ts +12 -0
  67. package/dist/render/gi/fieldReach.js +62 -0
  68. package/dist/render/gi/globalField.d.ts +8 -0
  69. package/dist/render/gi/globalField.js +31 -0
  70. package/dist/render/gi/probeTrace.d.ts +3 -1
  71. package/dist/render/gi/probeTrace.js +3 -1
  72. package/dist/render/gpuCapability.js +19 -4
  73. package/dist/render/lightBudget.d.ts +11 -0
  74. package/dist/render/lightBudget.js +11 -0
  75. package/dist/render/pointLightSelection.d.ts +16 -0
  76. package/dist/render/pointLightSelection.js +178 -83
  77. package/dist/render/probeGrid.d.ts +11 -1
  78. package/dist/render/probeGrid.js +5 -2
  79. package/dist/render/probeSweeps.d.ts +45 -0
  80. package/dist/render/probeSweeps.js +77 -0
  81. package/dist/render/reflectionProbe.d.ts +43 -1
  82. package/dist/render/reflectionProbe.js +17 -3
  83. package/dist/render/renderQuality.d.ts +3 -1
  84. package/dist/render/rendererHarness.d.ts +9 -0
  85. package/dist/render/rendererHarness.js +18 -3
  86. package/dist/render/sceneTarget.d.ts +20 -0
  87. package/dist/render/sceneTarget.js +62 -1
  88. package/dist/render/shaders/agx.d.ts +31 -0
  89. package/dist/render/shaders/agx.js +81 -0
  90. package/dist/render/shaders/ambientOcclusion.d.ts +24 -5
  91. package/dist/render/shaders/ambientOcclusion.js +120 -63
  92. package/dist/render/shaders/cutoutCoverage.d.ts +31 -0
  93. package/dist/render/shaders/cutoutCoverage.js +40 -0
  94. package/dist/render/shaders/depth.d.ts +25 -0
  95. package/dist/render/shaders/depth.js +69 -3
  96. package/dist/render/shaders/exposure.d.ts +52 -0
  97. package/dist/render/shaders/exposure.js +124 -0
  98. package/dist/render/shaders/filmLook.d.ts +47 -0
  99. package/dist/render/shaders/filmLook.js +98 -0
  100. package/dist/render/shaders/flat/directionalShadow.js +35 -4
  101. package/dist/render/shaders/flat/driftLight.d.ts +29 -0
  102. package/dist/render/shaders/flat/driftLight.js +75 -0
  103. package/dist/render/shaders/flat/index.js +5 -0
  104. package/dist/render/shaders/flat/lobes.js +13 -0
  105. package/dist/render/shaders/flat/main.d.ts +1 -1
  106. package/dist/render/shaders/flat/main.js +68 -9
  107. package/dist/render/shaders/flat/preamble.js +23 -5
  108. package/dist/render/shaders/flat/probeGrid.js +46 -3
  109. package/dist/render/shaders/generated/ambientOcclusion.wgsl.d.ts +1 -1
  110. package/dist/render/shaders/generated/ambientOcclusion.wgsl.js +1 -1
  111. package/dist/render/shaders/generated/depth.wgsl.d.ts +100 -0
  112. package/dist/render/shaders/generated/depth.wgsl.js +100 -0
  113. package/dist/render/shaders/generated/exposure.wgsl.d.ts +42 -0
  114. package/dist/render/shaders/generated/exposure.wgsl.js +48 -0
  115. package/dist/render/shaders/generated/flat.wgsl.d.ts +1800 -1344
  116. package/dist/render/shaders/generated/flat.wgsl.js +1816 -1360
  117. package/dist/render/shaders/generated/localExposure.wgsl.d.ts +18 -0
  118. package/dist/render/shaders/generated/localExposure.wgsl.js +24 -0
  119. package/dist/render/shaders/generated/rush.wgsl.d.ts +40 -10
  120. package/dist/render/shaders/generated/rush.wgsl.js +40 -10
  121. package/dist/render/shaders/generated/temporalResolve.wgsl.d.ts +1 -1
  122. package/dist/render/shaders/generated/temporalResolve.wgsl.js +1 -1
  123. package/dist/render/shaders/gi/driftLight.wgsl.d.ts +16 -0
  124. package/dist/render/shaders/gi/driftLight.wgsl.js +49 -0
  125. package/dist/render/shaders/gi/probeBake.wgsl.d.ts +29 -4
  126. package/dist/render/shaders/gi/probeBake.wgsl.js +190 -20
  127. package/dist/render/shaders/globalMedium.js +4 -0
  128. package/dist/render/shaders/localExposure.d.ts +35 -0
  129. package/dist/render/shaders/localExposure.js +138 -0
  130. package/dist/render/shaders/prefilter.d.ts +1 -1
  131. package/dist/render/shaders/prefilter.js +6 -0
  132. package/dist/render/shaders/rush.js +33 -5
  133. package/dist/render/shaders/tangentFrame.d.ts +1 -1
  134. package/dist/render/shaders/tangentFrame.js +15 -3
  135. package/dist/render/shaders/temporalResolve.js +39 -1
  136. package/dist/render/shadowCasters.d.ts +5 -3
  137. package/dist/render/shadowMap.js +13 -0
  138. package/dist/render/surfaceTexture.d.ts +5 -0
  139. package/package.json +6 -6
  140. package/scripts/gpuCompute.mjs +24 -3
  141. package/scripts/png.mjs +23 -12
  142. package/src/cinematic/cameraPath.ts +178 -0
  143. package/src/environment/daylight.ts +152 -0
  144. package/src/geometry/meshConcat.ts +100 -0
  145. package/src/index.ts +32 -0
  146. package/src/render/backend/createRenderer.ts +22 -6
  147. package/src/render/backend/webgl2/renderer.ts +462 -20
  148. package/src/render/backend/webgpu/buffers.ts +51 -8
  149. package/src/render/backend/webgpu/depthPass.ts +78 -10
  150. package/src/render/backend/webgpu/exposurePass.ts +234 -0
  151. package/src/render/backend/webgpu/fieldCompose.ts +15 -0
  152. package/src/render/backend/webgpu/flatPass.ts +10 -2
  153. package/src/render/backend/webgpu/particlePass.ts +9 -0
  154. package/src/render/backend/webgpu/probeBake.ts +143 -9
  155. package/src/render/backend/webgpu/probeTargets.ts +211 -0
  156. package/src/render/backend/webgpu/renderer.ts +807 -271
  157. package/src/render/backend/webgpu/scatterPass.ts +7 -7
  158. package/src/render/backend/webgpu/skinPaletteRing.ts +10 -0
  159. package/src/render/backend/webgpu/skyPass.ts +5 -1
  160. package/src/render/backend/webgpu/uniformRing.ts +49 -3
  161. package/src/render/bloomChain.ts +9 -0
  162. package/src/render/clusteredLights.ts +108 -63
  163. package/src/render/cutoutCaster.ts +44 -0
  164. package/src/render/driftLight/bake.ts +125 -0
  165. package/src/render/driftLight/falloff.ts +26 -0
  166. package/src/render/driftLight/layout.ts +177 -0
  167. package/src/render/driftLight/lightField.ts +227 -0
  168. package/src/render/driftLight/uniforms.ts +61 -0
  169. package/src/render/driftLight/visibility.ts +58 -0
  170. package/src/render/emptyTexture.ts +41 -0
  171. package/src/render/exposurePass.ts +186 -0
  172. package/src/render/flameLight.ts +135 -0
  173. package/src/render/gi/bounceLights.ts +68 -0
  174. package/src/render/gi/fieldReach.ts +74 -0
  175. package/src/render/gi/globalField.ts +39 -0
  176. package/src/render/gi/probeTrace.ts +3 -1
  177. package/src/render/gpuCapability.ts +18 -5
  178. package/src/render/lightBudget.ts +12 -0
  179. package/src/render/pointLightSelection.ts +191 -79
  180. package/src/render/probeGrid.ts +13 -2
  181. package/src/render/probeSweeps.ts +80 -0
  182. package/src/render/reflectionProbe.ts +54 -2
  183. package/src/render/renderQuality.ts +3 -1
  184. package/src/render/rendererHarness.ts +25 -3
  185. package/src/render/sceneTarget.ts +75 -1
  186. package/src/render/shaders/ambientOcclusion.ts +125 -63
  187. package/src/render/shaders/cutoutCoverage.ts +43 -0
  188. package/src/render/shaders/depth.ts +80 -3
  189. package/src/render/shaders/exposure.ts +128 -0
  190. package/src/render/shaders/filmLook.ts +111 -0
  191. package/src/render/shaders/flat/directionalShadow.ts +35 -4
  192. package/src/render/shaders/flat/driftLight.ts +75 -0
  193. package/src/render/shaders/flat/index.ts +5 -0
  194. package/src/render/shaders/flat/lobes.ts +13 -0
  195. package/src/render/shaders/flat/main.ts +68 -9
  196. package/src/render/shaders/flat/preamble.ts +23 -5
  197. package/src/render/shaders/flat/probeGrid.ts +46 -3
  198. package/src/render/shaders/generated/ambientOcclusion.wgsl.ts +1 -1
  199. package/src/render/shaders/generated/depth.wgsl.ts +103 -0
  200. package/src/render/shaders/generated/exposure.wgsl.ts +51 -0
  201. package/src/render/shaders/generated/flat.wgsl.ts +1816 -1360
  202. package/src/render/shaders/generated/localExposure.wgsl.ts +26 -0
  203. package/src/render/shaders/generated/rush.wgsl.ts +40 -10
  204. package/src/render/shaders/generated/temporalResolve.wgsl.ts +1 -1
  205. package/src/render/shaders/gi/driftLight.wgsl.ts +49 -0
  206. package/src/render/shaders/gi/probeBake.wgsl.ts +191 -20
  207. package/src/render/shaders/globalMedium.ts +4 -0
  208. package/src/render/shaders/localExposure.ts +154 -0
  209. package/src/render/shaders/prefilter.ts +6 -0
  210. package/src/render/shaders/rush.ts +33 -5
  211. package/src/render/shaders/tangentFrame.ts +15 -3
  212. package/src/render/shaders/temporalResolve.ts +39 -1
  213. package/src/render/shadowCasters.ts +5 -3
  214. package/src/render/shadowMap.ts +14 -0
  215. package/src/render/surfaceTexture.ts +5 -0
@@ -0,0 +1,77 @@
1
+ /** Sort and check the keys. Throws at construction, so a bad palette never reaches a frame. */
2
+ export function createDaylightPalette(keys) {
3
+ if (keys.length === 0)
4
+ throw new Error('a daylight palette needs at least one key');
5
+ const sorted = [...keys].sort((a, b) => a.at - b.at);
6
+ for (let i = 0; i < sorted.length; i++) {
7
+ const current = sorted[i];
8
+ if (!(current.exposure > 0)) {
9
+ throw new Error(`the key at ${current.at} has exposure ${current.exposure}; it must be > 0`);
10
+ }
11
+ if (i > 0 && sorted[i - 1].at === current.at) {
12
+ throw new Error(`a daylight palette has two keys at ${current.at}`);
13
+ }
14
+ }
15
+ return { keys: sorted };
16
+ }
17
+ export function createDaylightState() {
18
+ return {
19
+ sunColor: [0, 0, 0],
20
+ moonColor: [0, 0, 0],
21
+ skyTop: [0, 0, 0],
22
+ skyHorizon: [0, 0, 0],
23
+ skyDeep: [0, 0, 0],
24
+ ambient: [0, 0, 0],
25
+ ambientGround: [0, 0, 0],
26
+ fogColor: [0, 0, 0],
27
+ fogDensity: 0,
28
+ shadowStrength: 0,
29
+ emissiveGain: 0,
30
+ exposure: 1,
31
+ };
32
+ }
33
+ function blendInto(out, a, b, t) {
34
+ out[0] = a[0] + (b[0] - a[0]) * t;
35
+ out[1] = a[1] + (b[1] - a[1]) * t;
36
+ out[2] = a[2] + (b[2] - a[2]) * t;
37
+ }
38
+ /** The palette at `at`, into `out`. Past either end the nearest key holds. */
39
+ export function resolveDaylight(at, palette, out) {
40
+ const keys = palette.keys;
41
+ let upper = 0;
42
+ while (upper < keys.length && keys[upper].at < at)
43
+ upper++;
44
+ const b = keys[Math.min(upper, keys.length - 1)];
45
+ const a = keys[Math.max(upper - 1, 0)];
46
+ const t = a === b ? 0 : (at - a.at) / (b.at - a.at);
47
+ blendInto(out.sunColor, a.sunColor, b.sunColor, t);
48
+ blendInto(out.moonColor, a.moonColor, b.moonColor, t);
49
+ blendInto(out.skyTop, a.skyTop, b.skyTop, t);
50
+ blendInto(out.skyHorizon, a.skyHorizon, b.skyHorizon, t);
51
+ blendInto(out.skyDeep, a.skyDeep, b.skyDeep, t);
52
+ blendInto(out.ambient, a.ambient, b.ambient, t);
53
+ blendInto(out.ambientGround, a.ambientGround, b.ambientGround, t);
54
+ blendInto(out.fogColor, a.fogColor, b.fogColor, t);
55
+ out.fogDensity = a.fogDensity + (b.fogDensity - a.fogDensity) * t;
56
+ out.shadowStrength = a.shadowStrength + (b.shadowStrength - a.shadowStrength) * t;
57
+ out.emissiveGain = a.emissiveGain + (b.emissiveGain - a.emissiveGain) * t;
58
+ out.exposure = t === 0 ? a.exposure : a.exposure * (b.exposure / a.exposure) ** t;
59
+ return out;
60
+ }
61
+ /**
62
+ * `current` moved toward `target` over `dtSec`, closing half the distance in stops every
63
+ * `halfLifeSec`.
64
+ *
65
+ * **In time, not per frame**, so a 144 Hz display adapts exactly as fast as a 60 Hz one: the
66
+ * remaining distance after any number of steps is `2^(−elapsed / halfLife)` of what it was, however
67
+ * the elapsed time was cut up. A half-life of zero is a cut to the target. Both exposures must be
68
+ * positive, which is what an exposure is.
69
+ */
70
+ export function easeExposure(current, target, dtSec, halfLifeSec) {
71
+ if (halfLifeSec <= 0)
72
+ return target;
73
+ if (dtSec <= 0)
74
+ return current;
75
+ const closed = 1 - 2 ** (-dtSec / halfLifeSec);
76
+ return current * (target / current) ** closed;
77
+ }
@@ -0,0 +1,9 @@
1
+ import type { MeshData } from '../render/mesh.ts';
2
+ /**
3
+ * `mesh` scaled uniformly and then moved by `x, y, z`. The same object when the fit is the
4
+ * identity; otherwise a copy of the positions and every other attribute shared, since a uniform
5
+ * scale turns no normal. Morph deltas are the caller's to scale.
6
+ */
7
+ export declare function placeMesh(mesh: MeshData, x: number, y: number, z: number, scale?: number): MeshData;
8
+ /** `meshes` as one, in order, each member's indices moved past the vertices before it. */
9
+ export declare function concatMeshes(meshes: readonly MeshData[]): MeshData;
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Meshes moved and joined as typed arrays: the loader's fast path, with no builder in between.
3
+ *
4
+ * **`MeshBuilder` is for building geometry, and a loader was using it to copy geometry.** It
5
+ * pushes every vertex one number at a time into growable arrays, and it carries the attributes a
6
+ * procedural mesh has. Streaming a bought courtyard spent seven seconds of its main thread there,
7
+ * copying each part twice, once to upload it and once into its merge group. Worse, the builder has
8
+ * no tangent channel, so every normal-mapped part lost the frame its file carried and the shader
9
+ * fell back to derivatives.
10
+ *
11
+ * So `placeMesh` moves a mesh by a fit, or hands it back untouched when the fit is the identity,
12
+ * and `concatMeshes` joins a group once, into arrays sized in advance. An attribute one member
13
+ * lacks is filled with the value a mesh without it draws with (`ABSENT_ATTRIBUTE`). One no member
14
+ * carries is left out, as absent rather than invented.
15
+ */
16
+ import { ABSENT_ATTRIBUTE } from '../render/vertexDefaults.js';
17
+ /** The optional per-vertex attributes, with how many floats a vertex each carries. */
18
+ const OPTIONAL = [
19
+ ['specular', 1],
20
+ ['tangents', 4],
21
+ ['uvs', 2],
22
+ ['emissiveColor', 3],
23
+ ['roughness', 1],
24
+ ['grain', 1],
25
+ ['relief', 1],
26
+ ['channel', 4],
27
+ ['joints', 4],
28
+ ['weights', 4],
29
+ ];
30
+ /**
31
+ * `mesh` scaled uniformly and then moved by `x, y, z`. The same object when the fit is the
32
+ * identity; otherwise a copy of the positions and every other attribute shared, since a uniform
33
+ * scale turns no normal. Morph deltas are the caller's to scale.
34
+ */
35
+ export function placeMesh(mesh, x, y, z, scale = 1) {
36
+ if (x === 0 && y === 0 && z === 0 && scale === 1)
37
+ return mesh;
38
+ const from = mesh.positions;
39
+ const positions = new Float32Array(from.length);
40
+ for (let i = 0; i + 2 < from.length; i += 3) {
41
+ positions[i] = from[i] * scale + x;
42
+ positions[i + 1] = from[i + 1] * scale + y;
43
+ positions[i + 2] = from[i + 2] * scale + z;
44
+ }
45
+ return { ...mesh, positions };
46
+ }
47
+ /** `meshes` as one, in order, each member's indices moved past the vertices before it. */
48
+ export function concatMeshes(meshes) {
49
+ const only = meshes[0];
50
+ if (meshes.length === 1 && only !== undefined)
51
+ return only;
52
+ let vertices = 0;
53
+ let indexCount = 0;
54
+ for (const mesh of meshes) {
55
+ vertices += mesh.positions.length / 3;
56
+ indexCount += mesh.indices.length;
57
+ }
58
+ const out = {
59
+ positions: new Float32Array(vertices * 3),
60
+ normals: new Float32Array(vertices * 3),
61
+ colors: new Float32Array(vertices * 3),
62
+ emissive: new Float32Array(vertices),
63
+ indices: new Uint32Array(indexCount),
64
+ };
65
+ const optional = out;
66
+ for (const [key, width] of OPTIONAL) {
67
+ if (meshes.some((mesh) => mesh[key] !== undefined)) {
68
+ optional[key] = new Float32Array(vertices * width);
69
+ }
70
+ }
71
+ let vertex = 0;
72
+ let index = 0;
73
+ for (const mesh of meshes) {
74
+ const count = mesh.positions.length / 3;
75
+ out.positions.set(mesh.positions, vertex * 3);
76
+ out.normals.set(mesh.normals, vertex * 3);
77
+ out.colors.set(mesh.colors, vertex * 3);
78
+ out.emissive.set(mesh.emissive, vertex);
79
+ for (const [key, width] of OPTIONAL) {
80
+ const target = optional[key];
81
+ if (target === undefined)
82
+ continue;
83
+ const source = mesh[key];
84
+ if (source !== undefined) {
85
+ target.set(source, vertex * width);
86
+ continue;
87
+ }
88
+ const fill = ABSENT_ATTRIBUTE[key] ?? [];
89
+ for (let v = 0; v < count; v++) {
90
+ for (let c = 0; c < width; c++)
91
+ target[(vertex + v) * width + c] = fill[c] ?? 0;
92
+ }
93
+ }
94
+ const from = mesh.indices;
95
+ for (let i = 0; i < from.length; i++)
96
+ out.indices[index + i] = from[i] + vertex;
97
+ vertex += count;
98
+ index += from.length;
99
+ }
100
+ return out;
101
+ }
package/dist/index.d.ts CHANGED
@@ -28,12 +28,16 @@ export { OnceSet } from './core/onceSet.ts';
28
28
  export { MAX_TIME_CURVE_AMOUNT, curveOffsetSec, curveSpanSec, linearCurve, timeCurve, } from './core/timeCurve.ts';
29
29
  export type { TimeCurve, TimeCurveKind, TimeCurveOptions } from './core/timeCurve.ts';
30
30
  export { CinematicPlayer } from './cinematic/player.ts';
31
+ export { createCameraPath, createCameraPathSample, sampleCameraPath, } from './cinematic/cameraPath.ts';
32
+ export type { CameraPath, CameraPathKey, CameraPathOptions, CameraPathSample, } from './cinematic/cameraPath.ts';
31
33
  export { defineCinematic, validateCinematic } from './cinematic/script.ts';
32
34
  export type { CameraKeyframe, CinematicLine, CinematicScript, CinematicShot, } from './cinematic/script.ts';
33
35
  export { MessageQueue } from './core/messageQueue.ts';
34
36
  export type { MessageQueueOptions, QueuedMessage } from './core/messageQueue.ts';
35
37
  export { celestialStateAt, createCelestialState, moonIllumination, } from './environment/celestialClock.ts';
36
38
  export type { CelestialSite, CelestialState } from './environment/celestialClock.ts';
39
+ export { createDaylightPalette, createDaylightState, easeExposure, resolveDaylight, } from './environment/daylight.ts';
40
+ export type { DaylightKey, DaylightPalette, DaylightState } from './environment/daylight.ts';
37
41
  export { TAU, DEG_TO_RAD, clamp, lerp, smoothstep, damp, dampTracking, angleDelta, dampAngle, wrapAngle, lerpAngle, } from './math/scalar.ts';
38
42
  export { hslToRgb, mixColor, mixColorInto, scaleColor } from './math/color.ts';
39
43
  export type { Vec3 } from './math/color.ts';
@@ -72,7 +76,7 @@ export type { OcclusionOptions } from './render/occlusion.ts';
72
76
  export { OcclusionBuffer } from './render/occlusion.ts';
73
77
  export type { ComputeContext, ComputeDefinition, ComputeDevice, ComputeHandle, } from './render/compute.ts';
74
78
  export { createRenderer } from './render/backend/createRenderer.ts';
75
- export type { CreatedRenderer, CreateRendererOptions, RenderPipeline, } from './render/backend/createRenderer.ts';
79
+ export type { CreatedRenderer, CreateRendererOptions, QualityForBackend, RenderPipeline, } from './render/backend/createRenderer.ts';
76
80
  export { GPU_DRIVEN_LISTS, GpuDrivenPass, MATERIAL_FLOATS, VERTEX_FLOATS, } from './render/backend/webgpu/gpuDrivenPass.ts';
77
81
  export type { GpuDrivenList, GpuDrivenMaterial, GpuDrivenShadowOptions, GpuDrivenView, } from './render/backend/webgpu/gpuDrivenPass.ts';
78
82
  export { atmosphereFog, createFogTarget } from './render/fog.ts';
@@ -113,6 +117,8 @@ export { GI_SOURCE_FIELD, GI_SOURCE_PROBES, GI_SOURCE_SCREEN, newIndirectResult,
113
117
  export type { GiResources, GiSource, IndirectRay, IndirectResult } from './render/gi/chain.ts';
114
118
  export { GLOBAL_FIELD_BLEND, composeGlobalField, createGlobalField, sampleGlobalField, } from './render/gi/globalField.ts';
115
119
  export type { FieldSource, GlobalField, GlobalFieldCascade, GlobalFieldInstance, } from './render/gi/globalField.ts';
120
+ export { FIELD_FADE_SEC, LightField } from './render/driftLight/lightField.ts';
121
+ export type { LightFieldOptions, LightFieldSource } from './render/driftLight/lightField.ts';
116
122
  export { GI_SCREEN_MARCH, SCREEN_TRACE_BIAS_M, screenRayOrigin, traceScreen, } from './render/gi/traceScreen.ts';
117
123
  export { FIELD_MARCH, coneRadiusAt, newFieldHit, traceField } from './render/gi/traceField.ts';
118
124
  export type { FieldHit, FieldMarch } from './render/gi/traceField.ts';
@@ -189,6 +195,7 @@ export type { PrefilterQuality } from './render/prefilterEnvMap.ts';
189
195
  export type { ProbeBakeOptions } from './render/reflectionProbe.ts';
190
196
  export type { DirectionalShadowDepthLayers, OutputTransform, RenderQuality, RenderQualityOptions, ShadowFilterTaps, WaterReflectionFilterTaps, } from './render/renderQuality.ts';
191
197
  export { MAX_POINT_LIGHTS, SURFACE_TEXTURE_UNIT } from './render/lightBudget.ts';
198
+ export { MAX_CLUSTERED_LIGHTS } from './render/clusteredLights.ts';
192
199
  export { SurfaceTexture } from './render/surfaceTexture.ts';
193
200
  export type { SurfaceMaterial, SurfaceTextureOptions } from './render/surfaceTexture.ts';
194
201
  export { DEFAULT_GOVERNOR_LIMITS, ResolutionGovernor } from './render/resolutionGovernor.ts';
@@ -204,6 +211,8 @@ export { describeGpu } from './render/gpuCapability.ts';
204
211
  export type { GpuIdentity, DescribeGpuOptions } from './render/gpuCapability.ts';
205
212
  export { DEFAULT_POINT_LIGHT_VIEW_RANGE, createPointLightBuffer, selectPointLights, } from './render/pointLightSelection.ts';
206
213
  export type { PointLightBuffer, PointLightSource } from './render/pointLightSelection.ts';
214
+ export { createFlame, flameFrequencyHz, updateFlame } from './render/flameLight.ts';
215
+ export type { Flame, FlameOptions } from './render/flameLight.ts';
207
216
  export { computeLightMatrix } from './render/lightMatrix.ts';
208
217
  export { PlumeRenderer } from './render/plumeRenderer.ts';
209
218
  export { createEnvironment } from './render/backend/webgl2/renderer.ts';
@@ -224,6 +233,7 @@ export { SMOKE_FRAG } from './render/shaders/smoke.ts';
224
233
  export { WaterRenderer } from './render/waterRenderer.ts';
225
234
  export type { WaterBody, WaterBounds, WaterSettings } from './render/waterRenderer.ts';
226
235
  export { MeshBuilder } from './geometry/meshBuilder.ts';
236
+ export { concatMeshes, placeMesh } from './geometry/meshConcat.ts';
227
237
  export { generateTangents } from './geometry/tangents.ts';
228
238
  export type { MeshBuildOptions } from './geometry/meshBuilder.ts';
229
239
  export { Spline, createSplineSample } from './geometry/spline.ts';
@@ -331,7 +341,7 @@ export { BoltBatch } from './render/boltBatch.ts';
331
341
  export { createLineSegments, setPolyline } from './render/linePoints.ts';
332
342
  export type { LineSegments } from './render/linePoints.ts';
333
343
  export { FlockRenderer } from './render/flockRenderer.ts';
334
- export { DEFAULT_TEXT_STYLE, deviceSnappedCellSize, textHeightPx, textWidthPx, } from './render/textLayout.ts';
344
+ export { DEFAULT_TEXT_STYLE, deviceSnappedCellSize, MAX_CELLS as MAX_TEXT_CELLS, textHeightPx, textWidthPx, } from './render/textLayout.ts';
335
345
  export type { TextStyle } from './render/textLayout.ts';
336
346
  export { GLYPH_HEIGHT, GLYPH_SPACING, GLYPH_WIDTH, countCells, forEachCell, forEachRun, glyphRows, hasGlyph, measureText, } from './geometry/pixelFont.ts';
337
347
  export { parseSdfFont } from './render/sdfFont.ts';
package/dist/index.js CHANGED
@@ -30,9 +30,11 @@ export { PreferenceStore, loadPreferences, savePreferences } from './core/prefer
30
30
  export { OnceSet } from './core/onceSet.js';
31
31
  export { MAX_TIME_CURVE_AMOUNT, curveOffsetSec, curveSpanSec, linearCurve, timeCurve, } from './core/timeCurve.js';
32
32
  export { CinematicPlayer } from './cinematic/player.js';
33
+ export { createCameraPath, createCameraPathSample, sampleCameraPath, } from './cinematic/cameraPath.js';
33
34
  export { defineCinematic, validateCinematic } from './cinematic/script.js';
34
35
  export { MessageQueue } from './core/messageQueue.js';
35
36
  export { celestialStateAt, createCelestialState, moonIllumination, } from './environment/celestialClock.js';
37
+ export { createDaylightPalette, createDaylightState, easeExposure, resolveDaylight, } from './environment/daylight.js';
36
38
  export { TAU, DEG_TO_RAD, clamp, lerp, smoothstep, damp, dampTracking, angleDelta, dampAngle, wrapAngle, lerpAngle, } from './math/scalar.js';
37
39
  export { hslToRgb, mixColor, mixColorInto, scaleColor } from './math/color.js';
38
40
  export { Camera } from './render/camera.js';
@@ -170,6 +172,7 @@ export { countSplatTiles, fillSplatTiles, splatPixelBox, splatTileGrid, splatTil
170
172
  */
171
173
  export { GI_SOURCE_FIELD, GI_SOURCE_PROBES, GI_SOURCE_SCREEN, newIndirectResult, traceIndirect, } from './render/gi/chain.js';
172
174
  export { GLOBAL_FIELD_BLEND, composeGlobalField, createGlobalField, sampleGlobalField, } from './render/gi/globalField.js';
175
+ export { FIELD_FADE_SEC, LightField } from './render/driftLight/lightField.js';
173
176
  export { GI_SCREEN_MARCH, SCREEN_TRACE_BIAS_M, screenRayOrigin, traceScreen, } from './render/gi/traceScreen.js';
174
177
  export { FIELD_MARCH, coneRadiusAt, newFieldHit, traceField } from './render/gi/traceField.js';
175
178
  export { PROBE_VISIBILITY_SHARPNESS, bakeProbeVisibility, createProbeVisibility, probeUpdateSchedule, probeVisibilityWeight, sampleProbeVolume, visibleProbes, } from './render/gi/probeVolume.js';
@@ -244,6 +247,8 @@ export { MAX_AREA_LIGHTS, createAreaLightBuffer, selectAreaLights } from './rend
244
247
  */
245
248
  export { areaShadowLayerCount, castingRange, firstAreaShadowLayer, } from './render/areaShadowSet.js';
246
249
  export { MAX_POINT_LIGHTS, SURFACE_TEXTURE_UNIT } from './render/lightBudget.js';
250
+ /* The width a light buffer can usefully be with `clusteredLights` on; `createPointLightBuffer`. */
251
+ export { MAX_CLUSTERED_LIGHTS } from './render/clusteredLights.js';
247
252
  export { SurfaceTexture } from './render/surfaceTexture.js';
248
253
  export { DEFAULT_GOVERNOR_LIMITS, ResolutionGovernor } from './render/resolutionGovernor.js';
249
254
  export { isWeakGpuFamily } from './render/gpuCapability.js';
@@ -255,6 +260,7 @@ export { isWeakGpuFamily } from './render/gpuCapability.js';
255
260
  */
256
261
  export { describeGpu } from './render/gpuCapability.js';
257
262
  export { DEFAULT_POINT_LIGHT_VIEW_RANGE, createPointLightBuffer, selectPointLights, } from './render/pointLightSelection.js';
263
+ export { createFlame, flameFrequencyHz, updateFlame } from './render/flameLight.js';
258
264
  export { computeLightMatrix } from './render/lightMatrix.js';
259
265
  export { PlumeRenderer } from './render/plumeRenderer.js';
260
266
  export { createEnvironment } from './render/backend/webgl2/renderer.js';
@@ -292,6 +298,7 @@ export { ARCANE_FRAG } from './render/shaders/arcane.js';
292
298
  export { SMOKE_FRAG } from './render/shaders/smoke.js';
293
299
  export { WaterRenderer } from './render/waterRenderer.js';
294
300
  export { MeshBuilder } from './geometry/meshBuilder.js';
301
+ export { concatMeshes, placeMesh } from './geometry/meshConcat.js';
295
302
  /* A tangent frame, which every map in the material track reads. */
296
303
  export { generateTangents } from './geometry/tangents.js';
297
304
  export { Spline, createSplineSample } from './geometry/spline.js';
@@ -439,7 +446,13 @@ export { DEFAULT_TEXT_STYLE,
439
446
  * the note at the cell upload in `render/textRenderer.ts`: snap once, then measure, lay out
440
447
  * and draw with that one number.
441
448
  */
442
- deviceSnappedCellSize, textHeightPx, textWidthPx, } from './render/textLayout.js';
449
+ deviceSnappedCellSize,
450
+ /*
451
+ * How many lit cells one text object draws before the rest of its string is cut. Exported so a
452
+ * caller laying out a runtime string, a readout that grows, can break it before the engine does:
453
+ * the cut is silent by design, since a clipped message beats a frame that does not render.
454
+ */
455
+ MAX_CELLS as MAX_TEXT_CELLS, textHeightPx, textWidthPx, } from './render/textLayout.js';
443
456
  export { GLYPH_HEIGHT, GLYPH_SPACING, GLYPH_WIDTH, countCells, forEachCell, forEachRun, glyphRows, hasGlyph, measureText, } from './geometry/pixelFont.js';
444
457
  /*
445
458
  * SDF text, reached the same way pixel text is: the verbs are on the renderer and the
@@ -34,6 +34,18 @@ export declare const DEFAULT_PIPELINE: RenderPipeline;
34
34
  */
35
35
  export declare function pipelineRefusal(pipeline: RenderPipeline, backend: RenderBackend, reason: string): string | null;
36
36
  /** Everything about selection a caller may want to decide instead of inherit. */
37
+ /**
38
+ * The quality to build with, or a function of the backend `createRenderer` chose.
39
+ *
40
+ * **A function is how an option only one backend has is asked of that backend alone.** Traced
41
+ * indirect light and reconstruction are WebGPU's, and WebGL2 refuses either in words when handed
42
+ * one: right for a consumer who asked for it there, and noise for one who wanted it wherever it
43
+ * runs, since every device that fell back printed a refusal. Called once for the backend that
44
+ * draws, and once more for WebGPU's timing request where WebGPU is tried. What would make it wrong
45
+ * is a consumer needing to know *why* the backend fell back before choosing, which `reason` on the
46
+ * result says after the fact and nothing says before.
47
+ */
48
+ export type QualityForBackend = RenderQualityOptions | ((backend: RenderBackend) => RenderQualityOptions);
37
49
  export interface CreateRendererOptions {
38
50
  /**
39
51
  * Whether to try WebGPU at all. **Defaults to true**: WebGPU is the backend this engine is
@@ -189,4 +201,4 @@ export interface CreatedRenderer {
189
201
  * returned and ignored by every caller for long enough that a silent fallback could be
190
202
  * mistaken for a comparison.
191
203
  */
192
- export declare function createRenderer(canvas: HTMLCanvasElement, quality?: RenderQualityOptions, options?: CreateRendererOptions): Promise<CreatedRenderer>;
204
+ export declare function createRenderer(canvas: HTMLCanvasElement, quality?: QualityForBackend, options?: CreateRendererOptions): Promise<CreatedRenderer>;
@@ -72,6 +72,7 @@ function presentOnFirstFrame(renderer, splash) {
72
72
  * mistaken for a comparison.
73
73
  */
74
74
  export async function createRenderer(canvas, quality = {}, options = {}) {
75
+ const qualityFor = (backend) => typeof quality === 'function' ? quality(backend) : quality;
75
76
  const search = options.search ?? globalThis.location?.search ?? '';
76
77
  /*
77
78
  * **Mounted before the probe, because the probe is part of the wait.** `selectBackend` asks for
@@ -143,7 +144,7 @@ export async function createRenderer(canvas, quality = {}, options = {}) {
143
144
  forward step makes `spent` exceed the budget, so the engine falls back to WebGL2 reporting
144
145
  "WebGPU stalled" about a device that was fine. */
145
146
  const startedAt = performance.now();
146
- const choice = await selectBackend(search, options.preferWebGpu ?? true, quality.gpuTiming ?? false, options.probeShaders ?? [], budgetMs);
147
+ const choice = await selectBackend(search, options.preferWebGpu ?? true, (options.preferWebGpu ?? true) ? (qualityFor('webgpu').gpuTiming ?? false) : false, options.probeShaders ?? [], budgetMs);
147
148
  if (choice.backend === 'webgpu' && choice.device !== null) {
148
149
  /*
149
150
  * **A failure here falls back rather than propagating.** Everything up to this point
@@ -185,7 +186,7 @@ export async function createRenderer(canvas, quality = {}, options = {}) {
185
186
  if (settled === TIMED_OUT) {
186
187
  device.destroy();
187
188
  return built({
188
- renderer: new Renderer(canvas, quality),
189
+ renderer: new Renderer(canvas, qualityFor('webgl2')),
189
190
  backend: 'webgl2',
190
191
  reason: `WebGPU stalled while ${stage}, fell back after ${budgetMs} ms`,
191
192
  });
@@ -204,7 +205,7 @@ export async function createRenderer(canvas, quality = {}, options = {}) {
204
205
  * resolves internally, so the two backends get the same numbers by construction rather
205
206
  * than from a copied set of defaults somebody has to keep in step.
206
207
  */
207
- renderer: new WebGPURenderer(surface, resolveRenderQuality(quality),
208
+ renderer: new WebGPURenderer(surface, resolveRenderQuality(qualityFor('webgpu')),
208
209
  /* The adapter's own words, so the capability clamp has a part number to
209
210
  recognise rather than the literal string `WebGPU`. */
210
211
  choice.rendererName ?? undefined),
@@ -216,7 +217,7 @@ export async function createRenderer(canvas, quality = {}, options = {}) {
216
217
  choice.device.destroy();
217
218
  const detail = error instanceof Error ? error.message : String(error);
218
219
  return built({
219
- renderer: new Renderer(canvas, quality),
220
+ renderer: new Renderer(canvas, qualityFor('webgl2')),
220
221
  backend: 'webgl2',
221
222
  reason: `WebGPU surface failed, fell back: ${detail}`,
222
223
  });
@@ -243,7 +244,7 @@ export async function createRenderer(canvas, quality = {}, options = {}) {
243
244
  console.warn(`[driftengine] WebGPU was asked for and is not being used: ${choice.reason}`);
244
245
  }
245
246
  return built({
246
- renderer: new Renderer(canvas, quality),
247
+ renderer: new Renderer(canvas, qualityFor('webgl2')),
247
248
  backend: 'webgl2',
248
249
  reason: choice.reason,
249
250
  });