@call-me-sensei/toonlab 0.2.0 → 0.3.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/AGENTS.md +127 -4
- package/ATTRIBUTION.md +41 -3
- package/README.md +234 -34
- package/docs/characters.md +144 -0
- package/docs/debug-panel.md +126 -0
- package/docs/docs.css +589 -0
- package/docs/environment.md +186 -0
- package/docs/getting-started.md +180 -0
- package/docs/index.html +14 -0
- package/docs/lab-architecture.md +100 -0
- package/docs/lighting.md +825 -0
- package/docs/main.jsx +739 -0
- package/docs/mcp.md +97 -0
- package/docs/post-processing.md +98 -0
- package/docs/settings-reference.md +1878 -0
- package/docs/shader-constants.md +77 -0
- package/docs/sky.md +182 -0
- package/docs/style-labs.md +309 -0
- package/docs/texture-lab.md +135 -0
- package/docs/toon-shading.md +183 -0
- package/docs/tsl-conventions.md +167 -0
- package/docs/vegetation-sky.md +275 -0
- package/docs/water.md +430 -0
- package/docs/weather.md +200 -0
- package/docs/world-scale.md +111 -0
- package/mcp/server.mjs +610 -0
- package/mcp/style-lab-tools.mjs +371 -0
- package/mcp/vite-plugin.mjs +174 -0
- package/mcp/workspace.mjs +397 -0
- package/package.json +64 -5
- package/src/ambientfx/INTEGRATION.md +164 -0
- package/src/ambientfx/ambientFxPresets.js +83 -0
- package/src/ambientfx/ambientFxSettings.js +368 -0
- package/src/ambientfx/emitters.js +169 -0
- package/src/ambientfx/index.js +5 -0
- package/src/ambientfx/particleBackbone.js +493 -0
- package/src/ambientfx/stylizedAmbientFx.js +450 -0
- package/src/assetlib/ambientcg.js +117 -0
- package/src/assetlib/assetRef.js +91 -0
- package/src/assetlib/importedEntry.js +40 -0
- package/src/assetlib/index.js +23 -0
- package/src/assetlib/kaykit.js +192 -0
- package/src/assetlib/kaykitStaticIndex.js +700 -0
- package/src/assetlib/loadImported.js +143 -0
- package/src/assetlib/opensource3d.js +113 -0
- package/src/assetlib/polyhaven.js +182 -0
- package/src/assetlib/polypizza.js +115 -0
- package/src/assetlib/smithsonian.js +214 -0
- package/src/assetlib/sources.js +279 -0
- package/src/assetlib/zip.js +58 -0
- package/src/biome/biomeGenerator.js +385 -0
- package/src/biome/biomeRuntime.js +299 -0
- package/src/biome/index.js +2 -0
- package/src/buildinggen/buildingAsset.js +44 -0
- package/src/buildinggen/buildingGrammar.js +311 -0
- package/src/buildinggen/buildingMesh.js +451 -0
- package/src/buildinggen/buildingPresets.js +46 -0
- package/src/buildinggen/buildingRecipe.js +100 -0
- package/src/buildinggen/buildingSettings.js +238 -0
- package/src/buildinggen/index.js +6 -0
- package/src/camera/cameraDirector.js +157 -0
- package/src/camera/cameraGenerator.js +367 -0
- package/src/camera/cameraRig.js +570 -0
- package/src/camera/cameraSettings.js +236 -0
- package/src/camera/index.js +7 -0
- package/src/catalog/builtinEntries.js +245 -0
- package/src/catalog/catalog.js +210 -0
- package/src/catalog/index.js +3 -0
- package/src/catalog/manifest.js +84 -0
- package/src/core/generation.js +529 -0
- package/src/environment/environmentRigs.js +21 -1
- package/src/environment/environmentSettings.js +4 -0
- package/src/environment/environmentSunShadowPass.js +8 -0
- package/src/fauna/INTEGRATION.md +174 -0
- package/src/fauna/boids.js +861 -0
- package/src/fauna/faunaBodies.js +492 -0
- package/src/fauna/faunaPresets.js +52 -0
- package/src/fauna/faunaSettings.js +525 -0
- package/src/fauna/index.js +5 -0
- package/src/fauna/stylizedFauna.js +395 -0
- package/src/game-feel/gameFeelGenerator.js +402 -0
- package/src/game-feel/gameFeelRuntime.js +549 -0
- package/src/game-feel/index.js +2 -0
- package/src/index.js +17 -6
- package/src/lighting/colorIntensity.js +177 -0
- package/src/lighting/index.js +161 -0
- package/src/lighting/lightDescriptors.js +249 -0
- package/src/lighting/lightingCapabilities.js +79 -0
- package/src/lighting/lightingDocuments.js +247 -0
- package/src/lighting/lightingFixtures.js +446 -0
- package/src/lighting/lightingGenerator.js +449 -0
- package/src/lighting/lightingPresets.js +319 -0
- package/src/lighting/lightingRuntime.js +723 -0
- package/src/lighting/lightingStyle.js +386 -0
- package/src/lighting/lightingSystem.js +774 -0
- package/src/lighting/unrealExport.js +186 -0
- package/src/lighting/utils.js +87 -0
- package/src/motion/index.js +5 -0
- package/src/motion/motionClip.js +441 -0
- package/src/motion/motionController.js +628 -0
- package/src/motion/motionDocuments.js +225 -0
- package/src/motion/motionGraph.js +307 -0
- package/src/motion/motionSettings.js +222 -0
- package/src/pathgen/index.js +7 -0
- package/src/pathgen/pathBridge.js +232 -0
- package/src/pathgen/pathPresets.js +35 -0
- package/src/pathgen/pathRibbon.js +410 -0
- package/src/pathgen/pathRouter.js +380 -0
- package/src/pathgen/pathSettings.js +335 -0
- package/src/pathgen/pathTextures.js +123 -0
- package/src/pathgen/stylizedPaths.js +453 -0
- package/src/post/index.js +1 -0
- package/src/post/postGenerator.js +177 -0
- package/src/post/postProcessing.js +41 -0
- package/src/propgen/generatorsWave1.js +379 -0
- package/src/propgen/generatorsWave2.js +462 -0
- package/src/propgen/index.js +5 -0
- package/src/propgen/propAsset.js +323 -0
- package/src/propgen/propParts.js +170 -0
- package/src/propgen/propPlacement.js +459 -0
- package/src/propgen/propPresets.js +82 -0
- package/src/propgen/propSettings.js +395 -0
- package/src/shaders-tsl/chunks/projected-water-caustics.js +242 -0
- package/src/shaders-tsl/chunks/vegetation-style.js +360 -0
- package/src/shaders-tsl/chunks/water-shore-state.js +31 -0
- package/src/shaders-tsl/chunks/water-waves.js +90 -11
- package/src/shaders-tsl/environment.js +15 -1
- package/src/shaders-tsl/flower.js +279 -30
- package/src/shaders-tsl/grass.js +60 -33
- package/src/shaders-tsl/sky.js +125 -31
- package/src/shaders-tsl/tree-leaf.js +61 -25
- package/src/shaders-tsl/water-breaker.js +7 -4
- package/src/shaders-tsl/water-shore-state-simulation.js +523 -0
- package/src/shaders-tsl/water.js +439 -49
- package/src/shaders-tsl/woody-surface.js +154 -0
- package/src/sky/sceneOverrideLayers.js +10 -0
- package/src/sky/skyQuality.js +26 -0
- package/src/sky/stylizedSky.js +753 -45
- package/src/soundscape/index.js +4 -0
- package/src/soundscape/soundscapeGenerator.js +179 -0
- package/src/soundscape/soundscapeRuntime.js +806 -0
- package/src/soundscape/soundscapeSettings.js +292 -0
- package/src/styles/index.js +13 -0
- package/src/styles/styleBundle.js +325 -0
- package/src/stylizedTerrain.js +32 -2
- package/src/stylizedWorld.js +423 -20
- package/src/texgen/evaluateTexture.js +675 -0
- package/src/texgen/index.js +60 -0
- package/src/texgen/noise2.js +210 -0
- package/src/texgen/textureAi.js +436 -0
- package/src/texgen/textureGenerators.js +516 -0
- package/src/texgen/texturePresets.js +490 -0
- package/src/texgen/textureSettings.js +342 -0
- package/src/texgen/textureThree.js +59 -0
- package/src/vegetation/flowerSpecies.js +15 -3
- package/src/vegetation/grassPalettes.js +153 -0
- package/src/vegetation/index.js +6 -0
- package/src/vegetation/stylizedBush.js +2 -0
- package/src/vegetation/stylizedFlower.js +82 -0
- package/src/vegetation/stylizedFlowers.js +48 -7
- package/src/vegetation/stylizedForest.js +29 -1
- package/src/vegetation/stylizedGrass.js +291 -56
- package/src/vegetation/stylizedTree.js +38 -2
- package/src/vegetation/stylizedTreeFoliage.js +2 -1
- package/src/vegetation/vegetationShaders.js +1110 -0
- package/src/vfxgen/INTEGRATION.md +145 -0
- package/src/vfxgen/core/burstBackbone.js +380 -0
- package/src/vfxgen/core/projectileCore.js +92 -0
- package/src/vfxgen/core/spriteShapes.js +98 -0
- package/src/vfxgen/core/trailRibbon.js +272 -0
- package/src/vfxgen/core/vfxRandom.js +29 -0
- package/src/vfxgen/effects/emitHelpers.js +37 -0
- package/src/vfxgen/effects/magicEffects.js +162 -0
- package/src/vfxgen/effects/movementEffects.js +87 -0
- package/src/vfxgen/effects/weaponEffects.js +118 -0
- package/src/vfxgen/index.js +18 -0
- package/src/vfxgen/moves/moveController.js +146 -0
- package/src/vfxgen/moves/moveLibrary.js +335 -0
- package/src/vfxgen/vfxPresets.js +98 -0
- package/src/vfxgen/vfxSettings.js +384 -0
- package/src/vfxgen/vfxSystem.js +449 -0
- package/src/vfxgen/weapons/stylizedWeapons.js +137 -0
- package/src/villagegen/index.js +4 -0
- package/src/villagegen/stylizedVillage.js +490 -0
- package/src/villagegen/villageArchetypes.js +160 -0
- package/src/villagegen/villageNames.js +40 -0
- package/src/villagegen/villageSites.js +105 -0
- package/src/water/sceneOverrideLayers.js +23 -0
- package/src/water/water.js +5 -0
- package/src/water/waterBreakerSystem.js +15 -1
- package/src/water/waterCurrentField.js +447 -0
- package/src/water/waterMaterial.js +12 -0
- package/src/water/waterNearshorePhase.js +320 -0
- package/src/water/waterScenePasses.js +83 -30
- package/src/water/waterSettings.js +325 -13
- package/src/water/waterShoreMaterial.js +322 -0
- package/src/water/waterShoreStateField.js +605 -0
- package/src/water/waterSurface.js +797 -28
- package/src/weather/index.js +6 -0
- package/src/weather/weatherPrecipitation.js +221 -0
- package/src/weather/weatherPresets.js +258 -0
- package/src/weather/weatherSettings.js +269 -0
- package/src/weather/weatherSystem.js +871 -0
- package/src/worldMinimap.js +62 -0
- package/src/worldPresets.js +4 -1
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Shader constants reference
|
|
2
|
+
|
|
3
|
+
Constants that are deliberately **not** exposed as settings — either because
|
|
4
|
+
they are physics, because a CPU mirror must stay in lockstep with the GPU
|
|
5
|
+
code, or because changing them requires re-deriving neighbors. If you need to
|
|
6
|
+
tune one, edit the TSL shader source or its CPU mirror; this page tells you where and what will
|
|
7
|
+
break.
|
|
8
|
+
|
|
9
|
+
Everything that *is* meant to be tuned lives in the settings schemas
|
|
10
|
+
(`TOON_SETTING_FIELD_SCHEMA`, `WATER_SETTING_FIELD_SCHEMA`,
|
|
11
|
+
`ENVIRONMENT_SETTING_FIELD_SCHEMA`, `POST_PROCESSING_SETTING_FIELD_SCHEMA`,
|
|
12
|
+
`VEGETATION_SHADER_FIELD_SCHEMA`, and the
|
|
13
|
+
`GRASS/FLOWER/STYLIZED_TREE/SKY_SETTING_FIELD_SCHEMA` families) and renders in the
|
|
14
|
+
`@call-me-sensei/toonlab/debug` panel.
|
|
15
|
+
|
|
16
|
+
## Water
|
|
17
|
+
|
|
18
|
+
| Constant | Where | Why fixed |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| `WATER_GERSTNER_WAVE_COUNT = 8` | `src/water/waterSettings.js` + wave loops in `src/shaders-tsl/chunks/water-waves.js` | Loop count baked into the shader; `buildGerstnerWaves()` (the CPU mirror used for buoyancy/physics) must produce exactly this many waves. Changing it means editing both in lockstep. |
|
|
21
|
+
| Wavelength falloff `0.68`, min wavelength `0.05` | `buildGerstnerWaves()` in `waterSettings.js` | Wave-spectrum shape: each successive wave is 0.68× the previous wavelength. Part of the tuned spectrum, mirrored on the GPU. |
|
|
22
|
+
| Slope limit `0.4` (`amplitude * waveNumber > 0.4`) | `buildGerstnerWaves()` | Gerstner waves self-intersect (loop over) past steepness ~1; 0.4 keeps the tuned look stable at every `waveIntensity`. |
|
|
23
|
+
| Gravity `9.81` | `buildGerstnerWaves()` | Deep-water dispersion relation (`speed = sqrt(g/k)`). Physics. |
|
|
24
|
+
| Detail-normal distance fade `smoothstep(16.0, 60.0, viewDistance)` and near/far blend `mix(0.2, 1.0, detailFade)` | `src/shaders-tsl/water.js` | Screen-stability tuning: full detail near, 20% far, fading over 16–60 m. Honest candidates for uniforms later; documented here until then. |
|
|
25
|
+
| Detail UV advection factors `0.55` / `0.34`, second-layer rotation `1.9` rad | `src/shaders-tsl/water.js` | Two detail layers must drift at different, incommensurate rates or the surface visibly tiles. The triplet was tuned together. |
|
|
26
|
+
| View-depth blend `0.18` (`effectiveDepth = columnDepth + viewDepthDiff * 0.18`) | `src/shaders-tsl/chunks/water-color.js` | How much grazing-angle view depth deepens the absorption color; tuned against the shoreline film fix. |
|
|
27
|
+
| Absorption divisor `24.0` (`viewDepthDiff / 24.0`) | `src/shaders-tsl/chunks/water-color.js` | Far-field opacity floor so open water never goes glassy at distance. |
|
|
28
|
+
|
|
29
|
+
Quality tiers (`WATER_DETAIL_OCTAVES`, `WATER_FOAM_OCTAVES`) **are** exposed:
|
|
30
|
+
pass `quality: 'low'|'medium'|'high'` or a custom
|
|
31
|
+
`{ detailOctaves, foamOctaves, qualityLevel }` — see
|
|
32
|
+
`resolveWaterQualityDefines()` in `src/water/waterMaterial.js`.
|
|
33
|
+
|
|
34
|
+
## Character (toon)
|
|
35
|
+
|
|
36
|
+
| Constant | Where | Why fixed |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| Bayer 4×4 dither matrix | `src/shaders-tsl/chunks/character-color.js` | Screen-door fade pattern (`alpha.ditherOpacity`); the matrix itself is canonical. |
|
|
39
|
+
| Cel edge anti-alias derivative math | `src/shaders-tsl/chunks/character-lighting.js` | Driven by `celShade.edgeAntiAliasStrength` (exposed); the fwidth-based widening formula is not a tunable. |
|
|
40
|
+
| Self-shadow PCF tap offsets (4/9-tap) | `characterRenderPasses.js` + shadow chunks | Kernel shape; strength/bias are exposed via `selfShadow.*`. |
|
|
41
|
+
|
|
42
|
+
## Environment
|
|
43
|
+
|
|
44
|
+
| Constant | Where | Why fixed |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| Lightmap painterly remap (warm dark end, lift floor) | `src/shaders-tsl/chunks/environment-lighting.js` | The remap curve IS the art direction; its inputs (strengths, tints) are exposed in `environmentSettings`. |
|
|
47
|
+
| Vertex-AO golden-spiral hemisphere sample set | `src/environment/environmentVertexAo.js` | Deterministic sampling pattern — changing it invalidates every baked result. Budget/strength are exposed. |
|
|
48
|
+
|
|
49
|
+
## Vegetation / sky
|
|
50
|
+
|
|
51
|
+
Formerly hardcoded uniforms (grass cloud-shadow coverage/scale/velocity,
|
|
52
|
+
backlit strength, tree gnarl frequencies/amplitude, foliage shadow strengths)
|
|
53
|
+
are now settings — see the vegetation/sky schemas. What remains fixed:
|
|
54
|
+
|
|
55
|
+
| Constant | Where | Why fixed |
|
|
56
|
+
|---|---|---|
|
|
57
|
+
| Grass blade segment count / geometry proportions | `stylizedGrass.js` geometry builder | Baked into instanced geometry at construction; density/height ARE settings (construction-time). |
|
|
58
|
+
| Tree trunk ring/segment tessellation | `stylizedTree.js` | Geometry topology; regenerating is the designed path (see the tree recipe system). |
|
|
59
|
+
| Sky far-plane clip epsilon and horizon branch guards | `src/shaders-tsl/sky.js` | Numerical/render-order safeguards, not art direction. Dome radius remains constructor-compatible but is visually invariant because the vertex stage pins the dome to the far plane. |
|
|
60
|
+
| Sky FBM implementation and deployment octave tiers | `src/shaders-tsl/sky.js`, `src/sky/skyQuality.js`, `chunks/water-common.js` | Noise/hash internals define deterministic parity. Shipped quality tiers compile 2/3/4 octaves (`low`/`medium`/`high`), with 1–5 custom; quality stays outside the portable art preset while cloud shape, seed, projection, softness, shading, and motion are exposed. |
|
|
61
|
+
| Sky coverage calibration and projection singularity guards | `src/shaders-tsl/sky.js` | Stable mapping from the authored coverage/altitude controls to safe procedural thresholds. All visually meaningful colors, curve shapes, sun/glow terms, cloud treatment, and star treatment are schema fields. |
|
|
62
|
+
|
|
63
|
+
## Post-processing
|
|
64
|
+
|
|
65
|
+
All colors, strengths, and thresholds are exposed
|
|
66
|
+
(`POST_PROCESSING_SETTING_FIELD_SCHEMA`, 29 parameters). The bloom pyramid's
|
|
67
|
+
level count is exposed (`bloomLevels`, 2–8); the downsample filter weights are
|
|
68
|
+
not (standard dual-filter kernel).
|
|
69
|
+
|
|
70
|
+
## TSL texture binding budget
|
|
71
|
+
|
|
72
|
+
The raw GLSL `USE_*` define plumbing was removed with Phase 11, but the
|
|
73
|
+
binding budget did not disappear. The app currently requests default WebGPU
|
|
74
|
+
limits, so native WebGPU and the forced WebGL2 fallback both need the same
|
|
75
|
+
16-sampled-texture discipline. Optional maps must stay graph-gated in
|
|
76
|
+
`src/shaders-tsl/anime.js`, `src/shaders-tsl/environment.js`, and their chunks:
|
|
77
|
+
only construct/sample a texture node when the corresponding map exists.
|
package/docs/sky.md
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# Sky system
|
|
2
|
+
|
|
3
|
+
`@call-me-sensei/toonlab/sky` provides a procedural stylized sky for Three.js:
|
|
4
|
+
a three-stop vertical dome, sun disc and glow, sun-side horizon scattering,
|
|
5
|
+
two-tone painterly clouds, and a procedural star field. It uses the same TSL
|
|
6
|
+
material on WebGPU and the WebGL2 fallback and requires no texture assets.
|
|
7
|
+
|
|
8
|
+
Sky is a World System in ToonLab. Its appearance shader and procedural motion
|
|
9
|
+
ship as one versioned preset because the cloud, sun, horizon, and star terms
|
|
10
|
+
must be judged together. It is not a fourth IP-wide Shader Lab; see
|
|
11
|
+
[Lab responsibilities](lab-architecture.md).
|
|
12
|
+
|
|
13
|
+
## Quickstart
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
import { StylizedSky } from '@call-me-sensei/toonlab/sky';
|
|
17
|
+
|
|
18
|
+
const sky = new StylizedSky({
|
|
19
|
+
preset: 'call_me_sensei',
|
|
20
|
+
quality: 'high', // deployment policy; not saved in the art preset
|
|
21
|
+
});
|
|
22
|
+
scene.add(sky);
|
|
23
|
+
|
|
24
|
+
renderer.setAnimationLoop(() => {
|
|
25
|
+
const delta = clock.getDelta();
|
|
26
|
+
sky.update(delta, camera); // animates clouds/stars and follows the camera
|
|
27
|
+
renderer.render(scene, camera);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// Live runtime retuning does not rebuild the material.
|
|
31
|
+
sky.applySettings({ cloudCoverage: 0.55, starsStrength: 0.2 });
|
|
32
|
+
sky.setPreset('golden_hour'); // replaces the authored look from scratch
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`StylizedSky` centers its dome on the camera and pins it to the far plane, so it
|
|
36
|
+
does not intersect scene geometry. Add the same sky to scenes containing a
|
|
37
|
+
`WaterSurface`; water reflection passes then capture the active composed sky rather
|
|
38
|
+
than relying on a separate color approximation.
|
|
39
|
+
|
|
40
|
+
## Settings and scope
|
|
41
|
+
|
|
42
|
+
`createSkySettings(options)` normalizes flat settings. The public
|
|
43
|
+
`SKY_SETTING_GROUPS` and `SKY_SETTING_FIELD_SCHEMA` drive Sky Lab and custom
|
|
44
|
+
editors. The schema contains 46 portable art fields; the constructor-only dome
|
|
45
|
+
radius is the single non-portable field.
|
|
46
|
+
|
|
47
|
+
| Group | Owns |
|
|
48
|
+
|---|---|
|
|
49
|
+
| Gradient | Zenith, horizon, and below-horizon colors; zenith/ground curve shape; horizon-band width, sun focus, and scattering strength. |
|
|
50
|
+
| Sun | Baseline disc direction and color; size, edge softness, intensity; broad/core glow shape; dense-cloud occlusion. |
|
|
51
|
+
| Clouds | Coverage, scale, deterministic seed, projection, silhouette softness/opacity, direction and speed, two-tone shade controls, light-sample depth, silver lining, and horizon fade. |
|
|
52
|
+
| Stars | Strength, color, deterministic seed, density, pattern scale, glint size, twinkle depth/speed, and horizon fade. |
|
|
53
|
+
|
|
54
|
+
The runtime constructor still accepts `radius` for compatibility. Because the
|
|
55
|
+
dome is centered on the camera and pinned to the far plane, changing that
|
|
56
|
+
geometry radius does not change the rendered look. Sky Lab therefore does not
|
|
57
|
+
surface it, and portable Sky preset documents do not serialize it.
|
|
58
|
+
|
|
59
|
+
Sky settings do not own the current clock, directional-light intensity or
|
|
60
|
+
shadow policy, precipitation, weather transition, fog volume, exposure, or
|
|
61
|
+
camera. Lighting and Weather systems remain authoritative and may modulate the
|
|
62
|
+
active sky at runtime. Independent owners use ordered layers rather than
|
|
63
|
+
writing the same settings object:
|
|
64
|
+
|
|
65
|
+
```js
|
|
66
|
+
import { SKY_SCENE_OVERRIDE_PRIORITIES } from '@call-me-sensei/toonlab/sky';
|
|
67
|
+
|
|
68
|
+
const lightingLayer = Symbol('lighting');
|
|
69
|
+
const weatherLayer = Symbol('weather');
|
|
70
|
+
|
|
71
|
+
sky.setSceneOverrideLayer(lightingLayer, {
|
|
72
|
+
sunDirection: lightingState.sunDirection,
|
|
73
|
+
zenithColor: lightingState.zenithColor,
|
|
74
|
+
}, { priority: SKY_SCENE_OVERRIDE_PRIORITIES.lighting });
|
|
75
|
+
|
|
76
|
+
// A resolver receives the result of lower-priority layers. Rain therefore
|
|
77
|
+
// darkens the current time-of-day instead of replacing it with a stale color.
|
|
78
|
+
sky.setSceneOverrideLayer(weatherLayer, (base) => ({
|
|
79
|
+
cloudCoverage: weatherState.atmosphere.cloudCoverage,
|
|
80
|
+
zenithColor: base.zenithColor.map((channel) => channel * weatherSkyScale),
|
|
81
|
+
}), { priority: SKY_SCENE_OVERRIDE_PRIORITIES.weather });
|
|
82
|
+
|
|
83
|
+
sky.clearSceneOverrideLayer(weatherLayer); // Lighting remains active
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Layers compose in ascending priority: Lighting (100), Weather (200), then the
|
|
87
|
+
manual scene layer (300). `applySettings()` edits the authored baseline and
|
|
88
|
+
recomposes every active resolver; `setPreset(name, overrides)` replaces that
|
|
89
|
+
baseline. `sky.settings` is always authored data, while
|
|
90
|
+
`sky.renderedSettings`, `sky.sceneOverrides`, and `sky.sceneOverrideLayers`
|
|
91
|
+
expose the effective runtime state.
|
|
92
|
+
|
|
93
|
+
`setSceneOverrides()` is the convenience manual layer and
|
|
94
|
+
`clearSceneOverrides()` removes only that layer. Named owners must call
|
|
95
|
+
`clearSceneOverrideLayer(id)` so they cannot erase each other;
|
|
96
|
+
`clearAllSceneOverrideLayers()` is reserved for a host that explicitly owns
|
|
97
|
+
the complete teardown. `LightingSystem.attachWorld(world)` and
|
|
98
|
+
`WeatherSystem` use private layers and release only their own state.
|
|
99
|
+
|
|
100
|
+
The visible dome clouds and the world-projected cloud-shadow field are related
|
|
101
|
+
weather signals, not the same procedural texture: the dome is angular and the
|
|
102
|
+
shadow field is spatial over terrain, water, and vegetation. Weather coordinates
|
|
103
|
+
coverage, wind, and intensity policy; games that require exact cloud-to-shadow
|
|
104
|
+
registration should supply a shared host cloud-field adapter.
|
|
105
|
+
|
|
106
|
+
## Deployment quality
|
|
107
|
+
|
|
108
|
+
Sky quality is runtime policy, not art direction. `quality: 'low' | 'medium' |
|
|
109
|
+
'high'` compiles two, three, or four FBM octaves respectively for each cloud
|
|
110
|
+
sample. The graph is compile-time-unrolled, so `sky.setQuality(tier)` rebuilds
|
|
111
|
+
only the Sky material while preserving authored settings, active scene layers,
|
|
112
|
+
and animation time. Custom policies may pass `{ cloudOctaves: 1..5 }`.
|
|
113
|
+
|
|
114
|
+
`SKY_QUALITY_TIERS`, `SKY_QUALITY_OPTIONS`, and `resolveSkyQuality()` are public.
|
|
115
|
+
Quality is a preview control in Sky Lab and is deliberately absent from
|
|
116
|
+
portable Sky preset documents.
|
|
117
|
+
|
|
118
|
+
## Presets and portable documents
|
|
119
|
+
|
|
120
|
+
Built-in presets include `default`, `call_me_sensei`, `clear_day`,
|
|
121
|
+
`golden_hour`, `overcast`, and `moonlit`. `getSkyPresetOptions()` lists them
|
|
122
|
+
and any project registrations.
|
|
123
|
+
|
|
124
|
+
```js
|
|
125
|
+
import {
|
|
126
|
+
createSkyPresetDocument,
|
|
127
|
+
createSkySettings,
|
|
128
|
+
parseSkyPresetDocument,
|
|
129
|
+
registerSkyPreset,
|
|
130
|
+
registerSerializedSkyPreset,
|
|
131
|
+
serializeSkyPreset,
|
|
132
|
+
} from '@call-me-sensei/toonlab/sky';
|
|
133
|
+
|
|
134
|
+
registerSkyPreset('violet_twilight', {
|
|
135
|
+
label: 'Violet Twilight',
|
|
136
|
+
settings: {
|
|
137
|
+
zenithColor: [0.12, 0.08, 0.32],
|
|
138
|
+
horizonColor: [0.88, 0.38, 0.5],
|
|
139
|
+
starsStrength: 0.35,
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
const document = createSkyPresetDocument('violet_twilight', {
|
|
144
|
+
label: 'Violet Twilight',
|
|
145
|
+
settings: createSkySettings('violet_twilight'),
|
|
146
|
+
});
|
|
147
|
+
const json = serializeSkyPreset(document);
|
|
148
|
+
const result = parseSkyPresetDocument(json);
|
|
149
|
+
if (result.ok) registerSerializedSkyPreset(json, { overwrite: true });
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Documents use `{ type: 'toonlab/sky-preset', version, id, label,
|
|
153
|
+
description, settings }`. Use `validateSkyPresetDocument` when a parsed object
|
|
154
|
+
is already available. Documents contain complete normalized appearance
|
|
155
|
+
settings, so they remain portable if a named base preset changes later.
|
|
156
|
+
|
|
157
|
+
## Low-level material API
|
|
158
|
+
|
|
159
|
+
Applications that own their dome mesh can use the same production material:
|
|
160
|
+
|
|
161
|
+
```js
|
|
162
|
+
import {
|
|
163
|
+
applySkySettingsToMaterial,
|
|
164
|
+
createSkyMaterial,
|
|
165
|
+
} from '@call-me-sensei/toonlab/sky';
|
|
166
|
+
|
|
167
|
+
const material = createSkyMaterial({ preset: 'moonlit' });
|
|
168
|
+
applySkySettingsToMaterial(material, { starsStrength: 1.2 });
|
|
169
|
+
applySkySettingsToMaterial(material, { preset: 'clear_day' }); // full reset
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
`createSkyMaterial` returns the TSL node material used by `StylizedSky`.
|
|
173
|
+
`applySkySettingsToMaterial` updates the shared uniform contract without
|
|
174
|
+
replacing the material.
|
|
175
|
+
|
|
176
|
+
## Sky Lab
|
|
177
|
+
|
|
178
|
+
Run `/sky-lab/` in the repository or `/labs/sky` on ToonLab Pro. The lab uses
|
|
179
|
+
the npm settings schema directly and supports preset selection, undo/redo,
|
|
180
|
+
local saves, JSON import/export, WebGPU/WebGL comparison, and preview-only
|
|
181
|
+
weather/lighting fixtures. Exported documents contain all 46 reusable
|
|
182
|
+
sky-system art fields and no current scene state or quality tier.
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
# Generative style domains
|
|
2
|
+
|
|
3
|
+
ToonLab's style domains are configuration authoring tools, not small preset
|
|
4
|
+
catalogs. A developer defines a domain, chooses a nonzero seed in the 32-bit seed
|
|
5
|
+
space, locks the decisions that already work, and keeps generating. The same
|
|
6
|
+
recipe can therefore produce thousands or millions of reproducible candidates,
|
|
7
|
+
and applications can register new families, operators, graph nodes, events, and
|
|
8
|
+
layer types without changing ToonLab's built-in lists.
|
|
9
|
+
|
|
10
|
+
## Status (2026-07 triage)
|
|
11
|
+
|
|
12
|
+
The dedicated browser labs for these domains were removed from the labs grid:
|
|
13
|
+
behavioral domains (camera, game feel, motion) cannot be judged against a demo
|
|
14
|
+
stage, and the visual ones are curated via MCP batches + review instead. The
|
|
15
|
+
domains themselves were triaged by one test — *does this simplify a Three.js
|
|
16
|
+
game developer's life today?*
|
|
17
|
+
|
|
18
|
+
| Domain | npm export | Lab | Notes |
|
|
19
|
+
|---|---|---|---|
|
|
20
|
+
| Post & color | ✅ `./post` | removed (future feature) | Curate presets via MCP; needs 3–5 owner-reviewed presets |
|
|
21
|
+
| Camera | ✅ `./camera` | removed (future feature) | Ships as a code library; needs README quickstart |
|
|
22
|
+
| Game feel | ✅ `./game-feel` | removed (future feature) | Ships as a code library; needs README quickstart |
|
|
23
|
+
| Lighting | ✅ `./lighting` | ✅ `/lighting-lab/` | Styles + fixtures; see [lighting.md](lighting.md) |
|
|
24
|
+
| Motion | ⏸ held (source at `src/motion/`) | removed (future feature) | Returns when a demo drives real GLTF clips end-to-end |
|
|
25
|
+
| Soundscape | ⏸ held (source at `src/soundscape/`) | removed (future feature) | Rethink as adaptive mixing over curated audio assets |
|
|
26
|
+
| Biome | ❌ cut (source at `src/biome/`) | removed (future feature) | Value lives in `stylizedTerrain`/`stylizedWorld`, already exported |
|
|
27
|
+
| UI theme | ❌ removed entirely | removed (future feature) | Out of scope for a Three.js game library; recoverable from history |
|
|
28
|
+
|
|
29
|
+
The product boundary is:
|
|
30
|
+
|
|
31
|
+
```mermaid
|
|
32
|
+
flowchart LR
|
|
33
|
+
M["Local MCP server"] --> R["Portable generator recipe"]
|
|
34
|
+
R --> G["Deterministic seed resolution"]
|
|
35
|
+
G --> P["Flat runtime preset"]
|
|
36
|
+
P --> N["npm package runtime"]
|
|
37
|
+
N --> F["Game frame loop"]
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
- MCP provides design-time recipe creation, validation, batch generation, and
|
|
41
|
+
`.toonlab/` persistence to coding agents.
|
|
42
|
+
- The npm package owns shipping runtime behavior. It accepts resolved presets,
|
|
43
|
+
enforces relevant quality budgets, exposes update/configure/regenerate and
|
|
44
|
+
dispose lifecycle methods, and never depends on a lab UI.
|
|
45
|
+
|
|
46
|
+
## One open generator contract
|
|
47
|
+
|
|
48
|
+
Every generator recipe is a versioned JSON document with the same core fields:
|
|
49
|
+
|
|
50
|
+
```js
|
|
51
|
+
{
|
|
52
|
+
type: 'toonlab/biome-generator',
|
|
53
|
+
version: 1,
|
|
54
|
+
id: 'painted-valley',
|
|
55
|
+
label: 'Painted Valley',
|
|
56
|
+
seed: 4635,
|
|
57
|
+
basePreset: 'outdoorGameplay',
|
|
58
|
+
configuration: {},
|
|
59
|
+
domains: {
|
|
60
|
+
terrain: {
|
|
61
|
+
morphology: {
|
|
62
|
+
rolling: {
|
|
63
|
+
amp: { $type: 'range', min: 8, max: 42, step: 0.25 },
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
locks: ['terrain.palette.meadow'],
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Domain leaves support continuous ranges, weighted choices, booleans, colors,
|
|
73
|
+
and constants. A domain can be narrowed, widened, replaced, or extended with
|
|
74
|
+
new paths. Named random streams make a result deterministic and keep unrelated
|
|
75
|
+
settings stable when another branch is added. Locks preserve selected paths
|
|
76
|
+
while the remaining paths continue to vary.
|
|
77
|
+
|
|
78
|
+
The result of generation is a flat, versioned preset. Runtime code does not
|
|
79
|
+
sample a domain every frame. This keeps shipping behavior deterministic,
|
|
80
|
+
serializable, debuggable, and inexpensive.
|
|
81
|
+
|
|
82
|
+
## The domains
|
|
83
|
+
|
|
84
|
+
### Post & color
|
|
85
|
+
|
|
86
|
+
**Shipped in npm; lab removed (future feature).** Authors color grade, bloom,
|
|
87
|
+
outline, vignette, depth cue, motion blur, and vertical grade together so the
|
|
88
|
+
result reads as one look.
|
|
89
|
+
|
|
90
|
+
- Open generation: every feature flag and numeric/color parameter is a domain;
|
|
91
|
+
custom post families and ordinary runtime presets are registerable.
|
|
92
|
+
- Runtime: `createPostProcessingPipeline` applies the resolved settings, lazily
|
|
93
|
+
allocates the pyramid bloom chain, skips inactive passes, reports render-target
|
|
94
|
+
statistics, resizes safely, and disposes owned GPU resources.
|
|
95
|
+
- Budgets: mobile removes depth-heavy effects and limits bloom; balanced limits
|
|
96
|
+
simultaneous depth consumers; cinematic preserves the authored intent.
|
|
97
|
+
|
|
98
|
+
Import from `@call-me-sensei/toonlab/post`.
|
|
99
|
+
|
|
100
|
+
### Camera
|
|
101
|
+
|
|
102
|
+
**Shipped in npm; lab removed (future feature).** Builds a stack of camera
|
|
103
|
+
operators instead of selecting one hard-coded camera type. Follow, framing,
|
|
104
|
+
collision, damping, procedural noise, impulses, and lens behavior can be
|
|
105
|
+
composed or extended.
|
|
106
|
+
|
|
107
|
+
- Open generation: archetypes seed an editable domain; new generator
|
|
108
|
+
archetypes and runtime operator factories can be registered.
|
|
109
|
+
- Runtime: `createCameraRig` evaluates the operator stack without editor state;
|
|
110
|
+
`createCameraDirector` blends between rigs and `addImpulse` handles event
|
|
111
|
+
response without coupling gameplay code to camera math.
|
|
112
|
+
- Scale: one resolved operator stack is evaluated per active camera. Noise and
|
|
113
|
+
impulses are time-based and no candidate generation occurs in the frame loop.
|
|
114
|
+
|
|
115
|
+
Import from `@call-me-sensei/toonlab/camera`.
|
|
116
|
+
|
|
117
|
+
### Motion (held — future feature)
|
|
118
|
+
|
|
119
|
+
**Held out of the npm exports; lab removed.** The runtime survives at
|
|
120
|
+
`src/motion/` (verified by `verify:motion`) but does not ship until a demo
|
|
121
|
+
drives real GLTF clips on a real character end-to-end. Authors an arbitrary
|
|
122
|
+
animation graph, not a finite animation menu. Clip slots keep game assets
|
|
123
|
+
separate from reusable locomotion logic.
|
|
124
|
+
|
|
125
|
+
- Open generation: recursive 1D/2D/weighted blend nodes, any number of states,
|
|
126
|
+
transitions, parameters, layers, masks, and clip slots; procedural harmonic,
|
|
127
|
+
keyframe, and Three.js clip samplers share one pose contract.
|
|
128
|
+
- Runtime: `createMotionController` evaluates transitions and layered poses,
|
|
129
|
+
supports root-motion policies and stepped/smooth cadence, and applies results
|
|
130
|
+
through a replaceable rig adapter.
|
|
131
|
+
- Scale: graph validation catches missing slots and transition references
|
|
132
|
+
before runtime. Generation changes timing/style parameters while preserving
|
|
133
|
+
arbitrary user graph topology.
|
|
134
|
+
|
|
135
|
+
### UI Theme Lab (removed — future feature)
|
|
136
|
+
|
|
137
|
+
UI theming (semantic token generation, contrast auditing, scoped CSS export)
|
|
138
|
+
was removed from the package and the labs grid: it serves web UI authoring, not
|
|
139
|
+
Three.js game development, so it sits outside ToonLab's scope. The domain may
|
|
140
|
+
return as a separate product if game-HUD theming becomes a real need. The last
|
|
141
|
+
implementation lived at `src/ui-theme/` + `labs/ui-theme-lab/` (removed
|
|
142
|
+
2026-07; recoverable from history).
|
|
143
|
+
|
|
144
|
+
### Biome (cut — future feature)
|
|
145
|
+
|
|
146
|
+
**Export cut; lab removed.** The runtime at `src/biome/` is a lifecycle wrapper
|
|
147
|
+
that hard-requires ToonLab's own renderer/scene, so it is not consumable as a
|
|
148
|
+
standalone package export; the underlying value (`stylizedTerrain`,
|
|
149
|
+
`stylizedWorld`) is already exported from the package root. Treated a biome as
|
|
150
|
+
continuous terrain morphology plus a linked palette, water, atmosphere, and
|
|
151
|
+
vegetation system.
|
|
152
|
+
|
|
153
|
+
- Open generation: terrain height/depth/frequency/terracing/islands, palette
|
|
154
|
+
endpoints, water colors, fog, grass/flower/tree density and size, and wind
|
|
155
|
+
are domain values; new terrain archetypes and biome families are registerable.
|
|
156
|
+
- Runtime: `createBiomeRuntime` constructs the terrain and stylized world,
|
|
157
|
+
exposes race-safe asynchronous regeneration, updates world systems, reports
|
|
158
|
+
scene statistics, and owns disposal.
|
|
159
|
+
- Budgets: mobile, balanced, and cinematic cap terrain segments and vegetation
|
|
160
|
+
radius/density/spacing so authored density never defeats the target device.
|
|
161
|
+
|
|
162
|
+
### Soundscape (held — future feature)
|
|
163
|
+
|
|
164
|
+
**Held out of the npm exports; lab removed.** The runtime survives at
|
|
165
|
+
`src/soundscape/` (verified by `verify:soundscape`) but purely synthesized
|
|
166
|
+
ambience has a quality ceiling below the asset bar; the likely return path is
|
|
167
|
+
adaptive mixing over curated audio assets. A procedural audio graph that can
|
|
168
|
+
use synthesized layers immediately and resolve project audio through an asset
|
|
169
|
+
resolver later.
|
|
170
|
+
|
|
171
|
+
- Open generation: any number of buses, layers, adaptive parameters,
|
|
172
|
+
modulation mappings, snapshots, and transitions; both generator families and runtime
|
|
173
|
+
layer factories are registerable.
|
|
174
|
+
- Runtime: `createSoundscapeRuntime` creates its `AudioContext` lazily after a
|
|
175
|
+
user gesture, owns Web Audio nodes, transitions without rebuilding every
|
|
176
|
+
frame, exposes adaptive inputs, and disposes or closes owned resources.
|
|
177
|
+
- Budgets: quality tiers cap nodes, layers, and voices. The runtime reports
|
|
178
|
+
skipped layers rather than silently exceeding its budget.
|
|
179
|
+
|
|
180
|
+
### Game feel
|
|
181
|
+
|
|
182
|
+
**Shipped in npm; lab removed (future feature).** Maps named gameplay events to
|
|
183
|
+
coordinated response graphs. It is the integration layer for impact, not
|
|
184
|
+
another VFX asset catalog.
|
|
185
|
+
|
|
186
|
+
- Open generation: event definitions and effect factories are registries;
|
|
187
|
+
projects can add `parry`, `harvest`, `dialogueBeat`, or any other event and
|
|
188
|
+
compose built-in camera punch, hit-stop/time warp, squash, flash, audio, and
|
|
189
|
+
haptics; custom effect factories can connect project VFX or particles.
|
|
190
|
+
- Runtime: `createGameFeelRuntime` schedules effects on scaled and unscaled
|
|
191
|
+
clocks, enforces cooldown/concurrency rules, returns gameplay delta after
|
|
192
|
+
time effects, and drives replaceable adapters instead of assuming a renderer
|
|
193
|
+
or input library.
|
|
194
|
+
- Safety: haptics and audio are capability-gated; an adapter returning `false`
|
|
195
|
+
explicitly declines so fallback diagnostics remain honest. Unsupported
|
|
196
|
+
effects do not consume supported-effect capacity, errors are isolated,
|
|
197
|
+
trigger/drop statistics are exposed, and disposal restores time/camera/UI
|
|
198
|
+
state. Runtime quality tiers can tighten recipes, resolved presets, or raw
|
|
199
|
+
settings.
|
|
200
|
+
|
|
201
|
+
Import from `@call-me-sensei/toonlab/game-feel`.
|
|
202
|
+
|
|
203
|
+
### Lighting Lab
|
|
204
|
+
|
|
205
|
+
`/lighting-lab/` authors the game's lighting identity as two generative
|
|
206
|
+
artifacts instead of per-scene light configuration: **lighting styles**
|
|
207
|
+
(`toonlab/lighting-style` — the full day as one curve: sun kelvin/intensity
|
|
208
|
+
per hour, sun path, ambient policy, fog palette, exposure philosophy, shadow
|
|
209
|
+
policy) and **light fixtures** (`toonlab/light-fixture` — reusable practicals
|
|
210
|
+
like street lamps and lanterns with seeded per-placement variation, flicker,
|
|
211
|
+
and day/night schedules).
|
|
212
|
+
|
|
213
|
+
- Open generation: style families (`anime-day`, `call-me-sensei`, `golden`,
|
|
214
|
+
`noir-neon`, `pastel-overcast`) and fixture families (`warm-practical`,
|
|
215
|
+
`cms-practical`, `flame`, `neon`) are registries on the shared domain
|
|
216
|
+
grammar; subtree locks (`sun`, `atmosphere`, `exposure`) survive reseeds.
|
|
217
|
+
- Runtime: `createLightingSystem` applies a style + fixtures to any scene or
|
|
218
|
+
stylized world — `setTimeOfDay(hour)` moves the whole look along the day
|
|
219
|
+
cycle, `place(fixture, position, { seed })` realizes budget-managed lights
|
|
220
|
+
with deterministic variation, `setWeatherModulation` is the single hook for
|
|
221
|
+
weather, and `dispose()` restores captured fog/exposure/sun state. Area
|
|
222
|
+
lights gate on LTC lookup-texture loading instead of crashing node backends.
|
|
223
|
+
- Preview scenes: outdoor, interior, and city-night stages with a time-of-day
|
|
224
|
+
scrubber and weather modulation presets, so a style is judged standing next
|
|
225
|
+
to a lantern at night, not only at editor noon.
|
|
226
|
+
|
|
227
|
+
Import from `@call-me-sensei/toonlab/lighting`.
|
|
228
|
+
|
|
229
|
+
## MCP authoring
|
|
230
|
+
|
|
231
|
+
The local MCP server exposes four tools shared by the shipped domains (post,
|
|
232
|
+
camera, game feel, lighting styles, light fixtures):
|
|
233
|
+
|
|
234
|
+
- `list_style_labs` returns runtime imports/APIs, extension families,
|
|
235
|
+
and generation capabilities.
|
|
236
|
+
- `create_style_recipe` creates and optionally saves a recipe below
|
|
237
|
+
`.toonlab/creations/`.
|
|
238
|
+
- `generate_style_presets` resolves one to 64 consecutive seeds in one call,
|
|
239
|
+
validates every result, and optionally saves the deterministic batch.
|
|
240
|
+
- `validate_style_document` validates either an editable recipe or flat preset.
|
|
241
|
+
|
|
242
|
+
For example, an agent can create a broad post-look recipe, lock the grade after
|
|
243
|
+
review, generate seeds 2000–2063, and save the batch without inventing a finite
|
|
244
|
+
catalog of look names. See [Local MCP and workspace](mcp.md) for connection
|
|
245
|
+
instructions.
|
|
246
|
+
|
|
247
|
+
## Runtime example
|
|
248
|
+
|
|
249
|
+
```js
|
|
250
|
+
import {
|
|
251
|
+
createPostGeneratorRecipe,
|
|
252
|
+
createGeneratedPostPresetDocument,
|
|
253
|
+
createPostProcessingPipeline,
|
|
254
|
+
} from '@call-me-sensei/toonlab/post';
|
|
255
|
+
|
|
256
|
+
// Usually authored and saved via MCP.
|
|
257
|
+
const recipe = createPostGeneratorRecipe('soft-anime', { seed: 4635 });
|
|
258
|
+
const preset = createGeneratedPostPresetDocument(recipe, { quality: 'balanced' });
|
|
259
|
+
|
|
260
|
+
const post = createPostProcessingPipeline({
|
|
261
|
+
camera,
|
|
262
|
+
renderer,
|
|
263
|
+
scene,
|
|
264
|
+
settings: preset.settings,
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
renderer.setAnimationLoop(() => {
|
|
268
|
+
post.render(clock.getDelta());
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// post.dispose();
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
Applications may ship recipes when runtime re-rolling is a feature, or resolve
|
|
275
|
+
and check in presets when exact art direction is required. Both paths use the
|
|
276
|
+
same npm implementation.
|
|
277
|
+
|
|
278
|
+
## Engine practices adopted
|
|
279
|
+
|
|
280
|
+
The architecture follows useful patterns from established engines while
|
|
281
|
+
remaining native to Three.js:
|
|
282
|
+
|
|
283
|
+
- Unreal Engine's Procedural Content Generation framework separates reusable
|
|
284
|
+
graphs, subgraphs, inspection/debugging, and editor/runtime generation. The
|
|
285
|
+
ToonLab equivalent is an extensible recipe domain plus a flat inspected
|
|
286
|
+
result.
|
|
287
|
+
- Unreal Engine MetaSounds treats audio as a procedural runtime graph with
|
|
288
|
+
reusable patches and parameterized inputs. Soundscape uses the same graph and
|
|
289
|
+
registry mindset with explicit Web Audio budgets.
|
|
290
|
+
- Unity Volume profiles separate reusable effect settings from local runtime
|
|
291
|
+
overrides. ToonLab recipes, resolved presets, locks, and quality overrides
|
|
292
|
+
serve the same separation.
|
|
293
|
+
- Unity Cinemachine composes camera behaviors and provides separate impulse and
|
|
294
|
+
noise systems. ToonLab's camera domain uses an operator stack with event-driven impulses
|
|
295
|
+
and deterministic noise.
|
|
296
|
+
- Unity Audio Mixer snapshots support controlled transitions between mixes;
|
|
297
|
+
Soundscape transitions buses and layers rather than hard-switching graphs.
|
|
298
|
+
- Unity's Input System makes haptic support an optional device capability;
|
|
299
|
+
Game Feel uses adapters and capability checks rather than assuming a gamepad.
|
|
300
|
+
|
|
301
|
+
Primary references:
|
|
302
|
+
|
|
303
|
+
- [Unreal Engine Procedural Content Generation Framework](https://dev.epicgames.com/documentation/en-us/unreal-engine/procedural-content-generation-framework-in-unreal-engine)
|
|
304
|
+
- [Unreal Engine MetaSounds](https://dev.epicgames.com/documentation/unreal-engine/metasounds-the-next-generation-sound-sources-in-unreal-engine?lang=en-US)
|
|
305
|
+
- [Unity URP Volumes](https://docs.unity3d.com/ja/Packages/com.unity.render-pipelines.universal%4014.0/manual/Volumes.html)
|
|
306
|
+
- [Unity Cinemachine](https://docs.unity3d.com/ja/current/Manual/com.unity.cinemachine.html)
|
|
307
|
+
- [Unity Cinemachine Impulse](https://docs.unity3d.com/ja/Packages/com.unity.cinemachine%402.6/manual/CinemachineImpulse.html)
|
|
308
|
+
- [Unity Audio Mixer snapshot transitions](https://docs.unity3d.com/jp/current/ScriptReference/Audio.AudioMixer.TransitionToSnapshots.html)
|
|
309
|
+
- [Unity Input System gamepad haptics](https://docs.unity3d.com/ja/Packages/com.unity.inputsystem%401.4/api/UnityEngine.InputSystem.Gamepad.html)
|