83 lines
5.5 KiB
Markdown
83 lines
5.5 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Project overview
|
|
|
|
Web-based 3D configurator for infissi (windows/doors) — "kreiosinfissi-vite". It renders a Three.js scene
|
|
(GLB models) driven by JSON product data and a jQuery-based menu UI, and is meant to run **inside an
|
|
`<iframe>`** embedded on `https://www.kreiosinfissi.it` (or `https://kreiosinfissi.test` in dev), with the
|
|
final "add to cart" action posted back to the parent window via `postMessage`.
|
|
|
|
## Commands
|
|
|
|
Package manager is **pnpm** (`pnpm-lock.yaml` is the lockfile of record even though `package-lock.json` is
|
|
also present).
|
|
|
|
```bash
|
|
pnpm install # install deps
|
|
pnpm dev # vite dev server on 0.0.0.0:5173
|
|
pnpm build # production build -> dist/ (root is src/, see vite.config.js)
|
|
pnpm preview # preview the production build
|
|
```
|
|
|
|
There is no test suite (`pnpm test` is a stub that exits with an error) and no linter configured.
|
|
|
|
### Regenerating PVC price lists
|
|
|
|
`scripts/extract_listini_pvc.py` parses `PVC_LISTINO.xls` and regenerates
|
|
`src/assets/data/modelli/pvc/<modello>/listino.json` files. Requires a Python venv with `xlrd`
|
|
(`pip install -r scripts/requirements.txt`). Run with `python3 scripts/extract_listini_pvc.py` from repo root.
|
|
Any new title in the spreadsheet needs an entry in that script's `KNOWN_FOLDERS` map or it won't be matched
|
|
to an existing model folder.
|
|
|
|
## Architecture
|
|
|
|
Entry point is `src/js/starter.js`, loaded from `src/index.html`. Flow on load (`start()`):
|
|
|
|
1. **`ParamsParser.getQueryParams()`** (`src/js/params_parser.js`) reads the URL query string. Two params
|
|
drive everything: `sistema` (`pvc` | `alluminio` | `legno` | `acciaio`) and `type` (model id). See
|
|
`docs/URL_PARAMS.md` for the full param contract and the list of valid `type` values per `sistema`.
|
|
*Note: that doc describes a more modular refactor (`Application.js`, `communication/UrlParamsParser.js`,
|
|
`communication/IframeBridge.js`) that does not exist yet in `src/js` — the current implementation is the
|
|
flatter `starter.js`/`params_parser.js` described here.*
|
|
2. Product/catalog data is fetched as JSON from `src/assets/data/sistemi/<sistema>/modelli.json` and
|
|
`src/assets/data/modelli/<sistema>/<cartella>/{form,modello,maniglia,avvolgibile,vetro,listino}.json`
|
|
(which JSON files are fetched depends on the `moduli` array in the matched `modelli.json` entry).
|
|
3. **`MenuBuilder.build()`** (`src/js/menu_builder.js`) injects an HTML template (`assets/_menu.html`, or
|
|
`assets/_menu-cassonetto.html` when `type=cassonetto`) into `#left-container`, builds the model-picker
|
|
list, handles the mobile-portrait/landscape layout reflow, and initializes `PriceCalculator`. It returns
|
|
the price calculator instance used by the rest of the app.
|
|
4. **`Configurator.init()` / `.enable()`** (`src/js/configurator.js`) wires a single delegated `input` handler
|
|
on the size fields, selects and radios. On every change it recomputes price via `PriceCalculator`, builds
|
|
`window.configurazione` (the object that gets posted to the parent on "add to cart"), and updates the DOM.
|
|
5. **`APP.Player`** (`src/js/app.js`) wraps a Three.js renderer/scene/camera (scene graph loaded from
|
|
`src/assets/app.json`, a three.js-editor-style export) plus the actual product GLB
|
|
(`src/assets/models/<sistema>/<modello.modello>`). Two players are created: `player` (visible canvas) and
|
|
`playerOff` (offscreen, used only to render the PNG snapshot sent to the cart). Key methods: `swapModel`/
|
|
`hideModel` (toggle between pre-loaded variants in the same scene), `changeTexture`/`changeColor` (applied
|
|
per `userData.categoria` mesh tag — categories like `interno`, `esterno`, `maniglia`, `vetro`, `cerniere`),
|
|
`flipView` (180° GSAP-animated turn between front/back view), `addMarker` (in-scene hotspot with a video
|
|
popup).
|
|
6. **`PriceCalculator`** (`src/js/price_calculator.js`) is a stateless-ish module (single module-level
|
|
`listini` cache set via `init`) that looks up a base price from a width/height grid (`listino.json`,
|
|
rounded up to the nearest 10cm) and layers on percentage/flat supplements for finish, glass, hinges, handle
|
|
height, and actuator type, then adds 22% VAT.
|
|
|
|
### Data conventions
|
|
|
|
- Every 3D-visible part is tagged with `userData.categoria` in the GLB/scene so JS can show/hide/retexture it
|
|
without knowing mesh names (`interno`, `esterno`, `maniglia`, `cerniere`, `vetro`, ...).
|
|
- Each model folder under `src/assets/data/modelli/<sistema>/<cartella>/` follows the same file set:
|
|
`form.json` (UI radios/selects/finiture wiring — declares which named `<select>`/radio groups exist and
|
|
which categories/texture folders they map to), `modello.json` (finish options), `maniglia.json` (handle
|
|
options), `avvolgibile.json` (shutter, cassonetto-only), `vetro.json` (glass options), `listino.json`
|
|
(price grid).
|
|
- Texture images live under `src/assets/data/immagini/<sistema>/<folder>/<texture_folder>/<id>/...` and are
|
|
loaded lazily per selection (`APP.Player.changeTexture`); a monotonically-checked `isStale()` guard discards
|
|
a texture load if the user changed the selection again before it finished.
|
|
- `window.*` globals (`window.configurazione`, `window.cambiaTexture`, `window.caricaModello`,
|
|
`window.rotate`, `window.sistema`, etc.) are the integration surface between the jQuery-driven menu markup
|
|
(inline `onclick`/`onchange` in the `_menu*.html` templates) and the JS modules — expect to grep for a
|
|
`window.<name> =` assignment when tracing menu behavior, not for exported module functions.
|