@babylonjs-toolkit/agent 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +344 -0
- package/bin/bt-agent.js +266 -0
- package/lib/doctor.js +59 -0
- package/lib/install.js +145 -0
- package/lib/manifest.js +46 -0
- package/lib/paths.js +66 -0
- package/lib/payload.js +56 -0
- package/lib/persona.js +177 -0
- package/lib/targets.js +105 -0
- package/package.json +43 -0
- package/persona.md +5 -0
- package/scripts/postinstall.js +49 -0
- package/skills/bt-atlas/SKILL.md +192 -0
- package/skills/bt-atlas/scripts/composite_skin.py +58 -0
- package/skills/bt-atlas/scripts/preview.py +70 -0
- package/skills/bt-atlas/scripts/requirements.txt +2 -0
- package/skills/bt-atlas/scripts/uv_island_mask.py +87 -0
- package/skills/bt-convert/SKILL.md +32 -0
- package/skills/bt-copycat/SKILL.md +184 -0
- package/skills/bt-design/SKILL.md +187 -0
- package/skills/bt-design/references/3d-hero-docs.md +976 -0
- package/skills/bt-design/references/3d-hero-scroll.md +269 -0
- package/skills/bt-design/templates/3d-hero-scroll/HeroScroll.tsx +167 -0
- package/skills/bt-design/templates/3d-hero-scroll/hero-scroll.css +268 -0
- package/skills/bt-design/templates/3d-hero-scroll/hero-scroll.d.ts +67 -0
- package/skills/bt-design/templates/3d-hero-scroll/hero-scroll.html +78 -0
- package/skills/bt-design/templates/3d-hero-scroll/hero-scroll.js +559 -0
- package/skills/bt-execute/SKILL.md +130 -0
- package/skills/bt-gauntlet/SKILL.md +335 -0
- package/skills/bt-hero/SKILL.md +158 -0
- package/skills/bt-landing/SKILL.md +126 -0
- package/skills/bt-plan/SKILL.md +172 -0
- package/skills/bt-prototype/SKILL.md +161 -0
- package/skills/bt-spec/SKILL.md +328 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bt-atlas
|
|
3
|
+
description: "The Babylon Toolkit Texture Atlas Skill generates texture atlas skin variations for a UV-mapped 3D model that stay strictly inside the UV islands, so they are drop-in swaps for the same geometry. Use whenever the user wants new skins / texture variants (different colors, faces, materials, camo, liveries, etc.) from a base color texture and its UV layout. Works for any model — not specific to any one asset."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Invocation
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
/bt-atlas <base-texture> <uv-layout> <variation-brief>
|
|
10
|
+
```
|
|
11
|
+
- **`<base-texture>`** — the existing skin; defines overall look & feel.
|
|
12
|
+
- **`<uv-layout>`** — the wireframe/island map for the same texture.
|
|
13
|
+
- **`<variation-brief>`** — how to vary the texture while staying within the UV islands.
|
|
14
|
+
- If any input is missing, ask for it before starting. Never guess a file path or URL.
|
|
15
|
+
|
|
16
|
+
Example:
|
|
17
|
+
```
|
|
18
|
+
/bt-atlas → base_texture.png → uv_layout.png → "Change clothing + face, keep the horse hide and the eye island"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
# Generate Texture Atlas (UV-safe atlas variations)
|
|
24
|
+
|
|
25
|
+
Create N variations of a model's base color texture atlas using AI image
|
|
26
|
+
generation, guaranteeing every output keeps the **exact same UV layout** as the
|
|
27
|
+
base so it can be swapped onto the same model geometry/UVs without re-mapping.
|
|
28
|
+
|
|
29
|
+
Use the user's message after the skill name as the `arguments`.
|
|
30
|
+
|
|
31
|
+
The core trick: AI image editors will not respect UV-island edges on their own —
|
|
32
|
+
they bleed paint into the empty/padding areas and sometimes shift islands. So we
|
|
33
|
+
**never ship the raw AI output**. We generate, then **mask-and-composite**: keep
|
|
34
|
+
only the pixels inside the UV-island footprint from the AI image and take
|
|
35
|
+
everything else verbatim from the base texture.
|
|
36
|
+
|
|
37
|
+
This skill is general purpose. It makes no assumption about where islands sit in
|
|
38
|
+
the atlas (top/bottom/left/right) — the mask is derived automatically from the
|
|
39
|
+
UV layout image.
|
|
40
|
+
|
|
41
|
+
## Inputs you need from the user (ask if missing)
|
|
42
|
+
1. **Base color texture** (PNG) — the existing skin; defines overall look & feel.
|
|
43
|
+
A local file path or an `http(s)://` URL both work.
|
|
44
|
+
2. **UV layout image** (PNG) — the wireframe/island map for the same texture
|
|
45
|
+
(white island outlines on dark background is the typical export). If only a
|
|
46
|
+
combined "all submeshes" layout exists, that works too. A local file path or
|
|
47
|
+
an `http(s)://` URL both work.
|
|
48
|
+
3. **What to vary vs preserve** — e.g. "change clothing + face, keep the horse
|
|
49
|
+
hide and the eye island". Inspect the base + layout yourself to identify the
|
|
50
|
+
islands; confirm ambiguous ones with the user.
|
|
51
|
+
4. **Number of variations and a brief per-variation description** (the creative
|
|
52
|
+
direction: skin tones, faces, color schemes, materials, etc.).
|
|
53
|
+
5. **Output directory** — default to a `SkinVariations/` folder next to the base
|
|
54
|
+
texture if not specified.
|
|
55
|
+
|
|
56
|
+
If the base texture or UV layout isn't supplied at all, ask for it — don't
|
|
57
|
+
guess or substitute a placeholder. If it IS supplied (local path or URL) but is
|
|
58
|
+
wrong (path doesn't exist, URL isn't reachable / doesn't return an image, or
|
|
59
|
+
the content isn't actually an image), STOP before generating anything — do not
|
|
60
|
+
guess, substitute a different file, or continue with a partial setup. Tell the
|
|
61
|
+
user exactly which input failed and why, and ask for a corrected path/URL.
|
|
62
|
+
|
|
63
|
+
## Tools
|
|
64
|
+
- **Image generation**: use whichever image-generation tool is available by
|
|
65
|
+
default on the current platform (an MCP image-generation server such as
|
|
66
|
+
`kie-image-mcp`, a built-in model image-generation capability, or any other
|
|
67
|
+
configured image tool) — don't assume one specific provider. If the user
|
|
68
|
+
names a particular tool or model in their request (e.g. "use nano-banana-2",
|
|
69
|
+
"use Flux", "use imagen4"), use that one instead of the default. Whichever
|
|
70
|
+
tool is used, pass BOTH the base texture and the UV layout as reference
|
|
71
|
+
images to it. Match `aspect_ratio` to the texture (usually `1:1`), request a
|
|
72
|
+
resolution/size close to the texture size (e.g. `2K` for 2048px), and request
|
|
73
|
+
PNG output. If no image-generation tool is available at all, tell the user
|
|
74
|
+
and ask them to configure one before proceeding.
|
|
75
|
+
- **Helper scripts** live in the `scripts/` folder next to this SKILL.md
|
|
76
|
+
(need Python 3 + Pillow + numpy):
|
|
77
|
+
- `scripts/uv_island_mask.py` — build the island mask from the UV layout.
|
|
78
|
+
- `scripts/composite_skin.py` — composite one AI output through the mask onto the base.
|
|
79
|
+
- `scripts/preview.py` — `mask-overlay` to verify the mask; `sheet` for a contact sheet.
|
|
80
|
+
Resolve `<skilldir>` as the directory containing this SKILL.md file, so scripts
|
|
81
|
+
are at `<skilldir>/scripts/`. Install deps once if needed:
|
|
82
|
+
`python3 -m pip install -r <skilldir>/scripts/requirements.txt`
|
|
83
|
+
(or `python3 -m pip install pillow numpy`). Each script also auto-installs its
|
|
84
|
+
own missing deps on first run.
|
|
85
|
+
|
|
86
|
+
## Procedure
|
|
87
|
+
|
|
88
|
+
### 0. Validate inputs
|
|
89
|
+
Confirm the base texture and UV layout are both usable before doing anything
|
|
90
|
+
else:
|
|
91
|
+
- **Local path**: confirm it exists and opens as a valid image.
|
|
92
|
+
- **URL**: confirm it's reachable and actually returns image content, then
|
|
93
|
+
download it once into `<scratch>/` (e.g. `base_source.png` /
|
|
94
|
+
`uv_layout_source.png`) — the helper scripts below only work on local files,
|
|
95
|
+
so use these downloaded copies as "`<base.png>`"/"`<uv_layout.png>`" for every
|
|
96
|
+
step from here on.
|
|
97
|
+
|
|
98
|
+
If either input fails validation, stop and report which one and why (missing /
|
|
99
|
+
wrong path / URL unreachable / not an image) instead of proceeding — never fall
|
|
100
|
+
back to a default or unrelated file.
|
|
101
|
+
|
|
102
|
+
### 1. Inspect
|
|
103
|
+
Read the base texture and the UV layout as images. Note the texture pixel size
|
|
104
|
+
(`sips -g pixelWidth -g pixelHeight <file>` on macOS, or open the image and check
|
|
105
|
+
its dimensions). Decide which islands change and which are preserved.
|
|
106
|
+
|
|
107
|
+
### 2. Build the UV-island mask
|
|
108
|
+
```
|
|
109
|
+
python3 <skilldir>/scripts/uv_island_mask.py <uv_layout.png> <scratch>/island_mask.png --size <TEXSIZE>
|
|
110
|
+
```
|
|
111
|
+
Defaults: `--radius 9 --thresh 35`. Increase `--radius` if big internal triangles
|
|
112
|
+
leave holes; lower `--thresh` if the wireframe is faint. Coverage is printed —
|
|
113
|
+
sanity check it (a full-body atlas is typically 20–50%).
|
|
114
|
+
|
|
115
|
+
### 3. Verify the mask (do not skip)
|
|
116
|
+
```
|
|
117
|
+
python3 <skilldir>/scripts/preview.py mask-overlay <base.png> <scratch>/island_mask.png <scratch>/overlay.png
|
|
118
|
+
```
|
|
119
|
+
Read `overlay.png`. The red tint MUST cover exactly the islands you intend to
|
|
120
|
+
change and NOT the preserved islands / dead space. If it's inverted or off,
|
|
121
|
+
re-run step 2 with adjusted params (the script already auto-strips a white border
|
|
122
|
+
frame; if the layout has unusual framing, that is the usual culprit).
|
|
123
|
+
|
|
124
|
+
### 4. Generate each raw variation
|
|
125
|
+
Save raw AI outputs to `<scratch>/raw/skin_var_NN.png` (NOT the final folder).
|
|
126
|
+
Use this prompt template with the chosen image-generation tool (the platform's
|
|
127
|
+
default, or whichever one the user named), filling the per-variation creative
|
|
128
|
+
bits and the preserve/change lists for the specific asset:
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
You are editing a {W}x{H} game model TEXTURE ATLAS (UV unwrap). Reference image 1
|
|
132
|
+
is the base color atlas (use it as the guide for overall look, layout and
|
|
133
|
+
proportions). Reference image 2 is the UV ISLAND MAP showing exact wireframe
|
|
134
|
+
outlines of every UV island.
|
|
135
|
+
|
|
136
|
+
ABSOLUTE LAYOUT RULES (this is a skin swap for one shared model — the UV layout
|
|
137
|
+
MUST match exactly):
|
|
138
|
+
- Reproduce reference image 1's GEOMETRY/LAYOUT exactly: every UV island stays in
|
|
139
|
+
the same position, size, rotation and shape. Painted detail must fit inside the
|
|
140
|
+
same island outlines.
|
|
141
|
+
- Keep these islands unchanged: {LIST WHAT TO PRESERVE}.
|
|
142
|
+
- Do NOT add any new art, portrait or object anywhere. Do NOT paint into the
|
|
143
|
+
empty/black/white background. Paint ONLY inside existing colored islands.
|
|
144
|
+
- You may recolor/repattern ONLY: {LIST WHAT TO CHANGE}.
|
|
145
|
+
- Flat evenly-lit albedo/diffuse texture, no baked shadows.
|
|
146
|
+
|
|
147
|
+
VARIATION DETAILS: {creative description for this variant}
|
|
148
|
+
```
|
|
149
|
+
Generating several variants in parallel is fine. The raw output will likely bleed
|
|
150
|
+
outside the islands — that is expected and removed in the next step.
|
|
151
|
+
|
|
152
|
+
### 5. Composite through the mask -> final skins
|
|
153
|
+
For each variant:
|
|
154
|
+
```
|
|
155
|
+
python3 <skilldir>/scripts/composite_skin.py <base.png> <scratch>/island_mask.png \
|
|
156
|
+
<scratch>/raw/skin_var_NN.png <FINAL_DIR>/skin_var_NN.png
|
|
157
|
+
```
|
|
158
|
+
This writes the shippable skin: island pixels from the AI image, everything else
|
|
159
|
+
identical to the base. Optional `--feather` (default 1.0px) softens the seam.
|
|
160
|
+
|
|
161
|
+
### 6. Review
|
|
162
|
+
```
|
|
163
|
+
python3 <skilldir>/scripts/preview.py sheet <scratch>/contact_sheet.png <FINAL_DIR>/skin_var_*.png
|
|
164
|
+
```
|
|
165
|
+
Read the contact sheet (and crop into key islands like faces if needed) to
|
|
166
|
+
confirm variety and quality. Regenerate any weak variants by repeating steps 4–5
|
|
167
|
+
for just those indices.
|
|
168
|
+
|
|
169
|
+
## Notes & gotchas
|
|
170
|
+
- Always pass BOTH base + UV layout as references to the generator; never rely on
|
|
171
|
+
the prompt alone to hold the layout.
|
|
172
|
+
- The mask is the safety net. If a variant's island content is shifted inside its
|
|
173
|
+
island, the composite clips it to the island shape — re-prompt that variant
|
|
174
|
+
rather than widening the mask.
|
|
175
|
+
- Keep raw AI outputs separate from finals so you can re-composite without
|
|
176
|
+
re-generating (e.g. after tuning the mask).
|
|
177
|
+
- For engine import (Unity, Babylon, etc.), the finals go in the project's
|
|
178
|
+
texture folder; the engine generates its own meta/import settings.
|
|
179
|
+
|
|
180
|
+
## How to use this skill
|
|
181
|
+
- Invoke it directly (e.g. the `/bt-atlas` slash command, if your tool derives one
|
|
182
|
+
from this folder), or just ask in chat for new texture/skin variants — this
|
|
183
|
+
skill applies whenever the request matches its description.
|
|
184
|
+
- Provide: the base color texture path, the UV layout image path, how many
|
|
185
|
+
variations you want, and which islands to change vs preserve (a short
|
|
186
|
+
creative direction per variation helps too). For example:
|
|
187
|
+
> `/bt-atlas textures/hero_base.png textures/hero_uv_layout.png 4 vary armor color and face, keep the sword and hair`
|
|
188
|
+
- Anything you omit will be asked for before generation starts (see **Inputs**
|
|
189
|
+
below). You can also name a specific image-generation tool/model to use (see
|
|
190
|
+
**Tools** below) — otherwise the default available one is used.
|
|
191
|
+
- Output lands in `SkinVariations/` next to the base texture unless you specify
|
|
192
|
+
another output directory.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Composite a generated skin onto the base texture through a UV-island mask.
|
|
3
|
+
|
|
4
|
+
Keeps ONLY the pixels INSIDE the UV-island mask from the generated image and
|
|
5
|
+
takes everything else verbatim from the base texture. This guarantees the
|
|
6
|
+
generated skin can never alter the UV layout / dead space, so it stays a valid
|
|
7
|
+
drop-in skin swap for the same model geometry & UVs.
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
python3 composite_skin.py <base.png> <mask.png> <generated.png> <out.png> [--feather 1.0]
|
|
11
|
+
"""
|
|
12
|
+
import argparse
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _ensure_deps():
|
|
16
|
+
"""Auto-install Pillow/numpy on first run so users only need Python itself."""
|
|
17
|
+
import importlib
|
|
18
|
+
import subprocess
|
|
19
|
+
import sys
|
|
20
|
+
for mod, pkg in (("PIL", "pillow"), ("numpy", "numpy")):
|
|
21
|
+
try:
|
|
22
|
+
importlib.import_module(mod)
|
|
23
|
+
except ImportError:
|
|
24
|
+
print(f"[skin] installing missing dependency: {pkg} ...")
|
|
25
|
+
subprocess.check_call([sys.executable, "-m", "pip", "install", "--user", "--quiet", pkg])
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
_ensure_deps()
|
|
29
|
+
|
|
30
|
+
import numpy as np
|
|
31
|
+
from PIL import Image, ImageFilter
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def composite(base_path, mask_path, gen_path, out_path, feather=1.0):
|
|
35
|
+
base = Image.open(base_path).convert("RGB")
|
|
36
|
+
size = base.size
|
|
37
|
+
mask = Image.open(mask_path).convert("L").resize(size)
|
|
38
|
+
if feather > 0:
|
|
39
|
+
mask = mask.filter(ImageFilter.GaussianBlur(feather)) # avoid hard seams
|
|
40
|
+
gen = Image.open(gen_path).convert("RGB").resize(size)
|
|
41
|
+
|
|
42
|
+
ba = np.array(base, dtype=np.float32)
|
|
43
|
+
ga = np.array(gen, dtype=np.float32)
|
|
44
|
+
ma = (np.array(mask, dtype=np.float32) / 255.0)[..., None]
|
|
45
|
+
out = ga * ma + ba * (1.0 - ma)
|
|
46
|
+
Image.fromarray(out.astype(np.uint8)).save(out_path)
|
|
47
|
+
print("wrote", out_path)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
if __name__ == "__main__":
|
|
51
|
+
p = argparse.ArgumentParser()
|
|
52
|
+
p.add_argument("base")
|
|
53
|
+
p.add_argument("mask")
|
|
54
|
+
p.add_argument("gen")
|
|
55
|
+
p.add_argument("out")
|
|
56
|
+
p.add_argument("--feather", type=float, default=1.0)
|
|
57
|
+
args = p.parse_args()
|
|
58
|
+
composite(args.base, args.mask, args.gen, args.out, args.feather)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Verification helpers for the skin generation workflow.
|
|
3
|
+
|
|
4
|
+
mask-overlay : tint the base texture red where the island mask is active, so you
|
|
5
|
+
can confirm the mask covers the intended islands and nothing else.
|
|
6
|
+
sheet : build a contact sheet of several images for quick visual review.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
python3 preview.py mask-overlay <base.png> <mask.png> <out.png>
|
|
10
|
+
python3 preview.py sheet <out.png> <img1> <img2> ... [--cols 5] [--cell 300]
|
|
11
|
+
"""
|
|
12
|
+
import argparse
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _ensure_deps():
|
|
16
|
+
"""Auto-install Pillow/numpy on first run so users only need Python itself."""
|
|
17
|
+
import importlib
|
|
18
|
+
import subprocess
|
|
19
|
+
import sys
|
|
20
|
+
for mod, pkg in (("PIL", "pillow"), ("numpy", "numpy")):
|
|
21
|
+
try:
|
|
22
|
+
importlib.import_module(mod)
|
|
23
|
+
except ImportError:
|
|
24
|
+
print(f"[skin] installing missing dependency: {pkg} ...")
|
|
25
|
+
subprocess.check_call([sys.executable, "-m", "pip", "install", "--user", "--quiet", pkg])
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
_ensure_deps()
|
|
29
|
+
|
|
30
|
+
import numpy as np
|
|
31
|
+
from PIL import Image
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def mask_overlay(base_path, mask_path, out_path):
|
|
35
|
+
base = Image.open(base_path).convert("RGB")
|
|
36
|
+
size = base.size
|
|
37
|
+
mask = Image.open(mask_path).convert("L").resize(size)
|
|
38
|
+
ba = np.array(base, dtype=np.float32)
|
|
39
|
+
mm = (np.array(mask, dtype=np.float32) / 255.0)[..., None]
|
|
40
|
+
red = np.zeros_like(ba)
|
|
41
|
+
red[..., 0] = 255
|
|
42
|
+
ov = ba * (1 - 0.45 * mm) + red * (0.45 * mm)
|
|
43
|
+
Image.fromarray(ov.astype(np.uint8)).save(out_path)
|
|
44
|
+
print("wrote", out_path)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def sheet(out_path, imgs, cols=5, cell=300):
|
|
48
|
+
rows = (len(imgs) + cols - 1) // cols
|
|
49
|
+
s = Image.new("RGB", (cols * cell, rows * cell), (20, 20, 20))
|
|
50
|
+
for i, pth in enumerate(imgs):
|
|
51
|
+
im = Image.open(pth).convert("RGB").resize((cell, cell))
|
|
52
|
+
s.paste(im, ((i % cols) * cell, (i // cols) * cell))
|
|
53
|
+
s.save(out_path)
|
|
54
|
+
print("wrote", out_path)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
if __name__ == "__main__":
|
|
58
|
+
p = argparse.ArgumentParser()
|
|
59
|
+
sub = p.add_subparsers(dest="cmd", required=True)
|
|
60
|
+
a = sub.add_parser("mask-overlay")
|
|
61
|
+
a.add_argument("base"); a.add_argument("mask"); a.add_argument("out")
|
|
62
|
+
b = sub.add_parser("sheet")
|
|
63
|
+
b.add_argument("out"); b.add_argument("imgs", nargs="+")
|
|
64
|
+
b.add_argument("--cols", type=int, default=5)
|
|
65
|
+
b.add_argument("--cell", type=int, default=300)
|
|
66
|
+
args = p.parse_args()
|
|
67
|
+
if args.cmd == "mask-overlay":
|
|
68
|
+
mask_overlay(args.base, args.mask, args.out)
|
|
69
|
+
else:
|
|
70
|
+
sheet(args.out, args.imgs, args.cols, args.cell)
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Build a binary UV-island footprint mask from a UV wireframe layout image.
|
|
3
|
+
|
|
4
|
+
General purpose: makes NO assumption about where the islands sit in the texture
|
|
5
|
+
(top/bottom/left/right). It thresholds the wireframe, optionally strips an outer
|
|
6
|
+
white border frame, morphologically closes the triangles into solid island blobs,
|
|
7
|
+
fills interior holes (position-independent flood from a padded border), then erodes
|
|
8
|
+
back to the original boundary.
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
python3 uv_island_mask.py <uv_layout.png> <out_mask.png> \
|
|
12
|
+
[--size 2048] [--radius 9] [--thresh 35]
|
|
13
|
+
|
|
14
|
+
Tune --radius up if islands have large internal triangles that don't merge;
|
|
15
|
+
tune --thresh if the wireframe is faint (lower) or the background is noisy (higher).
|
|
16
|
+
"""
|
|
17
|
+
import argparse
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _ensure_deps():
|
|
21
|
+
"""Auto-install Pillow/numpy on first run so users only need Python itself."""
|
|
22
|
+
import importlib
|
|
23
|
+
import subprocess
|
|
24
|
+
import sys
|
|
25
|
+
for mod, pkg in (("PIL", "pillow"), ("numpy", "numpy")):
|
|
26
|
+
try:
|
|
27
|
+
importlib.import_module(mod)
|
|
28
|
+
except ImportError:
|
|
29
|
+
print(f"[skin] installing missing dependency: {pkg} ...")
|
|
30
|
+
subprocess.check_call([sys.executable, "-m", "pip", "install", "--user", "--quiet", pkg])
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
_ensure_deps()
|
|
34
|
+
|
|
35
|
+
import numpy as np
|
|
36
|
+
from PIL import Image, ImageFilter, ImageDraw, ImageOps
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def build_mask(uv_path, size=2048, radius=9, thresh=35):
|
|
40
|
+
uv = Image.open(uv_path).convert("L").resize((size, size), Image.BILINEAR)
|
|
41
|
+
a = np.array(uv)
|
|
42
|
+
fg = a > thresh # wireframe lines
|
|
43
|
+
|
|
44
|
+
# Auto-strip a white border frame if the image edge is mostly foreground
|
|
45
|
+
# (common in exported UV layout images). Harmless if no frame exists.
|
|
46
|
+
border = max(4, size // 170)
|
|
47
|
+
edge = np.concatenate([fg[0], fg[-1], fg[:, 0], fg[:, -1]])
|
|
48
|
+
if edge.mean() > 0.5:
|
|
49
|
+
fg[:border] = False
|
|
50
|
+
fg[-border:] = False
|
|
51
|
+
fg[:, :border] = False
|
|
52
|
+
fg[:, -border:] = False
|
|
53
|
+
|
|
54
|
+
m = Image.fromarray((fg.astype(np.uint8)) * 255)
|
|
55
|
+
|
|
56
|
+
# Close: dilate to merge wireframe triangles into solid island blobs
|
|
57
|
+
m = m.filter(ImageFilter.MaxFilter(2 * radius + 1))
|
|
58
|
+
|
|
59
|
+
# Fill interior holes, position-independent: flood the background starting
|
|
60
|
+
# from a 1px padded border, anything unreached is an interior hole.
|
|
61
|
+
inv = ImageOps.invert(m) # background bright
|
|
62
|
+
padded = ImageOps.expand(inv, 1, fill=255)
|
|
63
|
+
ImageDraw.floodfill(padded, (0, 0), 128, thresh=10)
|
|
64
|
+
parr = np.array(padded)[1:-1, 1:-1]
|
|
65
|
+
holes = parr == 255 # background not reached -> hole
|
|
66
|
+
filled = (np.array(m) > 127) | holes
|
|
67
|
+
mask = Image.fromarray((filled.astype(np.uint8)) * 255)
|
|
68
|
+
|
|
69
|
+
# Erode back to restore the original boundary size (undo the dilation),
|
|
70
|
+
# then a small safety dilation so island edges are not clipped.
|
|
71
|
+
mask = mask.filter(ImageFilter.MinFilter(2 * radius + 1))
|
|
72
|
+
mask = mask.filter(ImageFilter.MaxFilter(5))
|
|
73
|
+
return mask
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
if __name__ == "__main__":
|
|
77
|
+
p = argparse.ArgumentParser()
|
|
78
|
+
p.add_argument("uv")
|
|
79
|
+
p.add_argument("out")
|
|
80
|
+
p.add_argument("--size", type=int, default=2048)
|
|
81
|
+
p.add_argument("--radius", type=int, default=9)
|
|
82
|
+
p.add_argument("--thresh", type=int, default=35)
|
|
83
|
+
args = p.parse_args()
|
|
84
|
+
mk = build_mask(args.uv, args.size, args.radius, args.thresh)
|
|
85
|
+
mk.save(args.out)
|
|
86
|
+
cov = 100.0 * (np.array(mk) > 127).mean()
|
|
87
|
+
print(f"saved {args.out} ({mk.size[0]}x{mk.size[1]}), island coverage {cov:.1f}%")
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bt-convert
|
|
3
|
+
description: "The Babylon Toolkit Convert Skill converts source code to Babylon Toolkit TypeScript. Use when asked to convert source code or files to BabylonJS/Babylon Toolkit typescript."
|
|
4
|
+
allowed-tools: Read, Write, Edit, Glob, Grep
|
|
5
|
+
---
|
|
6
|
+
Your goal is to convert source code to Babylon Toolkit based TypeScript. Always adhere to any rules or requirements set out in the project's agent instructions (AGENTS.md / CLAUDE.md / .github/copilot-instructions.md) when responding.
|
|
7
|
+
|
|
8
|
+
* Create new typescript (.ts) files for converted code
|
|
9
|
+
* Make sure to convert all source code, do **not** omit anything (methods, properties, comments, etc), convert everything according to instructions
|
|
10
|
+
* If an interface is only referenced (not defined in the source code being converted), do **not** generate the interface, just reference it
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Invocation
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
/bt-convert <source-code> <conversion-brief>
|
|
18
|
+
```
|
|
19
|
+
- **`<source-code>`** — the source code to convert. This is the *blueprint*.
|
|
20
|
+
- **`<conversion-brief>`** — how to convert it. This is the *variable*.
|
|
21
|
+
- If either is missing, ask for it before starting. Never guess a URL.
|
|
22
|
+
|
|
23
|
+
Example:
|
|
24
|
+
```
|
|
25
|
+
/bt-convert → path/to/file.cs → "Convert to Babylon Toolkit TypeScript"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
**Use The Babylon Toolkit Agent Persona**
|
|
31
|
+
|
|
32
|
+
---
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bt-copycat
|
|
3
|
+
description: "The Babylon Toolkit Copycat Skill forensically studies a live reference website, extracts its full design + motion DNA, and rebuilds a pixel-faithful frontend re-imagined around a new theme/subject for use as our project's Home page. Use when the user gives a URL (often with a creative brief) and wants a site that copies the *mechanics and craft* of the original — scroll choreography, load sequence, animation timing, layout rhythm, the whole `feel` — while re-skinning the subject, palette, and copy to their prompt."
|
|
4
|
+
dependencies: bt-design
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Your goal is to **reverse-engineer the reference website down to its DNA and rebuild it, pixel-faithful in mechanics, re-imagined in subject.** Always adhere to any rules or requirements set out in the project's agent instructions (AGENTS.md / CLAUDE.md / .github/copilot-instructions.md) when responding.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Invocation
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
/bt-copycat [--copilot] <reference-url> <re-imagining brief>
|
|
15
|
+
```
|
|
16
|
+
- **`<reference-url>`** — the site to study. This is the *blueprint*.
|
|
17
|
+
- **`<re-imagining brief>`** — how to re-skin it. This is the *variable*.
|
|
18
|
+
- **`--copilot`** *(optional flag)* — force **Mode B (User-Driven / Co-Pilot)** from the very start: the agent launches the shared chrome-devtools browser, you drive the scroll, it snapshots each beat. Skip the headless attempt entirely. Aliases: `--copilot`, `--co-pilot`, `--mode-b`. You can also just say "use co-pilot mode" / "I'll drive" anywhere in the prompt and it means the same thing.
|
|
19
|
+
- If either the URL or brief is missing, ask for it before starting. Never guess a URL.
|
|
20
|
+
|
|
21
|
+
Example (co-pilot from the jump):
|
|
22
|
+
```
|
|
23
|
+
/bt-copycat --copilot → https://www.igloo.inc/ → <re-imagining brief>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Example:
|
|
27
|
+
```
|
|
28
|
+
/bt-copycat --copilot → https://www.igloo.inc/ → Redesign this starter template to be the frontend for the prototype of a third person action adventure game called `Project Alpha`. Make sure there is `copy` on each phase of the hero stages. You don't have to use the igloo object — pick some sort of monolith or something that makes sense, but it needs that mystical winter, almost interstellar vibe: gorgeous, cinematic, otherworldly. The 3D scrolling cinematic should end with some engaging `Enter The Void` user interface that launches the `Player Demo` to start the prototype.
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
# The Prime Directive
|
|
34
|
+
|
|
35
|
+
**The mechanics are sacred. The skin is the variable.**
|
|
36
|
+
|
|
37
|
+
You are NOT making "a site loosely inspired by" the reference. You are cloning the *machine that makes it feel amazing* — the exact scroll behavior, the exact load choreography, the exact animation timing and easing, the exact spatial rhythm and section cadence, the exact interaction feedback — and then swapping the subject, palette, typography flavor, imagery, and copy to match the brief.
|
|
38
|
+
|
|
39
|
+
Split everything you observe into two buckets:
|
|
40
|
+
|
|
41
|
+
| COPY EXACTLY (the DNA / mechanics) | RE-IMAGINE (the skin) |
|
|
42
|
+
| --- | --- |
|
|
43
|
+
| Scroll choreography & scrub mechanics | The hero object/subject |
|
|
44
|
+
| Page-load sequence & reveal timing | Color palette & mood |
|
|
45
|
+
| Animation durations, easings, stagger, delays | Typeface *personality* (not the exact font unless free) |
|
|
46
|
+
| Section order, count, and vertical rhythm | Imagery / video content & generated assets |
|
|
47
|
+
| Layout grid, alignment, spatial composition | Copywriting, headings, taglines |
|
|
48
|
+
| Interaction patterns (hover, cursor, sticky, parallax) | Iconography & decorative motifs |
|
|
49
|
+
| Pacing / "breathing" — where it holds and where it moves | Brand name, logo, product specifics |
|
|
50
|
+
| Depth, layering, z-order, transitions between sections | Sound *design* content (the actual tracks/SFX & their theme) |
|
|
51
|
+
| Audio behavior (ambient bed, scroll/hover SFX, mute UX, autoplay-gating) | |
|
|
52
|
+
|
|
53
|
+
If in doubt about which bucket something belongs in: **feel-defining → COPY; content-defining → RE-IMAGINE.** A visitor should feel "this moves and breathes exactly like igloo.inc" while seeing something that is unmistakably *ours*.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Phase 1 — Forensic Reconnaissance (DO NOT SKIP)
|
|
58
|
+
|
|
59
|
+
You cannot recreate what you have not studied frame by frame. **Never build from a memory or a guess of what the site "probably" does.** Go look at the real thing.
|
|
60
|
+
|
|
61
|
+
Prefer the **chrome-devtools** tools (a real headless browser — you can drive scroll, read the live DOM, capture the network, and profile motion). Fall back to **WebFetch** for raw HTML/CSS/JS only if a browser is unavailable, and **WebSearch** for "site of the year" write-ups, Awwwards case studies, and teardown articles that name the exact techniques used.
|
|
62
|
+
|
|
63
|
+
### Choosing a Capture Mode
|
|
64
|
+
|
|
65
|
+
Scroll-scrubbed 3D/video heroes (igloo.inc-class sites) are often **painfully slow or unreliable to drive headlessly** — the agent-driven scroll stutters, the WebGL timeline doesn't settle between frames, and a full teardown can stall out. When that happens, **do not keep grinding the headless scroll.** Switch to co-pilot mode. Pick the mode up front and tell the user which one you're using:
|
|
66
|
+
|
|
67
|
+
- **Mode A — Agent-Driven (default).** You drive everything through chrome-devtools: navigate, scroll, screenshot, read the DOM, trace motion. Use this for standard sites and whenever headless scrolling is smooth.
|
|
68
|
+
- **Mode B — User-Driven / Co-Pilot.** *You launch and share the chrome-devtools browser; the user drives the scroll while you direct and snapshot.* Use this when: the hero is a heavy scroll-scrubbed 3D/video timeline; headless scroll is janky, stalling, or not advancing the animation; the site blocks automation / needs a login or cookie wall; or the user simply asks to drive.
|
|
69
|
+
|
|
70
|
+
**Start directly in Mode B when asked.** If the invocation includes the **`--copilot`** flag (or `--co-pilot` / `--mode-b`), or the user says anything like "use co-pilot mode" / "I'll drive" / "let me scroll", **begin in Mode B immediately — skip the headless Mode A attempt entirely** and go straight to the Mode B setup below.
|
|
71
|
+
|
|
72
|
+
**Announce a switch:** if you start in Mode A and the scroll teardown is taking too long or not progressing after a couple of attempts, stop and say so — e.g. *"The headless scroll isn't keeping up with this 3D hero. Let's switch to co-pilot mode — I'll launch the browser, you drive the scroll, and I'll snapshot each beat."* — then follow the protocol below.
|
|
73
|
+
|
|
74
|
+
### Mode B — User-Driven Co-Pilot Protocol
|
|
75
|
+
|
|
76
|
+
You become the director; the user is the hands. Give **one clear instruction at a time, wait for the user's signal, then capture, then advance.** Never fire a wall of steps at once.
|
|
77
|
+
|
|
78
|
+
**Setup (agent launches the browser, user parks it at the top)**
|
|
79
|
+
1. **You launch the browser.** Open the reference URL in the shared **chrome-devtools** browser, maximized at desktop width. Let it fully load, then **say you're ready** and hand control to the user — e.g. *"Chrome DevTools is up on the reference site and fully loaded. It's yours — scroll it all the way back to the very top, get it parked and holding still, then say 'ready' and I'll take the first snapshot."*
|
|
80
|
+
2. **The user positions the page.** The user takes the shared browser, scrolls fully back to the very top of the experience, and lets it settle.
|
|
81
|
+
3. **Tell them the cadence + signal words** up front: the default checkpoint cadence is **~10% of page height per step**, plus any moment where the motion visibly changes. From the top the user signals **"ready"**; after that they follow your lead — scroll the amount you ask, let it hold still, and say **"ok"** / **"next"** (or "ready for the next snapshot") for each beat.
|
|
82
|
+
|
|
83
|
+
> **Shared browser is the default here.** Because *you* launched the chrome-devtools browser, *you* take every screenshot and read live values yourself (`evaluate_script`, `list_network_requests`) at each checkpoint — the user only drives the scroll. Only fall back to asking the user to paste screenshots/snippets if the browser can't be shared.
|
|
84
|
+
|
|
85
|
+
**Signal words (tell the user these up front)**
|
|
86
|
+
- **"ready"** — user has parked the page at the very top and it's holding still; you take the **first snapshot** now, then begin the loop.
|
|
87
|
+
- **"ok"** / **"next"** — user has completed the scroll step you asked for and the frame is holding still; safe for you to capture the next beat.
|
|
88
|
+
- **"done"** — user has reached the bottom / end of the sequence.
|
|
89
|
+
- **"back"** — user needs you to re-describe or repeat the previous step.
|
|
90
|
+
- **"stop"** — abort the capture.
|
|
91
|
+
|
|
92
|
+
**The loop (repeat until "done")**
|
|
93
|
+
0. **User:** signals **"ready"** at the top. **You:** take the first snapshot and read the load/first-paint values before asking for any scroll.
|
|
94
|
+
1. **You:** give exactly one instruction — e.g. *"Scroll down slowly until the object is roughly centered and the text has just finished fading in, then hold still and say 'ok'."* Be specific about what beat to stop on, not just a pixel amount.
|
|
95
|
+
2. **User:** performs it and replies **"ok"** / **"next"**.
|
|
96
|
+
3. **You:** capture the checkpoint yourself in the shared chrome-devtools browser — take the screenshot and read any live values you can. Note the scroll depth, what entered/exited, and the apparent timing/easing of that beat. (Only if the browser can't be shared, ask the user to paste/attach a screenshot.)
|
|
97
|
+
4. **You:** confirm and advance — *"Got it, checkpoint 3 captured. Next: keep scrolling until the horizon tilts and a new panel pins — hold and say 'ok'."*
|
|
98
|
+
5. Repeat. When the user says **"done"**, confirm you have top-to-bottom coverage; if a beat is missing, ask them to scroll back to it (**"back"**) and re-capture.
|
|
99
|
+
|
|
100
|
+
**What you still must extract in Mode B.** Manual scrolling replaces only the *screenshotting of the journey*. You still need the real numbers — design tokens, easings, asset/network inventory, scroll-distance ratios. If you share the chrome-devtools browser with the user, pull these yourself via `evaluate_script` / `list_network_requests` between checkpoints. If you cannot, ask the user to run small snippets (e.g. `getComputedStyle`, `document.body.scrollHeight`, the Network tab's asset list) and paste the results. **Screenshots alone are not enough — vibes fail Phase 5 verification.**
|
|
101
|
+
|
|
102
|
+
**Reuse this loop in Phase 5.** When verifying the rebuild's fidelity, run the exact same co-pilot protocol against *our* site so the storyboards are captured identically and compared beat-for-beat.
|
|
103
|
+
|
|
104
|
+
Run this teardown against the reference (in either mode):
|
|
105
|
+
|
|
106
|
+
1. **Load & watch the entrance.** Navigate to the URL. Capture the loader/preloader, the first paint, and the opening reveal. Note the *sequence and timing* of everything that animates in on load — order, delay, duration, easing. The first 3 seconds define the site's whole personality.
|
|
107
|
+
2. **Screenshot the full scroll journey.** Capture the viewport at many scroll depths (e.g. 0%, 10%, 20% … 100%) at desktop width. This is the storyboard you will rebuild. Also capture at a mobile width via `resize_page`/`emulate` — note what reflows, hides, or simplifies.
|
|
108
|
+
3. **Dissect the scroll mechanics.** Is the hero scroll-scrubbed (scroll position drives a video/3D timeline)? Sticky sections? Pinned panels? Horizontal scroll? Parallax layers at different speeds? Scroll-triggered reveals? Measure *how much scroll distance* maps to each beat of motion — this is the single most important thing to get right for a cinematic site.
|
|
109
|
+
4. **Extract the exact design tokens.** Use `evaluate_script` against the live DOM to pull real values, not eyeballed ones: computed colors (bg/ink/accent), font families & weights, type scale, spacing rhythm, border-radii, shadow recipes, blur/backdrop values, and CSS custom properties. Read the actual CSS.
|
|
110
|
+
5. **Time the motion.** Read `transition`/`animation` declarations and, where it matters, run a `performance_start_trace`/`stop_trace` across a scroll to see real durations and frame pacing. Capture easing curves (cubic-bezier values), stagger offsets, and loop timings.
|
|
111
|
+
6. **Inventory the assets & tech.** Use `list_network_requests` to see what actually loads: video files (and their length/resolution — critical for a scrub hero), image formats, fonts, and the animation/3D libraries in play (GSAP/ScrollTrigger, Lenis/smooth-scroll, Three.js/Babylon, Lottie, WebGL shaders). Knowing the technique is how you reproduce the feel.
|
|
112
|
+
7. **Map interactions.** Hover key elements, move through the nav, trigger the cursor — record custom cursors, magnetic buttons, hover distortions, link transitions, and any sound.
|
|
113
|
+
8. **Check for audio (do not skip).** Determine whether the site has sound at all — many award-winning cinematic sites ship an ambient audio bed, scroll/hover SFX, or a reveal sting. Inspect the network inventory for audio files (`.mp3`/`.ogg`/`.wav`/`.m4a`) and the DOM/JS for `<audio>` elements, `AudioContext`/Web Audio, Howler.js, or muted-autoplay video used purely for sound. Record: is there an ambient loop, per-interaction SFX, or scroll-synced audio? How is playback gated (autoplay policy — first user gesture, an explicit sound toggle)? Is there a mute/unmute control, and where does it live? What is the default state (on/off)? If the site has **no audio**, note that explicitly so the rebuild doesn't invent it.
|
|
114
|
+
|
|
115
|
+
**Deliverable of this phase:** enough captured evidence (screenshots + real numbers) that you could rebuild the site with the tab closed.
|
|
116
|
+
|
|
117
|
+
## Phase 2 — Write the DNA Blueprint
|
|
118
|
+
|
|
119
|
+
Before writing a single line of the new site, produce a written **DNA Blueprint** — the machine spec you will build against. Save it (e.g. `DNA-BLUEPRINT.md` in the work dir) so the rebuild is measured against it, not against vibes. It must contain:
|
|
120
|
+
|
|
121
|
+
- **One-line essence** — the feeling in a sentence ("a lone object drifting through an endless, mystical winter, revealed by scroll").
|
|
122
|
+
- **Load sequence** — ordered, timed list of what happens from blank page to interactive.
|
|
123
|
+
- **Section-by-section storyboard** — for each section: purpose, layout, what enters/exits, on what trigger, over what scroll distance, with what timing/easing.
|
|
124
|
+
- **Scroll model** — scrub vs. reveal vs. pin vs. parallax; scroll-distance-to-motion ratios; smooth-scroll behavior.
|
|
125
|
+
- **Motion table** — durations, easings (real cubic-beziers), stagger, delays for the key moments.
|
|
126
|
+
- **Audio model** — whether the site has sound at all; if so, the ambient bed / per-interaction SFX / scroll-synced audio, the playback-gating mechanism (autoplay policy, first-gesture unlock), the mute/unmute control and its default state — plus the **re-imagined** audio direction chosen for the brief. If the original is silent, say so.
|
|
127
|
+
- **Design tokens** — the real extracted values, then the **re-imagined** values chosen for the brief beside them.
|
|
128
|
+
- **Asset manifest** — every video/image/3D/audio asset the original uses, and what we will generate to replace it under the new theme.
|
|
129
|
+
- **Tech approach** — which libraries/techniques reproduce each mechanic.
|
|
130
|
+
|
|
131
|
+
## Phase 3 — Re-imagine to the Brief
|
|
132
|
+
|
|
133
|
+
Now apply the creative brief to the *skin only*. Choose the new subject/object, palette, typographic personality, mood, and copy so they serve the prompt — while keeping every mechanic from the blueprint intact. The igloo becomes a lone monolith / a drifting seed / a frozen relic — but it still moves through the world on scroll exactly as the igloo did. Push the aesthetic hard and specific per the brief; do not water it down toward generic.
|
|
134
|
+
|
|
135
|
+
**Fidelity governs the layout — but skin toward game-frontend console UI.** The reference's layout width and spatial composition live in the COPY-EXACTLY bucket, so match the original: if it's full-bleed / full page width (as the cinematic, award-winning references this skill targets almost always are), reproduce that faithfully; if it is genuinely fixed-width, keep it fixed-width — do **not** force full-bleed onto a reference that isn't. Within whatever width the blueprint dictates, push the *skin* toward the modern-console game-frontend feel from bt-design's *Layout Philosophy — Full-Bleed Console UI* (edge-anchored HUD/menu clusters, console focus/selection states, cinematic overlays), since the output is our game's Home page — never at the cost of a mechanic.
|
|
136
|
+
|
|
137
|
+
## Phase 4 — Rebuild with `bt-design`
|
|
138
|
+
|
|
139
|
+
**Load bt-design first — this phase is executed THROUGH it and cannot be done without it.** Where skills are loaded with a tool (the Babylon Toolkit App Builder platform), call `load_skill('bt-design')`, and fetch any of its bundled references with `read_skill_resource` using the paths the load returns — never a guessed path. Where skills are files on disk (Claude Code), read `bt-design/SKILL.md` from the same skills directory, `~/.claude/skills/` or the project's `.claude/skills/`. If bt-design is already in your context, skip the load. Earlier phases also lean on it by name (Phase 3's *Layout Philosophy — Full-Bleed Console UI*, and the anti-slop guidance below) — if you are reading those before you get here, load it there instead.
|
|
140
|
+
|
|
141
|
+
Hand the DNA Blueprint to the **bt-design** skill to build the actual frontend as our `Home` page (plus any supporting pages the original implies).
|
|
142
|
+
|
|
143
|
+
**Output target — where the rebuild lands (Babylon Toolkit projects):** the Home page is authored in **`src/pages/Home.tsx` + `src/pages/Home.css`** (supporting pieces in `src/pages/` / `src/components/`). It is deliberately pulled OUT of `app.tsx` — **`app.tsx` and `src/routing/**` are a READ-ONLY routing shell; never write the design into them.** The shell already routes `/` to `Home`, so replacing `Home.tsx`/`Home.css` IS replacing the landing page. Keep the play contract intact (`navigate('/play', { gameMode: … })` via `useUnifiedNavigation`; `src/pages`/`src/components` stay Babylon-free), and if the retheming extends to the game chrome (splash/preloader/overlay), that lives in `src/chrome/**` per the bt-landing skill's rules — including its ENGINE CONTRACT: the splash's engine-required element ids (`xbabylonjsSplashScreen`, `babylonjsLoadingDiv`, `babylonjsLoadingText`, `babylonjsLoadingDivStyle`, `xbabylonjsStatusTextDiv`) must survive any redesign byte-for-byte, or the engine cannot hide the splash to reveal the scene — and its IMPORTS rule: read each file you replace and copy its whole import block across character for character (`GameManager` is a DEFAULT export — `import GameManager from '../babylon/globals'`, never `{ GameManager }`). For non-Toolkit hosts, target whatever the root route's page component actually is — never a router/shell file.
|
|
144
|
+
|
|
145
|
+
Instruct bt-design to:
|
|
146
|
+
|
|
147
|
+
- Match the blueprint's mechanics and timing **exactly** — this is a fidelity job, not a fresh design. Where bt-design would normally improvise, here it executes the blueprint.
|
|
148
|
+
- Generate the re-imagined video/image/3D assets (image & video generation) to fill the asset manifest under the new theme — as beautiful and cinematic as the original's.
|
|
149
|
+
- Reproduce the load choreography, scroll behavior, and micro-interactions from the motion table.
|
|
150
|
+
- **Reproduce the audio model from the blueprint** — if the original has sound, rebuild the equivalent behavior (ambient bed, interaction/scroll SFX, mute toggle, autoplay-gating on first user gesture per browser policy) and generate re-imagined audio assets that match the new theme. If the original is silent, do not add audio unless the brief asks for it.
|
|
151
|
+
|
|
152
|
+
**Enforced build mandate (always apply):**
|
|
153
|
+
- Make the new site **as cinematic and award-winning as the original**, and make it **feel like a real game prototype, not a generic template**.
|
|
154
|
+
- **The user provides the prototype's own assets.** You may generate any *additional* cinematic imagery or video needed to fill out the storyboard — use image & video generation to create every necessary asset.
|
|
155
|
+
- Make the new site **fully responsive** and working on all devices.
|
|
156
|
+
- **Create a `DESIGN.md`** reflecting the new theme if it does not exist or is only an empty stub; otherwise update it.
|
|
157
|
+
- **Update `SPEC.md`** with any significant architectural changes, if any.
|
|
158
|
+
|
|
159
|
+
**Scroll-scrubbed / cinematic scroll heroes:** if the original's hero is scroll-driven (as igloo.inc is), this is a **3D-Hero-Scroll** job. Route through bt-design → `references/3d-hero-scroll.md` and copy the drop-in templates from `templates/3d-hero-scroll/` — do not re-implement the scrub engine from memory. Map the reference's real numbers (footage length, scroll-distance-per-second, telemetry, jump cuts) into `HS_CONFIG` and the `--hs-*` tokens.
|
|
160
|
+
|
|
161
|
+
**ONLY IF** the user requests to add `3D scroll controls`, use the (bt-design → 3D-Hero-Scroll → playback controls) sub-skill with the requested `sweep` (default: `page`) to add smooth cinematic playback controls.
|
|
162
|
+
|
|
163
|
+
## Phase 5 — Verify Fidelity Against the Original
|
|
164
|
+
|
|
165
|
+
A copycat that "feels off" has failed. Before declaring done, verify the rebuild the same way you studied the original:
|
|
166
|
+
|
|
167
|
+
- Open the rebuilt site in the browser and capture the **same scroll-depth storyboard** you captured in Phase 1. Compare side by side against the blueprint — does each beat land at the same scroll position with the same motion?
|
|
168
|
+
- Check the load sequence, easings, and stagger match the motion table.
|
|
169
|
+
- Confirm nothing is janky: smooth scrubbing, no layout shift, motion holds 60fps where the original does.
|
|
170
|
+
- Confirm the audio behavior matches the blueprint: if the original had sound, ours has the equivalent ambient bed / SFX, a working mute toggle, and correct autoplay-gating; if the original was silent, ours is too (unless the brief asked otherwise).
|
|
171
|
+
- Confirm the *skin* fully reads as the new brief, not a recolor of the original's content.
|
|
172
|
+
|
|
173
|
+
Report any beat where fidelity is imperfect and fix it — do not paper over a mechanic you couldn't reproduce.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Non-Negotiables
|
|
178
|
+
|
|
179
|
+
- **Study first, build second.** No recreation begins before Phase 1 evidence and a Phase 2 blueprint exist.
|
|
180
|
+
- **Numbers, not vibes.** Extract real colors, timings, and scroll ratios from the live site. "Roughly a fade" is not acceptable when you can read the exact `cubic-bezier`.
|
|
181
|
+
- **Mechanics are copied; content is re-imagined.** Never invent a different scroll feel; never ship the original's subject/branding.
|
|
182
|
+
- **Match the original's craft ceiling.** The reference is award-winning for a reason. The rebuild must be *as* beautiful — no generic AI-slop fallback (see bt-design's anti-slop guidance). If the original holds a held, breathing silence before a reveal, so does ours.
|
|
183
|
+
- **Ship a prototype, not a template.** The result must feel like a real game prototype — cinematic and award-winning — fully responsive on all devices. The user supplies the prototype's assets; generate any additional cinematic imagery/video to complete the storyboard. Create `DESIGN.md` for the new theme (if missing or an empty stub) and update `SPEC.md` for any significant architectural changes.
|
|
184
|
+
- **Verify against the source.** Done means the storyboards match.
|