Files
kreios/CLAUDE.md
T
2026-07-13 11:58:30 +02:00

5.5 KiB

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) — "infissionline-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.infissionline.it (or https://infissionline.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).

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.