reze-engine 0.63.0 → 0.65.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 (106) hide show
  1. package/dist/engine.d.ts +226 -96
  2. package/dist/engine.d.ts.map +1 -1
  3. package/dist/engine.js +1187 -732
  4. package/dist/graph/compile.d.ts.map +1 -1
  5. package/dist/graph/compile.js +4 -1
  6. package/dist/graph/registry.d.ts +3 -0
  7. package/dist/graph/registry.d.ts.map +1 -1
  8. package/dist/graph/registry.js +133 -0
  9. package/dist/graph/schema.d.ts +12 -0
  10. package/dist/graph/schema.d.ts.map +1 -1
  11. package/dist/graph/slots.d.ts.map +1 -1
  12. package/dist/graph/slots.js +15 -18
  13. package/dist/index.d.ts +9 -1
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +1 -1
  16. package/dist/model.d.ts +10 -1
  17. package/dist/model.d.ts.map +1 -1
  18. package/dist/model.js +15 -1
  19. package/dist/outline-normals.d.ts +12 -0
  20. package/dist/outline-normals.d.ts.map +1 -0
  21. package/dist/outline-normals.js +100 -0
  22. package/dist/pmx-loader.d.ts +3 -0
  23. package/dist/pmx-loader.d.ts.map +1 -1
  24. package/dist/pmx-loader.js +7 -2
  25. package/dist/shaders/lights.d.ts +3 -2
  26. package/dist/shaders/lights.d.ts.map +1 -1
  27. package/dist/shaders/lights.js +16 -3
  28. package/dist/shaders/materials/common.d.ts.map +1 -1
  29. package/dist/shaders/materials/common.js +65 -56
  30. package/dist/shaders/materials/nodes.d.ts +1 -1
  31. package/dist/shaders/materials/nodes.d.ts.map +1 -1
  32. package/dist/shaders/materials/nodes.js +210 -0
  33. package/dist/shaders/passes/bloom.d.ts +4 -3
  34. package/dist/shaders/passes/bloom.d.ts.map +1 -1
  35. package/dist/shaders/passes/bloom.js +58 -87
  36. package/dist/shaders/passes/composite.d.ts.map +1 -1
  37. package/dist/shaders/passes/composite.js +122 -64
  38. package/dist/shaders/passes/cull.d.ts +1 -1
  39. package/dist/shaders/passes/cull.d.ts.map +1 -1
  40. package/dist/shaders/passes/cull.js +7 -3
  41. package/dist/shaders/passes/ground.d.ts.map +1 -1
  42. package/dist/shaders/passes/ground.js +32 -55
  43. package/dist/shaders/passes/mirror.d.ts +18 -12
  44. package/dist/shaders/passes/mirror.d.ts.map +1 -1
  45. package/dist/shaders/passes/mirror.js +59 -13
  46. package/dist/shaders/passes/outline.d.ts.map +1 -1
  47. package/dist/shaders/passes/outline.js +71 -14
  48. package/dist/shaders/passes/particles.d.ts +1 -1
  49. package/dist/shaders/passes/particles.js +1 -1
  50. package/dist/shaders/scene-light-api.d.ts +18 -10
  51. package/dist/shaders/scene-light-api.d.ts.map +1 -1
  52. package/dist/shaders/scene-light-api.js +58 -46
  53. package/dist/shadow-cascades.d.ts +47 -20
  54. package/dist/shadow-cascades.d.ts.map +1 -1
  55. package/dist/shadow-cascades.js +36 -13
  56. package/dist/unity/character.d.ts +59 -0
  57. package/dist/unity/character.d.ts.map +1 -0
  58. package/dist/unity/character.js +120 -0
  59. package/dist/unity/globals.d.ts +93 -0
  60. package/dist/unity/globals.d.ts.map +1 -0
  61. package/dist/unity/globals.js +340 -0
  62. package/dist/unity/host.d.ts +152 -0
  63. package/dist/unity/host.d.ts.map +1 -0
  64. package/dist/unity/host.js +529 -0
  65. package/dist/unity/looks.d.ts +93 -0
  66. package/dist/unity/looks.d.ts.map +1 -0
  67. package/dist/unity/looks.js +312 -0
  68. package/dist/unity/skin.d.ts +9 -0
  69. package/dist/unity/skin.d.ts.map +1 -0
  70. package/dist/unity/skin.js +120 -0
  71. package/dist/unity/stage.d.ts +155 -0
  72. package/dist/unity/stage.d.ts.map +1 -0
  73. package/dist/unity/stage.js +410 -0
  74. package/dist/unity/state.d.ts +22 -0
  75. package/dist/unity/state.d.ts.map +1 -0
  76. package/dist/unity/state.js +170 -0
  77. package/package.json +1 -1
  78. package/src/engine.ts +1535 -964
  79. package/src/graph/compile.ts +3 -1
  80. package/src/graph/registry.ts +142 -0
  81. package/src/graph/schema.ts +9 -0
  82. package/src/graph/slots.ts +15 -18
  83. package/src/index.ts +12 -0
  84. package/src/model.ts +18 -1
  85. package/src/outline-normals.ts +110 -0
  86. package/src/pmx-loader.ts +8 -2
  87. package/src/shaders/lights.ts +16 -3
  88. package/src/shaders/materials/common.ts +65 -57
  89. package/src/shaders/materials/nodes.ts +210 -0
  90. package/src/shaders/passes/bloom.ts +59 -87
  91. package/src/shaders/passes/composite.ts +122 -64
  92. package/src/shaders/passes/cull.ts +7 -3
  93. package/src/shaders/passes/ground.ts +32 -55
  94. package/src/shaders/passes/mirror.ts +60 -13
  95. package/src/shaders/passes/outline.ts +71 -14
  96. package/src/shaders/passes/particles.ts +1 -1
  97. package/src/shaders/scene-light-api.ts +59 -46
  98. package/src/shadow-cascades.ts +61 -32
  99. package/src/unity/character.ts +169 -0
  100. package/src/unity/globals.ts +443 -0
  101. package/src/unity/host.ts +630 -0
  102. package/src/unity/looks.ts +391 -0
  103. package/src/unity/skin.ts +131 -0
  104. package/src/unity/stage.ts +604 -0
  105. package/src/unity/state.ts +172 -0
  106. package/src/shaders/agx-lut.ts +0 -30
package/dist/engine.d.ts CHANGED
@@ -8,6 +8,8 @@ import { type AssetReader } from "./asset-reader";
8
8
  import { type ParamKey } from "./param-track";
9
9
  import { type DissolveCycle, type EffectWindow } from "./effect-schedule";
10
10
  import { type ModelParentKey } from "./parent-keys";
11
+ import { type NativeLook } from "./unity/looks";
12
+ import { type NativeStagePackage, type NativeStageReader } from "./unity/stage";
11
13
  import { type HdrImage } from "./hdr";
12
14
  import { type LyricLine, type LyricRect } from "./shaders/lyrics-api";
13
15
  import { type BoneOverlayOptions, type JointOverlayOptions, type OverlayPrimitive, type RigidbodyOverlayOptions } from "./overlay";
@@ -128,6 +130,9 @@ type ParentTrack = {
128
130
  type SunOptions = {
129
131
  /** Linear color of the sun lamp (Blender: Light > Color). */
130
132
  color?: Vec3;
133
+ /** The rendering layers it keys, as bits; every layer by default. A
134
+ * directional light from setLights takes the layers the sun leaves. */
135
+ layers?: number;
131
136
  /** Lamp power in Blender units (Blender: Light > Strength). */
132
137
  strength?: number;
133
138
  /** Direction sunlight travels (points FROM sun TO scene, Blender: -light.rotation.Z). */
@@ -217,15 +222,21 @@ type CameraOptions = {
217
222
  /** Vertical field of view in radians. */
218
223
  fov?: number;
219
224
  };
220
- /** EEVEE Bloom panel (3D Viewport > Render > Bloom). Fields map 1:1 to Blender's UI. */
225
+ /** Bloom — Aether Gazer's own (shaders/passes/bloom.ts): a soft-knee prefilter,
226
+ * a Gaussian chain down to a few pixels, and a scatter blend back up, added to
227
+ * the scene before the view transform. The defaults ARE the game. */
221
228
  export type BloomOptions = {
222
229
  enabled: boolean;
230
+ /** Brightest-channel level where the glow starts (the game's per-scene
231
+ * threshold). The soft knee is always half of it. */
223
232
  threshold: number;
224
- knee: number;
225
- radius: number;
233
+ /** 0..1: how far each level leans toward the wider one on the way up — low is
234
+ * a tight halo, high a wide haze. The game: 0.77. */
235
+ scatter: number;
236
+ /** Tint on the glow; white is the game. */
226
237
  color: Vec3;
238
+ /** Multiplier on the glow added in the composite; 1 is the game. */
227
239
  intensity: number;
228
- clamp: number;
229
240
  };
230
241
  export declare const DEFAULT_BLOOM_OPTIONS: BloomOptions;
231
242
  /** Camera depth of field — a bokeh gather in the composite pass. Costs nothing
@@ -253,24 +264,27 @@ export type DepthOfFieldOptions = {
253
264
  quality: "performance" | "balanced" | "cinematic";
254
265
  };
255
266
  export declare const DEFAULT_DEPTH_OF_FIELD_OPTIONS: DepthOfFieldOptions;
256
- /** Blender Color Management / View (rendering.txt: Filmic, exposure, gamma). `look` is reserved for future curve tweaks. */
267
+ /** How the scene-linear frame becomes a display image: exposure, then a tone
268
+ * transform, then display gamma. */
257
269
  export type ViewTransformOptions = {
258
- /** Stops applied before Filmic: `linear *= 2^exposure`. */
270
+ /** Stops applied before the transform: `linear *= 2^exposure`. */
259
271
  exposure: number;
260
- /** After Filmic, display gamma (`pow(rgb, 1/gamma)`). */
272
+ /** After the transform, display gamma (`pow(rgb, 1/gamma)`). */
261
273
  gamma: number;
262
274
  /**
263
- * Which display transform the frame is formed with.
275
+ * Which display transform the frame is formed with (composite.ts, viewTransform).
264
276
  *
265
- * "standard" is Blender's Standard: the sRGB encoding and nothing else, which
266
- * is what NPR and anime work uses — the colours the graph computes are the
267
- * colours that land, with no film curve reinterpreting them. Both of the
268
- * reference Wuthering Waves projects render this way.
277
+ * "soft" — Aether Gazer's own final curve, (1 - e^(-2.5x))^1.4. The default.
278
+ * "neutral" — Unity URP's Neutral, the Khronos PBR Neutral operator: colour
279
+ * passes through until the top fifth, which rolls off.
280
+ * "aces" — Unity URP's ACES (RRT + ODT approximation from the Core RP).
281
+ * "none" — the sRGB encoding and nothing else.
269
282
  *
270
- * "filmic" is Blender 3.6's Filmic, Medium High Contrast, baked as a LUT.
283
+ * All four end in the sRGB encoding.
271
284
  */
272
- transform: "agx" | "filmic" | "standard";
285
+ transform: ViewTransformName;
273
286
  };
287
+ export type ViewTransformName = "soft" | "neutral" | "aces" | "none";
274
288
  export declare const DEFAULT_VIEW_TRANSFORM: ViewTransformOptions;
275
289
  /** Color grading applied to the tonemapped scene (ASC CDL — see grade() in
276
290
  * composite.ts). The three tonal controls are expressed as COLORS with
@@ -363,9 +377,9 @@ export type EngineOptions = {
363
377
  /** Canvas background (display-space sRGB 0–1), composited under the scene after
364
378
  * tonemapping. Omit/null = transparent canvas (see setBackgroundColor). */
365
379
  background?: Vec3 | null;
366
- /** Initial EEVEE-style bloom; tune at runtime with `setBloomOptions`. */
380
+ /** Initial bloom; tune at runtime with `setBloomOptions`. */
367
381
  bloom?: Partial<BloomOptions>;
368
- /** View transform (exposure/gamma) applied in composite before/after Filmic. */
382
+ /** View transform (exposure, tone transform, gamma) applied in the composite. */
369
383
  view?: Partial<ViewTransformOptions>;
370
384
  onRaycast?: RaycastCallback;
371
385
  /** See {@link GizmoDragCallback}. */
@@ -537,16 +551,19 @@ interface ModelInstance {
537
551
  indexBuffer: GPUBuffer;
538
552
  jointsBuffer: GPUBuffer;
539
553
  weightsBuffer: GPUBuffer;
554
+ /** The outline hull's own stream — smoothed normal + PMX edge scale per
555
+ * vertex (outline-normals.ts). Made with the first edge-flagged material,
556
+ * so a model with no outline never pays for it. */
557
+ outlineVertexBuffer?: GPUBuffer;
540
558
  skinMatrixBuffer: GPUBuffer;
541
559
  drawCalls: DrawCall[];
542
560
  shadowDrawCalls: DrawCall[];
543
561
  shadowBindGroups: GPUBindGroup[];
544
562
  mainPerInstanceBindGroup: GPUBindGroup;
545
- /** Its own light — fill, sun and options — when setModelFill, setModelSun or
546
- * setModelFlatSky gave it one: a 48-byte ModelLight, and the CPU copy it is
547
- * written from. */
548
- lightBuffer: GPUBuffer | null;
549
- modelLight: Float32Array | null;
563
+ /** Its ObjectLight — rendering layers, its own ambient, its fill — and the CPU copy it
564
+ * is written from. Every model has one: its layers decide its lights. */
565
+ lightBuffer: GPUBuffer;
566
+ objectLight: Float32Array<ArrayBuffer>;
550
567
  pickPerInstanceBindGroup: GPUBindGroup;
551
568
  pickDrawCalls: PickDrawCall[];
552
569
  /** Environment geometry added via addStage — no physics, no IK, and it
@@ -684,7 +701,27 @@ export type SceneLight = {
684
701
  aim?: XYZ;
685
702
  angle?: number;
686
703
  innerAngle?: number;
704
+ /**
705
+ * "directional": light along `aim` from infinitely far, as the sun is —
706
+ * position and radius unused; up to three, beside the sun. Otherwise a spot
707
+ * where an aim is given and a point where none is.
708
+ */
709
+ kind?: "point" | "spot" | "directional";
710
+ /**
711
+ * The rendering layers it reaches, as bits (RENDERING_LAYER_*). Omitted
712
+ * reaches every layer. A stage's daylight on RENDERING_LAYER_DEFAULT and the
713
+ * cast's key on RENDERING_LAYER_CHARACTER is how a game lights the two apart.
714
+ */
715
+ layers?: number;
687
716
  };
717
+ /**
718
+ * Rendering layers, as the game's pipeline (URP's rendering layers) uses them:
719
+ * every drawing carries layer bits and a light reaches it only where its mask
720
+ * shares one. A stage, prop or plane draws on DEFAULT; the cast on DEFAULT and
721
+ * CHARACTER, the bits Aether Gazer's characters carry (0x40000001).
722
+ */
723
+ export declare const RENDERING_LAYER_DEFAULT = 1;
724
+ export declare const RENDERING_LAYER_CHARACTER: number;
688
725
  export declare class Engine {
689
726
  private static instance;
690
727
  static getInstance(): Engine;
@@ -700,6 +737,8 @@ export declare class Engine {
700
737
  private cameraConfig;
701
738
  private lightUniformBuffer;
702
739
  private lightData;
740
+ private lightDataWords;
741
+ private sunLayers;
703
742
  private castShadow;
704
743
  private castShadowTexture;
705
744
  private castShadowView;
@@ -828,7 +867,6 @@ export declare class Engine {
828
867
  private mainPerFrameBindGroupLayout;
829
868
  private mainPerInstanceBindGroupLayout;
830
869
  /** What a model with no fill of its own binds: zero light. */
831
- private noFillBuffer;
832
870
  private mainPerMaterialBindGroupLayout;
833
871
  private outlinePerFrameBindGroupLayout;
834
872
  private outlinePerMaterialBindGroupLayout;
@@ -1191,6 +1229,7 @@ export declare class Engine {
1191
1229
  * premultiplied quantity and a blur has to move them together. */
1192
1230
  private mirrorMaskMipViews;
1193
1231
  private mirrorMaskBlurBindGroups;
1232
+ private mirrorDownsamplePipeline;
1194
1233
  private mirrorMaskDownsamplePipeline;
1195
1234
  /** Two blocks the ground reads its clip from: the camera's is inert, the
1196
1235
  * mirror's carries the live plane. Which one a draw sees is decided by which
@@ -1348,12 +1387,24 @@ export declare class Engine {
1348
1387
  /** Scene seconds, advanced by the frame delta — NOT wall time, so an offline
1349
1388
  * export samples the same path the editor showed. */
1350
1389
  private sceneClock;
1390
+ /** Models dressed in the game's own materials (unity/looks.ts); built on the
1391
+ * first look installed. */
1392
+ private nativeLooks;
1393
+ /** The scene pass's host for the game's shaders, and the shadow atlas's. */
1394
+ private nativeHost;
1395
+ private nativeShadowHost;
1396
+ /** A game stage drawn by its own shaders (unity/stage.ts). */
1397
+ private nativeStage;
1398
+ /** The frame's Unity globals, computed once for every native draw. */
1399
+ private nativeGlobals;
1400
+ private nativeFallback;
1401
+ /** A 1x1 depth map at the far plane: a game shader's shadow lookup into a
1402
+ * map the scene does not have reads lit. */
1403
+ private nativeNoShadowView;
1351
1404
  private trailAccum;
1352
1405
  /** Trail samples owed this frame, computed once so every trail on every
1353
1406
  * character samples in lockstep and their paths stay comparable. */
1354
1407
  private trailDue;
1355
- private agxLutTexture;
1356
- private agxFallbackTexture;
1357
1408
  /** The scene's own grade (setStageGrade): the cube as handed over, kept so a
1358
1409
  * call before init() still lands, and its texture once uploaded. */
1359
1410
  private stageGradeCube;
@@ -1378,29 +1429,44 @@ export declare class Engine {
1378
1429
  private readonly pipelineDescs;
1379
1430
  private readonly singleSided;
1380
1431
  private readonly singleSidedMirror;
1432
+ /** Twins whose async build is in flight, so a draw asks for each once. */
1433
+ private readonly sidedPending;
1434
+ private readonly sidedPendingMirror;
1435
+ private readonly shaderModuleCache;
1436
+ private readonly pipelineCache;
1437
+ private readonly bindGroupLayoutCache;
1438
+ private readonly pipelineLayoutCache;
1439
+ private readonly gpuObjectIds;
1440
+ private gpuObjectNext;
1441
+ /** Init's pipelines, built async and in parallel; init awaits them. Null
1442
+ * outside init, where a pipeline job builds the way it always did. */
1443
+ private initPipelineJobs;
1381
1444
  private readonly steppedHeld;
1382
1445
  private readonly steppedTick;
1383
1446
  private steppedLastClock;
1384
- private bloomBlitUniformBuffer;
1385
- private bloomUpsampleUniformBuffer;
1386
- private readonly bloomBlitUniformData;
1387
- private readonly bloomUpsampleUniformData;
1388
- private bloomBlitPipeline;
1389
- private bloomDownsamplePipeline;
1447
+ private bloomPrefilterBindGroupLayout;
1448
+ private bloomBlurBindGroupLayout;
1449
+ /** Single-attachment pass; colorAttachments[0].view set per bloom step. */
1450
+ private bloomPassDescriptor;
1451
+ private bloomPrefilterPipeline;
1452
+ private bloomBlurHPipeline;
1453
+ private bloomBlurVPipeline;
1390
1454
  private bloomUpsamplePipeline;
1391
- private bloomBlitBindGroupLayout;
1392
- private bloomDownsampleBindGroupLayout;
1393
1455
  private bloomUpsampleBindGroupLayout;
1456
+ private bloomUniformBuffer;
1457
+ private readonly bloomUniformData;
1394
1458
  private bloomDownTexture;
1395
1459
  private bloomUpTexture;
1396
- private bloomMipCount;
1397
- private bloomDownMipViews;
1398
- private bloomUpMipViews;
1399
- private bloomBlitBindGroup;
1400
- private bloomDownsampleBindGroups;
1460
+ private bloomLevels;
1461
+ private bloomDownViews;
1462
+ private bloomUpViews;
1463
+ private bloomPrefilterBindGroup;
1464
+ private bloomBlurHBindGroups;
1465
+ private bloomBlurVBindGroups;
1401
1466
  private bloomUpsampleBindGroups;
1402
- /** Single-attachment pass; colorAttachments[0].view set per bloom step. */
1403
- private bloomPassDescriptor;
1467
+ /** The game's prefilter clamps at 6550.4 — a tenth of the half-float ceiling
1468
+ * (its BloomPass _Params.y of 100 never reaches the shader). */
1469
+ private static readonly BLOOM_CLAMP;
1404
1470
  private static readonly BLOOM_MAX_LEVELS;
1405
1471
  private groundVertexBuffer?;
1406
1472
  private groundIndexBuffer?;
@@ -1408,13 +1474,11 @@ export declare class Engine {
1408
1474
  /** The user's own "no ground" switch — see setGroundVisible. Distinct from
1409
1475
  * hasGround, which records whether a ground was ever built. */
1410
1476
  private groundHidden;
1411
- private shadowMapTextures;
1412
- private shadowMapDepthViews;
1477
+ /** The sun's shadow atlas: every cascade in its own tile (shadow-cascades.ts). */
1478
+ private shadowAtlasTexture;
1479
+ private shadowAtlasView;
1413
1480
  private brdfLutTexture;
1414
1481
  private brdfLutView;
1415
- private filmicLutTexture;
1416
- private filmicLutView;
1417
- private static readonly FILMIC_LUT_WIDTH;
1418
1482
  private shadowDepthPipeline;
1419
1483
  private shadowLightVPBuffer;
1420
1484
  private shadowCascadeVPBuffers;
@@ -1478,10 +1542,10 @@ export declare class Engine {
1478
1542
  private bloomSettings;
1479
1543
  private viewTransform;
1480
1544
  constructor(canvas: HTMLCanvasElement, options?: EngineOptions);
1481
- /** Merge partial bloom with EEVEE defaults (same as constructor). */
1545
+ /** Merge partial bloom with the defaults (same as constructor). */
1482
1546
  static mergeBloomDefaults(partial?: Partial<BloomOptions>): BloomOptions;
1483
1547
  static mergeViewTransformDefaults(partial?: Partial<ViewTransformOptions>): ViewTransformOptions;
1484
- /** Current bloom settings (Blender names; tint is a copied `Vec3`). */
1548
+ /** Current bloom settings (tint is a copied `Vec3`). */
1485
1549
  getBloomOptions(): BloomOptions;
1486
1550
  getViewTransformOptions(): ViewTransformOptions;
1487
1551
  private colorGrading;
@@ -1547,6 +1611,8 @@ export declare class Engine {
1547
1611
  * it was written, expensive where it was reported.
1548
1612
  */
1549
1613
  private bloomContributes;
1614
+ /** viewU[6].y per transform — see viewTransform in composite.ts. */
1615
+ private static readonly VIEW_TRANSFORM_ID;
1550
1616
  private writeCompositeViewUniforms;
1551
1617
  /**
1552
1618
  * Set the canvas background color (display-space sRGB, 0–1 per channel — the
@@ -1724,7 +1790,7 @@ export declare class Engine {
1724
1790
  */
1725
1791
  private renderMirrorPass;
1726
1792
  /**
1727
- * Fill the mirror's mip levels — the bloom pyramid's own 13-tap downsample,
1793
+ * Fill the mirror's mip levels — a 13-tap downsample (MIRROR_DOWNSAMPLE_WGSL),
1728
1794
  * one pass per level. Only when the blur dial is up: at zero the ground
1729
1795
  * samples level 0 exactly and the chain would be work nobody reads.
1730
1796
  */
@@ -1932,7 +1998,13 @@ export declare class Engine {
1932
1998
  * lighting. Cleared, the world's own sky comes back.
1933
1999
  */
1934
2000
  setBackdropEquirect(source: ImageBitmap | HTMLImageElement | HTMLCanvasElement | null): void;
1935
- private makeCompositePipeline;
2001
+ /**
2002
+ * The scene composite's pair (gamma = 1, gamma ≠ 1), async and from the
2003
+ * shader cache. Its source depends only on which field mounts the scene
2004
+ * samples, so there are four at most, and an effect install that keeps the
2005
+ * mounts it had gets the pair already built.
2006
+ */
2007
+ private compositePipelines;
1936
2008
  /**
1937
2009
  * Install the scene's WGSL effect (shadertoy-style), rendered per-pixel in the
1938
2010
  * composite pass. ONE effect per scene, and the code says where it mounts by
@@ -2242,7 +2314,13 @@ export declare class Engine {
2242
2314
  private getModelBodyFocus;
2243
2315
  private writeDepthOfFieldUniforms;
2244
2316
  setBloomOptions(patch: Partial<BloomOptions>): void;
2317
+ private ensureBloomPipelines;
2318
+ /** The game's chain at the current canvas size (AGSimPostFX.Bloom): half
2319
+ * size, then floor(log2(longest side)) - 1 levels, each half the last. */
2320
+ private buildBloomTargets;
2245
2321
  private writeBloomUniforms;
2322
+ /** The game's chain, pass for pass (AGSimPostFX.Bloom). */
2323
+ private renderBloom;
2246
2324
  init(): Promise<void>;
2247
2325
  /** The frost tile the ground samples instead of evaluating fbm per pixel. */
2248
2326
  private groundNoiseTexture;
@@ -2258,17 +2336,8 @@ export declare class Engine {
2258
2336
  */
2259
2337
  private bakeGroundNoise;
2260
2338
  private bakeBrdfLut;
2261
- /**
2262
- * Decompress and upload Blender's AgX cube.
2263
- *
2264
- * Deliberately off the critical path: it is 723 KB once inflated, and a frame
2265
- * rendered before it lands should show the scene under whatever transform is
2266
- * already there rather than wait. Until then binding 10 holds a 1×1×1 stand-in,
2267
- * which is only ever sampled if someone selects AgX in that window.
2268
- */
2269
- private loadAgxLut;
2270
- private bakeFilmicLut;
2271
2339
  private createRenderPipeline;
2340
+ private renderPipelineDesc;
2272
2341
  private createPipelines;
2273
2342
  private setupResize;
2274
2343
  /** When set, render resolution is pinned to this size instead of tracking the
@@ -2810,10 +2879,6 @@ export declare class Engine {
2810
2879
  * back restores the scene the user had rather than an engine default.
2811
2880
  */
2812
2881
  setGroundVisible(on: boolean): void;
2813
- /** Per cascade: does its map currently hold nothing but the cleared far plane?
2814
- * Set by the cascade loop, which skips a cascade that is unwanted and already
2815
- * cleared rather than re-clearing it every frame. */
2816
- private shadowCascadeCleared;
2817
2882
  /**
2818
2883
  * Moves a model to a new key. Nothing about it is rebuilt — same GPU
2819
2884
  * buffers, same style groups, same physics — only which string the rest
@@ -2826,11 +2891,21 @@ export declare class Engine {
2826
2891
  * the name everything else in the app still expects.
2827
2892
  */
2828
2893
  renameModel(oldName: string, newName: string): void;
2894
+ /**
2895
+ * One model's own ambient: the irradiance arriving at it, as the 27 floats of
2896
+ * folded SH setWorldAmbient takes (ibl.ts), in place of the world's. Null
2897
+ * gives it the world's again.
2898
+ *
2899
+ * The game's pipeline lights every renderer by its own probe sample, and a
2900
+ * character by an ambient of its own; a loader that carries those hands them
2901
+ * in here. Linear radiance, strength included.
2902
+ */
2903
+ setModelAmbient(name: string, sh: ArrayLike<number> | null): boolean;
2829
2904
  /**
2830
2905
  * Light one model with more than the world gives it: a FILL, linear RGB times
2831
2906
  * its surface colour, added after its material graph. Null takes it away again.
2832
2907
  *
2833
- * After the graph, not in its ambient: an NPR ramp read an ambient fill as
2908
+ * After the graph, not in its ambient: an NPR ramp reads an ambient fill as
2834
2909
  * light, so sliding it moved her shadows and flipped whole regions across a
2835
2910
  * hard step. Added after, it brightens her evenly and every shadow stays put.
2836
2911
  *
@@ -2838,39 +2913,15 @@ export declare class Engine {
2838
2913
  * lit by their lamps and a near-black ambient, while its characters take a
2839
2914
  * flat base light of their own — so a stage whose World is right for the room
2840
2915
  * leaves a face turned from the lamps in the dark. This is that second light,
2841
- * for the models the host counts as cast.
2842
- */
2843
- setModelFill(name: string, fill: Vec3 | null): boolean;
2844
- /**
2845
- * A model's own sun: the colour and strength the scene's sun has FOR THIS
2846
- * MODEL, in place of the scene's. Null gives it the scene's sun back.
2847
- *
2848
- * The other half of lighting a stage and its cast apart. A game's stage is
2849
- * lit by its own daylight — Aether Gazer's kitchen at twenty times white —
2850
- * while its characters take a key light of their own that the stage never
2851
- * states. So a stage carries the sun it was lit by, and the scene's sun
2852
- * stays the cast's. Direction and shadow are still the scene's: one sun
2853
- * casts, and it casts the same way on both.
2854
- */
2855
- setModelSun(name: string, sun: Vec3 | null): boolean;
2856
- /**
2857
- * Light one model by the sky's AVERAGE rather than its shape: the world's
2858
- * colour and brightness from every direction alike. False gives it the
2859
- * directional sky back.
2860
- *
2861
- * For a cast under an anime look. An HDRI's sky is brighter and warmer one
2862
- * way than another, and taken at each normal it shades a face with soft
2863
- * realistic gradients that no toon ramp drew — PBR on an anime face. Aether
2864
- * Gazer gives its characters one flat base light instead. World strength and
2865
- * colour still reach her; only the shape is gone. A flat World is its own
2866
- * average, so without an HDRI this changes nothing.
2867
- */
2868
- setModelFlatSky(name: string, flat: boolean): boolean;
2869
- /** One part of a model's light, at `at` (0 the fill, 4 the sun, 8 its
2870
- * options) in its ModelLight; w says whether that part is set. All unset
2871
- * releases the buffer and the model takes the shared zero stand-in again. */
2872
- private writeModelLight;
2873
- /** The per-model group: its skinning matrices and its light, or the zero stand-in. */
2916
+ * for the models the host counts as cast. A model drawn by the game's own
2917
+ * shaders (src/unity) lights itself and takes none of it.
2918
+ */
2919
+ setModelFill(name: string, fill: {
2920
+ x: number;
2921
+ y: number;
2922
+ z: number;
2923
+ } | null): boolean;
2924
+ /** The per-model group: its skinning matrices and its ObjectLight. */
2874
2925
  private perInstanceBindGroup;
2875
2926
  removeModel(name: string): void;
2876
2927
  getModelNames(): string[];
@@ -3619,6 +3670,7 @@ export declare class Engine {
3619
3670
  * compiles, so the two are built from one description and cannot drift. */
3620
3671
  private groundShadowPipelineDesc;
3621
3672
  private buildGroundPipeline;
3673
+ private groundPipelineConfig;
3622
3674
  private groundMirrorPipeline;
3623
3675
  private groundMirrorSoftPipeline;
3624
3676
  /** The ground's pipeline for the mirror pass, built on the first frame a
@@ -3794,6 +3846,14 @@ export declare class Engine {
3794
3846
  * compile fails is not installed and its materials stay ungrouped (fallback-on-error).
3795
3847
  */
3796
3848
  applyStyleGroups(modelName: string, groups: StyleGroup[]): Promise<ApplyStyleGroupsResult>;
3849
+ /**
3850
+ * Compile style groups' pipelines before any model needs them — a scene's
3851
+ * groups while its bundle is still downloading. Installs nothing: the
3852
+ * pipelines land in the shader cache, and applyStyleGroups later finds them
3853
+ * there (or still in flight). A group that does not compile is skipped
3854
+ * silently; its real install reports it.
3855
+ */
3856
+ prewarmStyleGroups(groups: readonly StyleGroup[]): Promise<void>;
3797
3857
  /** Add or replace a single style group by id. `opts` may carry a `previewNode` for the
3798
3858
  * editor's node-output preview workflow. */
3799
3859
  upsertStyleGroup(modelName: string, group: StyleGroup, opts?: CompileOptions): Promise<ApplyStyleGroupResult>;
@@ -3894,6 +3954,11 @@ export declare class Engine {
3894
3954
  /** What setModelDissolve last set, or 1 for a model that has never dissolved. */
3895
3955
  getModelDissolve(modelName: string): number;
3896
3956
  private currentClaims;
3957
+ /** A graph's own images (ShaderGraph.images), fetched and decoded once per URL. */
3958
+ private graphImageCache;
3959
+ private graphImage;
3960
+ /** The group with its graph's images, where the group brings none of its own. */
3961
+ private withGraphImages;
3897
3962
  private compileAndInstallGroup;
3898
3963
  private assignDrawCallGroups;
3899
3964
  private writeGroupDefaults;
@@ -3908,6 +3973,39 @@ export declare class Engine {
3908
3973
  /** A pipeline whose descriptor is kept, so a single-sided twin can be built
3909
3974
  * from it on demand (see sidedPipeline). */
3910
3975
  private createModelPipeline;
3976
+ private static readonly SHADER_CACHE_MAX;
3977
+ private static readonly PIPELINE_CACHE_MAX;
3978
+ private static trimCache;
3979
+ /** A small stable id per GPU object, for cache keys. */
3980
+ private gpuObjectId;
3981
+ /** One module per WGSL source. */
3982
+ private cachedShaderModule;
3983
+ /** Drop a source whose module did not validate, so a retry reports afresh. */
3984
+ private forgetShaderModule;
3985
+ /** One bind group layout per entry list. */
3986
+ private cachedBindGroupLayout;
3987
+ /** One pipeline layout per bind group layout list. */
3988
+ private cachedPipelineLayout;
3989
+ private pipelineKey;
3990
+ private cachedPipeline;
3991
+ /** createRenderPipelineAsync, once per module + state. */
3992
+ private cachedRenderPipeline;
3993
+ /** createComputePipelineAsync, once per module + state. */
3994
+ private cachedComputePipeline;
3995
+ /**
3996
+ * A pipeline init builds: async, in parallel with the rest, and in place by
3997
+ * the time init returns (it awaits every job). Outside init — a pass built
3998
+ * on first use — it is the synchronous build it always was.
3999
+ */
4000
+ private initRenderPipeline;
4001
+ /** The compute twin of initRenderPipeline. */
4002
+ private initComputePipeline;
4003
+ /**
4004
+ * Build a model pipeline's single-sided twin off the draw path (see
4005
+ * sidedPipeline). Resolves once it is in place; never rejects — a twin that
4006
+ * fails leaves the draw on its double-sided pipeline, as before it existed.
4007
+ */
4008
+ private buildSidedTwin;
3911
4009
  /**
3912
4010
  * The pipeline a draw should use once its double-sided flag is honoured.
3913
4011
  *
@@ -4097,6 +4195,38 @@ export declare class Engine {
4097
4195
  */
4098
4196
  private clearTrailHistory;
4099
4197
  private writeTrail;
4198
+ /**
4199
+ * Dress a model in the game's own materials — a look exported with ag-rip
4200
+ * (translated shaders, their images, per-material passes and values, and a
4201
+ * character rig) — or take it off with null. The materials it names are
4202
+ * drawn by the game's shaders from then on; the rest keep their graphs, and
4203
+ * every one still casts its shadow through the engine's pass.
4204
+ */
4205
+ setModelNativeLook(name: string, look: NativeLook | null): boolean;
4206
+ /** Resolves once a model's native look can draw: every pass's pipeline is
4207
+ * compiled (async, at setModelNativeLook). Until then its dressed materials
4208
+ * sit out — a host reveals the model after this to avoid that gap. */
4209
+ nativeLookReady(name: string): Promise<void>;
4210
+ /** The hosts for the game's shaders: the scene pass's and the shadow atlas's,
4211
+ * with the stand-ins an empty slot reads. Built on first use. */
4212
+ private ensureNativeHosts;
4213
+ /**
4214
+ * Load a game stage as the game draws it - a package ag-rip's
4215
+ * stage_native.py exported (stage.json and the files beside it, read through
4216
+ * `read` by their paths in it) - or remove the one loaded with null. Its
4217
+ * scene settings (fog, tint, ambient, environment) become the game shaders'
4218
+ * for the whole scene; its lights are the caller's to set, as lights.
4219
+ */
4220
+ setNativeStage(pkg: NativeStagePackage | null, read?: NativeStageReader, onProgress?: (done: number, total: number) => void): Promise<void>;
4221
+ /** What went wrong in the game's shaders, and the names nothing supplied. */
4222
+ nativeReport(): {
4223
+ errors: string[];
4224
+ missing: Record<string, number>;
4225
+ };
4226
+ private nativeFrameTextures;
4227
+ private eyeArray;
4228
+ /** Before the scene pass: the dressed models' skinning and the game's globals. */
4229
+ private prepareNativeLooks;
4100
4230
  private updateSkinMatrices;
4101
4231
  private updateStats;
4102
4232
  }