Configurator voor Van Emous Mantelzorgwoningen: wanden, vloeren, units, woningen (L-vorm), plat dak met dakrand, buitenverlichting, latwerk op vochtdoek, trasraam, sandwichpanelen en PDF-tekenbladen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
15 KiB
15 KiB
Tectum — configurator Van Emous Mantelzorgwoningen (intern)
Losse, meerdere-bestanden-opzet van de eerdere single-file wand-tool, nu met een menubalk om tussen objecttypen (muur/vloer) te schakelen.
Copyright © 2026 Machiel Heinen. Alle rechten voorbehouden; gebruik uitsluitend met schriftelijke toestemming. Zie LICENTIE.md. Elk bronbestand begint met deze copyright-kop.
Draaien
Optie 1 — direct openen (geen server nodig):
Dubbelklik index.html. Alles werkt met gewone <script src="...">-tags
(geen ES-modules), dus dit werkt ook via file://.
Optie 2 — lokale server (optioneel):
cd project
python3 -m http.server 8000
en open http://localhost:8000.
Structuur
index.html app-shell: menubalk, splashscreen, over-deze-software
css/
app.css alle stijl, in één bestand
js/
vendor/
three.min.js three.js r128, lokaal gevendord (geen CDN meer)
OrbitControls.js eigen, compacte OrbitControls-vervanging (zie
"Bewuste keuzes" hieronder) — leunt op three.min.js
core/
geometry.js gedeelde, pure functies (regelwerk-verdeling,
polygon-oppervlaktes, clip-functies) — gebruikt
door zowel wall.js als floor.js, niet gedupliceerd
canvas-labels.js gedeelde stijl voor maatlabels ("X: 6000mm") in de
2D-canvassen van wand, vloer en unit
pdf-sheet.js gedeelde PDF-bouwstenen: titelblok, maatlijn, tabel
camera-memory.js onthoudt de 3D-camerastand per tabblad + onderdeel
view-filter.js "Weergave"-dropdown met vinkjes voor de 3D-weergaven
license.js licentietekst voor "Over deze software" (kopie van
LICENTIE.md, dat bestand is leidend)
logo-data.js logo als PNG-data voor de PDF-titelblokken
(opnieuw genereren uit assets/logo.svg, zie kop)
wall/
wall-model.js WallModel: ENIGE bron van de wand-logica (anker-
resolutie openingen, regelwerk, 3D-opbouw, specs,
validatie) — geen DOM
wall-pdf.js WallPdf: het wand-tekenblad (aanzicht, boven- en
zijaanzicht, materiaallijst) — losse wand én unit
wall.js wand-editor (UI: invoer, 2D, interactie, JSON/PDF)
floor/
floor-model.js FloorModel: ENIGE bron van de vloer-logica (balken,
doorvoeren, chassis, 3D-opbouw, specs, validatie)
floor-pdf.js FloorPdf: het vloer-tekenblad — losse vloer én unit
floor.js vloer-editor (UI, uitsluitend cirkelvormige
openingen/doorvoeren)
roof/
roof-model.js RoofModel: plat dak = vloer (FloorModel) 180°
gespiegeld + dakleer; dakrand (boeidelen met spots
of daktrim) als één doorlopende rand om de woning
lighting/
lighting-model.js LightingModel: buitenverlichting per unit (geen /
boeideel-spots / gevellampen), gevellampen per
wandstuk met terugval naar spots, override per wand
unit/
unit-model.js UnitModel: 1 vloer + 4 wanden, hoekaansluiting,
naden (wand vervalt deels/geheel) en wandstukken
house/
house-model.js HouseModel: woning = gekoppelde units + binnenwanden;
posities (koppelen aan zijde + uitlijning), naden,
totalen
house-pdf.js HousePdf: samenhangende PDF (plattegrond, per unit
vloer + wandstukken, binnenwanden, totalen)
house.js woning-editor (UI): navigatieboom, plattegrond met
selecteren/binnenwand tekenen, eigenschappen, 3D;
mount de echte wand-/vloer-editor per onderdeel
app.js menubalk-logica, versienummer, mount/unmount van
de actieve editor
json/
defaults/ referentie-JSON's die tonen wat "Nieuw" oplevert
(worden NIET ingeladen via fetch(), zie hieronder)
premade/ bestemmingsmap voor opgeslagen/geëxporteerde designs
assets/ logo (preloader) + bestemmingsmap voor toekomstige
GLB's/texturen
Bewuste keuzes / bekende beperkingen
- Volledig CDN-vrij. three.js (r128) staat lokaal in
js/vendor/three.min.js. OrbitControls is een eigen, compacte implementatie (js/vendor/OrbitControls.js) — het originele addon-bestand was niet beschikbaar om te vendoren, dus is de gebruikte subset (roteren via slepen, zoomen via scrollwiel, pannen via rechts-slepen,target/update()) opnieuw geschreven en losstaand getest (rotatie/zoom-richting/grenzen/pannen/dispose). Functioneel gelijkwaardig voor wat deze tool nodig heeft, maar geen 1-op-1 kopie van alle opties van de officiële addon (bijv. geen damping/inertia). - Geen ES-modules. Alle JS-bestanden zijn gewone
<script>-tags, geladen in een vaste volgorde (geometry.js→canvas-labels.js→ jsPDF →pdf-sheet.js→wall-model.js→wall-pdf.js→floor-model.js→floor-pdf.js→roof-model.js→lighting-model.js→wall.js→floor.js→unit-model.js→house-model.js→house-pdf.js→house.js→app.js). Reden: ES-module-imports (import ... from) breken bij rechtstreeks openen viafile://door browser-CORS-beleid. Dit was expliciet een vereiste ("gewoon via een index file"), dus is hier bewust voor gekozen. json/defaults/*.jsonworden niet gefetcht. Om dezelfde reden (fetch() van lokale bestanden werkt ook niet betrouwbaar viafile://): de standaardwaarden van "Nieuw" staan hardcoded inwall.js/floor.jszelf, en komen overeen met deze JSON-bestanden. De JSON's zijn dus referentie/ documentatie, en (voor wanden) een bestand dat je via "Importeer JSON" kan inladen — geen runtime-configuratiebron.- Alleen wall.js heeft Exporteer/Importeer JSON. floor.js nog niet.
- Floor.js heeft nu dezelfde soorten logica als wall.js. 2D-bovenaanzicht
- doorsnede, regelwerk (vloerbalken), cirkelvormige doorvoeren, een onderlaag van OSB-plaat (standaard 22mm, dikte + oppervlak + volume + gewicht), een isolatielaag (leegte tussen de balken, analytisch bepaald — net als bij de wand krijgt isolatie zelf bewust geen dichtheid/gewicht), een volwaardig 3D-perspectief (balken/isolatie/OSB met doorvoer-gaten/ chassis-wielen, met aan/uit-toggles voor OSB en isolatie, plus fullscreen- 2D/3D) en een specificaties-paneel met een gewichtstotaal. Losse, optionele chassis-laag (4 transportwielen in een "dobbelsteen 4"-indeling, exact gecentreerd op de vloer — spoorbreedte/wielbasis/wieldiameter instelbaar, geen interactie met de balkposities).
- Single point of truth wand/vloer/unit. Alle reken- en 3D-logica zit in
WallModel/FloorModel. De losse editors én de unit roepen die aan, dus een wijziging in de wand- of vloerlogica geldt automatisch overal. De unit bewaart per onderdeel een gewone wand-/vloer-state; wandbreedtes worden afgeleid uit vloermaat + wanddiktes + hoekaansluiting, openingen houden hun anker (links/midden/rechts). "Opslaan als" bij een unit geeft JSON + één samenhangende PDF: bovenaanzicht unit (U-1), vloer (V-1), elke wand (W-1…W-4, via WallPdf/FloorPdf) en een totalenblad (balken, zaaglijst, glaswol, plaatwerk, gewichten). Projectgegevens van de unit staan instate.projecten gelden voor alle bladen. - Standaarden (WallModel). Muurbalk 38 x 235 mm (stijlen én regels),
ingekocht in 3600/4200/4800/5400 mm; een zaagplan (
planStockCuttingin geometry.js) kiest per staaf de lengte met het minste snijverlies — bij een unit over alle wanden samen. Stukken langer dan 5400 worden opgeknipt. Elke wandkop heeft een dubbele hoekstijl (2 x 38 mm). De app start met een unit. - Woning (v0.2). Bestand → Nieuw → Woning (1 unit) of Woning L-vorm. Een unit koppel je aan een zijde van een andere unit (uitlijning start/midden/ eind + verschuiving). Op de naad vervalt de wand van beide units over het gedeelde stuk; een wand kan daardoor in meerdere stukken uiteenvallen (bijv. A-W2a/b), haakse wanden lopen dan door tot de vloerrand. Binnen- wanden teken je in de plattegrond (standaard 100 mm, spaanplaat beide zijden) en bewerk je met de gewone wand-editor. Een wandstuk dat aan een naad eindigt loopt de naad in door met de dikte van de haakse buurwand, zodat binnenhoeken (L-vorm) dicht zijn. Zijden heten naar windrichting t.o.v. het bovenaanzicht (boven = noord): voor = noord, achter = zuid, links = west, rechts = oost (intern blijven de oude sleutels). Oude unit-JSON's kunnen in een woning worden geïmporteerd. Units kunnen (nog) niet gedraaid worden.
- Mijlpaal v0.4 — gevelopbouw. Samenvatting van de v0.3.11–0.3.19-iteraties: kruislat-latwerk op vochtdoek (richting gevelbekleding globaal), lampen op de afgewerkte gevel (+52 mm), logo-watermerk op het doek, trasraam (cement- gebonden plaat, 350 mm vanaf het loopvlak), sandwichpanelen rondom (600 mm de grond in), hoekdoorloop van de buitenlagen over de hoekstijlen, en latwerk/ doek per doorlopende gevel over unit-naden heen. Details per onderdeel hieronder.
- Plat dak (v0.3). Elke unit heeft een dak (tweede laag) dat standaard de vloermaat volgt, maar een eigen maat/verschuiving mag krijgen. Opbouw = vloer 180° gespiegeld (OSB als plafond onder, balken, dakleer bovenop); het dak wordt bewerkt met de vloer-editor in dakmodus. De dakrand is woning- breed: boeidelen (overstek 200–400 mm vanaf de dakrand = standaard de gevel, 300 mm hoog, spots op 40% van de overstek, op elke (unit-)hoek en daartussen verdeeld met min/max h.o.h.) of een daktrim van 80 mm. De rand loopt als één geheel over de naden tussen units. Het dak ligt op de hoogste wandbovenkant van de unit; bij units met verschillende hoogtes ligt de dakrand op het hoogste dak.
- Dakrand & buitenverlichting (v0.3.3). Boeidelen aan/uit per unit (anders daktrim); de rand wordt per ribbe opgebouwd (in verstek, geen zichtbare naad). Verlichting is woning-breed: type (geen / boeideel-spots / gevellampen), lichtrichting en alle afstanden. Gevellampen worden per GEVEL verdeeld (aansluitende wandstukken in hetzelfde vlak, ook over een naad tussen units), niet per wand: op lamphoogte (standaard 1950) alleen op vrije stukken >= 2000 mm (openingen incl. raamwerk eraf), eerste/laatste 300 mm van hoek/opening, daartussen min/max h.o.h.; smallere stukken krijgen geen lampen. Gevellampen en boeideel-spots sluiten elkaar uit. De min. h.o.h. geldt over alle lampen van een gevel samen (ook bij afstand hoek/ opening en overrides): te dicht bij elkaar = samengevoegd tot één lamp in het midden. Per wandzijde blijft een override: automatisch / 500 mm naast elke opening / geen. Standaard unithoogte 2600 mm.
- 3D-weergave (v0.3.5). Filters als dropdown met vinkjes. Woning: Beplating (wandplaten, vloer- en plafondplaten, dakleer, boeideel/daktrim), Isolatie, Dak, Lampen. "Volle render": avondscène met maaiveld, elke gevellamp (per lichtrichting) en boeideel-spot is een echte SpotLight (zonder schaduwen, om het licht te houden); de nep-lichtkegels zijn dan verborgen.
- Latwerk gevelbekleding (v0.3.11). Bij vochtdoek komt er een kruislat op (WallModel.computeBattens): latten 20x30 mm, handelslengte 4000, 400 mm h.o.h. in beide richtingen, uitgespaard rond openingen en afgekapt op de (schuine) bovenrand. De bovenste laag staat haaks op de gevelbekleding (WEO/Novalit, 12 mm; richting per losse wand, in een woning voorlopig globaal als woning-instelling). Gevellampen hangen op de afgewerkte gevel: wandvlak + kruislat (40) + bekleding (12) = 52 mm naar buiten. Cement-gebonden platen (steenstrips) krijgen geen latwerk. Latten tellen mee in gewicht, specificaties, wand-PDF en woningtotalen; zichtbaar met "Beplating".
- Vochtdoek-bedrukking (v0.3.13). Net als op de echte doeken staat het logo als medium-grijs watermerk (geen kleur) onder 45° op het vochtdoek, 1,5 m breed, herhaald per tegel van 2 m (WallModel.createMaterials, CanvasTexture).
- Trasraam (v0.3.14). Woning-instelling (aan/uit + hoogte, standaard 350 mm vanaf Y=0 van de vloer = het beloopbare vlak / bovenkant vloer). Onderaan elke vochtdoek-gevel komt een strook cement-gebonden plaat (montage- achterkant), vóór het doek; het doek loopt er ongewijzigd achter door en het latwerk begint erboven. Zelfde plaat- en uitsparingslogica als de buitenplaten, dus openingen blijven gerespecteerd (WallModel.trasraamFor, build3D opts.trasraam, computeBattens). Telt mee in gewicht, wand-PDF en de woningtotalen ("Cementplaat (trasraam)").
- Hoekdoorloop buitenlagen (v0.3.18). Een wand die tussen twee doorlopende wanden past, bedekt met zijn buitenlagen ook de kopse kant (hoekstijlen) van die wanden: UnitModel geeft per wand(stuk) skinExt { left, right } (= dikte van de doorlopende wand, 0 bij naden/vrije einden), WallModel.cornerExt telt per laag de eigen diepte erbij. Latwerk en trasraam lopen door; vochtdoek en cementplaat (liggen in de beplatingsruimte) krijgen een strook net vóór het wandvlak.
- Latwerk en doek per gevel (v0.3.19). HouseModel.assignFacades groepeert collineaire, aansluitende buitenwandstukken over alle units tot gevels (groupFacadeRuns in core/geometry.js, ook gebruikt door de buitenverlichting) en geeft elk stuk p.facade { u0, extStart, isEnd }. Het verticale latten-raster (400 h.o.h.) en het watermerk op het doek lopen daardoor over unit-naden door; een eindlat komt alleen aan het einde van de gevel.
- Sandwichpanelen (v0.3.16). Woning-instelling aan/uit. SandwichModel (js/sandwich/sandwich-model.js) legt één doorlopende rand (in verstek) om de vereniging van alle unit-vloeren: 40 mm dik, van het loopvlak (bovenkant vloer) 600 mm naar beneden, de grond in. Plaat 495 x 1000 x 40 (9 kg), verticaal: één plaat per 495 mm gevel, 1000 afgezaagd op 600. Naden per 495 mm; zichtbaar met "Beplating"; m2, aantal platen en gewicht (hele platen) in de woningtotalen.
- Openingtypes. Raam (500x1900), deur (900x2150) en voordeur (1150x2150); type kiezen zet de standaardmaat, daarna vrij aan te passen. De app start met een L-woning met een voordeur (noord, unit A) en 3 ramen (zuid, unit B).
- Woning-instellingen. Regelwerk-h.o.h. (min/max) geldt globaal voor alle buitenwanden resp. alle binnenwanden; in de wand-editor zijn die velden binnen een woning vergrendeld.
- Versienummer staat als enkele constante (
APP_VERSION) inapp.js. Conventie: laatste cijfer per kleine iteratie, middelste per mijlpaal (aangegeven in chat), eerste bij live-gang.