@call-me-sensei/toonlab 0.1.1 → 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 +254 -0
- package/ATTRIBUTION.md +41 -3
- package/README.md +300 -27
- 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 +66 -6
- 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/debrisgen/debrisPresets.js +7 -0
- package/src/environment/environmentPresets.js +19 -0
- package/src/environment/environmentRigs.js +21 -1
- package/src/environment/environmentSettings.js +14 -0
- package/src/environment/environmentSunShadowPass.js +8 -0
- package/src/environment/environmentTextureResolver.js +3 -0
- package/src/environment/index.js +1 -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 +22 -4
- 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 +69 -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/rockgen/rockgenPresets.js +8 -0
- package/src/rockgen/rockgenSettings.js +47 -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 +75 -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 +488 -45
- 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 +776 -20
- 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 +631 -0
- package/src/stylizedWorld.js +903 -0
- 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 +8 -0
- package/src/vegetation/scatter.js +297 -0
- package/src/vegetation/stylizedBush.js +2 -0
- package/src/vegetation/stylizedFlower.js +82 -0
- package/src/vegetation/stylizedFlowers.js +96 -8
- package/src/vegetation/stylizedForest.js +476 -0
- package/src/vegetation/stylizedGrass.js +331 -48
- package/src/vegetation/stylizedTree.js +109 -4
- package/src/vegetation/stylizedTreeFoliage.js +13 -3
- 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 +86 -29
- package/src/water/waterSettings.js +335 -13
- package/src/water/waterShoreMaterial.js +322 -0
- package/src/water/waterShoreStateField.js +605 -0
- package/src/water/waterSurface.js +824 -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/worldCollision.js +94 -0
- package/src/worldMinimap.js +214 -0
- package/src/worldPresets.js +125 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
# ToonLab — guide for AI coding agents
|
|
2
|
+
|
|
3
|
+
You are helping a developer use `@call-me-sensei/toonlab` (alias: `toonlab`),
|
|
4
|
+
a stylized anime game kit for Three.js (WebGPU-first TSL materials, WebGL2
|
|
5
|
+
fallback; 1 world unit = 1 meter). The look is NOT in any single API — it
|
|
6
|
+
emerges from the assembly: sky feeds water reflections, an aligned sun rig +
|
|
7
|
+
three-layer fog set the palette, cloud shadows tie ground/canopy/water
|
|
8
|
+
together. Skipping the assembly produces gray, flat, "programmer-art" scenes.
|
|
9
|
+
|
|
10
|
+
## Golden path — a full world in minutes
|
|
11
|
+
|
|
12
|
+
```js
|
|
13
|
+
import { createStylizedTerrain, createStylizedWorld } from '@call-me-sensei/toonlab';
|
|
14
|
+
|
|
15
|
+
// 1. Terrain: any seed is a valid world. waterCoverage is the "more water"
|
|
16
|
+
// knob; height/depth set mountain amplitude and basin depth; size takes
|
|
17
|
+
// a number or { x, z }; floatingIslands / sinkholes are one option each.
|
|
18
|
+
const terrain = createStylizedTerrain({
|
|
19
|
+
seed: 42,
|
|
20
|
+
size: 1000,
|
|
21
|
+
archetype: 'terracedKarst', // 'lakeland' | 'alpine' | 'rollingPlains' | 'archipelago'
|
|
22
|
+
});
|
|
23
|
+
const terrainRoot = new THREE.Group();
|
|
24
|
+
terrainRoot.add(terrain.root);
|
|
25
|
+
scene.add(terrainRoot);
|
|
26
|
+
|
|
27
|
+
// 2. Everything else: environment shading, aligned sun + shadows, sky,
|
|
28
|
+
// water, LOD forests, follow-window grass, cloud shadows, collision.
|
|
29
|
+
const world = await createStylizedWorld({
|
|
30
|
+
renderer, scene, camera,
|
|
31
|
+
terrain: { heightAt: terrain.heightAt, root: terrainRoot, size: terrain.meshExtent },
|
|
32
|
+
water: { level: terrain.waterLevel },
|
|
33
|
+
followTarget: characterRoot, // splashes, wakes, grass push
|
|
34
|
+
});
|
|
35
|
+
characterRoot.position.copy(terrain.spawn); // probed: walkable, near shore
|
|
36
|
+
// render loop, before rendering:
|
|
37
|
+
world.update(delta);
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Bring your own terrain** (no generator): the ONLY contract is a pure
|
|
41
|
+
`heightAt(x, z) → meters` plus a displaced mesh under `terrain.root` with
|
|
42
|
+
`frustumCulled = false`. Everything else (masks, scatter, collision,
|
|
43
|
+
minimap) derives from `heightAt` and `water.level`. Even
|
|
44
|
+
`heightAt = (x, z) => 12 * Math.sin(x / 90) * Math.cos(z / 90)` gives a
|
|
45
|
+
complete shaded, forested, swimmable world.
|
|
46
|
+
|
|
47
|
+
Character: `applyToonShader(root, { settings: createToonSettings({ preset:
|
|
48
|
+
'call_me_sensei' }) })` + `createCharacterRenderPasses` (call
|
|
49
|
+
`passes.update()` per frame). Post: `createPostProcessingPipeline` with
|
|
50
|
+
preset `call_me_sensei`; `post.render(delta)` replaces `renderer.render`.
|
|
51
|
+
Minimap: `createWorldMinimap({ heightAt, size, waterLevel, onPick })` —
|
|
52
|
+
call `minimap.setPlayer(x, z, heading)` per frame.
|
|
53
|
+
Every cluster has a `default` and a studio-managed `call_me_sensei` preset.
|
|
54
|
+
|
|
55
|
+
## Quality rules (validated against reference-class modern anime worlds)
|
|
56
|
+
|
|
57
|
+
- Align the visible sky sun and the light rig, and match the hour: 2 PM sun
|
|
58
|
+
is HIGH (`sunDirection` y ≈ 0.8, warm-white); golden hour is LOW (y ≈ 0.4).
|
|
59
|
+
- Three-layer atmosphere: scene.fog (set by createStylizedWorld) +
|
|
60
|
+
environment heightFog (`heightFogColor` luminous blue [0.63,0.8,0.98],
|
|
61
|
+
density ≈ 0.0012–0.0016, falloff ≈ 400) + post depthCue (~0.3, blue).
|
|
62
|
+
White or absent fog is the #1 giveaway of a bad scene. EVERY custom
|
|
63
|
+
surface must join the height-fog layer or it reads as pasted on —
|
|
64
|
+
`createStylizedWorld` wires water and forest impostors automatically
|
|
65
|
+
(`setDistanceFog`); lower the density per aerial view or flyovers gray out.
|
|
66
|
+
- Cast shadows: terrain `castShadow = true`, near rocks both flags, forests
|
|
67
|
+
`lod: { castShadow: true }` (only live near trees cast — correct).
|
|
68
|
+
- Vividness is palette + saturation, not brightness: environment
|
|
69
|
+
`saturation ≈ 1.24`, `exposure ≈ 1.1`, `shadowTintColor [0.6,0.66,0.82]`,
|
|
70
|
+
saturated cerulean zenith, two-tone cumulus with blue-shaded bottoms,
|
|
71
|
+
green-dominant canopy list with ONE gold accent variant (muddy autumn
|
|
72
|
+
mixes read as confetti), turquoise water ramp.
|
|
73
|
+
- Cluster forests with `createNoisePatchMask`; tree `size` 2.5–4.
|
|
74
|
+
- Cliffs: steep faces need material, not flat paint — set
|
|
75
|
+
`material.userData.envTriplanarMap` (painted stone tile) +
|
|
76
|
+
`triplanarDetail: 1`, `triplanarDetailScale ≈ 14`,
|
|
77
|
+
`triplanarEdgeHighlight` for painted lip highlights; keep per-vertex
|
|
78
|
+
paint LOW-frequency (bands finer than the mesh grid alias into zigzag
|
|
79
|
+
triangles) and gate meadow/gold paint hard by slope.
|
|
80
|
+
- Never let ground hover within ±1.6 m of water level over large areas
|
|
81
|
+
(broken water slivers); end the map in a hazy mountain rim;
|
|
82
|
+
`frustumCulled = false` on world-scale meshes.
|
|
83
|
+
- Budgets: trees ≤ 3,000 via `StylizedForest` (16-vert billboard far LOD —
|
|
84
|
+
pass `renderer` or you get the expensive legacy path), grass ≤ 320k
|
|
85
|
+
blades in a follow window, startup < 10 s. Give every repeated mesh set
|
|
86
|
+
(rocks, cliff decor) a hi/lo distance LOD using TRUE 3D distance so
|
|
87
|
+
aerial cameras demote everything. Exclude above-water dressing from
|
|
88
|
+
water passes: `userData.waterExclude` (all passes) or
|
|
89
|
+
`waterGrabExclude` (refraction only, keeps the reflection).
|
|
90
|
+
- Perf triage: add URL toggles per system and read the FPS meter — the
|
|
91
|
+
water scene passes (grab/depth/reflection) multiply every other cost, so
|
|
92
|
+
measure with and without water first. Scale them via
|
|
93
|
+
`water.settings.passes = { reflectionScale: 0.4, sceneColorScale: 0.6 }`.
|
|
94
|
+
|
|
95
|
+
## Subpath imports
|
|
96
|
+
|
|
97
|
+
`/toon` `/environment` `/lighting` `/weather` `/water` `/vegetation` (incl. scatter helpers +
|
|
98
|
+
`StylizedForest`) `/vegetation-shaders` `/grass-palettes` `/sky` `/post` `/character` `/loaders` `/rockgen`
|
|
99
|
+
`/debrisgen` `/pathgen` `/debug`; root adds `createStylizedTerrain`,
|
|
100
|
+
`createStylizedWorld`, `createWorldCollision`, `createWorldMinimap`,
|
|
101
|
+
`resolveWorldPreset`, `createStylizedPaths`.
|
|
102
|
+
|
|
103
|
+
Authoring scope: Character/Vegetation/Environment Shader Labs save reusable
|
|
104
|
+
IP-wide material treatments; Tree/Flower/Grass and other Asset Labs save asset
|
|
105
|
+
identity and geometry; Water/Sky Labs save complete runtime-system presets
|
|
106
|
+
with their shader controls embedded, so do not create separate Water Shader or
|
|
107
|
+
Sky Shader documents. Current lighting, weather, camera, and interactions
|
|
108
|
+
remain host-owned.
|
|
109
|
+
|
|
110
|
+
Sky and Water keep authored and current-scene state separate. `.settings` is
|
|
111
|
+
the portable authored baseline; `.renderedSettings` is the composition after
|
|
112
|
+
named transient layers. Lighting, Weather, and other owners must use unique
|
|
113
|
+
ids with `setSceneOverrideLayer`, clear only their own id with
|
|
114
|
+
`clearSceneOverrideLayer`, and never persist the composed result. The manual
|
|
115
|
+
`setSceneOverrides`/`clearSceneOverrides` pair owns only the `scene` layer;
|
|
116
|
+
`clearAllSceneOverrideLayers` is for explicit host teardown.
|
|
117
|
+
|
|
118
|
+
`lighting.attachWorld(world)` owns the world sun adapter plus private
|
|
119
|
+
priority-100 Sky/Water layers. If Weather is present it also installs Lighting
|
|
120
|
+
as Weather's sun/ambient/fog bridge: Lighting remains the sole writer, Weather
|
|
121
|
+
provides modulation and private priority-200 Sky/Water layers, and either
|
|
122
|
+
system removes only its own state on detach/dispose.
|
|
123
|
+
The adapter is `world.setSun({ direction, color, sky })`; it aligns the real
|
|
124
|
+
light/shadows with Grass, Flower, Forest, Ambient FX, Sky, and Water inputs.
|
|
125
|
+
For a standalone custom Weather coordinator, supply paired `getSun`/`setSun`
|
|
126
|
+
and baselines for any write-only cloud/surface adapters so teardown is exact.
|
|
127
|
+
|
|
128
|
+
Sky documents contain exactly 46 portable art fields; constructor-only radius
|
|
129
|
+
and quality are excluded. Sky quality is compile-time (`low`/`medium`/`high`
|
|
130
|
+
= 2/3/4 cloud octaves, or custom `{ cloudOctaves: 1..5 }`), and
|
|
131
|
+
`sky.setQuality()` rebuilds the material while preserving authored/layered
|
|
132
|
+
state. Water quality is selected when constructing `WaterSurface`; a tier
|
|
133
|
+
change requires replacing/rebuilding the surface, never `applySettings()`.
|
|
134
|
+
|
|
135
|
+
Lighting (`/lighting`) owns portable, versioned recipes and looks rather than
|
|
136
|
+
a replacement renderer. Use `createLightingManager({ scene, camera, renderer,
|
|
137
|
+
recipe, quality })`, call `update()` as the focus/camera moves, and save JSON
|
|
138
|
+
with the recipe/look serializers. Luminaire, rig, look, and quality presets
|
|
139
|
+
come from `getLightingPresetOptions(kind)`. Disc/tube area lights, IES, tag
|
|
140
|
+
linking, and Unreal Engine 5.8 MegaLights/Lumen are explicit adapter intent;
|
|
141
|
+
the capability report and diagnostics state each runtime fallback. Author and
|
|
142
|
+
stress-test them in `/lighting-lab/`.
|
|
143
|
+
|
|
144
|
+
`createLightingManager` is the lower-level rig-realization API. For a composed
|
|
145
|
+
world and day cycle, use `createLightingSystem(...)`, then call
|
|
146
|
+
`lighting.attachWorld(world)` for the sun/Sky/Water ownership and Weather
|
|
147
|
+
modulation bridge described above.
|
|
148
|
+
|
|
149
|
+
Paths/roads/bridges: `createStylizedWorld({ paths: { seed, auto: { count: 4,
|
|
150
|
+
styles: ['dirt', 'stone'] } } })` routes seeded trails around slopes, bridges
|
|
151
|
+
water crossings, parts grass/trees around the ribbon, and feeds the flattened
|
|
152
|
+
profile to `world.collision.groundHeight` — use that (not raw `heightAt`) for
|
|
153
|
+
character ground so bridges carry the walk. Minimap: pass `paths: world.paths`
|
|
154
|
+
to `createWorldMinimap` for the network overlay.
|
|
155
|
+
|
|
156
|
+
Catalog (`@call-me-sensei/toonlab/catalog`): the whole procedural library,
|
|
157
|
+
queryable and spawnable —
|
|
158
|
+
`catalog.list({ tags, cluster, text })`, `catalog.get(id)`, and the headline
|
|
159
|
+
`catalog.spawn(id, { seed })` → a PropAsset for any prop / building / tree /
|
|
160
|
+
rock / debris entry (settings presets throw with their copy-paste snippet
|
|
161
|
+
instead). `catalog.register(entry)` adds user assets;
|
|
162
|
+
`catalog.addSource(url, { headers })` mounts remote registries (the pro
|
|
163
|
+
seam). The browser Gallery at `/gallery/` searches third-party open assets;
|
|
164
|
+
the procedural Catalog itself is a runtime API rather than a standalone lab.
|
|
165
|
+
|
|
166
|
+
Villages (`/villagegen`): `createStylizedWorld({ pois: { seed, villages: 2,
|
|
167
|
+
shrines: 1, pierHamlets: 1, size } })` → named settlements (seeded syllable
|
|
168
|
+
names) with streets merged into the world path network, buildings facing
|
|
169
|
+
their street behind picket fences, wells/lanterns/clutter by archetype, POI
|
|
170
|
+
entries auto-connected by roads. `world.pois` feeds
|
|
171
|
+
`createWorldMinimap({ markers })` labels. Fully-shadowed building facades
|
|
172
|
+
need `parameters.sunShadowStrength ≈ 0.7` in worlds that run near-zero
|
|
173
|
+
ambient (full-strength cast shadows crush large vertical masses to black).
|
|
174
|
+
|
|
175
|
+
Fauna (`/fauna`) and ambient VFX (`/ambientfx`) are one option each:
|
|
176
|
+
`createStylizedWorld({ fauna: { species: { birds: 40, fish: 80 } },
|
|
177
|
+
ambientfx: { effects: { petals: true, fireflies: true } } })` — both join
|
|
178
|
+
the world's fog/wind/cloud-shadow automatically.
|
|
179
|
+
|
|
180
|
+
Weather (`/weather`) is a cross-system coordinator, not an environment
|
|
181
|
+
catch-all: `createStylizedWorld({ weather: { preset: 'snow' } })`, then
|
|
182
|
+
`world.setWeather('thunderstorm', { duration: 4 })`. Its 22 shared presets
|
|
183
|
+
drive sky/sun/fog/cloud shadows, wind across vegetation/fauna/ambient FX,
|
|
184
|
+
one-draw GPU rain/snow/sleet/hail/dust, water waves/ripples, lightning and
|
|
185
|
+
thunder events. Surface `{ wetness, snowCover, ice }` values are host-facing
|
|
186
|
+
outputs for custom terrain/prop/character materials. Labs should read
|
|
187
|
+
`getWeatherPresetOptions()` rather than maintaining a private condition list.
|
|
188
|
+
|
|
189
|
+
Gameplay VFX (`/vfxgen`): event-driven combat/movement effects, spawned at
|
|
190
|
+
gameplay moments (not a world option) — `createVfxSystem({ seed, preset,
|
|
191
|
+
heightAt })` then `vfx.spawn('slash' | 'impact' | 'fireball' | 'footstep' |
|
|
192
|
+
'landing', { at | follow, power, look })` and `vfx.update(delta, camera)`
|
|
193
|
+
per frame. All bursts share TWO draw calls; slash trails / fireball cores
|
|
194
|
+
are pooled meshes. `vfx.setDistanceFog(...)` joins the height-fog layer;
|
|
195
|
+
`vfx.setTimeScale(0)` is hit-stop. Weapons + moves are batteries-included:
|
|
196
|
+
`createStylizedWeapon({ type: 'sword' | 'greatsword' | 'spear' | 'dagger'
|
|
197
|
+
| 'hammer' })` + `createMoveController({ weapon, vfx })` →
|
|
198
|
+
`attack.play('slash' | 'overhead' | 'thrust' | 'spin' | 'plunge')` — authored
|
|
199
|
+
phase-based motions whose event tracks fire the VFX at the right beats
|
|
200
|
+
(plunge = the full crouch→leap→dive→landfall decomposition); weapon weight
|
|
201
|
+
scales timing and hit power. Design interactively in the VFX Lab
|
|
202
|
+
(`/vfx-lab/`): weapon picker + move triggers + schema panels, exports a
|
|
203
|
+
recipe (preset + seed + overrides) that drops straight into `createVfxSystem`.
|
|
204
|
+
The `call_me_sensei` preset targets the reference action-RPG hit language
|
|
205
|
+
(smooth gradient arcs, four-point star + shockwave circle per hit,
|
|
206
|
+
hard-saturated pyro fireball). Demo loop: `examples/vfx-arena/`.
|
|
207
|
+
|
|
208
|
+
Buildings (`/buildinggen`): seeded grammar exteriors —
|
|
209
|
+
`buildingAsset({ type: 'cottage' | 'shed' | 'farmhouse' | 'watchtower' |
|
|
210
|
+
'shrine', seed })` is a PropAsset (multi-circle footprint, buried foundation
|
|
211
|
+
skirt for slopes ≤ ~20°, hi/lo LOD, `door` anchor with outward normal for
|
|
212
|
+
street-facing placement). `createBuildingFromRecipe(recipe)` rebuilds
|
|
213
|
+
deterministically; ≤ 6 draw calls per building.
|
|
214
|
+
|
|
215
|
+
Props (`/propgen`): every placeable thing is a PropAsset —
|
|
216
|
+
`createPropAsset({ asset: { type: 'lantern', variant: 'stoneToro', seed } })`
|
|
217
|
+
or `propAssetFromObject(importedGlb)` (auto footprint + ground anchor).
|
|
218
|
+
Place with ONE call: `placeAlongSpline({ asset, spline: world.paths.splines[0],
|
|
219
|
+
spacing, offset, mask, heightAt: world.paths.heightAt, collision:
|
|
220
|
+
world.collision, parent })` (fences/walls build continuously; point props
|
|
221
|
+
instance with hi/lo LOD — call the returned `update(delta, camera)` per
|
|
222
|
+
frame), or `scatterProps`/`placeProps`. Props added after `createStylizedWorld`
|
|
223
|
+
need `applyEnvironmentShader(propsRoot, { parameters: { …fog } })` to join the
|
|
224
|
+
look; pass a dry-land `mask` so dressing never marches into water.
|
|
225
|
+
|
|
226
|
+
## Symptom table — check before debugging blind
|
|
227
|
+
|
|
228
|
+
| Looks like | Cause → fix |
|
|
229
|
+
|---|---|
|
|
230
|
+
| Terrain gray/flat | environment shader never applied → put meshes under `terrain.root` |
|
|
231
|
+
| Distant trees sharp saturated dots on hazed mountains | surface missing the height-fog layer → update ToonLab (impostors/water auto-wired via `setDistanceFog`); custom surfaces must join it |
|
|
232
|
+
| Distant water bright band "cutting into" mountains | same fog-layer mismatch → `waterSurface.setDistanceFog({ color, density })` |
|
|
233
|
+
| Giant white "iceberg" wedges at far shorelines | outdated ToonLab (swash film climbed steep banks) → update |
|
|
234
|
+
| Full-detail trees popping in aerial views | LOD by horizontal distance → update ToonLab (3D distance) |
|
|
235
|
+
| Gold/orange tree with green-shadow or pink-crown leaves | outdated ToonLab (palette derivation broke on warm hues) → update |
|
|
236
|
+
| Billboards upside down / trunk-up | render-target bakes are written top-down → update ToonLab |
|
|
237
|
+
| Trees like confetti from the air | uniform scatter → `createNoisePatchMask`; palette too mixed → green-dominant + one gold |
|
|
238
|
+
| White valley blotches | white height fog → sky-blue `heightFogColor` |
|
|
239
|
+
| Fog has no effect | `heightFogFalloff` too small → ≈ 400 |
|
|
240
|
+
| Everything pale/gray from the air | one fog density for all views → lower `heightFogDensity` for aerial cameras (terrain uniforms + `water/forest.setDistanceFog`) |
|
|
241
|
+
| Cliff walls flat, untextured up close | planar UVs stretch on walls → `envTriplanarMap` + `triplanarDetail` |
|
|
242
|
+
| Zigzag triangles on cliff walls | per-vertex paint finer than the grid, or hue bleeding through stone → low-frequency bands; luminance-only tint is built in |
|
|
243
|
+
| Flat light, no shadows | vertical/misaligned sun, nothing casts → align sun, enable castShadow |
|
|
244
|
+
| Mountains vanish when centered | frustum culling on displaced meshes → `frustumCulled = false` |
|
|
245
|
+
| Minute-long startup | unique tree per placement → `StylizedForest` |
|
|
246
|
+
| ~20 fps in a big world | full-res meshes in every water pass → billboard forests (pass `renderer`), hi/lo rock LOD, `waterExclude`/`waterGrabExclude`, pass scales, `?dpr=1` on retina |
|
|
247
|
+
| Character walks through rocks/trees | blockers unregistered → `world.collision.addCircles([{x,z,radius}])` + `world.collision.resolve(character.position, 0.35)` per frame (trunks are pre-registered) |
|
|
248
|
+
| Character floats over/sinks into water | float on `water.getHeightAt(x, z)` with chest at the waterline; calm swim default, fast stroke on Shift, `action.timeScale = clamp(speed/1.7, 0.75, 1.35)` |
|
|
249
|
+
|
|
250
|
+
Full runbook with budgets and verification workflow:
|
|
251
|
+
`agents/skills/*/outdoor-world/SKILL.md` in the repo; complete reference
|
|
252
|
+
app: `examples/outdoor-world/`. Verify by headless Playwright screenshot
|
|
253
|
+
(`--enable-unsafe-webgpu --enable-gpu`), not by assumption — and LOOK at
|
|
254
|
+
the images.
|
package/ATTRIBUTION.md
CHANGED
|
@@ -8,9 +8,18 @@ Code is MIT-licensed by Hyperbond Studio PTE. LTD. (see LICENSE). The assets bun
|
|
|
8
8
|
|---|---|---|---|
|
|
9
9
|
| Mannequin character (45 embedded animation clips) | `public/characters/mannequin.glb` | CC0 1.0 | [Quaternius — Universal Animation Library](https://quaternius.com/packs/universalanimationlibrary.html), recolored to neutral grays. See `public/characters/LICENSE.md`. |
|
|
10
10
|
| Landscape textures (grassy-land, land, mountain, rock, sand, tree-trunk) | `labs/shared/textures/` | CC0 1.0 | First-party (created by the toonlab authors), dedicated to the public domain. |
|
|
11
|
+
| Water Lab sea fern model | `public/water-lab/cc0/quaternius/fern-1.glb` | CC0 1.0 | [Quaternius — Fern 1, Stylized Nature MegaKit](https://quaternius.itch.io/stylized-nature-megakit), selected through the [ToonLab catalog](https://toonlab.io/asset/quaternius:stylized-nature-megakit-fern-1). |
|
|
12
|
+
| Water Lab Coast Sand 01 texture set | `public/water-lab/cc0/polyhaven/` | CC0 1.0 | [Rob Tuytel — Coast Sand 01, Poly Haven](https://polyhaven.com/a/coast_sand_01), selected through the [ToonLab catalog](https://toonlab.io/asset/polyhaven:coast_sand_01). |
|
|
13
|
+
| City street models (buildings, roads, cars, street props — 28 models) | `public/props/cc0/kaykit-city/` | CC0 1.0 | [Kay Lousberg — KayKit City Builder Bits](https://kaylousberg.com). Attribution optional under CC0; credited with thanks. See the bundled `LICENSE.txt`. |
|
|
14
|
+
| Furniture models (tables, chairs, couch, lamps, shelves — 17 models) | `public/props/cc0/kaykit-furniture/` | CC0 1.0 | [Kay Lousberg — KayKit Furniture Bits](https://kaylousberg.com). Attribution optional under CC0; credited with thanks. See the bundled `LICENSE.txt`. |
|
|
15
|
+
| Environment Lab Wood Floor texture | `public/environments/cc0/polyhaven/wood-floor-diff-1k.jpg` | CC0 1.0 | [Dimitrios Savva — Wood Floor, Poly Haven](https://polyhaven.com/a/wood_floor) |
|
|
16
|
+
| Environment Lab Painted Plaster Wall texture | `public/environments/cc0/polyhaven/painted-plaster-wall-diff-1k.jpg` | CC0 1.0 | [Amal Kumar — Painted Plaster Wall, Poly Haven](https://polyhaven.com/a/painted_plaster_wall) |
|
|
17
|
+
| Environment Lab photoscanned furniture (Sofa 02, Modern Arm Chair 01, Round Wooden Table 01, Classic Console 01, Steel Frame Shelves 01, Potted Plant 04) | `public/environments/cc0/polyhaven/models/` | CC0 1.0 | [Poly Haven models](https://polyhaven.com/models) (1k glTF), per-asset credits on each asset page |
|
|
18
|
+
| Environment Lab museum scans (baluster vase F1980.190-.194; Colonoware pot) | `public/environments/cc0/smithsonian/` | CC0 1.0 | [Smithsonian Open Access 3D](https://3d.si.edu), selected through the [ToonLab catalog](https://toonlab.io/gallery?src=smithsonian) |
|
|
19
|
+
| Draco + Basis decoders (model decompression) | `public/draco/`, `public/basis/` | Apache 2.0 | [google/draco](https://github.com/google/draco), [BinomialLLC/basis_universal](https://github.com/BinomialLLC/basis_universal) — bundled three.js decoder builds |
|
|
11
20
|
|
|
12
21
|
Everything else that renders — water, sky, grass, flowers, trees, foliage,
|
|
13
|
-
splashes, post-processing — is procedural code
|
|
22
|
+
splashes, post-processing — is procedural code.
|
|
14
23
|
|
|
15
24
|
## Not bundled (bring your own)
|
|
16
25
|
|
|
@@ -32,9 +41,38 @@ folder that is **not** part of this repository:
|
|
|
32
41
|
|
|
33
42
|
## Recommended free sources
|
|
34
43
|
|
|
44
|
+
The machine-readable version of this list (license facts, integration level,
|
|
45
|
+
quality tier, enable/disable flags) is `src/assetlib/sources.js`; the Asset
|
|
46
|
+
Browser lab surfaces it.
|
|
47
|
+
|
|
35
48
|
- [Quaternius](https://quaternius.com) — CC0 models + the Universal
|
|
36
|
-
Animation Library (v1 and v2 free tiers)
|
|
49
|
+
Animation Library (v1 and v2 free tiers); most of the catalog is
|
|
50
|
+
searchable via Poly Pizza.
|
|
37
51
|
- [Poly Haven](https://polyhaven.com) — CC0 textures/HDRIs/models.
|
|
38
|
-
- [Kenney](https://kenney.nl) — CC0 game assets.
|
|
52
|
+
- [Kenney](https://kenney.nl) — CC0 game assets (no file API; manual import).
|
|
53
|
+
- [KayKit](https://kaylousberg.com) — CC0 stylized low-poly packs (city,
|
|
54
|
+
furniture, dungeon, characters …) on GitHub; integrated in the Asset
|
|
55
|
+
Browser (disabled by default — below the platform quality bar).
|
|
56
|
+
Attribution optional; credited with thanks.
|
|
57
|
+
- [Open Source 3D Assets](https://opensource3dassets.com) — keyless CC0
|
|
58
|
+
registry (Polygonal Mind collections); integrated, pending quality review.
|
|
59
|
+
- [Poly Pizza](https://poly.pizza) — low-poly aggregator, CC0/CC-BY
|
|
60
|
+
(BYO free API key).
|
|
61
|
+
- [Smithsonian 3D Open Access](https://3d.si.edu) — museum scans; only
|
|
62
|
+
records explicitly marked CC0.
|
|
63
|
+
- [Sketchfab CC0 search](https://sketchfab.com/search?features=downloadable&licenses=cc0&type=models)
|
|
64
|
+
— download manually (their download API is per-user OAuth with branding
|
|
65
|
+
terms; deliberately not automated).
|
|
66
|
+
- [The Base Mesh](https://thebasemesh.com) — CC0 base meshes (manual import).
|
|
67
|
+
- [3DTextures.me](https://3dtextures.me) — CC0 stylized materials
|
|
68
|
+
(manual import).
|
|
69
|
+
- [TextureCan](https://www.texturecan.com) — CC0 textures (manual import).
|
|
70
|
+
- [ShareTextures](https://www.sharetextures.com) — CC0 files, but their
|
|
71
|
+
platform terms prohibit automated downloads/hotlinking — browse manually
|
|
72
|
+
only, never wire an adapter.
|
|
39
73
|
- [OpenGameArt](https://opengameart.org) — filter by CC0/CC-BY.
|
|
74
|
+
- [Openverse](https://openverse.org) — openly licensed images/audio
|
|
75
|
+
(per-record license).
|
|
76
|
+
- [Freesound](https://freesound.org) — sounds; free API tier is
|
|
77
|
+
non-commercial.
|
|
40
78
|
- [VRoid Hub](https://hub.vroid.com) — VRM avatars (check per-model terms).
|