@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
|
@@ -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.
|