@call-me-sensei/toonlab 0.4.19 → 0.4.21
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/NPM-LIBRARY.md +230 -0
- package/README.md +78 -36
- package/agents/PROMPTS.md +91 -0
- package/agents/README.md +9 -14
- package/agents/claude/CLAUDE.md +8 -0
- package/agents/codex/AGENTS.md +161 -0
- package/agents/cursor/toonlab.mdc +37 -0
- package/agents/references/mcp-asset-discovery.md +12 -9
- package/agents/references/runtime-entry-points.md +5 -4
- package/agents/skills/claude/asset-sourcing/SKILL.md +9 -6
- package/agents/skills/claude/rock-ground-shaders/SKILL.md +16 -0
- package/agents/skills/claude/vegetation-sky/SKILL.md +7 -4
- package/agents/skills/codex/asset-sourcing/SKILL.md +9 -6
- package/agents/skills/codex/rock-ground-shaders/SKILL.md +16 -0
- package/agents/skills/codex/vegetation-sky/SKILL.md +7 -4
- package/cli/toonlab.mjs +3 -2
- package/database/fal-patina.mjs +131 -0
- package/database/generation-service.mjs +108 -7
- package/database/migrations/0007_creation_revisions.sql +80 -0
- package/database/migrations/0008_creation_revision_hardening.sql +98 -0
- package/database/migrations/0009_creation_revision_delete_integrity.sql +11 -0
- package/database/migrations/0010_external_catalog_assets.sql +28 -0
- package/database/providers.mjs +195 -16
- package/database/repository.mjs +518 -70
- package/database/seeds/catalog/0003_2026-08-open-assets.sql +159086 -0
- package/database/seeds/catalog/0004_2026-08-c7-rocks.sql +39405 -0
- package/mcp/public-catalog.mjs +4 -52
- package/mcp/server.mjs +175 -12
- package/mcp/vite-plugin.mjs +78 -2
- package/package.json +32 -12
- package/scripts/generate-catalog-seed.mjs +34 -7
- package/src/asset-policy/catalogLicenses.js +64 -6
- package/src/assetlib/loadImported.js +15 -1
- package/src/catalog/officialCatalogAssetRuntime.js +13 -2
- package/src/catalog/officialCatalogLod.js +34 -1
- package/src/catalog/officialCatalogPlacement.js +29 -14
- package/src/character/animationRetarget.js +2 -0
- package/src/character/characterRig.js +6 -1
- package/src/character/characterRuntime.js +175 -7
- package/src/environment/environmentMaterialAdapter.js +30 -0
- package/src/environment/environmentPresets.js +90 -0
- package/src/environment/environmentSunShadowPass.js +42 -0
- package/src/environment/toonLabSurfaceLighting.js +108 -10
- package/src/environment/urbanPropMaterial.js +104 -2
- package/src/lighting/lightingSystem.js +65 -10
- package/src/renderer/index.js +7 -0
- package/src/renderer/styleComparison.js +985 -0
- package/src/rock-shader/index.js +5 -0
- package/src/rock-shader/rockGeometryDetail.js +701 -0
- package/src/rock-shader/rockMaterial.js +782 -39
- package/src/rock-shader/rockRegionRuntime.js +185 -0
- package/src/rock-shader/rockSemanticMaterialRuntime.js +337 -0
- package/src/rock-shader/rockShaderRuntime.js +354 -67
- package/src/rock-shader/rockShaderSettings.js +246 -16
- package/src/rock-shader/rockTangentIntegrity.js +136 -0
- package/src/rock-shader/rockTextureIntegrity.js +115 -0
- package/src/rockgen/index.js +1 -0
- package/src/rockgen/rockDocument.js +27 -3
- package/src/rockgen/surface/c7GeologySurface.js +372 -0
- package/src/shaders-tsl/water.js +8 -0
- package/src/sky/cloudShadow.js +25 -1
- package/src/sky/skySystem.js +9 -0
- package/src/styles/index.js +23 -0
- package/src/styles/neutralStylePresets.js +712 -0
- package/src/styles/sceneStyleRuntime.js +51 -4
- package/src/styles/styleAdapters.js +13 -2
- package/src/styles/styleBundle.js +1 -1
- package/src/texgen/evaluateTexture.js +30 -3
- package/src/texgen/textureGenerators.js +63 -31
- package/src/texgen/textureSettings.js +25 -8
- package/src/toon/toonSettings.js +96 -2
- package/src/vegetation/branchTree.js +327 -42
- package/src/vegetation/index.js +24 -2
- package/src/vegetation/scatter.js +372 -1
- package/src/vegetation/stylizedTree.js +312 -126
- package/src/vegetation/stylizedTreeFoliage.js +229 -7
- package/src/vegetation/treeSurfaceTextures.js +328 -0
- package/src/version.js +1 -1
- package/src/water/waterSettings.js +15 -7
- package/types/asset-policy/catalogLicenses.d.ts +2 -0
- package/types/asset-policy/index.d.ts +2 -0
- package/types/assetlib/loadImported.d.ts +3 -1
- package/types/catalog/officialCatalogLod.d.ts +63 -5
- package/types/character/characterRig.d.ts +59 -0
- package/types/character/characterRuntime.d.ts +1 -0
- package/types/environment/environmentMaterialAdapter.d.ts +3 -1
- package/types/environment/toonLabSurfaceLighting.d.ts +20 -3
- package/types/index.d.ts +89 -7
- package/types/lighting/lightingSystem.d.ts +7 -0
- package/types/react/index.d.ts +20 -0
- package/types/renderer/index.d.ts +1 -0
- package/types/renderer/styleComparison.d.ts +409 -0
- package/types/rock-shader/index.d.ts +5 -0
- package/types/rock-shader/rockGeometryDetail.d.ts +300 -0
- package/types/rock-shader/rockMaterial.d.ts +3 -0
- package/types/rock-shader/rockRegionRuntime.d.ts +86 -0
- package/types/rock-shader/rockSemanticMaterialRuntime.d.ts +29 -0
- package/types/rock-shader/rockShaderRuntime.d.ts +2 -0
- package/types/rock-shader/rockShaderSettings.d.ts +19 -5
- package/types/rock-shader/rockTangentIntegrity.d.ts +51 -0
- package/types/rock-shader/rockTextureIntegrity.d.ts +61 -0
- package/types/rockgen/index.d.ts +1 -0
- package/types/rockgen/rockDocument.d.ts +29 -1
- package/types/rockgen/surface/c7GeologySurface.d.ts +8 -0
- package/types/sky/cloudShadow.d.ts +1 -0
- package/types/styles/index.d.ts +1 -0
- package/types/styles/neutralStylePresets.d.ts +944 -0
- package/types/styles/sceneStyleRuntime.d.ts +20 -0
- package/types/vegetation/branchTree.d.ts +4 -0
- package/types/vegetation/index.d.ts +9 -7
- package/types/vegetation/scatter.d.ts +1 -0
- package/types/vegetation/stylizedTree.d.ts +1 -2
- package/types/vegetation/stylizedTreeFoliage.d.ts +1 -0
- package/types/version.d.ts +1 -1
- package/agents/references/geology-playbook.md +0 -118
- package/agents/skills/claude/karst-cliff-construction/SKILL.md +0 -258
- package/agents/skills/claude/outdoor-world/SKILL.md +0 -492
- package/agents/skills/claude/outdoor-world/references/coastal-landform-formation.md +0 -100
- package/agents/skills/codex/karst-cliff-construction/SKILL.md +0 -258
- package/agents/skills/codex/outdoor-world/SKILL.md +0 -492
- package/agents/skills/codex/outdoor-world/references/coastal-landform-formation.md +0 -100
- package/src/vegetation/legacyTreePresets.js +0 -120
- package/types/vegetation/legacyTreePresets.d.ts +0 -22
|
@@ -80,6 +80,7 @@ export function createSceneStyleRuntime({ collision, collisionAdapter, collision
|
|
|
80
80
|
z: number;
|
|
81
81
|
};
|
|
82
82
|
};
|
|
83
|
+
setSunDirection(direction?: any): any[];
|
|
83
84
|
advanceTime(hoursDelta: any): {
|
|
84
85
|
accentScale: any;
|
|
85
86
|
ambientScale: any;
|
|
@@ -311,6 +312,7 @@ export function createSceneStyleRuntime({ collision, collisionAdapter, collision
|
|
|
311
312
|
z: number;
|
|
312
313
|
};
|
|
313
314
|
};
|
|
315
|
+
readonly sunDirection: any[];
|
|
314
316
|
readonly manager: {
|
|
315
317
|
addLight: (descriptorSource: any) => string;
|
|
316
318
|
addToScene: (nextScene: any) => /*elided*/ any;
|
|
@@ -578,6 +580,7 @@ export function createSceneStyleRuntime({ collision, collisionAdapter, collision
|
|
|
578
580
|
z: number;
|
|
579
581
|
};
|
|
580
582
|
};
|
|
583
|
+
setSunDirection(direction?: any): any[];
|
|
581
584
|
advanceTime(hoursDelta: any): {
|
|
582
585
|
accentScale: any;
|
|
583
586
|
ambientScale: any;
|
|
@@ -809,6 +812,7 @@ export function createSceneStyleRuntime({ collision, collisionAdapter, collision
|
|
|
809
812
|
z: number;
|
|
810
813
|
};
|
|
811
814
|
};
|
|
815
|
+
readonly sunDirection: any[];
|
|
812
816
|
readonly manager: {
|
|
813
817
|
addLight: (descriptorSource: any) => string;
|
|
814
818
|
addToScene: (nextScene: any) => /*elided*/ any;
|
|
@@ -1083,6 +1087,7 @@ export function createSceneStyleRuntime({ collision, collisionAdapter, collision
|
|
|
1083
1087
|
z: number;
|
|
1084
1088
|
};
|
|
1085
1089
|
};
|
|
1090
|
+
setSunDirection(direction?: any): any[];
|
|
1086
1091
|
/**
|
|
1087
1092
|
* Replaces the physical SkySystem condition while preserving the active
|
|
1088
1093
|
* style bundle's sky/cloud presentation and coordinated lighting frame.
|
|
@@ -1352,6 +1357,7 @@ export function createSceneStyleRuntime({ collision, collisionAdapter, collision
|
|
|
1352
1357
|
z: number;
|
|
1353
1358
|
};
|
|
1354
1359
|
};
|
|
1360
|
+
setSunDirection(direction?: any): any[];
|
|
1355
1361
|
advanceTime(hoursDelta: any): {
|
|
1356
1362
|
accentScale: any;
|
|
1357
1363
|
ambientScale: any;
|
|
@@ -1583,6 +1589,7 @@ export function createSceneStyleRuntime({ collision, collisionAdapter, collision
|
|
|
1583
1589
|
z: number;
|
|
1584
1590
|
};
|
|
1585
1591
|
};
|
|
1592
|
+
readonly sunDirection: any[];
|
|
1586
1593
|
readonly manager: {
|
|
1587
1594
|
addLight: (descriptorSource: any) => string;
|
|
1588
1595
|
addToScene: (nextScene: any) => /*elided*/ any;
|
|
@@ -1751,8 +1758,21 @@ export function createSceneStyleRuntime({ collision, collisionAdapter, collision
|
|
|
1751
1758
|
uncoveredTargetIds: readonly any[];
|
|
1752
1759
|
}>;
|
|
1753
1760
|
readonly ready: boolean;
|
|
1761
|
+
readonly health: Readonly<{
|
|
1762
|
+
backend: "node" | "classic-webgl-unused";
|
|
1763
|
+
casterCount: number;
|
|
1764
|
+
farReady: boolean;
|
|
1765
|
+
hiddenNonCasterCount: number;
|
|
1766
|
+
ok: boolean;
|
|
1767
|
+
ready: boolean;
|
|
1768
|
+
reason: string;
|
|
1769
|
+
renderCount: number;
|
|
1770
|
+
sunName: any;
|
|
1771
|
+
}>;
|
|
1754
1772
|
readonly renderCount: number;
|
|
1755
1773
|
readonly shadowTexture: any;
|
|
1774
|
+
readonly nearShadowTarget: any;
|
|
1775
|
+
readonly farShadowTarget: any;
|
|
1756
1776
|
readonly shadowMatrix: import("three").Matrix4;
|
|
1757
1777
|
readonly farShadowTexture: any;
|
|
1758
1778
|
dispose: () => void;
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
// Source inference fallback: public names retained with permissive signatures.
|
|
2
|
+
export const BRANCH_TREE_ARCHITECTURE: any;
|
|
3
|
+
export const BRANCH_TREE_CANOPY_ARCHITECTURES: any;
|
|
2
4
|
export const BRANCH_TREE_DOCUMENT_TYPE: any;
|
|
3
5
|
export const BRANCH_TREE_DOCUMENT_VERSION: any;
|
|
4
6
|
export const BRANCH_TREE_LEAF_SHAPES: any;
|
|
5
7
|
export class BranchTree { constructor(...args: any[]); [key: string]: any; }
|
|
6
8
|
export const DEFAULT_BRANCH_TREE_SETTINGS: any;
|
|
9
|
+
export function branchTreeStylizedOptions(...args: any[]): any;
|
|
7
10
|
export function createBranchTree(...args: any[]): any;
|
|
8
11
|
export function createBranchTreeDocument(...args: any[]): any;
|
|
12
|
+
export function createBranchTreeRecipe(...args: any[]): any;
|
|
9
13
|
export function createBranchTreeSettings(...args: any[]): any;
|
|
10
14
|
export function parseBranchTreeDocument(...args: any[]): any;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// Source inference fallback: public names retained with permissive signatures.
|
|
2
2
|
export const BARK_SHADER: any;
|
|
3
|
+
export const BRANCH_TREE_ARCHITECTURE: any;
|
|
4
|
+
export const BRANCH_TREE_CANOPY_ARCHITECTURES: any;
|
|
3
5
|
export const BRANCH_TREE_DOCUMENT_TYPE: any;
|
|
4
6
|
export const BRANCH_TREE_DOCUMENT_VERSION: any;
|
|
5
7
|
export const BRANCH_TREE_LEAF_SHAPES: any;
|
|
@@ -37,11 +39,9 @@ export const GRASS_SHADER_PROFILE: any;
|
|
|
37
39
|
export const GRASS_SHADER_PROFILE_DOCUMENT_TYPE: any;
|
|
38
40
|
export const GRASS_SHADER_PROFILE_SCHEMA_VERSION: any;
|
|
39
41
|
export const LEAF_SHAPE_PRESETS: any;
|
|
40
|
-
export const
|
|
41
|
-
export const LEGACY_TREE_PRESETS: any;
|
|
42
|
+
export const NEEDLE_LEAF_SHAPES: any;
|
|
42
43
|
export class RetainedGrassClumpField { constructor(...args: any[]); [key: string]: any; }
|
|
43
44
|
export const STYLIZED_FOREST_IMPOSTOR_QUALITY: any;
|
|
44
|
-
export const STYLIZED_TREE_EXAMPLES: any;
|
|
45
45
|
export const STYLIZED_TREE_SETTING_FIELD_SCHEMA: any;
|
|
46
46
|
export const STYLIZED_TREE_SETTING_GROUPS: any;
|
|
47
47
|
export class StylizedBush { constructor(...args: any[]); [key: string]: any; }
|
|
@@ -63,6 +63,7 @@ export const TREE_SHADER_DOCUMENT_TYPE: any;
|
|
|
63
63
|
export const TREE_SHADER_PROFILE: any;
|
|
64
64
|
export const TREE_SHADER_SCHEMA_VERSION: any;
|
|
65
65
|
export const TREE_SURFACE_PROFILES: any;
|
|
66
|
+
export const TREE_SURFACE_PROFILE_ALIASES: any;
|
|
66
67
|
export const TREE_SURFACE_PROFILE_DEFAULTS: any;
|
|
67
68
|
export const TREE_TRUNK_STYLES: any;
|
|
68
69
|
export const UNDERSTORY_AERIAL_FADE: any;
|
|
@@ -89,6 +90,7 @@ export function applyGrassShader(...args: any[]): any;
|
|
|
89
90
|
export function applyVegetationShader(...args: any[]): any;
|
|
90
91
|
export function applyVegetationShaderScope(...args: any[]): any;
|
|
91
92
|
export function bakeFoliageGeometry(...args: any[]): any;
|
|
93
|
+
export function branchTreeStylizedOptions(...args: any[]): any;
|
|
92
94
|
export function combineMasks(...args: any[]): any;
|
|
93
95
|
export function createBakedFoliageMaterial(...args: any[]): any;
|
|
94
96
|
export function createBakedLeafTexture(...args: any[]): any;
|
|
@@ -96,6 +98,7 @@ export function createBarkGradientMap(...args: any[]): any;
|
|
|
96
98
|
export function createBarkShaderSettings(...args: any[]): any;
|
|
97
99
|
export function createBranchTree(...args: any[]): any;
|
|
98
100
|
export function createBranchTreeDocument(...args: any[]): any;
|
|
101
|
+
export function createBranchTreeRecipe(...args: any[]): any;
|
|
99
102
|
export function createBranchTreeSettings(...args: any[]): any;
|
|
100
103
|
export function createBranchTubeGeometry(...args: any[]): any;
|
|
101
104
|
export function createBranchingTreeSkeleton(...args: any[]): any;
|
|
@@ -103,6 +106,7 @@ export function createCallMeSenseiGrassField(...args: any[]): any;
|
|
|
103
106
|
export function createCallMeSenseiGrassMaterial(...args: any[]): any;
|
|
104
107
|
export function createCanopyBlobs(...args: any[]): any;
|
|
105
108
|
export function createCapEdgeWeight(...args: any[]): any;
|
|
109
|
+
export function createCurveFrame(...args: any[]): any;
|
|
106
110
|
export function createDensityWeightMask(...args: any[]): any;
|
|
107
111
|
export function createFlowerBloomNodeMaterial(...args: any[]): any;
|
|
108
112
|
export function createFlowerHeadBillboardNodeMaterial(...args: any[]): any;
|
|
@@ -126,7 +130,6 @@ export function createGrassShaderProfileSettings(...args: any[]): any;
|
|
|
126
130
|
export function createGrassShaderSettings(...args: any[]): any;
|
|
127
131
|
export function createImportedVegetationMaterial(...args: any[]): any;
|
|
128
132
|
export function createLeafSpriteTexture(...args: any[]): any;
|
|
129
|
-
export function createLegacyTree(...args: any[]): any;
|
|
130
133
|
export function createNoisePatchMask(...args: any[]): any;
|
|
131
134
|
export function createOrganLeafSpriteTexture(...args: any[]): any;
|
|
132
135
|
export function createSlopeMask(...args: any[]): any;
|
|
@@ -152,8 +155,6 @@ export function deriveCanopyPalette(...args: any[]): any;
|
|
|
152
155
|
export function disposeExportGroup(...args: any[]): any;
|
|
153
156
|
export function getFlowerPresetOptions(...args: any[]): any;
|
|
154
157
|
export function getGrassPresetOptions(...args: any[]): any;
|
|
155
|
-
export function getLegacyTreePreset(...args: any[]): any;
|
|
156
|
-
export function getLegacyTreePresetOptions(...args: any[]): any;
|
|
157
158
|
export function getStylizedTreePresetOptions(...args: any[]): any;
|
|
158
159
|
export function getTreeSurfaceProfileOptions(...args: any[]): any;
|
|
159
160
|
export function getVegetationMaterialContract(...args: any[]): any;
|
|
@@ -162,7 +163,6 @@ export function getVegetationShaderScopeExcludedFields(...args: any[]): any;
|
|
|
162
163
|
export function getVegetationShaderScopeFieldSchema(...args: any[]): any;
|
|
163
164
|
export function getVegetationShaderScopeSettingGroups(...args: any[]): any;
|
|
164
165
|
export function isVegetationSharedShaderGroup(...args: any[]): any;
|
|
165
|
-
export function layoutTreeRow(...args: any[]): any;
|
|
166
166
|
export function loadCallMeSenseiGrassClump(...args: any[]): any;
|
|
167
167
|
export function loadCompiledTreeAsset(...args: any[]): any;
|
|
168
168
|
export function matchGrassColorPalette(...args: any[]): any;
|
|
@@ -187,7 +187,9 @@ export function registerStylizedTreePreset(...args: any[]): any;
|
|
|
187
187
|
export function registerVegetationShaderPreset(...args: any[]): any;
|
|
188
188
|
export function resolveCanopyColor(...args: any[]): any;
|
|
189
189
|
export function resolveGrassColorPalette(...args: any[]): any;
|
|
190
|
+
export function resolvePadPruning(...args: any[]): any;
|
|
190
191
|
export function resolveTreeDitherMode(...args: any[]): any;
|
|
192
|
+
export function resolveTreeSurfaceProfileId(...args: any[]): any;
|
|
191
193
|
export function resolveVegetationShaderPreset(...args: any[]): any;
|
|
192
194
|
export function resolveVegetationShaderRoleSettings(...args: any[]): any;
|
|
193
195
|
export function sanitizeGrassPresetSettings(...args: any[]): any;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Source inference fallback: public names retained with permissive signatures.
|
|
2
2
|
export function combineMasks(...args: any[]): any;
|
|
3
3
|
export function createCapEdgeWeight(...args: any[]): any;
|
|
4
|
+
export function createCurveFrame(...args: any[]): any;
|
|
4
5
|
export function createDensityWeightMask(...args: any[]): any;
|
|
5
6
|
export function createNoisePatchMask(...args: any[]): any;
|
|
6
7
|
export function createSlopeMask(...args: any[]): any;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// Source inference fallback: public names retained with permissive signatures.
|
|
2
2
|
export const DEFAULT_STYLIZED_TREE_SETTINGS: any;
|
|
3
|
-
export const STYLIZED_TREE_EXAMPLES: any;
|
|
4
3
|
export const STYLIZED_TREE_SETTING_FIELD_SCHEMA: any;
|
|
5
4
|
export const STYLIZED_TREE_SETTING_GROUPS: any;
|
|
6
5
|
export class StylizedTree { constructor(...args: any[]); [key: string]: any; }
|
|
@@ -13,7 +12,7 @@ export function createStylizedTreeSettings(...args: any[]): any;
|
|
|
13
12
|
export function createTreeSkeleton(...args: any[]): any;
|
|
14
13
|
export function createTreeTrunkGeometry(...args: any[]): any;
|
|
15
14
|
export function getStylizedTreePresetOptions(...args: any[]): any;
|
|
16
|
-
export function layoutTreeRow(...args: any[]): any;
|
|
17
15
|
export function polarProfileFromOutline(...args: any[]): any;
|
|
18
16
|
export function registerStylizedTreePreset(...args: any[]): any;
|
|
17
|
+
export function resolvePadPruning(...args: any[]): any;
|
|
19
18
|
export function serializableTreeOptions(...args: any[]): any;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Source inference fallback: public names retained with permissive signatures.
|
|
2
2
|
export const LEAF_SHAPE_PRESETS: any;
|
|
3
|
+
export const NEEDLE_LEAF_SHAPES: any;
|
|
3
4
|
export class StylizedTreeFoliage { constructor(...args: any[]); [key: string]: any; }
|
|
4
5
|
export const TREE_FOLIAGE_ARCHITECTURES: any;
|
|
5
6
|
export const TREE_FOLIAGE_BLOBS: any;
|
package/types/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const TOONLAB_VERSION: "0.4.
|
|
1
|
+
export const TOONLAB_VERSION: "0.4.21";
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
# Geology assembly playbook
|
|
2
|
-
|
|
3
|
-
Use this reference with `karst-cliff-construction` and `outdoor-world`. It
|
|
4
|
-
describes reusable landform craft without depending on project-specific
|
|
5
|
-
helpers, asset IDs, or a frozen catalog count.
|
|
6
|
-
|
|
7
|
-
## 1. Establish the parent mass
|
|
8
|
-
|
|
9
|
-
Approve an untextured continuous terrain/heightfield silhouette first:
|
|
10
|
-
headlands, bays, terraces, tower envelopes, channel, beach, and submerged bed.
|
|
11
|
-
Catalog rocks dress and articulate that parent mass; they must not be the only
|
|
12
|
-
thing preventing the world from reading as hollow.
|
|
13
|
-
|
|
14
|
-
Reject before dressing when:
|
|
15
|
-
|
|
16
|
-
- the hero silhouette is wrong;
|
|
17
|
-
- the channel or beach footprint is clogged;
|
|
18
|
-
- the cliff is a thin wall with no top/underwater continuation;
|
|
19
|
-
- separate towers overlap into one clump from an approved camera.
|
|
20
|
-
|
|
21
|
-
## 2. Select donors by visible role
|
|
22
|
-
|
|
23
|
-
Query the connected ToonLab OSS or Pro catalog and shortlist with positive
|
|
24
|
-
`dimensionsMeters`, taxonomy, scale class, and immutable preview/asset URLs.
|
|
25
|
-
Family names and tags are search hints, not visual proof. Review contact sheets
|
|
26
|
-
or finalists under one neutral material and camera azimuth.
|
|
27
|
-
|
|
28
|
-
Useful morphology:
|
|
29
|
-
|
|
30
|
-
| Role | Visible requirement |
|
|
31
|
-
|---|---|
|
|
32
|
-
| Primary face | Broad load-bearing plane, gravity-aligned relief, no prop-like outline |
|
|
33
|
-
| Corner/termination | A turn or return face that buries cleanly into the parent mass |
|
|
34
|
-
| Bedding ledge | A real horizontal lip with enough depth to cast a recess shadow |
|
|
35
|
-
| Buttress/wedge | A seam bridge whose rear and toe can be buried |
|
|
36
|
-
| Waterline notch | Rounded or undercut lip that continues below the surface |
|
|
37
|
-
| Talus | Small jointed collapse block; free rotation is appropriate only here |
|
|
38
|
-
|
|
39
|
-
Choose target dimensions in metres from the published native dimensions.
|
|
40
|
-
Reject missing or invalid dimensions before download. Avoid solving an entire
|
|
41
|
-
wall by stretching one small donor; report mean/max scale and worst axis ratio
|
|
42
|
-
per structural role.
|
|
43
|
-
|
|
44
|
-
## 3. Build courses, not rubble
|
|
45
|
-
|
|
46
|
-
Primary faces share a near-common up axis and facing. Vary crop, burial,
|
|
47
|
-
neighbour overlap, tier, yaw silhouette, and moderate scale; do not tumble
|
|
48
|
-
load-bearing panels. Free three-axis tumbling belongs to collapse products.
|
|
49
|
-
|
|
50
|
-
Starting burial ranges, to be verified in silhouette:
|
|
51
|
-
|
|
52
|
-
- primary faces: bury roughly 30–60% of module depth;
|
|
53
|
-
- bedding ledges: bury the rear majority so only the lip projects;
|
|
54
|
-
- tower cores: seat the footing/course overlap, not most of the tower;
|
|
55
|
-
- talus: rest in contact and bury enough to remove floating toes.
|
|
56
|
-
|
|
57
|
-
Build in this order:
|
|
58
|
-
|
|
59
|
-
1. primary faces at noses, re-entrants, terminations, and terrace breaks;
|
|
60
|
-
2. bridging ledges, buttresses, crevice wedges, and recessed corbels;
|
|
61
|
-
3. waterline/submerged continuation and restrained talus;
|
|
62
|
-
4. vegetation caps and story dressing.
|
|
63
|
-
|
|
64
|
-
If a placement helper automatically splits an oversized request into a stack,
|
|
65
|
-
make that result explicit and refusable. Subdivision must not introduce yaw,
|
|
66
|
-
pitch, or roll jitter unless the caller deliberately requests a tumbled role.
|
|
67
|
-
|
|
68
|
-
## 4. Publish shared formation contracts
|
|
69
|
-
|
|
70
|
-
Sibling modules must consume the same world-space values rather than derive
|
|
71
|
-
private approximations:
|
|
72
|
-
|
|
73
|
-
- parent height/envelope;
|
|
74
|
-
- water level and submerged bed;
|
|
75
|
-
- bedding elevation ladder;
|
|
76
|
-
- visible face plane/standoff;
|
|
77
|
-
- cliff-top and vegetation-cap polygons;
|
|
78
|
-
- fall lips, landing pools, and exclusion zones.
|
|
79
|
-
|
|
80
|
-
One useful bedding ladder is `base + courseIndex * spacing`; derive `base` and
|
|
81
|
-
`spacing` from the terrain terracing/style rather than copying the qualifying
|
|
82
|
-
scene's numbers. Align visible beds across neighbouring formations.
|
|
83
|
-
|
|
84
|
-
## 5. Unify the material treatment
|
|
85
|
-
|
|
86
|
-
Use one intentional parent lithology. The rock shader can replace source
|
|
87
|
-
albedo and apply one projected treatment across morphologically compatible
|
|
88
|
-
donors, but it cannot change incompatible geometry into the same geology.
|
|
89
|
-
Record any cross-taxonomy donor override and judge the result from silhouette,
|
|
90
|
-
bedding, and surface response.
|
|
91
|
-
|
|
92
|
-
Prefer one `applyRockShader(formationRoot, settings)` call. Verify the report's
|
|
93
|
-
texture source and shadow defaults. Use `setRockShaderSceneState` for the
|
|
94
|
-
current water level so the wet band follows the shoreline.
|
|
95
|
-
|
|
96
|
-
## 6. Prevent recognizable repetition
|
|
97
|
-
|
|
98
|
-
Repeated asset ids are normal modular modelling. Repeated camera-facing
|
|
99
|
-
silhouettes are the defect. For nearby copies vary at least three of: visible
|
|
100
|
-
crop/burial, tier, neighbour overlap, meaningful scale, and camera-facing yaw.
|
|
101
|
-
Never use regular spacing or a visible kit row.
|
|
102
|
-
|
|
103
|
-
Placement metrics are rejection floors. They cannot prove that the rendered
|
|
104
|
-
formation reads as one mass.
|
|
105
|
-
|
|
106
|
-
## 7. Verify before approval
|
|
107
|
-
|
|
108
|
-
- Wait for application readiness and a stable rendered scene graph.
|
|
109
|
-
- Capture hero, wide, close, flyover, and top-down views.
|
|
110
|
-
- Isolate terrain, rock formation, water, and lighting when assigning a defect.
|
|
111
|
-
- Scan world-space extents for accidental slabs, dams, or oversized caps.
|
|
112
|
-
- Report module counts, donor dimensions, transformed dimensions, burial,
|
|
113
|
-
per-role scale statistics, and active LODs.
|
|
114
|
-
- Squint at the silhouette: if individual boulders or a sawtooth crest remain
|
|
115
|
-
legible, the cliff is still a pile.
|
|
116
|
-
|
|
117
|
-
Automated checks may reject gaps, invalid scale, and repeated transforms. Only
|
|
118
|
-
rendered multi-view evidence can approve the formation.
|
|
@@ -1,258 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: karst-cliff-construction
|
|
3
|
-
description: Experimental research guidance for assembling a stylized cliff, gorge, karst tower, or sea stack from catalog rocks, including silhouette selection, parent geology, transform grammar, and measurable rubble-pile rejection gates; not a supported automatic cliff builder.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Experimental cliff construction from catalog rocks
|
|
7
|
-
|
|
8
|
-
This is retained as research and review guidance. ToonLab can find rocks,
|
|
9
|
-
report their dimensions/taxonomy, and shade supplied geometry, but neither the
|
|
10
|
-
package nor an LLM is currently qualified to turn those assets into a polished
|
|
11
|
-
cliff automatically. Use it only for an explicit experiment, record every
|
|
12
|
-
manual placement/transform decision, and do not present success as a stable
|
|
13
|
-
one-shot feature.
|
|
14
|
-
|
|
15
|
-
This is the assembly craft that sits between `rockgen` (which makes a rock) and
|
|
16
|
-
the `outdoor-world` skill (which owns the whole scene). Read
|
|
17
|
-
`../outdoor-world/SKILL.md` first for the landform-before-props ordering and the
|
|
18
|
-
rejection gates; this skill is how you actually execute the rock layer. Read
|
|
19
|
-
the agent-neutral
|
|
20
|
-
[geology playbook](../../../references/geology-playbook.md) for the compact
|
|
21
|
-
morphology, course, burial, and verification reference.
|
|
22
|
-
|
|
23
|
-
Everything here was derived by building a reference-driven karst gorge from the
|
|
24
|
-
full catalog available during qualification and having it rejected
|
|
25
|
-
several times. Catalog contents change; query the connected OSS or Pro MCP
|
|
26
|
-
surface instead of assuming a fixed asset count or frozen family membership.
|
|
27
|
-
The failure modes are listed as prominently as the method, because they are
|
|
28
|
-
what cost the time.
|
|
29
|
-
|
|
30
|
-
## The single most important rule
|
|
31
|
-
|
|
32
|
-
**A cliff is one mass. Individual rocks must not be legible as individual
|
|
33
|
-
rocks.**
|
|
34
|
-
|
|
35
|
-
Squint at the frame from the hero camera. If you can pick out separate boulders
|
|
36
|
-
in the wall face, the formation has failed, no matter how good the rocks are or
|
|
37
|
-
how correct the metrics look. Every rule below exists to serve that one read.
|
|
38
|
-
|
|
39
|
-
The characteristic failure is an **angular rubble pile**: many modules at many
|
|
40
|
-
orientations, each individually readable, with a sawtooth crest. It looks like
|
|
41
|
-
quarry spoil. It happens because tumbling every rock feels like variety, and
|
|
42
|
-
because an anti-repetition gate seems to demand it. It does not.
|
|
43
|
-
|
|
44
|
-
## Selection: look, do not read tags
|
|
45
|
-
|
|
46
|
-
**Family names do not guarantee silhouette.** In the tested catalog snapshot,
|
|
47
|
-
`column-field` contains no columnar geometry at all; `broad-wall` is mostly
|
|
48
|
-
hourglass pedestals; the only assets that genuinely read as vertical fluting
|
|
49
|
-
live in `vertical-face`. Selecting by `familyId` or by tag produces the wrong
|
|
50
|
-
formation when the current previews disagree with the label.
|
|
51
|
-
|
|
52
|
-
So: **render contact sheets and choose visually.** Download the catalog
|
|
53
|
-
thumbnails, lay them out in a labelled grid per family, and look at every one
|
|
54
|
-
before choosing. Better still, render the actual GLBs under a single flat
|
|
55
|
-
material at the intended camera azimuth — thumbnails show baked material colour,
|
|
56
|
-
which is discarded at runtime (see below), so silhouette is the only thing that
|
|
57
|
-
matters and the thumbnail can mislead you about it.
|
|
58
|
-
|
|
59
|
-
Budget an hour for this. It is the highest-leverage hour in the whole job.
|
|
60
|
-
|
|
61
|
-
**Use the published donor dimensions.** Current OSS and Pro rock search results
|
|
62
|
-
include positive `dimensionsMeters.width`, `.height`, and `.depth`. Reject a
|
|
63
|
-
record with missing, zero, negative, or axis-ambiguous dimensions before
|
|
64
|
-
download. Load a finalist only to verify silhouette/material compatibility,
|
|
65
|
-
not to discover its size. Drive placement from **target metres**, never from a
|
|
66
|
-
raw scale multiplier. A project helper such as `place({ height: 40 })` is
|
|
67
|
-
reviewable; `scale: 6.3` is not a ToonLab contract or an art-direction decision.
|
|
68
|
-
|
|
69
|
-
## Geology: one parent rock, many catalog families
|
|
70
|
-
|
|
71
|
-
A formation must read as **one lithology**. Limestone, sandstone and granite do
|
|
72
|
-
not alternate between adjacent modules unless the level authors a readable fault.
|
|
73
|
-
|
|
74
|
-
This can conflict with selecting by silhouette, because useful shapes may span
|
|
75
|
-
families with different `taxonomy.geology`. Treat geology as meaningful search
|
|
76
|
-
metadata, but allow an intentional stylized donor override when the visible
|
|
77
|
-
morphology is compatible and one material treatment makes the formation read
|
|
78
|
-
as a deliberate parent rock. Record that override; never imply that replacing
|
|
79
|
-
albedo changes the source mesh's physical morphology.
|
|
80
|
-
|
|
81
|
-
So the working method is:
|
|
82
|
-
|
|
83
|
-
1. Select every rock by **role and silhouette**, ignoring its geology tag.
|
|
84
|
-
2. Apply the rock shader to the whole formation root with one settings object.
|
|
85
|
-
3. Verify that every included part reports the same intended texture source and
|
|
86
|
-
material profile. One root call is the safest way to prevent call-site drift;
|
|
87
|
-
repeated calls with byte-identical settings are visually equivalent.
|
|
88
|
-
|
|
89
|
-
Two consequences worth knowing before you are surprised by them:
|
|
90
|
-
|
|
91
|
-
- Baked green grass caps on some catalog rocks **disappear** under `replace`.
|
|
92
|
-
Re-create caps deliberately, via the shader's grass layer or via vegetation.
|
|
93
|
-
- Per-part calls invite accidental settings drift. Prefer the formation root
|
|
94
|
-
unless a deliberately distinct lithology needs its own documented pass.
|
|
95
|
-
|
|
96
|
-
For a genuinely different stone in the same frame — a quarried quay against a
|
|
97
|
-
natural cliff — mark those meshes `userData.rockShaderExclude = true`, run the
|
|
98
|
-
main pass, then clear the flag and run a second pass over just that group.
|
|
99
|
-
Order matters: setting the flag before your own pass silently disables it.
|
|
100
|
-
|
|
101
|
-
### Matching geology to real morphology
|
|
102
|
-
|
|
103
|
-
Choose donors by what the landform actually does, not by name:
|
|
104
|
-
|
|
105
|
-
| Landform feature | What to look for |
|
|
106
|
-
|---|---|
|
|
107
|
-
| Rillenkarren (vertical dissolution runnels on karst) | Parallel vertical prism relief — columnar-basalt donors read as this almost exactly |
|
|
108
|
-
| Broad fluted wall envelope | Barrel-curved faces with wide vertical creases |
|
|
109
|
-
| Bedding partings | Donors with true horizontal lips and shelf stacks |
|
|
110
|
-
| Undercut karst tower | Inverted flares — wider at mid-height than at the base |
|
|
111
|
-
| Solution notch at the waterline | River-worn blocks with a rounded overhanging lip |
|
|
112
|
-
| Collapse product below a wall | Jointed angular blocks, tumbled freely — the one place tumbling is correct |
|
|
113
|
-
|
|
114
|
-
## The transform grammar
|
|
115
|
-
|
|
116
|
-
Per role, and these ranges are the difference between a landform and a pile:
|
|
117
|
-
|
|
118
|
-
**Primary wall faces.** Share a near-common up axis and a near-common facing.
|
|
119
|
-
Yaw varies the silhouette *edge*, not the rock's orientation. Pitch and roll
|
|
120
|
-
near zero — fluting is gravity-parallel, and a tilted flute reads as a mistake.
|
|
121
|
-
Bury 30–60 % of module depth. Present the face, not the corners.
|
|
122
|
-
|
|
123
|
-
**Corners and terminations.** Yaw is set by the turn, not jittered. Turn the
|
|
124
|
-
broad mass toward the coastline change and bury the return face into its
|
|
125
|
-
neighbour so it never shows a free edge.
|
|
126
|
-
|
|
127
|
-
**Shelves and bedding ledges.** Rotate a useful plane upward, crop the rear into
|
|
128
|
-
the parent mass, and support the underside with a face or buttress so the
|
|
129
|
-
overhang is a shadowed recess rather than a lit floating slab.
|
|
130
|
-
|
|
131
|
-
**Crevice wedges.** The one primary role where roll is large — 8–15° — because a
|
|
132
|
-
wedge is *supposed* to be jammed at an angle.
|
|
133
|
-
|
|
134
|
-
**Talus and waterline blocks.** Free three-axis rotation, 0.7–1.4 non-uniform
|
|
135
|
-
scale, always resting in contact with the surface below.
|
|
136
|
-
|
|
137
|
-
### Scale discipline
|
|
138
|
-
|
|
139
|
-
**Cap the uniform scale, and audit it.** Blowing a 6 m donor up 22× is what makes
|
|
140
|
-
a wall read as stretched rather than stacked: the projected texture smears, the
|
|
141
|
-
silhouette loses its authored detail, and one module tries to do the work of a
|
|
142
|
-
course. Prefer more modules near native size over fewer giant ones.
|
|
143
|
-
|
|
144
|
-
Instrument it. Report per-role mean and max uniform scale and the worst axis
|
|
145
|
-
ratio, and warn loudly when a role exceeds its ceiling, so a wall module cannot
|
|
146
|
-
silently stretch a donor. A run that measured `mean 6.35, max 22.3, worst axis
|
|
147
|
-
ratio 4.08` was visibly stretched and nobody noticed until an art director said
|
|
148
|
-
"why is it stretched".
|
|
149
|
-
|
|
150
|
-
### Placement helpers must not reinterpret intent
|
|
151
|
-
|
|
152
|
-
An oversized authored wall module must never silently become a jittered stack.
|
|
153
|
-
Make any over-ceiling substitution **explicit and refusable**: accept an option
|
|
154
|
-
such as `onOverCeiling: 'reject' | 'shrink' | 'stack'`, default load-bearing wall
|
|
155
|
-
roles to `reject`, and return/report the actual strategy and placement count.
|
|
156
|
-
Reserve `stack` for an intentional course plan; reserve tumbling for talus.
|
|
157
|
-
|
|
158
|
-
Keep course variation separate from scatter variation. Load-bearing faces use
|
|
159
|
-
`courseJitter: 0` unless the author requests a measured, small range; they must
|
|
160
|
-
not inherit free yaw/roll jitter from a rubble scatter helper. Likewise, label
|
|
161
|
-
Euler rotations by their local-axis order. A field named `pitch` is not a
|
|
162
|
-
world-space lean after yaw. Prefer a world-space contract such as
|
|
163
|
-
`leanInto: { direction, angle }`, or document and test the exact local axis.
|
|
164
|
-
|
|
165
|
-
## Anti-repetition, correctly understood
|
|
166
|
-
|
|
167
|
-
The gate is **recognizable repetition**, not a repeated asset id. Reusing a good
|
|
168
|
-
modular rock is normal environment modelling.
|
|
169
|
-
|
|
170
|
-
Two copies of one id must not present the same camera-facing silhouette. Satisfy
|
|
171
|
-
at least three of: yaw differs ≥ 25° against the camera-facing normal; different
|
|
172
|
-
tier; uniform scale differs ≥ 25 %; burial fraction differs ≥ 8 points so a
|
|
173
|
-
different portion of the outline survives; different overlapping neighbour.
|
|
174
|
-
|
|
175
|
-
Absolute prohibitions: no twins within ~35 m at the same tier; no regular
|
|
176
|
-
spacing interval; no kit rows.
|
|
177
|
-
|
|
178
|
-
**Audit it, but do not trust the audit.** A placement-based audit scores
|
|
179
|
-
positions and transforms — it cannot see the rendered silhouette. Zero offences
|
|
180
|
-
and a rubble pile are entirely compatible. The audit is a floor, not approval.
|
|
181
|
-
|
|
182
|
-
## Structural coherence
|
|
183
|
-
|
|
184
|
-
**Bedding must be continuous across formations.** Beds are the same beds. Derive
|
|
185
|
-
one elevation ladder for the whole scene — ideally from the terrain's own
|
|
186
|
-
terracing, so rock and parent mass agree — and place every bedding ledge on it.
|
|
187
|
-
Bands that line up across neighbouring towers at equal elevation is the single
|
|
188
|
-
detail that sells a karst formation.
|
|
189
|
-
|
|
190
|
-
**Publish it.** The wall that computes the ladder should expose it, and every
|
|
191
|
-
other formation should read it rather than re-deriving. Be aware of build order:
|
|
192
|
-
if a composer builds parts in sequence, a later part cannot read an earlier
|
|
193
|
-
part's published values through a context object that is only assigned after the
|
|
194
|
-
whole composer returns. Pass shared values through the composer explicitly, or
|
|
195
|
-
have each part fall back to a documented constant and log which path ran.
|
|
196
|
-
|
|
197
|
-
Publish a shared **face plane** as well as the terrain/height envelope. Shelves,
|
|
198
|
-
bridges, falls, vegetation lips, and sibling wall modules must read the same
|
|
199
|
-
world-space surface contract instead of hard-coding a standoff against a wall
|
|
200
|
-
revision that can move later.
|
|
201
|
-
|
|
202
|
-
**Bridge every seam.** After the primary masses, rasterise their footprints,
|
|
203
|
-
find pairs with a traceable boundary, and wedge shelves, buttresses and crevice
|
|
204
|
-
slabs across them, each with a corbel tucked beneath so the overhang is a
|
|
205
|
-
shadowed recess. Terrain must never show through a gap between rocks.
|
|
206
|
-
|
|
207
|
-
**Do not let painted detail do geometry's job.** Horizontal stratification drawn
|
|
208
|
-
into a projected texture becomes a stretched line on a scaled rock, and thin
|
|
209
|
-
crack layers alias into dashed "stitched" lines at any realistic tile
|
|
210
|
-
resolution. Deliver bedding as **stacked silhouettes** — real courses with real
|
|
211
|
-
overhangs — and reserve the texture for surface grain.
|
|
212
|
-
|
|
213
|
-
## Build order
|
|
214
|
-
|
|
215
|
-
Do not start by scattering rocks.
|
|
216
|
-
|
|
217
|
-
1. **Macro landform.** A continuous heightfield with the full silhouette:
|
|
218
|
-
headlands, bays, terraces, the channel, the bed. Approve it untextured. If
|
|
219
|
-
the macro silhouette is wrong, no rock dressing saves it.
|
|
220
|
-
2. **Primary structure.** Large faces at structural events only — noses,
|
|
221
|
-
re-entrants, terminations, terrace breaks. Subordinate to the macro mass.
|
|
222
|
-
3. **Secondary structure.** Bridging shelves, buttresses, crevice wedges.
|
|
223
|
-
4. **Tertiary dressing.** Waterline notch, submerged continuation, minimal
|
|
224
|
-
talus, story detail.
|
|
225
|
-
|
|
226
|
-
Talus quantity is a geology decision, not a dressing preference. A dissolution
|
|
227
|
-
gorge has almost none; a frost-shattered alpine face has fans. An evenly spread
|
|
228
|
-
scree carpet is always wrong.
|
|
229
|
-
|
|
230
|
-
## Verification
|
|
231
|
-
|
|
232
|
-
Numeric checks reject obvious failure; only looking can approve.
|
|
233
|
-
|
|
234
|
-
- **Isolate before blaming.** Render subsystems alone — with their light rig, or
|
|
235
|
-
you get black — to attribute a defect. A "flowing water" texture on the cliffs
|
|
236
|
-
turned out to be the terrain's ground shader, not the waterfalls, and only an
|
|
237
|
-
isolation capture settled it.
|
|
238
|
-
- **Scan for outliers.** Traverse the scene for meshes above a size threshold and
|
|
239
|
-
print path, world extent and position. This catches the 104 m slab damming a
|
|
240
|
-
72 m channel that nobody sees because it reads as "background".
|
|
241
|
-
- **Squint at the silhouette first**, before texture, before colour. One mass or
|
|
242
|
-
a pile.
|
|
243
|
-
- **Judge from every approved camera**: hero, wide, close, flyover, top-down. A
|
|
244
|
-
formation can read as one mass from the hero and as a kit row from above.
|
|
245
|
-
- **Settle the scene before screenshotting.** Modules resolve async work — GLB
|
|
246
|
-
loads, render passes — after their factory returns. Wait for a stable scene
|
|
247
|
-
graph, not a fixed frame count, or you will review a frame with subsystems
|
|
248
|
-
missing while the manifest claims they are present.
|
|
249
|
-
|
|
250
|
-
## Performance notes that shape the art
|
|
251
|
-
|
|
252
|
-
- The rock shader creates a **material per mesh**, so instancing is unavailable
|
|
253
|
-
and every tertiary rock costs a draw call. Budget the tertiary layer.
|
|
254
|
-
- Catalog GLBs carry baked LODs; use the higher indices for distant modules.
|
|
255
|
-
- Catalog GLBs can require KTX2/Draco decoders. Create one shared transcoder set
|
|
256
|
-
with `createModelAssetTranscoders({ decoderBasePath, renderer })`, pass it to
|
|
257
|
-
every `loadModelAsset(url, { transcoders })` call, and dispose it once after
|
|
258
|
-
all model loads. Do not construct decoder/transcoder resources per rock.
|