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) — "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).
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()):
ParamsParser.getQueryParams()(src/js/params_parser.js) reads the URL query string. Two params drive everything:sistema(pvc|alluminio|legno|acciaio) andtype(model id). Seedocs/URL_PARAMS.mdfor the full param contract and the list of validtypevalues persistema. Note: that doc describes a more modular refactor (Application.js,communication/UrlParamsParser.js,communication/IframeBridge.js) that does not exist yet insrc/js— the current implementation is the flatterstarter.js/params_parser.jsdescribed here.- Product/catalog data is fetched as JSON from
src/assets/data/sistemi/<sistema>/modelli.jsonandsrc/assets/data/modelli/<sistema>/<cartella>/{form,modello,maniglia,avvolgibile,vetro,listino}.json(which JSON files are fetched depends on themoduliarray in the matchedmodelli.jsonentry). MenuBuilder.build()(src/js/menu_builder.js) injects an HTML template (assets/_menu.html, orassets/_menu-cassonetto.htmlwhentype=cassonetto) into#left-container, builds the model-picker list, handles the mobile-portrait/landscape layout reflow, and initializesPriceCalculator. It returns the price calculator instance used by the rest of the app.Configurator.init()/.enable()(src/js/configurator.js) wires a single delegatedinputhandler on the size fields, selects and radios. On every change it recomputes price viaPriceCalculator, buildswindow.configurazione(the object that gets posted to the parent on "add to cart"), and updates the DOM.APP.Player(src/js/app.js) wraps a Three.js renderer/scene/camera (scene graph loaded fromsrc/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) andplayerOff(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 peruserData.categoriamesh tag — categories likeinterno,esterno,maniglia,vetro,cerniere),flipView(180° GSAP-animated turn between front/back view),addMarker(in-scene hotspot with a video popup).PriceCalculator(src/js/price_calculator.js) is a stateless-ish module (single module-levellistinicache set viainit) 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.categoriain 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-checkedisStale()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 (inlineonclick/onchangein the_menu*.htmltemplates) and the JS modules — expect to grep for awindow.<name> =assignment when tracing menu behavior, not for exported module functions.