@call-me-sensei/toonlab 0.4.20 → 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 +11 -6
- package/README.md +25 -19
- package/agents/PROMPTS.md +10 -6
- package/agents/codex/AGENTS.md +6 -4
- package/agents/references/mcp-asset-discovery.md +12 -9
- package/agents/skills/claude/asset-sourcing/SKILL.md +9 -6
- package/agents/skills/claude/vegetation-sky/SKILL.md +7 -4
- package/agents/skills/codex/asset-sourcing/SKILL.md +9 -6
- package/agents/skills/codex/vegetation-sky/SKILL.md +7 -4
- package/mcp/public-catalog.mjs +4 -52
- package/mcp/server.mjs +147 -2
- package/package.json +3 -4
- package/src/vegetation/index.js +22 -2
- package/src/vegetation/scatter.js +6 -1
- package/src/vegetation/stylizedTree.js +3 -107
- package/src/version.js +1 -1
- package/types/index.d.ts +0 -7
- package/types/vegetation/index.d.ts +0 -7
- package/types/vegetation/stylizedTree.d.ts +0 -2
- package/types/version.d.ts +1 -1
- package/src/vegetation/legacyTreePresets.js +0 -120
- package/types/vegetation/legacyTreePresets.d.ts +0 -22
package/NPM-LIBRARY.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# ToonLab npm library guide
|
|
2
2
|
|
|
3
3
|
This guide is included in `@call-me-sensei/toonlab`. It is the package-first
|
|
4
|
-
reference for version 0.4.
|
|
4
|
+
reference for version 0.4.21 and does not require access to the source
|
|
5
5
|
repository.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
@@ -45,7 +45,7 @@ them:
|
|
|
45
45
|
- `@call-me-sensei/toonlab/styles` for portable bundles, strict labels,
|
|
46
46
|
auditing, and coordinated application;
|
|
47
47
|
- `@call-me-sensei/toonlab/assetlib`, `/asset-policy`, and
|
|
48
|
-
`/official-catalog` for policy-aware
|
|
48
|
+
`/official-catalog` for policy-aware local/released-catalog integration;
|
|
49
49
|
- `@call-me-sensei/toonlab/character` and `/loaders` for supported preview and
|
|
50
50
|
host-model integration;
|
|
51
51
|
- `@call-me-sensei/toonlab/runtime`, `/renderer`, `/lighting`, and
|
|
@@ -76,7 +76,9 @@ The npm artifact contains four supported layers:
|
|
|
76
76
|
It does not contain the ToonLab website, Lab application UIs, examples,
|
|
77
77
|
screenshots, models, textures, or other binary media. Optional public fixtures
|
|
78
78
|
are identified by immutable `https://assets.toonlab.io` metadata rather than
|
|
79
|
-
being bundled.
|
|
79
|
+
being bundled. Authored tree recipes are assets too: the reviewed public tree
|
|
80
|
+
collection remains in the Gallery and is discovered through MCP instead of
|
|
81
|
+
being hard-coded into the JavaScript runtime.
|
|
80
82
|
|
|
81
83
|
## Use a focused runtime
|
|
82
84
|
|
|
@@ -167,7 +169,7 @@ it uses the disk workspace passed through `--workspace`; no account is needed.
|
|
|
167
169
|
"command": "npx",
|
|
168
170
|
"args": [
|
|
169
171
|
"-y",
|
|
170
|
-
"@call-me-sensei/toonlab@0.4.
|
|
172
|
+
"@call-me-sensei/toonlab@0.4.21",
|
|
171
173
|
"--workspace",
|
|
172
174
|
"/absolute/path/to/your-game/.toonlab"
|
|
173
175
|
],
|
|
@@ -181,8 +183,11 @@ it uses the disk workspace passed through `--workspace`; no account is needed.
|
|
|
181
183
|
|
|
182
184
|
This server provides the anime-game profile, runtime guide, live-Lab
|
|
183
185
|
contracts, deterministic document creation and mutation, policy validation,
|
|
184
|
-
public
|
|
185
|
-
generation when the developer supplies server-side provider
|
|
186
|
+
public Gallery search/retrieval, local Library operations, and optional
|
|
187
|
+
provider-backed generation when the developer supplies server-side provider
|
|
188
|
+
keys. Authored tree recipes are not bundled. Call `search_public_gallery` with
|
|
189
|
+
`{ query: "tree", type: "tree-recipe" }`, then use
|
|
190
|
+
`get_public_gallery_asset` to retrieve the reviewed portable recipe.
|
|
186
191
|
|
|
187
192
|
### ToonLab Pro MCP
|
|
188
193
|
|
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ Use ToonLab as a focused runtime library (`@call-me-sensei/toonlab` on npm), as
|
|
|
19
19
|
an asset/preset authoring workspace, or as an asset-discovery service—not as a
|
|
20
20
|
one-shot world generator.
|
|
21
21
|
|
|
22
|
-
## Versioned expectation: 0.4.
|
|
22
|
+
## Versioned expectation: 0.4.21
|
|
23
23
|
|
|
24
24
|
For a correctly constructed and semantically labeled scene, one strict Call Me
|
|
25
25
|
Sensei bundle application is expected to establish the supported visual
|
|
@@ -310,10 +310,13 @@ npm run dev
|
|
|
310
310
|
# In an MCP client, use the command/config shown at /settings/.
|
|
311
311
|
```
|
|
312
312
|
|
|
313
|
-
The local server can search
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
313
|
+
The local server can search your workspace, the public ToonLab Gallery, the
|
|
314
|
+
released official catalog, and public CC0 sources; read saved presets and
|
|
315
|
+
exported files; generate approved seeded recipes; and import assets into the
|
|
316
|
+
project. Authored Gallery recipes are fetched with their public license and
|
|
317
|
+
provenance instead of being copied into the npm package. The server uses stdio,
|
|
318
|
+
requires no account or OAuth for public discovery, and keeps local work local.
|
|
319
|
+
See [Local MCP and workspace](https://github.com/call-me-sensei/toonlab/blob/main/docs/mcp.md) and
|
|
317
320
|
[Local database and public asset releases](https://github.com/call-me-sensei/toonlab/blob/main/docs/local-database-and-public-assets.md).
|
|
318
321
|
|
|
319
322
|
## The labs
|
|
@@ -375,7 +378,7 @@ camera behavior, and game feel remain host-owned or pre-beta.
|
|
|
375
378
|
| Toon character shading | `@call-me-sensei/toonlab/toon` | Modern anime character shader: cel bands with art-directed face lighting, skin-tone shadow management, shadow-color HSV control, scene/self/contact shadows, average-shadow smoothing, rim light (fresnel or screen-space depth), stylized + anisotropic hair highlights, eye catchlights, role-aware specular, source map routing (normal/AO/emissive/MatCap/ramp/detail), inverted-hull outlines, glitter, stickers, perspective removal, shell fur, dither fades — 23 settings groups, all preset-serializable. [Docs](https://github.com/call-me-sensei/toonlab/blob/main/docs/toon-shading.md) |
|
|
376
379
|
| Environment shading | `@call-me-sensei/toonlab/environment` | Modern anime-style scene shader for texture packs, standard glTF, and untextured scenes: material-role classification, wrapped lighting, packed-map hints, window cutouts, sun/lamp rigs, time-of-day, six-direction ambient probe, planar floor reflections, BVH vertex-AO baking, height fog, cloud shadows. [Docs](https://github.com/call-me-sensei/toonlab/blob/main/docs/environment.md) |
|
|
377
380
|
| Water | `@call-me-sensei/toonlab/water` | Focused water treatment for a host-authored water footprint, continuous shore, and closed seabed: Gerstner waves, absorption color, refraction/caustics/foam, ripples, splashes, wakes, kelp, underwater treatment, and CPU buoyancy sampling. It does not design the coast or underwater habitat. [Docs](https://github.com/call-me-sensei/toonlab/blob/main/docs/water.md) |
|
|
378
|
-
| Vegetation | `@call-me-sensei/toonlab/vegetation` |
|
|
381
|
+
| Vegetation | `@call-me-sensei/toonlab/vegetation` | Tree/grass/flower construction and shader runtimes, including the focused procedural broadleaf `BranchTree` with deterministic branching, five leaf silhouettes, caller-supplied leaf/bark textures, and a portable recipe. No authored tree asset collection is bundled or exported: reviewed tree recipes remain searchable Gallery assets delivered through MCP with their CC0 metadata. Package-generated trees preserve authored bark first and otherwise select a registered deterministic bark surface instead of a bare trunk. The experimental species roster remains repository-only. [Docs](https://github.com/call-me-sensei/toonlab/blob/main/docs/vegetation-sky.md) |
|
|
379
382
|
| Rock shader | `@call-me-sensei/toonlab/rock-shader` | Detailed, versioned rock-material profiles with projected detail, distance tint, normal fading, striping, moss and optional top layers, plus explicit source-albedo and vertex-color/AO integration. Call Me Sensei is the default. Geometry generation remains separate in `rockgen`. [Docs](https://github.com/call-me-sensei/toonlab/blob/main/docs/rock-shader.md) |
|
|
380
383
|
| Ground shader | `@call-me-sensei/toonlab/ground-shader` | Splat-weighted anime terrain with slope/cliff detail, shoreline and weather response, HDR sun/shade controls, safe shadow defaults, and flat-albedo ground-field output for vegetation adoption. [Docs](https://github.com/call-me-sensei/toonlab/blob/main/docs/ground-shader.md) |
|
|
381
384
|
| Sky | `@call-me-sensei/toonlab/sky` | Reusable atmosphere, palette, sun, moon, stars, and god-ray settings authored by Sky Lab and Sky & Cloud Lab. Your application coordinates final lighting and scene state. [Docs](https://github.com/call-me-sensei/toonlab/blob/main/docs/sky.md) |
|
|
@@ -460,21 +463,21 @@ profile parameters for other authored styles. Its recipe-v3 LOD0/1/2 topology
|
|
|
460
463
|
uses 40/14/6 primary blades and compensates retained stroke width so zooming
|
|
461
464
|
does not make the underlying terrain appear to change color.
|
|
462
465
|
|
|
463
|
-
|
|
464
|
-
|
|
466
|
+
ToonLab does not ship predefined tree assets in npm. Search reviewed public
|
|
467
|
+
tree recipes through MCP, then pass the retrieved portable recipe options to
|
|
468
|
+
the runtime:
|
|
465
469
|
|
|
466
470
|
```js
|
|
467
|
-
import {
|
|
468
|
-
LEGACY_TREE_IDS,
|
|
469
|
-
createLegacyTree,
|
|
470
|
-
} from '@call-me-sensei/toonlab/vegetation';
|
|
471
|
+
import { StylizedTree } from '@call-me-sensei/toonlab/vegetation';
|
|
471
472
|
|
|
472
|
-
|
|
473
|
-
|
|
473
|
+
// treeRecipe is the document returned by get_public_gallery_asset after
|
|
474
|
+
// search_public_gallery({ query: 'tree', type: 'tree-recipe' }).
|
|
475
|
+
const tree = new StylizedTree({
|
|
476
|
+
...treeRecipe.options,
|
|
474
477
|
trunkMap: barkTexture,
|
|
475
478
|
vegetationShader: { preset: 'call_me_sensei' },
|
|
476
479
|
});
|
|
477
|
-
scene.add(
|
|
480
|
+
scene.add(tree);
|
|
478
481
|
```
|
|
479
482
|
|
|
480
483
|
For a configurable recursive branch-type broadleaf, use the focused wrapper:
|
|
@@ -495,7 +498,8 @@ scene.add(tree);
|
|
|
495
498
|
shapes. Botanical species generation is not a public package claim.
|
|
496
499
|
|
|
497
500
|
Water, sky, flowers, trees, grass, and splashes keep procedural defaults, while
|
|
498
|
-
|
|
501
|
+
Gallery tree recipes, `StylizedTree`, and `BranchTree` may use caller-owned
|
|
502
|
+
leaf and bark textures. The
|
|
499
503
|
Call Me Sensei tree path resolves bark in this order: explicit
|
|
500
504
|
`trunkSurfaceProfile`, authored `trunkMap`, then the registered
|
|
501
505
|
`call-me-sensei-bark-v1` fallback. Use `getTreeSurfaceProfileOptions()` when a
|
|
@@ -698,9 +702,11 @@ Ready-to-paste supported prompts are included in
|
|
|
698
702
|
Two servers, and they compose:
|
|
699
703
|
|
|
700
704
|
**Local (free, no account).** The stdio server included in this package
|
|
701
|
-
searches
|
|
702
|
-
|
|
703
|
-
into a disk-backed
|
|
705
|
+
searches local/project content, reviewed public Gallery recipes, the released
|
|
706
|
+
official catalog, and public CC0 sources; reads saved presets and Lab exports;
|
|
707
|
+
generates approved seeded recipes; and imports assets into a disk-backed
|
|
708
|
+
`.toonlab/` workspace. Use `search_public_gallery` for authored assets such as
|
|
709
|
+
the public tree collection—those recipes are not npm built-ins:
|
|
704
710
|
|
|
705
711
|
```json
|
|
706
712
|
{
|
package/agents/PROMPTS.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# ToonLab agent prompts
|
|
2
2
|
|
|
3
3
|
These prompts are included with the npm package. They use only the supported
|
|
4
|
-
0.4.
|
|
4
|
+
0.4.21 runtime, agent skills, and MCP workflows.
|
|
5
5
|
|
|
6
6
|
## Existing-scene integration
|
|
7
7
|
|
|
@@ -55,11 +55,15 @@ document.
|
|
|
55
55
|
|
|
56
56
|
```text
|
|
57
57
|
Using the ToonLab vegetation-sky skill, create the requested tree, shrub,
|
|
58
|
-
grass, or groundcover
|
|
59
|
-
|
|
60
|
-
shader
|
|
61
|
-
|
|
62
|
-
|
|
58
|
+
grass, or groundcover. For an existing authored tree, search the public Gallery
|
|
59
|
+
through MCP first and retrieve its portable recipe; the npm package contains
|
|
60
|
+
tree construction/shader capability but no predefined tree asset collection.
|
|
61
|
+
Author a new `StylizedTree` or `BranchTree` only when requested or when accepted
|
|
62
|
+
discovery does not close the role. Keep recipe, seed, geometry, palette, and
|
|
63
|
+
placement separate from the Tree/Grass/Flower shader profile. Emit stable
|
|
64
|
+
modeled-part and material-role labels, preserve the recipe for regeneration,
|
|
65
|
+
and verify LOD and shadow behavior. Do not use the repository-only experimental
|
|
66
|
+
species engine.
|
|
63
67
|
```
|
|
64
68
|
|
|
65
69
|
## Rock generation and shader separation
|
package/agents/codex/AGENTS.md
CHANGED
|
@@ -82,10 +82,12 @@ or environment with ToonLab's runtime library in their own Three.js app.
|
|
|
82
82
|
system preset with embedded shader controls. Sky, Cloud, and Sky & Cloud are
|
|
83
83
|
live focused authoring surfaces. Vegetation is one shared
|
|
84
84
|
implementation family with separate Tree, Grass, and Flower shader profiles;
|
|
85
|
-
their Generation Labs own geometry/material data. The
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
their Generation Labs own geometry/material data. The public package ships
|
|
86
|
+
tree construction and shader capability, not predefined tree assets. Search
|
|
87
|
+
reviewed authored tree recipes through MCP; use `StylizedTree` or
|
|
88
|
+
`BranchTree` to instantiate or deliberately author them. Repository species
|
|
89
|
+
work is experimental and must not be presented as supported. Ground is a
|
|
90
|
+
separate shader domain. Scene weather,
|
|
89
91
|
lighting, camera, interactions, and complete Sky/Cloud composition stay
|
|
90
92
|
host-owned or experimental.
|
|
91
93
|
- For style-bundle, multi-shader, or arbitrary-asset work, read
|
|
@@ -10,11 +10,12 @@ Inspect the connected server's tool names before calling anything. Do not
|
|
|
10
10
|
assume the developer has ToonLab Pro, and do not assume a local OSS checkout.
|
|
11
11
|
|
|
12
12
|
- **ToonLab OSS local MCP** exposes `get_workspace_info`,
|
|
13
|
-
`
|
|
14
|
-
`
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
`search_public_gallery`, `get_public_gallery_asset`, `search_cc0_assets`,
|
|
14
|
+
`get_cc0_asset`, and `import_cc0_asset`. Its `search_assets` searches
|
|
15
|
+
approved built-in generator/settings entries, the local released official
|
|
16
|
+
catalog, and the disk-backed project/library/workspace. Authored assets such
|
|
17
|
+
as reviewed tree recipes are searched through `search_public_gallery` rather
|
|
18
|
+
than copied into npm.
|
|
18
19
|
- **ToonLab Pro remote MCP** exposes `get_runtime_guide`,
|
|
19
20
|
`search_public_gallery`, and `get_toonlab_asset`. Its `search_assets`
|
|
20
21
|
searches indexed external open assets; first-party rocks/trees and community
|
|
@@ -41,10 +42,12 @@ the surface the developer actually has and report which surface was used.
|
|
|
41
42
|
1. Call `list_my_creations` with the task's text and exact tag filters, then
|
|
42
43
|
`search_assets` with `source: 'library'`,
|
|
43
44
|
`'workspace'`, `'workspace-storage'`, or `'builtin'` as appropriate. If no
|
|
44
|
-
accepted local entry closes the role, call
|
|
45
|
-
|
|
46
|
-
`
|
|
47
|
-
|
|
45
|
+
accepted local entry closes the role, call `search_public_gallery` for
|
|
46
|
+
authored public assets and follow `nextOffset` until null. Use
|
|
47
|
+
`type: 'tree-recipe'` for reviewed trees. Use `search_assets` with
|
|
48
|
+
`source: 'official'` only for the installed released catalog.
|
|
49
|
+
2. Call local `get_public_gallery_asset` for a selected Gallery document or
|
|
50
|
+
`get_asset` for a local/released-catalog record.
|
|
48
51
|
3. When policy permits external CC0, call `search_cc0_assets`, then
|
|
49
52
|
`get_cc0_asset`; call `import_cc0_asset` only after selection to download
|
|
50
53
|
bytes plus their provenance manifest into `.toonlab/imports/`.
|
|
@@ -50,9 +50,11 @@ scene-kit role.
|
|
|
50
50
|
2. **Reuse what exists.** In OSS, earlier imports, saved presets, and exports
|
|
51
51
|
live in `.toonlab/`; call local `list_my_creations` and `search_assets` with
|
|
52
52
|
`source: 'workspace'`, `'workspace-storage'`, `'library'`, or `'builtin'`.
|
|
53
|
-
If those do not close the role, use local `
|
|
54
|
-
`
|
|
55
|
-
`
|
|
53
|
+
If those do not close the role, use local `search_public_gallery` and follow
|
|
54
|
+
`nextOffset` until null; use `type: 'tree-recipe'` for authored trees and
|
|
55
|
+
retrieve a finalist with `get_public_gallery_asset`. Use local
|
|
56
|
+
`search_assets({ source: 'official' })` only for the installed released
|
|
57
|
+
catalog.
|
|
56
58
|
In Pro, call cloud `list_my_creations`, then `search_public_gallery`; use
|
|
57
59
|
`source: 'toonlab'` plus the appropriate catalog for first-party assets and
|
|
58
60
|
follow `nextOffset`. For rocks on either surface, shortlist from positive
|
|
@@ -195,9 +197,10 @@ table, as the source of truth):
|
|
|
195
197
|
|
|
196
198
|
- Seamless PBR material sets (brick, wood, ground …) → ambientCG.
|
|
197
199
|
- Photoscanned props, HDRIs, high-end texture sets → Poly Haven.
|
|
198
|
-
-
|
|
199
|
-
|
|
200
|
-
|
|
200
|
+
- Authored stylized/toon-ready models and vegetation → the public Gallery
|
|
201
|
+
first; retrieve their portable document and provenance through MCP. Use a
|
|
202
|
+
built-in procedural family only when it passed the base-set reliability gate
|
|
203
|
+
and the task calls for new generation rather than an existing asset.
|
|
201
204
|
- Stylized *seamless textures* → `@call-me-sensei/toonlab/texgen` in code
|
|
202
205
|
(60+ presets); the catalog has no texture entries, so this route is a
|
|
203
206
|
package import, not an MCP call.
|
|
@@ -80,8 +80,11 @@ User guidance:
|
|
|
80
80
|
create the pass after all writer meshes exist, call its `update()` every frame before grass, require
|
|
81
81
|
`writerCount > 0` and `ready`, and call `invalidate()` after repainting a
|
|
82
82
|
writer without a transform change.
|
|
83
|
-
-
|
|
84
|
-
|
|
83
|
+
- The public package contains tree construction and shader capability, not a
|
|
84
|
+
predefined tree asset collection. For an authored tree, use the connected
|
|
85
|
+
MCP's `search_public_gallery` and `get_public_gallery_asset` tools, then
|
|
86
|
+
instantiate its portable recipe with `StylizedTree`. Use `BranchTree` when
|
|
87
|
+
the developer explicitly wants
|
|
85
88
|
recursive branching, five broadleaf silhouettes, leaf color/texture plus a
|
|
86
89
|
portable lit/shadow/crown palette, independent leaf `coverageScale`, bark
|
|
87
90
|
color/texture, authored trunk bend/twist/taper, roots, portable documents,
|
|
@@ -108,11 +111,11 @@ User guidance:
|
|
|
108
111
|
`GRASS_SHADER_PROFILE`, and `FLOWER_SHADER_PROFILE` through the bundle's
|
|
109
112
|
`treeShader`, `grassShader`, and `flowerShader` slots. They share a renderer
|
|
110
113
|
family and semantic material contract, but serialize and apply independently.
|
|
111
|
-
Keep asset albedo and
|
|
114
|
+
Keep asset albedo and Gallery-recipe/BranchTree geometry/material inputs separate from all
|
|
112
115
|
three shader treatments.
|
|
113
116
|
- Grass palettes update base, tip, and shadow tint together; they do not change
|
|
114
117
|
shadow strength, wind, or current weather.
|
|
115
|
-
- Use the public versioned Grass, vegetation-shader,
|
|
118
|
+
- Use the public versioned Grass, vegetation-shader, BranchTree/flower recipe, and Sky
|
|
116
119
|
preset document APIs for portable data; do not copy lab-local validators.
|
|
117
120
|
- Treat Sky as one integrated World System, not a separate Shader Lab. Its
|
|
118
121
|
shader, sun, clouds, stars, and procedural motion form one system preset with
|
|
@@ -50,9 +50,11 @@ scene-kit role.
|
|
|
50
50
|
2. **Reuse what exists.** In OSS, earlier imports, saved presets, and exports
|
|
51
51
|
live in `.toonlab/`; call local `list_my_creations` and `search_assets` with
|
|
52
52
|
`source: 'workspace'`, `'workspace-storage'`, `'library'`, or `'builtin'`.
|
|
53
|
-
If those do not close the role, use local `
|
|
54
|
-
`
|
|
55
|
-
`
|
|
53
|
+
If those do not close the role, use local `search_public_gallery` and follow
|
|
54
|
+
`nextOffset` until null; use `type: 'tree-recipe'` for authored trees and
|
|
55
|
+
retrieve a finalist with `get_public_gallery_asset`. Use local
|
|
56
|
+
`search_assets({ source: 'official' })` only for the installed released
|
|
57
|
+
catalog.
|
|
56
58
|
In Pro, call cloud `list_my_creations`, then `search_public_gallery`; use
|
|
57
59
|
`source: 'toonlab'` plus the appropriate catalog for first-party assets and
|
|
58
60
|
follow `nextOffset`. For rocks on either surface, shortlist from positive
|
|
@@ -195,9 +197,10 @@ table, as the source of truth):
|
|
|
195
197
|
|
|
196
198
|
- Seamless PBR material sets (brick, wood, ground …) → ambientCG.
|
|
197
199
|
- Photoscanned props, HDRIs, high-end texture sets → Poly Haven.
|
|
198
|
-
-
|
|
199
|
-
|
|
200
|
-
|
|
200
|
+
- Authored stylized/toon-ready models and vegetation → the public Gallery
|
|
201
|
+
first; retrieve their portable document and provenance through MCP. Use a
|
|
202
|
+
built-in procedural family only when it passed the base-set reliability gate
|
|
203
|
+
and the task calls for new generation rather than an existing asset.
|
|
201
204
|
- Stylized *seamless textures* → `@call-me-sensei/toonlab/texgen` in code
|
|
202
205
|
(60+ presets); the catalog has no texture entries, so this route is a
|
|
203
206
|
package import, not an MCP call.
|
|
@@ -80,8 +80,11 @@ User guidance:
|
|
|
80
80
|
create the pass after all writer meshes exist, call its `update()` every frame before grass, require
|
|
81
81
|
`writerCount > 0` and `ready`, and call `invalidate()` after repainting a
|
|
82
82
|
writer without a transform change.
|
|
83
|
-
-
|
|
84
|
-
|
|
83
|
+
- The public package contains tree construction and shader capability, not a
|
|
84
|
+
predefined tree asset collection. For an authored tree, use the connected
|
|
85
|
+
MCP's `search_public_gallery` and `get_public_gallery_asset` tools, then
|
|
86
|
+
instantiate its portable recipe with `StylizedTree`. Use `BranchTree` when
|
|
87
|
+
the developer explicitly wants
|
|
85
88
|
recursive branching, five broadleaf silhouettes, leaf color/texture plus a
|
|
86
89
|
portable lit/shadow/crown palette, independent leaf `coverageScale`, bark
|
|
87
90
|
color/texture, authored trunk bend/twist/taper, roots, portable documents,
|
|
@@ -108,11 +111,11 @@ User guidance:
|
|
|
108
111
|
`GRASS_SHADER_PROFILE`, and `FLOWER_SHADER_PROFILE` through the bundle's
|
|
109
112
|
`treeShader`, `grassShader`, and `flowerShader` slots. They share a renderer
|
|
110
113
|
family and semantic material contract, but serialize and apply independently.
|
|
111
|
-
Keep asset albedo and
|
|
114
|
+
Keep asset albedo and Gallery-recipe/BranchTree geometry/material inputs separate from all
|
|
112
115
|
three shader treatments.
|
|
113
116
|
- Grass palettes update base, tip, and shadow tint together; they do not change
|
|
114
117
|
shadow strength, wind, or current weather.
|
|
115
|
-
- Use the public versioned Grass, vegetation-shader,
|
|
118
|
+
- Use the public versioned Grass, vegetation-shader, BranchTree/flower recipe, and Sky
|
|
116
119
|
preset document APIs for portable data; do not copy lab-local validators.
|
|
117
120
|
- Treat Sky as one integrated World System, not a separate Shader Lab. Its
|
|
118
121
|
shader, sun, clouds, stars, and procedural motion form one system preset with
|
package/mcp/public-catalog.mjs
CHANGED
|
@@ -25,62 +25,14 @@ function entry(input) {
|
|
|
25
25
|
});
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
const CURATED_PLANT_RECIPES = Object.freeze([
|
|
29
|
-
entry({
|
|
30
|
-
cluster: 'vegetation',
|
|
31
|
-
description: 'Mid-size broadleaf starting recipe for anime environments.',
|
|
32
|
-
id: 'tree/broadleaf/sensei',
|
|
33
|
-
kind: 'recipe',
|
|
34
|
-
label: 'Sensei broadleaf',
|
|
35
|
-
recipe: {
|
|
36
|
-
options: { seed: 3, size: 3.2 },
|
|
37
|
-
schema: 'treeRecipe',
|
|
38
|
-
type: 'tree',
|
|
39
|
-
version: 1,
|
|
40
|
-
},
|
|
41
|
-
spawn: 'createPlantFromRecipe(entry.recipe)',
|
|
42
|
-
tags: ['tree', 'vegetation', 'anime'],
|
|
43
|
-
thumbnail: thumbnailFor('tree/broadleaf/sensei'),
|
|
44
|
-
}),
|
|
45
|
-
entry({
|
|
46
|
-
cluster: 'vegetation',
|
|
47
|
-
description: 'Ground-hugging foliage mass for yards and path edges.',
|
|
48
|
-
id: 'tree/bush/hedge',
|
|
49
|
-
kind: 'recipe',
|
|
50
|
-
label: 'Hedge bush',
|
|
51
|
-
recipe: {
|
|
52
|
-
options: { seed: 5, size: 1.2 },
|
|
53
|
-
schema: 'treeRecipe',
|
|
54
|
-
type: 'bush',
|
|
55
|
-
version: 1,
|
|
56
|
-
},
|
|
57
|
-
spawn: 'createPlantFromRecipe(entry.recipe)',
|
|
58
|
-
tags: ['bush', 'vegetation', 'anime'],
|
|
59
|
-
thumbnail: thumbnailFor('tree/bush/hedge'),
|
|
60
|
-
}),
|
|
61
|
-
entry({
|
|
62
|
-
cluster: 'vegetation',
|
|
63
|
-
description: 'Flowering plant with daisy heads.',
|
|
64
|
-
id: 'tree/flower/daisy',
|
|
65
|
-
kind: 'recipe',
|
|
66
|
-
label: 'Daisy flower',
|
|
67
|
-
recipe: {
|
|
68
|
-
options: { seed: 9, size: 0.5, species: 'daisy' },
|
|
69
|
-
schema: 'treeRecipe',
|
|
70
|
-
type: 'flower',
|
|
71
|
-
version: 1,
|
|
72
|
-
},
|
|
73
|
-
spawn: 'createPlantFromRecipe(entry.recipe)',
|
|
74
|
-
tags: ['flower', 'vegetation', 'anime'],
|
|
75
|
-
thumbnail: thumbnailFor('tree/flower/daisy'),
|
|
76
|
-
}),
|
|
77
|
-
]);
|
|
78
|
-
|
|
79
28
|
let cached = null;
|
|
80
29
|
|
|
81
30
|
export function publicMcpCatalogEntries() {
|
|
82
31
|
if (cached) return cached;
|
|
83
|
-
|
|
32
|
+
// Authored vegetation recipes are Gallery assets, not package built-ins.
|
|
33
|
+
// The packaged MCP discovers them from the public Gallery so provenance,
|
|
34
|
+
// license, review state, and immutable documents stay attached.
|
|
35
|
+
const entries = [];
|
|
84
36
|
|
|
85
37
|
for (const option of getRockgenPresetOptions()) {
|
|
86
38
|
const id = `rock/${slug(option.value)}`;
|
package/mcp/server.mjs
CHANGED
|
@@ -82,6 +82,8 @@ const SERVER_NAME = 'toonlab-oss';
|
|
|
82
82
|
const SERVER_VERSION = JSON.parse(
|
|
83
83
|
readFileSync(new URL('../package.json', import.meta.url), 'utf8'),
|
|
84
84
|
).version;
|
|
85
|
+
const PUBLIC_GALLERY_ENDPOINT = process.env.TOONLAB_PUBLIC_GALLERY_URL
|
|
86
|
+
?? 'https://toonlab.io/api/v1/creations';
|
|
85
87
|
const LATEST_PROTOCOL_VERSION = '2025-11-25';
|
|
86
88
|
const SUPPORTED_PROTOCOL_VERSIONS = new Set([
|
|
87
89
|
LATEST_PROTOCOL_VERSION,
|
|
@@ -289,6 +291,112 @@ function normalizeDiscovery(entry, summary, { domain = '', policy = null } = {})
|
|
|
289
291
|
};
|
|
290
292
|
}
|
|
291
293
|
|
|
294
|
+
function publicGalleryUrl(path = '') {
|
|
295
|
+
let endpoint;
|
|
296
|
+
try {
|
|
297
|
+
endpoint = new URL(PUBLIC_GALLERY_ENDPOINT);
|
|
298
|
+
} catch {
|
|
299
|
+
throw new Error('TOONLAB_PUBLIC_GALLERY_URL must be an absolute HTTP(S) URL.');
|
|
300
|
+
}
|
|
301
|
+
if (!['http:', 'https:'].includes(endpoint.protocol)) {
|
|
302
|
+
throw new Error('TOONLAB_PUBLIC_GALLERY_URL must use HTTP(S).');
|
|
303
|
+
}
|
|
304
|
+
endpoint.search = '';
|
|
305
|
+
endpoint.hash = '';
|
|
306
|
+
if (!path) return endpoint;
|
|
307
|
+
endpoint.pathname = `${endpoint.pathname.replace(/\/$/u, '')}/${encodeURIComponent(path)}`;
|
|
308
|
+
return endpoint;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function absoluteGalleryReference(reference) {
|
|
312
|
+
if (typeof reference !== 'string' || !reference.trim()) return null;
|
|
313
|
+
return new URL(reference, publicGalleryUrl()).href;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
async function fetchPublicGalleryJson(url) {
|
|
317
|
+
let response;
|
|
318
|
+
try {
|
|
319
|
+
response = await fetch(url, {
|
|
320
|
+
headers: { accept: 'application/json' },
|
|
321
|
+
signal: AbortSignal.timeout(15_000),
|
|
322
|
+
});
|
|
323
|
+
} catch (cause) {
|
|
324
|
+
throw new Error(`ToonLab public Gallery request failed: ${cause?.message ?? String(cause)}`);
|
|
325
|
+
}
|
|
326
|
+
if (!response.ok) {
|
|
327
|
+
throw new Error(`ToonLab public Gallery returned HTTP ${response.status}.`);
|
|
328
|
+
}
|
|
329
|
+
try {
|
|
330
|
+
return await response.json();
|
|
331
|
+
} catch {
|
|
332
|
+
throw new Error('ToonLab public Gallery returned invalid JSON.');
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function normalizePublicGalleryItem(item, args = {}) {
|
|
337
|
+
const id = String(item?.id ?? '').trim();
|
|
338
|
+
if (!id) throw new Error('ToonLab public Gallery returned an item without an id.');
|
|
339
|
+
const type = String(item.type ?? 'creation');
|
|
340
|
+
const entry = {
|
|
341
|
+
attribution: item.attribution ?? null,
|
|
342
|
+
author: item.author ?? null,
|
|
343
|
+
cluster: type,
|
|
344
|
+
description: item.description ?? null,
|
|
345
|
+
documentUrl: absoluteGalleryReference(item.download ?? item.documentUrl),
|
|
346
|
+
id,
|
|
347
|
+
kind: type,
|
|
348
|
+
label: String(item.label ?? id),
|
|
349
|
+
license: item.license ?? null,
|
|
350
|
+
source: 'gallery',
|
|
351
|
+
sourceClass: 'toonlab-gallery',
|
|
352
|
+
tags: Array.isArray(item.tags) ? item.tags.map(String) : [],
|
|
353
|
+
thumbnail: absoluteGalleryReference(item.thumbnail),
|
|
354
|
+
updatedAt: item.updated_at ?? null,
|
|
355
|
+
url: absoluteGalleryReference(item.url ?? `/c/${item.slug ?? id}`),
|
|
356
|
+
};
|
|
357
|
+
return normalizeDiscovery(entry, entry, args);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
async function searchPublicGallery(args = {}) {
|
|
361
|
+
const limit = limitValue(args.limit, 20, 60);
|
|
362
|
+
const offset = Math.max(0, Math.floor(Number(args.offset) || 0));
|
|
363
|
+
const endpoint = publicGalleryUrl();
|
|
364
|
+
endpoint.searchParams.set('limit', String(limit));
|
|
365
|
+
endpoint.searchParams.set('offset', String(offset));
|
|
366
|
+
if (String(args.query ?? '').trim()) endpoint.searchParams.set('q', String(args.query).trim());
|
|
367
|
+
if (String(args.type ?? '').trim()) endpoint.searchParams.set('type', String(args.type).trim());
|
|
368
|
+
const response = await fetchPublicGalleryJson(endpoint);
|
|
369
|
+
if (!Array.isArray(response?.items)) {
|
|
370
|
+
throw new Error('ToonLab public Gallery response is missing items.');
|
|
371
|
+
}
|
|
372
|
+
const items = response.items.map((item) => normalizePublicGalleryItem(item, args));
|
|
373
|
+
return {
|
|
374
|
+
count: items.length,
|
|
375
|
+
items,
|
|
376
|
+
limit,
|
|
377
|
+
nextOffset: items.length === limit ? offset + items.length : null,
|
|
378
|
+
offset,
|
|
379
|
+
source: 'toonlab-public-gallery',
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
async function getPublicGalleryAsset(args = {}) {
|
|
384
|
+
const id = String(args.id ?? '').trim();
|
|
385
|
+
if (!id) throw new Error('A public Gallery asset id or slug is required.');
|
|
386
|
+
const item = await fetchPublicGalleryJson(publicGalleryUrl(id));
|
|
387
|
+
const normalized = normalizePublicGalleryItem({
|
|
388
|
+
...item,
|
|
389
|
+
download: item.documentUrl ?? null,
|
|
390
|
+
thumbnail: item.thumbnail ?? null,
|
|
391
|
+
url: item.url ?? `/c/${item.slug ?? id}`,
|
|
392
|
+
}, args);
|
|
393
|
+
return {
|
|
394
|
+
...normalized,
|
|
395
|
+
document: item.document ?? null,
|
|
396
|
+
files: Array.isArray(item.files) ? item.files : [],
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
|
|
292
400
|
function summarizeCatalogEntry(entry) {
|
|
293
401
|
const metadata = entry.metadata && typeof entry.metadata === 'object' && !Array.isArray(entry.metadata)
|
|
294
402
|
? entry.metadata
|
|
@@ -989,7 +1097,7 @@ const TOOLS = [
|
|
|
989
1097
|
},
|
|
990
1098
|
{
|
|
991
1099
|
annotations: { readOnlyHint: true },
|
|
992
|
-
description: 'Search built-in
|
|
1100
|
+
description: 'Search approved built-in generator/settings entries, the local released official catalog, saved library entries, lab presets, and files on disk. Official rock summaries include compact dimensions and taxonomy metadata; follow nextOffset until null.',
|
|
993
1101
|
inputSchema: {
|
|
994
1102
|
additionalProperties: false,
|
|
995
1103
|
properties: {
|
|
@@ -1008,6 +1116,40 @@ const TOOLS = [
|
|
|
1008
1116
|
name: 'search_assets',
|
|
1009
1117
|
title: 'Search ToonLab assets',
|
|
1010
1118
|
},
|
|
1119
|
+
{
|
|
1120
|
+
annotations: { openWorldHint: true, readOnlyHint: true },
|
|
1121
|
+
description: 'Search public ToonLab Gallery creations with their license, attribution, tags, thumbnail, and immutable portable-document URL. Authored tree recipes live here rather than in npm; use type="tree-recipe" and follow nextOffset until null.',
|
|
1122
|
+
inputSchema: {
|
|
1123
|
+
additionalProperties: false,
|
|
1124
|
+
properties: {
|
|
1125
|
+
domain: { type: 'string' },
|
|
1126
|
+
limit: { maximum: 60, minimum: 1, type: 'integer' },
|
|
1127
|
+
offset: { minimum: 0, type: 'integer' },
|
|
1128
|
+
policy: { type: 'object' },
|
|
1129
|
+
query: { type: 'string' },
|
|
1130
|
+
type: { type: 'string' },
|
|
1131
|
+
},
|
|
1132
|
+
type: 'object',
|
|
1133
|
+
},
|
|
1134
|
+
name: 'search_public_gallery',
|
|
1135
|
+
title: 'Search the ToonLab public Gallery',
|
|
1136
|
+
},
|
|
1137
|
+
{
|
|
1138
|
+
annotations: { openWorldHint: true, readOnlyHint: true },
|
|
1139
|
+
description: 'Get one public ToonLab Gallery creation by publication id or slug, including its complete portable document and immutable public files.',
|
|
1140
|
+
inputSchema: {
|
|
1141
|
+
additionalProperties: false,
|
|
1142
|
+
properties: {
|
|
1143
|
+
domain: { type: 'string' },
|
|
1144
|
+
id: { type: 'string' },
|
|
1145
|
+
policy: { type: 'object' },
|
|
1146
|
+
},
|
|
1147
|
+
required: ['id'],
|
|
1148
|
+
type: 'object',
|
|
1149
|
+
},
|
|
1150
|
+
name: 'get_public_gallery_asset',
|
|
1151
|
+
title: 'Get a ToonLab public Gallery asset',
|
|
1152
|
+
},
|
|
1011
1153
|
{
|
|
1012
1154
|
annotations: { readOnlyHint: true },
|
|
1013
1155
|
description: 'Get a complete asset, recipe, preset, library entry, or workspace file descriptor by id.',
|
|
@@ -1415,6 +1557,8 @@ async function callTool(name, args = {}) {
|
|
|
1415
1557
|
case 'get_lab_features': return getLabFeatures(args.lab);
|
|
1416
1558
|
case 'create_lab_document': return createLabDocumentTool(args);
|
|
1417
1559
|
case 'search_assets': return searchAssets(args);
|
|
1560
|
+
case 'search_public_gallery': return searchPublicGallery(args);
|
|
1561
|
+
case 'get_public_gallery_asset': return getPublicGalleryAsset(args);
|
|
1418
1562
|
case 'get_asset': return getAsset(args);
|
|
1419
1563
|
case 'list_my_creations': return listMyCreations(args);
|
|
1420
1564
|
case 'get_my_creation': return getMyCreation(args);
|
|
@@ -1486,6 +1630,7 @@ async function callTool(name, args = {}) {
|
|
|
1486
1630
|
available: [
|
|
1487
1631
|
'Generate deterministic recipes from the stable public ToonLab catalog entries.',
|
|
1488
1632
|
'Save and retrieve editable lab documents through the shared .toonlab workspace.',
|
|
1633
|
+
'Search and retrieve authored public Gallery recipes with license and provenance.',
|
|
1489
1634
|
'Search and import CC0 assets from Poly Haven and ambientCG.',
|
|
1490
1635
|
'Use each recipe\'s spawn snippet to integrate it into a Three.js project.',
|
|
1491
1636
|
],
|
|
@@ -1536,7 +1681,7 @@ async function handleRequest(message) {
|
|
|
1536
1681
|
jsonrpc: '2.0',
|
|
1537
1682
|
result: {
|
|
1538
1683
|
capabilities: { resources: {}, tools: {} },
|
|
1539
|
-
instructions: 'ToonLab builds anime-style games, characters, and environments for Three.js. Call list_live_labs and get_lab_features when authoring a Lab artifact, use create_lab_document for a valid starter, and prefer mutate_lab_creation over hand-editing structural arrays. Official Rock details include a source-GLB starter. This OSS server may edit any non-secret creation or lab-state entry in its local workspace; deletions require explicit confirmation. Load the selected style bundle first. If no asset-sourcing policy exists, ask the developer, then continue with library-first advisory discovery while recording the unresolved decision. Search the project and
|
|
1684
|
+
instructions: 'ToonLab builds anime-style games, characters, and environments for Three.js. Call list_live_labs and get_lab_features when authoring a Lab artifact, use create_lab_document for a valid starter, and prefer mutate_lab_creation over hand-editing structural arrays. Official Rock details include a source-GLB starter. This OSS server may edit any non-secret creation or lab-state entry in its local workspace; deletions require explicit confirmation. Load the selected style bundle first. If no asset-sourcing policy exists, ask the developer, then continue with library-first advisory discovery while recording the unresolved decision. Search the project and local library first, then search_public_gallery for reviewed authored assets such as tree recipes, before external sources. Generate or hand-author only when policy permits. Validate every candidate, preserve provenance, evaluate anime-fit in scene, and record a gap before adding a custom shader, texture, model, or adapter. When local provider keys are configured, generate_ai_asset exposes image generation, Meshy 7 image/multiview-to-3D, and Text -> selected image model -> Meshy 7 through MCP.',
|
|
1540
1685
|
protocolVersion: SUPPORTED_PROTOCOL_VERSIONS.has(requested) ? requested : LATEST_PROTOCOL_VERSION,
|
|
1541
1686
|
serverInfo: { name: SERVER_NAME, version: SERVER_VERSION },
|
|
1542
1687
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@call-me-sensei/toonlab",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.21",
|
|
4
4
|
"description": "Anime-style game toolkit for Three.js with cel shading, vegetation, rocks, water, sky, clouds, procedural textures, and portable Lab artifacts",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Hyperbond Studio PTE. LTD. (Call Me Sensei)",
|
|
@@ -347,7 +347,6 @@
|
|
|
347
347
|
"verify:quality-integration": "node scripts/verify-quality-budget-integration.mjs && node scripts/verify-packaged-quality-budget-integration.mjs",
|
|
348
348
|
"verify:vegetation-shader": "node scripts/verify-vegetation-shader.mjs",
|
|
349
349
|
"verify:lab-styles": "node scripts/verify-lab-style-boundaries.mjs",
|
|
350
|
-
"verify:legacy-trees": "node scripts/verify-legacy-trees.mjs",
|
|
351
350
|
"verify:branch-tree": "node scripts/verify-branch-tree.mjs",
|
|
352
351
|
"verify:tree-doodle": "node scripts/verify-tree-doodle.mjs",
|
|
353
352
|
"verify:tree-woody": "node scripts/verify-tree-woody-engine.mjs",
|
|
@@ -365,7 +364,7 @@
|
|
|
365
364
|
"verify:collision-package": "node scripts/verify-packaged-world-collision.mjs",
|
|
366
365
|
"verify:official-catalog": "node scripts/verify-official-catalog-provider.mjs && node scripts/verify-official-catalog-runtime.mjs && node scripts/verify-official-catalog-lod.mjs && node scripts/verify-official-catalog-placement.mjs && node scripts/verify-playground-official-catalog.mjs && node scripts/verify-packaged-official-catalog.mjs",
|
|
367
366
|
"verify:system-style": "node scripts/verify-system-style-policy.mjs",
|
|
368
|
-
"verify:release": "npm run verify:system-style && npm run verify:style-contract && npm run verify:style-labels-package && npm run verify:collision-package && npm run verify:scene-collision && npm run verify:official-catalog && npm run verify:public-labs && npm run verify:live-labs && npm run verify:rock-shader && npm run verify:rock-generation-lab && npm run verify:rock-lab-lifecycle && npm run verify:ground-shader && npm run verify:manufactured-materials && npm run verify:material-labeling:agent && npm run verify:material-labeling:mcp && npm run verify:water-lab && npm run verify:water && npm run verify:vegetation-labs && npm run verify:texgen && npm run verify:cloud-shader && npm run verify:sky-cloud-lab && npm run verify:world-quality && npm run verify:scatter && npm run verify:
|
|
367
|
+
"verify:release": "npm run verify:system-style && npm run verify:style-contract && npm run verify:style-labels-package && npm run verify:collision-package && npm run verify:scene-collision && npm run verify:official-catalog && npm run verify:public-labs && npm run verify:live-labs && npm run verify:rock-shader && npm run verify:rock-generation-lab && npm run verify:rock-lab-lifecycle && npm run verify:ground-shader && npm run verify:manufactured-materials && npm run verify:material-labeling:agent && npm run verify:material-labeling:mcp && npm run verify:water-lab && npm run verify:water && npm run verify:vegetation-labs && npm run verify:texgen && npm run verify:cloud-shader && npm run verify:sky-cloud-lab && npm run verify:world-quality && npm run verify:scatter && npm run verify:branch-tree && npm run verify:grass-package && npm run verify:character-package && npm run verify:locomotion-state && npm run verify:ground-stabilizer && npm run verify:water-interaction && npm run verify:walkable-character && npm run verify:playground-walkable && npm run verify:renderer-configuration && npm run verify:scene-scheduler && npm run verify:scene-surface && npm run verify:shared-shadow-receivers && npm run verify:scene-quality && npm run verify:quality-integration && npm run verify:lab-asset-provenance && npm run verify:api && npm run verify:types && npm run verify:mcp && npm run verify:skills && npm run verify:docs && npm run verify:local-database && npm run verify:package",
|
|
369
368
|
"verify:generation": "node scripts/verify-generation.mjs",
|
|
370
369
|
"verify:post": "node scripts/verify-post.mjs",
|
|
371
370
|
"verify:camera": "node scripts/verify-camera.mjs",
|
|
@@ -374,7 +373,7 @@
|
|
|
374
373
|
"verify:soundscape": "node scripts/verify-soundscape.mjs",
|
|
375
374
|
"verify:game-feel": "node scripts/verify-game-feel.mjs",
|
|
376
375
|
"verify:world-quality": "node scripts/verify-world-quality.mjs",
|
|
377
|
-
"verify:all": "npm run verify:system-style && npm run verify:product-namespace && npm run verify:generation && npm run verify:post && npm run verify:camera && npm run verify:motion && npm run verify:biome && npm run verify:soundscape && npm run verify:game-feel && npm run verify:world-quality && npm run verify:rock-shader && npm run verify:ground-shader && npm run verify:rockgen && npm run verify:rock-generation-lab && npm run verify:pathgen && npm run verify:propgen && npm run verify:buildinggen && npm run verify:villagegen && npm run verify:fauna && npm run verify:ambientfx && npm run verify:vfxgen && npm run verify:water && npm run verify:landscape && npm run verify:lighting && npm run verify:lighting-lab && npm run verify:live-labs && npm run verify:lab-preview && npm run verify:weather && npm run verify:climate && npm run verify:atmospheric-condition-lab && npm run verify:sky && npm run verify:cloud-shader && npm run verify:sky-cloud-lab && npm run verify:environment-cycle && npm run verify:manufactured-materials && npm run verify:ground-field && npm run verify:grass && npm run verify:grass-package && npm run verify:character-package && npm run verify:vegetation-shader && npm run verify:lab-styles && npm run verify:scatter && npm run verify:
|
|
376
|
+
"verify:all": "npm run verify:system-style && npm run verify:product-namespace && npm run verify:generation && npm run verify:post && npm run verify:camera && npm run verify:motion && npm run verify:biome && npm run verify:soundscape && npm run verify:game-feel && npm run verify:world-quality && npm run verify:rock-shader && npm run verify:ground-shader && npm run verify:rockgen && npm run verify:rock-generation-lab && npm run verify:pathgen && npm run verify:propgen && npm run verify:buildinggen && npm run verify:villagegen && npm run verify:fauna && npm run verify:ambientfx && npm run verify:vfxgen && npm run verify:water && npm run verify:landscape && npm run verify:lighting && npm run verify:lighting-lab && npm run verify:live-labs && npm run verify:lab-preview && npm run verify:weather && npm run verify:climate && npm run verify:atmospheric-condition-lab && npm run verify:sky && npm run verify:cloud-shader && npm run verify:sky-cloud-lab && npm run verify:environment-cycle && npm run verify:manufactured-materials && npm run verify:ground-field && npm run verify:grass && npm run verify:grass-package && npm run verify:character-package && npm run verify:vegetation-shader && npm run verify:lab-styles && npm run verify:scatter && npm run verify:branch-tree && npm run verify:collision-package && npm run verify:scene-collision && npm run verify:official-catalog && npm run verify:api && npm run verify:package && npm run verify:catalog && npm run verify:assetlib && npm run verify:mcp && npm run verify:local-generation",
|
|
378
377
|
"verify:catalog": "node scripts/verify-catalog.mjs",
|
|
379
378
|
"verify:assetlib": "node scripts/verify-assetlib.mjs",
|
|
380
379
|
"verify:mcp": "node scripts/verify-mcp.mjs",
|
package/src/vegetation/index.js
CHANGED
|
@@ -4,9 +4,29 @@ export * from './grassClump.js';
|
|
|
4
4
|
export * from './callMeSenseiGrass.js';
|
|
5
5
|
export * from './stylizedFlowers.js';
|
|
6
6
|
export * from './flowerSpecies.js';
|
|
7
|
-
|
|
7
|
+
// Public tree construction/runtime surface. Authored tree recipes are assets
|
|
8
|
+
// and are discovered through ToonLab MCP; showcase/example recipe arrays are
|
|
9
|
+
// deliberately not re-exported from the npm package.
|
|
10
|
+
export {
|
|
11
|
+
DEFAULT_STYLIZED_TREE_SETTINGS,
|
|
12
|
+
STYLIZED_TREE_SETTING_FIELD_SCHEMA,
|
|
13
|
+
STYLIZED_TREE_SETTING_GROUPS,
|
|
14
|
+
TREE_RECIPE_SCHEMA,
|
|
15
|
+
TREE_RECIPE_VERSION,
|
|
16
|
+
TREE_TRUNK_STYLES,
|
|
17
|
+
StylizedTree,
|
|
18
|
+
createBranchTubeGeometry,
|
|
19
|
+
createBranchingTreeSkeleton,
|
|
20
|
+
createStylizedTreeSettings,
|
|
21
|
+
createTreeSkeleton,
|
|
22
|
+
createTreeTrunkGeometry,
|
|
23
|
+
getStylizedTreePresetOptions,
|
|
24
|
+
polarProfileFromOutline,
|
|
25
|
+
registerStylizedTreePreset,
|
|
26
|
+
resolvePadPruning,
|
|
27
|
+
serializableTreeOptions,
|
|
28
|
+
} from './stylizedTree.js';
|
|
8
29
|
export * from './branchTree.js';
|
|
9
|
-
export * from './legacyTreePresets.js';
|
|
10
30
|
export * from './stylizedTreeFoliage.js';
|
|
11
31
|
export * from './stylizedBush.js';
|
|
12
32
|
export * from './stylizedFlower.js';
|
|
@@ -247,7 +247,12 @@ export function scatterGrassAround({
|
|
|
247
247
|
* straight to StylizedTree for silhouette variation:
|
|
248
248
|
*
|
|
249
249
|
* for (const p of scatterForest({ center, radius: 80, spacing: 9, heightAt, mask })) {
|
|
250
|
-
* const tree = new StylizedTree({
|
|
250
|
+
* const tree = new StylizedTree({
|
|
251
|
+
* ...galleryTreeRecipe.options,
|
|
252
|
+
* seed: p.seed,
|
|
253
|
+
* size: 3.2,
|
|
254
|
+
* vegetationShader: { preset: 'call_me_sensei' },
|
|
255
|
+
* });
|
|
251
256
|
* tree.position.set(p.x, p.y, p.z);
|
|
252
257
|
* scene.add(tree);
|
|
253
258
|
* }
|
|
@@ -1334,88 +1334,6 @@ export const TREE_TRUNK_STYLES = Object.freeze({
|
|
|
1334
1334
|
height: 1.8, radiusBottom: 0.24 },
|
|
1335
1335
|
});
|
|
1336
1336
|
|
|
1337
|
-
// Ready-made example recipes, ordered least → most complex configuration.
|
|
1338
|
-
// Used by Tree Lab and the playground scene's showcase row; each is a
|
|
1339
|
-
// complete options object for `new StylizedTree(...)`.
|
|
1340
|
-
export const STYLIZED_TREE_EXAMPLES = Object.freeze([
|
|
1341
|
-
// 1. Baseline: straight trunk, default crown, one flat color.
|
|
1342
|
-
{ seed: 3, size: 1.7, canopyColor: 0x4da258, leafDensity: 1,
|
|
1343
|
-
trunk: TREE_TRUNK_STYLES.straight },
|
|
1344
|
-
// 2. Leaning trunk, same simple crown.
|
|
1345
|
-
{ seed: 8, size: 1.8, canopyColor: 0x54a85e, leafDensity: 1,
|
|
1346
|
-
trunk: TREE_TRUNK_STYLES.leaning },
|
|
1347
|
-
// 3. Slight see-through: gap pockets open, branches peek through.
|
|
1348
|
-
{ seed: 5, size: 1.9, canopyColor: 0x5eb063, leafDensity: 0.85,
|
|
1349
|
-
trunk: TREE_TRUNK_STYLES.leaning },
|
|
1350
|
-
// 4. Curved trunk + its own irregular crown layout.
|
|
1351
|
-
{ seed: 11, size: 2.0, canopyColor: 0x58ab5c, leafDensity: 0.95,
|
|
1352
|
-
trunk: TREE_TRUNK_STYLES.curved },
|
|
1353
|
-
// 5. Color picked from a list, per-seed (forest variation from one spec).
|
|
1354
|
-
{ seed: 17, size: 2.0, canopyColor: [0x4da258, 0x7fb84e, 0x9cbf46], leafDensity: 0.95,
|
|
1355
|
-
trunk: TREE_TRUNK_STYLES.curved },
|
|
1356
|
-
// 6. Wide-and-shallow crown (X reach 1.6, Z reach 0.7).
|
|
1357
|
-
{ seed: 9, size: 2.0, canopyColor: 0x6db54f, leafDensity: 0.95,
|
|
1358
|
-
canopyWidth: 1.6, canopyDepth: 0.7, trunk: TREE_TRUNK_STYLES.leaning },
|
|
1359
|
-
// 7. Autumn blend: seeded mix between two colors.
|
|
1360
|
-
{ seed: 21, size: 2.1, canopyColor: { from: 0xe8a33c, to: 0xd96f29 }, leafDensity: 0.9,
|
|
1361
|
-
trunk: TREE_TRUNK_STYLES.curved },
|
|
1362
|
-
// 8. Gnarled old tree: knotted growth, sparser crown shows the wood.
|
|
1363
|
-
{ seed: 14, size: 2.0, canopyColor: 0x8f9e44, leafDensity: 0.72,
|
|
1364
|
-
trunk: TREE_TRUNK_STYLES.gnarled },
|
|
1365
|
-
// 9. Bonsai: corkscrew twist, flat wide pads, HSL-range blossom color.
|
|
1366
|
-
{ seed: 26, size: 1.7, leafDensity: 0.8, canopyWidth: 1.4, canopyDepth: 1.2,
|
|
1367
|
-
canopyColor: { hue: [0.9, 1.0], saturation: [0.45, 0.6], lightness: [0.62, 0.72] },
|
|
1368
|
-
trunk: TREE_TRUNK_STYLES.bonsai },
|
|
1369
|
-
// 10. The Liyue golden gingko: fat-based serpentine trunk (bow right,
|
|
1370
|
-
// top swept hard left, S locked by leanOffset), extra-wide crown,
|
|
1371
|
-
// pinned pale-gold highlight tone. bendDirection 0 keeps the S in the
|
|
1372
|
-
// X-Y plane so the silhouette reads head-on in the showcase row.
|
|
1373
|
-
{ seed: 12, size: 2.4, canopyColor: 0xf5c531, canopyPalette: { crown: 0xffe98a },
|
|
1374
|
-
leafDensity: 0.95, canopyWidth: 1.5,
|
|
1375
|
-
skeleton: { radialSegments: 10 },
|
|
1376
|
-
trunk: { ...TREE_TRUNK_STYLES.swooping, bend: 0.5, lean: 0.95,
|
|
1377
|
-
bendDirection: 0, height: 2.0, radiusBottom: 0.28 } },
|
|
1378
|
-
// 11. Sumeru-style: long bare pale limbs reaching out of the crown with
|
|
1379
|
-
// violet leaf bushes only at the branch ends (leafPlacement 'tips').
|
|
1380
|
-
{ seed: 31, size: 2.3, pale: true, canopyColor: 0x8578e6,
|
|
1381
|
-
canopyPalette: { crown: 0xbdb2ff },
|
|
1382
|
-
leafDensity: 0.9, canopyWidth: 1.45, leafPlacement: 'tips',
|
|
1383
|
-
trunkReceiveShadow: false,
|
|
1384
|
-
skeleton: { attractionCount: 70, influenceRadius: 1.35 },
|
|
1385
|
-
trunk: { ...TREE_TRUNK_STYLES.curved, bend: 0.3, lean: 0.35, gnarl: 0.45,
|
|
1386
|
-
height: 1.9, radiusBottom: 0.26 } },
|
|
1387
|
-
// 12. MASSIVE climbable Sumeru tree: thick bare limbs long and low enough
|
|
1388
|
-
// to stand or sit on (scenes read `climbable: true` and collide the
|
|
1389
|
-
// wood as a trimesh instead of a trunk capsule), sparse skeleton so
|
|
1390
|
-
// the pale limbs stay on show, foliage clouds only at the limb ends.
|
|
1391
|
-
{ seed: 46, size: 4.0, pale: true, climbable: true,
|
|
1392
|
-
canopyColor: 0x8578e6, canopyPalette: { crown: 0xbdb2ff },
|
|
1393
|
-
leafDensity: 0.92, canopyWidth: 1.75, canopyDepth: 1.2,
|
|
1394
|
-
leafPlacement: 'tips', trunkReceiveShadow: false,
|
|
1395
|
-
skeleton: { attractionCount: 55, influenceRadius: 1.7, killRadius: 0.55,
|
|
1396
|
-
segmentLength: 0.36, attractionReach: 0.95, radialSegments: 14,
|
|
1397
|
-
tipRadius: 0.05, minLimbRadius: 0.04, maxNodes: 130 },
|
|
1398
|
-
canopy: { cardsPerCluster: 12, clusterRadius: 0.62 },
|
|
1399
|
-
trunk: { ...TREE_TRUNK_STYLES.leaning, bend: 0.24, lean: 0.42,
|
|
1400
|
-
height: 1.4, radiusBottom: 0.48 } },
|
|
1401
|
-
]);
|
|
1402
|
-
|
|
1403
|
-
// Centered X offsets for a showcase row: cumulative spacing from each tree's
|
|
1404
|
-
// approximate crown footprint, so a massive example doesn't swallow its
|
|
1405
|
-
// neighbors the way fixed spacing would.
|
|
1406
|
-
export function layoutTreeRow(configs, { margin = 1.6 } = {}) {
|
|
1407
|
-
const footprints = configs.map((config) =>
|
|
1408
|
-
(config.size ?? 1) * (config.canopyWidth ?? 1) * 2.3 + 1.4);
|
|
1409
|
-
const offsets = [];
|
|
1410
|
-
let cursor = 0;
|
|
1411
|
-
footprints.forEach((footprint, index) => {
|
|
1412
|
-
if (index > 0) cursor += (footprints[index - 1] + footprint) / 2 + margin;
|
|
1413
|
-
offsets.push(cursor);
|
|
1414
|
-
});
|
|
1415
|
-
const center = cursor / 2;
|
|
1416
|
-
return offsets.map((offset) => offset - center);
|
|
1417
|
-
}
|
|
1418
|
-
|
|
1419
1337
|
// Recipe documents: a plant serialized as { schema, version, type, options }.
|
|
1420
1338
|
// The options are exactly what the constructor takes, so a recipe rebuilds
|
|
1421
1339
|
// the identical plant (generation is deterministic per seed). Defined here —
|
|
@@ -1667,37 +1585,15 @@ export const DEFAULT_STYLIZED_TREE_SETTINGS = Object.freeze({
|
|
|
1667
1585
|
}),
|
|
1668
1586
|
});
|
|
1669
1587
|
|
|
1670
|
-
// Named
|
|
1671
|
-
//
|
|
1672
|
-
//
|
|
1673
|
-
// registerStylizedTreePreset().
|
|
1588
|
+
// Named runtime settings: npm ships only the neutral baseline. Authored tree
|
|
1589
|
+
// recipes live in the public Gallery and may be registered explicitly after
|
|
1590
|
+
// MCP discovery when an application wants name-based selection.
|
|
1674
1591
|
const stylizedTreePresetRegistry = new Map([
|
|
1675
1592
|
['default', Object.freeze({
|
|
1676
1593
|
description: 'Baseline stylized tree.',
|
|
1677
1594
|
label: 'Default',
|
|
1678
1595
|
settings: Object.freeze({}),
|
|
1679
1596
|
})],
|
|
1680
|
-
['call_me_sensei', Object.freeze({
|
|
1681
|
-
description: 'Studio-managed signature tree, curated by Call Me Sensei and updated over releases. Open broadleaf with visible branching: leaf clusters sit at the branch tips instead of filling a solid shell, so the limb structure reads through the crown.',
|
|
1682
|
-
label: 'Call Me Sensei',
|
|
1683
|
-
settings: Object.freeze({
|
|
1684
|
-
skeleton: Object.freeze({ attractionCount: 55, influenceRadius: 1.35 }),
|
|
1685
|
-
tree: Object.freeze({
|
|
1686
|
-
canopyWidth: 1.35,
|
|
1687
|
-
leafDensity: 1.15,
|
|
1688
|
-
leafPlacement: 'tips',
|
|
1689
|
-
trunkColor: Object.freeze([0.58, 0.36, 0.2]),
|
|
1690
|
-
}),
|
|
1691
|
-
trunk: Object.freeze({
|
|
1692
|
-
...TREE_TRUNK_STYLES.curved,
|
|
1693
|
-
bend: 0.24,
|
|
1694
|
-
gnarl: 0.22,
|
|
1695
|
-
height: 1.9,
|
|
1696
|
-
lean: 0.24,
|
|
1697
|
-
radiusBottom: 0.2,
|
|
1698
|
-
}),
|
|
1699
|
-
}),
|
|
1700
|
-
})],
|
|
1701
1597
|
]);
|
|
1702
1598
|
|
|
1703
1599
|
/**
|
package/src/version.js
CHANGED
package/types/index.d.ts
CHANGED
|
@@ -299,8 +299,6 @@ export const HERO_CLOUD_RECIPE_VERSION: any;
|
|
|
299
299
|
export const HUMANOID_ROLES: any;
|
|
300
300
|
export const LEAF_SHAPE_PRESETS: any;
|
|
301
301
|
export const LEGACY_STYLE_BUNDLE_SCHEMA_VERSION: any;
|
|
302
|
-
export const LEGACY_TREE_IDS: any;
|
|
303
|
-
export const LEGACY_TREE_PRESETS: any;
|
|
304
302
|
export const LIGHTING_LOOK_DOCUMENT_TYPE: any;
|
|
305
303
|
export const LIGHTING_LOOK_PRESETS: any;
|
|
306
304
|
export const LIGHTING_LOOK_SCHEMA_VERSION: any;
|
|
@@ -505,7 +503,6 @@ export const STYLE_TARGET_DOMAINS: any;
|
|
|
505
503
|
export const STYLE_TARGET_LABEL_KEY: any;
|
|
506
504
|
export const STYLE_TARGET_LABEL_SCHEMA_VERSION: any;
|
|
507
505
|
export const STYLIZED_FOREST_IMPOSTOR_QUALITY: any;
|
|
508
|
-
export const STYLIZED_TREE_EXAMPLES: any;
|
|
509
506
|
export const STYLIZED_TREE_SETTING_FIELD_SCHEMA: any;
|
|
510
507
|
export const STYLIZED_TREE_SETTING_GROUPS: any;
|
|
511
508
|
export const SUN_COLOR_FIELD: any;
|
|
@@ -869,7 +866,6 @@ export function createHeroCloudWeatherTexture(...args: any[]): any;
|
|
|
869
866
|
export function createImportedVegetationMaterial(...args: any[]): any;
|
|
870
867
|
export function createIndirectLightSettings(...args: any[]): any;
|
|
871
868
|
export function createLeafSpriteTexture(...args: any[]): any;
|
|
872
|
-
export function createLegacyTree(...args: any[]): any;
|
|
873
869
|
export function createLightArtisticSettings(...args: any[]): any;
|
|
874
870
|
export function createLightColor(...args: any[]): any;
|
|
875
871
|
export function createLightCookie(...args: any[]): any;
|
|
@@ -1098,8 +1094,6 @@ export function getGeometryTriangleCount(...args: any[]): any;
|
|
|
1098
1094
|
export function getGrassPresetOptions(...args: any[]): any;
|
|
1099
1095
|
export function getGroundShaderPresetOptions(...args: any[]): any;
|
|
1100
1096
|
export function getHeroCloudPreviewCenter(...args: any[]): any;
|
|
1101
|
-
export function getLegacyTreePreset(...args: any[]): any;
|
|
1102
|
-
export function getLegacyTreePresetOptions(...args: any[]): any;
|
|
1103
1097
|
export function getLightFixtureGeneratorFamilyOptions(...args: any[]): any;
|
|
1104
1098
|
export function getLightFixtureOptions(...args: any[]): any;
|
|
1105
1099
|
export function getLightingPresetOptions(...args: any[]): any;
|
|
@@ -1159,7 +1153,6 @@ export function isVegetationSharedShaderGroup(...args: any[]): any;
|
|
|
1159
1153
|
export function isWindowCutoutMaterial(...args: any[]): any;
|
|
1160
1154
|
export function labelManufacturedStyleTarget(...args: any[]): any;
|
|
1161
1155
|
export function labelStyleTarget(...args: any[]): any;
|
|
1162
|
-
export function layoutTreeRow(...args: any[]): any;
|
|
1163
1156
|
export function listFirstPartyStyleBundles(...args: any[]): any;
|
|
1164
1157
|
export function listSurfaceMaterialModes(...args: any[]): any;
|
|
1165
1158
|
export function loadAsync(...args: any[]): any;
|
|
@@ -39,12 +39,9 @@ export const GRASS_SHADER_PROFILE: any;
|
|
|
39
39
|
export const GRASS_SHADER_PROFILE_DOCUMENT_TYPE: any;
|
|
40
40
|
export const GRASS_SHADER_PROFILE_SCHEMA_VERSION: any;
|
|
41
41
|
export const LEAF_SHAPE_PRESETS: any;
|
|
42
|
-
export const LEGACY_TREE_IDS: any;
|
|
43
|
-
export const LEGACY_TREE_PRESETS: any;
|
|
44
42
|
export const NEEDLE_LEAF_SHAPES: any;
|
|
45
43
|
export class RetainedGrassClumpField { constructor(...args: any[]); [key: string]: any; }
|
|
46
44
|
export const STYLIZED_FOREST_IMPOSTOR_QUALITY: any;
|
|
47
|
-
export const STYLIZED_TREE_EXAMPLES: any;
|
|
48
45
|
export const STYLIZED_TREE_SETTING_FIELD_SCHEMA: any;
|
|
49
46
|
export const STYLIZED_TREE_SETTING_GROUPS: any;
|
|
50
47
|
export class StylizedBush { constructor(...args: any[]); [key: string]: any; }
|
|
@@ -133,7 +130,6 @@ export function createGrassShaderProfileSettings(...args: any[]): any;
|
|
|
133
130
|
export function createGrassShaderSettings(...args: any[]): any;
|
|
134
131
|
export function createImportedVegetationMaterial(...args: any[]): any;
|
|
135
132
|
export function createLeafSpriteTexture(...args: any[]): any;
|
|
136
|
-
export function createLegacyTree(...args: any[]): any;
|
|
137
133
|
export function createNoisePatchMask(...args: any[]): any;
|
|
138
134
|
export function createOrganLeafSpriteTexture(...args: any[]): any;
|
|
139
135
|
export function createSlopeMask(...args: any[]): any;
|
|
@@ -159,8 +155,6 @@ export function deriveCanopyPalette(...args: any[]): any;
|
|
|
159
155
|
export function disposeExportGroup(...args: any[]): any;
|
|
160
156
|
export function getFlowerPresetOptions(...args: any[]): any;
|
|
161
157
|
export function getGrassPresetOptions(...args: any[]): any;
|
|
162
|
-
export function getLegacyTreePreset(...args: any[]): any;
|
|
163
|
-
export function getLegacyTreePresetOptions(...args: any[]): any;
|
|
164
158
|
export function getStylizedTreePresetOptions(...args: any[]): any;
|
|
165
159
|
export function getTreeSurfaceProfileOptions(...args: any[]): any;
|
|
166
160
|
export function getVegetationMaterialContract(...args: any[]): any;
|
|
@@ -169,7 +163,6 @@ export function getVegetationShaderScopeExcludedFields(...args: any[]): any;
|
|
|
169
163
|
export function getVegetationShaderScopeFieldSchema(...args: any[]): any;
|
|
170
164
|
export function getVegetationShaderScopeSettingGroups(...args: any[]): any;
|
|
171
165
|
export function isVegetationSharedShaderGroup(...args: any[]): any;
|
|
172
|
-
export function layoutTreeRow(...args: any[]): any;
|
|
173
166
|
export function loadCallMeSenseiGrassClump(...args: any[]): any;
|
|
174
167
|
export function loadCompiledTreeAsset(...args: any[]): any;
|
|
175
168
|
export function matchGrassColorPalette(...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,6 @@ 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;
|
|
19
17
|
export function resolvePadPruning(...args: any[]): 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,120 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
STYLIZED_TREE_EXAMPLES,
|
|
3
|
-
StylizedTree,
|
|
4
|
-
TREE_RECIPE_SCHEMA,
|
|
5
|
-
TREE_RECIPE_VERSION,
|
|
6
|
-
serializableTreeOptions,
|
|
7
|
-
} from './stylizedTree.js';
|
|
8
|
-
|
|
9
|
-
const LEGACY_TREE_DEFINITIONS = Object.freeze([
|
|
10
|
-
Object.freeze({ id: 'straight', label: 'Straight' }),
|
|
11
|
-
Object.freeze({ id: 'leaning', label: 'Leaning' }),
|
|
12
|
-
Object.freeze({ id: 'see-through', label: 'See-through' }),
|
|
13
|
-
Object.freeze({ id: 'curved', label: 'Curved' }),
|
|
14
|
-
Object.freeze({ id: 'forest-mix', label: 'Forest Mix' }),
|
|
15
|
-
Object.freeze({ id: 'wide-crown', label: 'Wide Crown' }),
|
|
16
|
-
Object.freeze({ id: 'autumn-blend', label: 'Autumn Blend' }),
|
|
17
|
-
Object.freeze({ id: 'gnarled', label: 'Gnarled' }),
|
|
18
|
-
Object.freeze({ id: 'bonsai', label: 'Bonsai' }),
|
|
19
|
-
Object.freeze({ id: 'golden-gingko', label: 'Golden Gingko' }),
|
|
20
|
-
Object.freeze({ id: 'sumeru-tips', label: 'Sumeru Tips' }),
|
|
21
|
-
Object.freeze({ id: 'massive-sumeru', label: 'Massive Sumeru' }),
|
|
22
|
-
]);
|
|
23
|
-
|
|
24
|
-
function clone(value) {
|
|
25
|
-
if (Array.isArray(value)) return value.map(clone);
|
|
26
|
-
if (value && typeof value === 'object') {
|
|
27
|
-
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, clone(entry)]));
|
|
28
|
-
}
|
|
29
|
-
return value;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function deepFreeze(value) {
|
|
33
|
-
if (!value || typeof value !== 'object' || Object.isFrozen(value)) return value;
|
|
34
|
-
for (const entry of Object.values(value)) deepFreeze(entry);
|
|
35
|
-
return Object.freeze(value);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function legacyOptions(example) {
|
|
39
|
-
// `pale` and `climbable` are old showcase-scene hints, not tree generator
|
|
40
|
-
// inputs. Preserve them as document metadata without feeding them into the
|
|
41
|
-
// stable constructor surface.
|
|
42
|
-
const { pale = false, climbable = false, ...options } = example;
|
|
43
|
-
return {
|
|
44
|
-
metadata: { climbable: Boolean(climbable), pale: Boolean(pale) },
|
|
45
|
-
options: serializableTreeOptions(options),
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* The twelve pre-species ToonLab trees, now named and versioned explicitly.
|
|
51
|
-
*
|
|
52
|
-
* This is the supported legacy set that existed before the repository's
|
|
53
|
-
* botanical species research. It contains only generic stylized silhouettes;
|
|
54
|
-
* none of the documents claims a botanical species identity.
|
|
55
|
-
*/
|
|
56
|
-
export const LEGACY_TREE_PRESETS = deepFreeze(LEGACY_TREE_DEFINITIONS.map((definition, index) => {
|
|
57
|
-
const normalized = legacyOptions(STYLIZED_TREE_EXAMPLES[index]);
|
|
58
|
-
return {
|
|
59
|
-
builtIn: true,
|
|
60
|
-
id: definition.id,
|
|
61
|
-
label: definition.label,
|
|
62
|
-
metadata: normalized.metadata,
|
|
63
|
-
options: normalized.options,
|
|
64
|
-
schema: TREE_RECIPE_SCHEMA,
|
|
65
|
-
type: 'tree',
|
|
66
|
-
version: TREE_RECIPE_VERSION,
|
|
67
|
-
};
|
|
68
|
-
}));
|
|
69
|
-
|
|
70
|
-
export const LEGACY_TREE_IDS = Object.freeze(LEGACY_TREE_PRESETS.map(({ id }) => id));
|
|
71
|
-
|
|
72
|
-
/** Returns one immutable legacy recipe document, or null. */
|
|
73
|
-
export function getLegacyTreePreset(id) {
|
|
74
|
-
return LEGACY_TREE_PRESETS.find((preset) => preset.id === id) ?? null;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/** Lists the stable legacy IDs and labels without duplicating recipe data. */
|
|
78
|
-
export function getLegacyTreePresetOptions() {
|
|
79
|
-
return LEGACY_TREE_PRESETS.map(({ id, label, metadata }) => ({
|
|
80
|
-
id,
|
|
81
|
-
label,
|
|
82
|
-
metadata: { ...metadata },
|
|
83
|
-
}));
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Creates one tree from the supported pre-species set.
|
|
88
|
-
*
|
|
89
|
-
* Overrides remain the ordinary StylizedTree contract, including `leafShape`,
|
|
90
|
-
* `trunkMap`, `foliage.leafMap`, and `vegetationShader`. Nested generator and
|
|
91
|
-
* material groups merge over the selected recipe instead of replacing it.
|
|
92
|
-
*/
|
|
93
|
-
export function createLegacyTree(id, overrides = {}) {
|
|
94
|
-
const preset = getLegacyTreePreset(id);
|
|
95
|
-
if (!preset) throw new Error(`Unknown legacy tree preset "${String(id)}".`);
|
|
96
|
-
const base = clone(preset.options);
|
|
97
|
-
const source = overrides && typeof overrides === 'object' && !Array.isArray(overrides)
|
|
98
|
-
? overrides
|
|
99
|
-
: {};
|
|
100
|
-
const tree = new StylizedTree({
|
|
101
|
-
...base,
|
|
102
|
-
...source,
|
|
103
|
-
canopy: { ...(base.canopy ?? {}), ...(source.canopy ?? {}) },
|
|
104
|
-
foliage: { ...(base.foliage ?? {}), ...(source.foliage ?? {}) },
|
|
105
|
-
skeleton: { ...(base.skeleton ?? {}), ...(source.skeleton ?? {}) },
|
|
106
|
-
tree: {
|
|
107
|
-
...(base.tree ?? {}),
|
|
108
|
-
...(source.tree ?? {}),
|
|
109
|
-
trunkReceiveShadow: source.tree?.trunkReceiveShadow ?? true,
|
|
110
|
-
},
|
|
111
|
-
trunk: { ...(base.trunk ?? {}), ...(source.trunk ?? {}) },
|
|
112
|
-
});
|
|
113
|
-
tree.name = `LegacyTree:${preset.id}`;
|
|
114
|
-
tree.userData.legacyTree = {
|
|
115
|
-
id: preset.id,
|
|
116
|
-
label: preset.label,
|
|
117
|
-
recipeVersion: preset.version,
|
|
118
|
-
};
|
|
119
|
-
return tree;
|
|
120
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/** Returns one immutable legacy recipe document, or null. */
|
|
2
|
-
export function getLegacyTreePreset(id: any): any;
|
|
3
|
-
/** Lists the stable legacy IDs and labels without duplicating recipe data. */
|
|
4
|
-
export function getLegacyTreePresetOptions(): any;
|
|
5
|
-
/**
|
|
6
|
-
* Creates one tree from the supported pre-species set.
|
|
7
|
-
*
|
|
8
|
-
* Overrides remain the ordinary StylizedTree contract, including `leafShape`,
|
|
9
|
-
* `trunkMap`, `foliage.leafMap`, and `vegetationShader`. Nested generator and
|
|
10
|
-
* material groups merge over the selected recipe instead of replacing it.
|
|
11
|
-
*/
|
|
12
|
-
export function createLegacyTree(id: any, overrides?: {}): StylizedTree;
|
|
13
|
-
/**
|
|
14
|
-
* The twelve pre-species ToonLab trees, now named and versioned explicitly.
|
|
15
|
-
*
|
|
16
|
-
* This is the supported legacy set that existed before the repository's
|
|
17
|
-
* botanical species research. It contains only generic stylized silhouettes;
|
|
18
|
-
* none of the documents claims a botanical species identity.
|
|
19
|
-
*/
|
|
20
|
-
export const LEGACY_TREE_PRESETS: any;
|
|
21
|
-
export const LEGACY_TREE_IDS: any;
|
|
22
|
-
import { StylizedTree } from './stylizedTree.js';
|