# Spec for delivering GLB models to the Schirmmacher 3D designer

## Where to upload

Upload your `.glb` to **https://3dassets.schirmmacher.com**, into the `models/` folder, named `<art_nummer>.glb` (e.g. `9719.glb`).

On upload, the portal runs an automatic validator against everything in this spec — name conventions, scale, origin, UV layout — and shows a live 3D preview with a color picker and a UV-debug overlay. **If the validator reports an error, the upload is blocked**; fix and re-drop. Warnings can be overridden if you're confident.

You can re-validate any already-uploaded `.glb` from the file list (the small clipboard-check icon in the row).

## File format

- **glTF 2.0 binary (`.glb`)** — Blender → File → Export → glTF 2.0 → `.glb` Binary
- Embed textures inside the GLB (the exporter's default). No external image files.

## Scale & units

- Export at **Blender default: 1 unit = 1 meter**. Do not apply extra scale.
- A typical pocket umbrella should be ~1 m diameter; a parasol ~3 m. Real-world sizes.
- The designer auto-scales 100× on load. If your export is wildly off-scale, the validator and the browser console will warn ("bounding diagonal outside the 0.3–5 m range") — that's the cue to recheck units / unapplied transforms in Blender.

## Origin & orientation

- **Origin at the umbrella's geometric center** — symmetric around (0, 0, 0).
  - Canopy points along **+Y** (up).
  - Handle hangs along **−Y** (down).
- **+Y is up, −Z is forward** (Blender default — don't change axis settings on export).

## How mesh names drive runtime behaviour

> **Read this before naming meshes.** The `umbrella_*` prefix is not just a label — it's a switch that tells the designer's loader "**override the material I authored**". Use one of these names **only** when you want the runtime behaviour in the table. If you want a mesh to keep the exact material you painted in Blender (e.g. a handle that must stay black regardless of the customer's fabric colour), use **any free-form name** (`handle`, `mango`, `rib_1`, `strap` — anything not starting with `umbrella_`) and the loader will leave it alone.

## Required mesh names

These exact names (lowercase, underscores, **no typos** — the validator catches `umbrella_bleck` → `umbrella_black`).

| Mesh name | Runtime behaviour |
|---|---|
| `umbrella_fabric` | Canopy panels (one mesh covering all 8 panels), UV-mapped to the octagonal layout described below. Recoloured live to the customer's chosen fabric colour. |
| `umbrella_fabric_label` | Second skin sitting just on top of `umbrella_fabric`, reproducing its **UV mapping over the printable region** (a plain copy of the fabric is foolproof; a different vertex count is allowed — see below), transparent material. The customer's printed motif renders onto this mesh. **Required** — without it, no logo / motif can appear on the umbrella. |

## Optional mesh names (only if the product has them)

Use these exact names only when you want the listed override; otherwise give the mesh any free-form name.

| Mesh name | Runtime behaviour |
|---|---|
| `umbrella_handle` | The grip the customer holds. **Recoloured live to the customer's chosen fabric colour** — use this name only when the handle should match the canopy. **If the handle must stay a fixed colour you painted in Blender, call the mesh `handle`** (or anything else not starting with `umbrella_`) and the loader will preserve your material. |
| `umbrella_handle_button` | Press button on auto-open models. **Recoloured live to the customer's chosen fabric colour.** |
| `umbrella_folds` | Alternate / layered fabric mesh (e.g. visible fold detail). **Recoloured live to the customer's chosen fabric colour**, treated exactly like `umbrella_fabric`. |
| `umbrella_fabric_dark` | Inside-facing canopy layer. **Recoloured live to 0.7 × the customer's chosen fabric colour** (slightly darker shade). |
| `umbrella_fabric_inside` | Inside-facing canopy layer with its **own independent colour picker** (separate from the outer fabric). Use this only when the product offers a distinct inside-colour selection. Otherwise prefer `umbrella_fabric_dark` (auto-derived from the outer colour). |
| `umbrella_fabric_black` | Dedicated all-black canopy variant. **Forced to `#000000`** regardless of the customer's pick. |
| `umbrella_plastic` | Black plastic connecting joints (rib hubs etc.). **Forced to `#222222`** (matte). |
| `umbrella_metal` / `umbrella_chrome` | Frame parts. **Forced to bright chrome** (`#ECECEC`, glossy, half-metallic). |
| `umbrella_metal_white` / `umbrella_plastic_white` | White-finish variants. **Forced to pure white** with low emissive. |
| `umbrella_metal_black` / `umbrella_plastic_black` | Black-finish frame / joint parts — the counterpart to the `_white` variants. **Forced to satin black** (`#222222`). Use when frame or plastic parts must render black instead of the default chrome / white. |
| `umbrella_metal_gray_mat` / `umbrella_plastic_gray_mat` | Matte mid-grey. **Forced to `#383E42`**. |
| `umbrella_alluminium_matte` / `umbrella_fabric_label_corners` | Brushed-aluminium parts. The loader swaps the material for a matcap shader that fakes brushed metal — your authored material is replaced, so just give the mesh sensible geometry and don't worry about its shader. |

For everything else (ribs, struts, stocks, straps, decorative pieces, fixed-colour parts) — pick any free-form name and the material you authored in Blender is preserved exactly.

### Rainbow / multi-variant canopies

For products that ship both a "single-colour" and a "rainbow / multi-colour" variant, include both canopies in the same `.glb`:

- The default single-colour canopy is your standard `umbrella_fabric` (plus its matching `umbrella_fabric_label`).
- The rainbow variant is a second canopy mesh named **`umbrella_rainbow`** with the multi-colour artwork baked in.
- Optionally include an `umbrella_basic` mesh: the loader uses it as a visibility-toggle partner to `umbrella_rainbow`. When the customer picks a single colour, `umbrella_rainbow` is hidden and `umbrella_basic` (or `umbrella_fabric`) is shown; when they pick rainbow mode, the inverse.

If the product is single-variant, just ship `umbrella_fabric` and skip the rainbow / basic meshes entirely.

### Per-colour texture overlays (`umbrella_perch_image`)

If a product variant has a printed graphic that changes with the customer's colour pick (e.g. a coloured logo or perch-image baked into one of the panels), name that mesh **`umbrella_perch_image`**. At runtime the loader fetches a texture file from R2 at:

```
https://3d.schirmmacher.com/textures/<art_nummer>/<hex-color>.png
```

— one PNG per supported colour, lowercase hex, no `#`. You're responsible for uploading those PNGs to the `textures/<art_nummer>/` folder in the Asset Manager alongside the `.glb`. If a colour has no matching PNG, that pick will silently fall back to the previous texture.

## UV layout — critical for motif printing

The canopy must be UV-unwrapped to an **octagonal fan**: each of the 8 fabric panels mapped to one wedge of the octagon, all radiating from a single center point. That's the layout the customer interacts with in the designer's "Design Vorlage" panel — any logo they drop onto a wedge corresponds 1:1 to the matching panel on the 3D umbrella.

The simplest, foolproof `umbrella_fabric_label` is a **plain copy of `umbrella_fabric`** — same geometry, same UVs (share the UV accessor, or duplicate the mesh and its UVs exactly) — with a transparent material. A **different vertex count is not automatically wrong**: the legacy 9132 model has a 1728-vert label over a 2916-vert fabric and renders correctly. What's actually required is that the label's UVs reproduce `umbrella_fabric`'s UV→surface mapping over the printable region, so a motif lands in the **same place and orientation** as in the 2D editor. The validator **warns** (it no longer blocks) on a vertex-count mismatch — heed the warning and verify a test motif lands correctly, or just copy the fabric and skip the question. **Do not remodel the label or inset its UVs to "delimit" the print area** — the printable region is delimited by the uvMap SVG (see the next section), never by reshaping the label mesh. (Reshaping the label, plus a mismatched UV unwrap, was the #9720 release blocker; it was fixed by re-deriving the model from the legacy 9132 geometry that renders WYSIWYG.)

**Reference target** — open any of these existing UV maps in Blender for visual comparison; all use the same octagonal fan:

- https://schirmmacher.de/3d-designer-2021/assets/uvmaps/uvmap-9121.svg
- https://schirmmacher.de/3d-designer-2021/assets/uvmaps/uvmap-9707.svg
- https://schirmmacher.de/3d-designer-2021/assets/uvmaps/uvmap-9706.svg

To visually verify your UVs are correct, after uploading hit **UV-debug texture** in the preview. A correctly-unwrapped canopy shows each panel as a coloured wedge of the gradient; a collapsed or flat-stripped UV shows a single flat colour or stripe across the entire canopy.

## uvMap print zones — the `uvmap-<art>.svg` file

Alongside the GLB, each product has a `uvmap-<art_nummer>.svg` in the `uvmaps/` folder. It is a flat 2D drawing of the octagonal-fan UV layout, and it defines the **printable area** on each panel — the box the customer's motif is clipped to in the designer. **This is where you delimit the print area — not in the label mesh's UVs.**

Mark each panel's printable shape inside a group named **`Druckbereich`**:

```svg
<g id="Druckbereich">
  <polygon points="…" />   <!-- one per printable panel; <rect> also works -->
</g>
```

- **Preferred:** a `<g id="Druckbereich">` group wrapping one `<polygon>` (or `<rect>`) per panel.
- **Also accepted:** shapes named **`Siebdruck`** — Illustrator's default when you name the objects "Siebdruck" and export without a wrapper layer. The designer reads these even without a `Druckbereich` group, but wrapping them in `Druckbereich` is the documented convention.
- A uvMap with **neither** produces **no clip**: the motif is bounded only by the label-mesh UVs and is not confined to the panels. The validator **warns** when it finds no print zone.

The print-zone shapes must sit in the same coordinate space as the fan UVs, so a motif the customer places at a panel edge lands at that edge on the 3D umbrella.

## Materials

Material names are cosmetic — the loader ignores them. Pick names that keep your `.blend` file readable (`fabric`, `metal`, `plastic`, `handle_base`).

Use Blender's default Principled BSDF. The designer overrides colour / roughness / metalness on `umbrella_*` meshes at runtime; for any mesh with a non-`umbrella_*` name the material you authored is preserved exactly.

### One material per mesh slot

Every Blender object must have **exactly one** material. Don't combine multiple materials on a single mesh; if a part has two surface looks (e.g. a handle with a black plastic body and a coloured grip section), split it into two separate Blender objects.

**Why:** when a mesh has more than one material, Blender's exporter writes it as a multi-primitive glTF mesh. At runtime that becomes a `THREE.Group` with no single material, and the designer's recolour code silently skips it — so the recoloured part of the handle (or canopy) never picks up the customer's chosen colour. Several hours of debugging for one model (#9721) traced back to this exact pattern.

This applies most importantly to `umbrella_handle`, `umbrella_handle_button`, and `umbrella_fabric`. If multiple materials are unavoidable on the handle, name only the recolour-target part `umbrella_handle` and give the static parts free-form names (`handle_button`, `handle_collar`, `mango_negro`, etc.) so the loader leaves them with their authored material.

### `umbrella_fabric` and `umbrella_fabric_label` need separate material slots

These two meshes share geometry and UVs, but they **must not share a material**. In Blender, give each its own material datablock. The slot names don't matter — what matters is that they aren't the same datablock.

**Why:** the designer mutates the label's material at runtime (swaps in the customer's print canvas, switches to transparent blending, applies a polygon offset). When the canopy points at the same `Material` instance, those mutations leak onto the canopy and it goes invisible — same root cause as #9721.

### `umbrella_fabric_label` material must be transparent (Alpha Blend)

In the label material's settings, set **Blend Mode: Alpha Blend**. The designer paints the customer's logo onto this mesh with a transparent canvas; without alpha blending, the canvas is treated as opaque and the logo prints as a solid rectangle instead of cleanly compositing over the canopy.

Working reference: model **9719**'s label material has `alphaMode = BLEND` and the fabric material has `alphaMode = OPAQUE`. Compare against your `.blend` if unsure.

## Self-check before submission

The portal at https://3dassets.schirmmacher.com runs all of these checks automatically on upload, but a quick mental pass first speeds up the loop:

- [ ] File is `.glb` (binary), exported from Blender's glTF 2.0 exporter.
- [ ] Umbrella body is roughly 1 m tall/wide.
- [ ] Origin at (0, 0, 0); umbrella symmetric around it; canopy points +Y, handle points −Y.
- [ ] `umbrella_fabric` and `umbrella_fabric_label` are present, named exactly (lowercase, underscore).
- [ ] Handle is named `umbrella_handle` only if it should recolour with the canopy; otherwise use a free-form name like `handle`.
- [ ] `umbrella_fabric` is UV-unwrapped to the octagonal fan — open it in Blender's UV editor and compare against one of the reference `uvmap-*.svg` files above.
- [ ] `umbrella_fabric_label` has identical UVs **and the same vertex count** as `umbrella_fabric` — a plain copy, not a remodeled or inset mesh.
- [ ] The `uvmap-<art>.svg` marks each printable panel inside a `<g id="Druckbereich">` group (or with `Siebdruck`-named shapes). The print area is delimited here, not in the label mesh.
- [ ] Every Blender object has exactly one material slot (no multi-material meshes). Split combined parts into separate objects.
- [ ] `umbrella_fabric` and `umbrella_fabric_label` use **different** material datablocks (not the same one).
- [ ] `umbrella_fabric_label`'s material has **Blend Mode: Alpha Blend** in its settings.
