35 Commits
Author SHA1 Message Date
MachielandClaude Opus 5.5 a7215b9e62 v0.7.9: woningen van leads en klanten uit de CRM (alleen in de Docker-stack, api/crm/ via Caddy): bij Nieuw te zoeken en te openen, ?woning=<id> opent er direct één; Opslaan in CRM (ook Ctrl+S in zo'n tab) bewaart een nieuwe versie met opmerking, met waarschuwing als er intussen een nieuwere versie is; Downloaden (JSON + PDF) blijft; sluiten met niet-bewaarde wijzigingen vraagt bevestiging
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 19:40:51 +02:00
MachielandClaude Opus 5.5 0da1769f51 GLB voor AR zonder alles onder het maaiveld (GlbWriter clipBelow, zonder sandwichpanelen), AR op ware grootte; model Van den Berg (dubbel chalet met portiek en overdekte vlonder)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 17:30:01 +02:00
MachielandClaude Opus 5.5 4bb1548125 Light: optie price: false (of data-price="false"): geen prijs in het paneel en op het voorblad van de PDF; design().info.price blijft
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 17:30:01 +02:00
MachielandClaude Opus 5.5 73248a69c9 v0.7.8: light-versie in te bedden op elke pagina en eigen opslaan: texturen, kleurstalen en kosten/*.csv laden via tectumUrl() (js/core/geometry.js) vanaf de map van de scripts, zodat de engine niet naast de pagina hoeft te staan (modelpagina's van de site met de engine op /configurator/); paden in de data blijven relatief; TectumLight.mount(el, { save: { label, icon, onSave } }) vervangt de PDF-knop, onSave krijgt het ontwerp als house-design-JSON met kerncijfers, prijs en keuzes in woorden (ook el.tectumLight.design())
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 11:28:02 +02:00
MachielandClaude Opus 5.5 b8cc39275b v0.7.7: daktrim als echt profiel: voorkant 8 mm vóór de gevelbekleding, 30 mm boven het dak en over de bovenste trimHeight van de gevel (standaard 30 mm), opstand 20 mm diep met een flens van 3 mm op het dak over de bovenkant van de bekleding (RoofModel.TRIM); de bekleding loopt bij een daktrim door tot het dak; hoeken met daktrim/felsrand lopen op de buitenkant door, naast een boeideel stopt de trim ertegen; vrije uiteinden van binnenwanden afgewerkt in de binnenwandkleur (endCaps) in plaats van een zichtbare stijl; light-PDF: prijs op het voorblad rustig onder een dunne lijn, bedrag groot en vet, geen oranje vak
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 14:41:56 +02:00
MachielandClaude Opus 5.5 118ccf9098 v0.7.6: geen wolfsdak bij een overkapping (veranda, inpandig of uitpandig: het dak van een unit steekt buiten zijn vloer, HouseModel.hasCover): de keuze verdwijnt in configurator en light, een bestaand wolfsdak wordt een zadeldak met dezelfde goot en nok; afdekker op een stenen trasraam onder rabat, felsplaten of stuc (WallModel.TRAS_CAP): zetwerk achter de bekleding, 5° aflopend, neus 25 mm over de steen, onderbroken bij openingen, bij een buitenhoek door tot voorbij de buursteen, zwart/antraciet/wit (WallModel.TRIM_COLORS), in 3D, PDF-aanzichten, materialen, rapport en kosten; ventilatierooster van 40 mm op de gevel direct onder de onderplaat van alle boeidelen (RoofModel.VENT, niet boven een veranda of tegen een hogere gevel), sleuven in de textuur, aan/uit en kleur bij Dak › Boeideel, in 3D, PDF, rapport en kosten; light-versie: boeidelen of daktrim met kleur boeidelen (Dak) en één zetwerk-kleur voor afdekker en rooster (Gevel); 3D zijwaarts schuiven ook met de middelste muisknop, Shift/Ctrl/⌘ + slepen en de pijltjestoetsen met de muis boven de weergave (configurator en light, hints en sneltoetsenoverzicht bijgewerkt)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 13:45:26 +02:00
MachielandClaude Opus 5.5 432e0f494a v0.7.5: AR en schermvullend in de light-versie: knop rechtsboven in de weergave; op een telefoon/tablet het ontwerp als GLB in model-viewer over de hele pagina met "Bekijk in je tuin" (ware grootte, WebXR/Scene Viewer/Quick Look, op iOS maakt model-viewer de USDZ; model-viewer 4.3.1, Apache-2.0, UMD met eigen three.js, pas geladen bij de eerste keer AR), op de desktop de weergave schermvullend (scrollwiel zoomt dan direct); GlbWriter (js/core/glb-writer.js): glTF 2.0 binair uit three.js-objecten, één primitive per materiaal, PBR met lineaire kleuren, texturen als JPEG/PNG op een macht van 2 tot 1024 px met de textuurmatrix in de UV's, lichtbundels en -vegen weg, nul-driehoeken eruit en lege normalen naar de vlaknormaal (valideert zonder fouten); GLB één keer per ontwerp, el.tectumLight.glb() en een testknop GLB op light.html; HouseModel.rootGroups en groundOrigin gedeeld met de render-export
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 12:06:09 +02:00
MachielandClaude Opus 5.5 decbbb4b72 v0.7.4: light-versie voor de modelpagina's (light.html, js/light/, css/light.css; later in de HUGO-site in een Bootstrap col-12): één model in 3D, doorsnede (snijhoogte tot de goot) en 2D-plattegrond, met beperkte keuzes: per unit breedte en diepte (binnen UnitModel.LIMITS, per model/pagina te beperken), dakvorm met richting, goot- en nokhoogte (helling erbij) en wolfseind, dakbedekking, gevelbekleding met kleur en richting, accent van het model, trasraam (geen/steen, hoogte), binnenspots en buitenverlichting; zelfde berekening als de configurator maar alleen prijs (indicatief, incl. btw), maten, m², inhoud en gewicht zichtbaar; LightModel past keuzes toe op een schone kopie van het model (binnenwanden en inrichting schuiven mee, binnenwanden volgen de goot) en weigert keuzes die de indeling breken (ramen/deuren, binnenwanden, inrichting, ruimtes, overlap) met de dichtstbijzijnde maat die wel past; accordeon-paneel, responsief op de breedte van de tool (container queries), scrollwiel scrolt de pagina tenzij je in de 3D klikt of Ctrl houdt; opslaan = PDF (LightPdf): voorblad "Uw woningontwerp" met render, kerncijfers, keuzes, prijs, contact en QR-code naar de modelpagina (qrcode-generator, MIT), aanzichten en plattegrond (HousePdf klantvariant zonder productie-informatie) en het stappenplan met maatwerk en uitnodiging; doorsnede-afdekking naar HouseModel.sectionCaps (ook in de configurator): 1 mm boven de snede en over de wandtop van wanden die lager blijven, geen flikkerend regelwerk meer; OrbitControls met touch (één vinger draaien, twee vingers knijpen/schuiven); model Vecht (U-vorm 13 × 9,5 m, drie units rond een holte)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 11:48:51 +02:00
MachielandClaude Opus 5.5 51921650e3 v0.7.3: elektraleidingen nooit meer door een raam of deur (makeOpeningTest): een stijgleiding boven/onder een opening (wcd onder een raam) gaat eerst op dezelfde hoogte opzij tot naast de opening, langs dezelfde wand met een deur of raam ertussen via het plafond, gevellampen om verspringende gevelhoeken heen en het uit elkaar schuiven van buizen eindigt nooit in een opening (alle modellen 0 kruisingen); felsplaten als gevelafwerking (zink/antraciet/zwart, per woning, wand of wandstuk, opbouw als verticale rabat, kleuren gedeeld met het felsdak, in 3D, PDF en kosten); felsplaat op dak én gevel = geen boeideel, de dakplaat zet om over de rand zonder opstand, een boeideel ernaast stopt gelijk met zo'n rand (ook naast daktrim); zijwand bij een overkapping (Palen overkapping › Zijwand) in plaats van een hoekpaal, gestuukt, met de bekleding van de gevel in hetzelfde vlak aan de buitenkant (in 3D, plattegrond, PDF, DXF en kosten); model Reest (12,9 × 7,85 m, lessenaarsdak hoog aan de noordgevel over twee units in één vlak, overkapping bij de voordeur met witte zijwand, aanbouw met plat dak en daktrim, zuidgevel en dak in antraciet felsplaten, verder verticale rabat)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 21:27:20 +02:00
MachielandClaude Opus 5.5 89cadbebf7 v0.7.2: fixes uit de code-review van v0.7.1: elektraleidingen nemen niet langer het valse plafond van de buurruimte door de wand heen over (gebied zonder functie = geen vals plafond) en meten begin/eind 50 mm de ruimte in, zodat de zigzag bij een overgang vals plafond/dak verdwijnt (Amstel 249,9 → 246,8 m, 16 van 68 leidingen strakker); elektra en schoorsteen snijden mee met de doorsnede (geen zwevende buizen); PDF en de plaatfase van de IFC bouwen geen buizen meer; schoorsteen in 2D en 3D op de laag Gevelbekleding; Esc sluit elke dialoog via Annuleren en sneltoetsen gaan niet meer naar de editor erachter; toets 3 sluit het rapport; menu en popovers sluiten elkaar (één uitklapper tegelijk); paneelkop ge-escaped; na slepen/pannen buiten de plattegrond wordt de volgende klik niet meer ingeslikt en blijft de cursor van het gereedschap; "Alles" in Lagen zet ook beplating binnen/buiten terug; laag uit met een selectie erin werkt het paneel bij; opgeruimd: gedeelde werkbalk (UI.editorBar) voor woning, wand en vloer, één knopbouwer (UI.btnOf), dichte paneelsecties pas opgebouwd bij openen, dode knopacties weg, binnenwand verwijderen op één plek, doorgestuurde acties uit één lijst, render-export "alleen afgewerkt" volledig in HouseModel (finishedOnly), structuurboom springt alleen bij een andere selectie
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 00:01:13 +02:00
MachielandClaude Opus 5.5 ab0dca9bb5 v0.7.1: UI-overhaul, ribbon vervangen door de indeling van CAD/BIM-pakketten met elke functie op één plek: bovenbalk met menu Bestand (nieuw, openen, opslaan, exporteren, projectgegevens, kosten & tijden) · Beeld · Help, de ontwerpen als tabs en de knop Opslaan; links de structuur met inklapbare groepen (onthouden, groep met de selectie klapt vanzelf open); werkbalk boven de viewports met gereedschap (Selecteren V, Binnenwand W, Ruimte R, Inrichting I, opties van het gereedschap ernaast, Unit toevoegen) en weergave (één Lagen-menu met bouwfase voor 2D en 3D, Omgeving, Doorsnede X, Render, Lopen L, Rapport 4, 2D + 3D / 2D / 3D met 1/2/3); rechts het eigenschappenpaneel (Inspector: selectie met kruimelpad, of de woning met kerncijfers en inklapbare secties Gevel, Dak, Binnen, Verlichting, Elektra, Constructie); statusbalk met hint en meldingen; wand- en vloer/dak-editor in dezelfde indeling (paneel rechts met tab Resultaat, terug met ← Woning of Esc); sneltoetsenoverzicht (?), Ctrl+O, Ctrl+\ panelen verbergen; rapport als masonry; dubbele functies weg (lagenbalk, Beeld-tab en Weergave-filter, export en kosten op twee plekken, Snel nieuw); oude onderdelen gelijkgetrokken (dialoogknoppen, materiaalknoppen, chassis als schakelaar, eenheden); weergavelagen (ViewLayers) i.p.v. bouwfasen, elk los aan/uit; render-export met Blender-script voor de lampen; elektraleidingen boven een vals plafond en haaks binnen de units bij een L/T-vorm
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 23:16:43 +02:00
MachielandClaude Opus 5.5 adb3c74f85 v0.7.0: exports voor CAD, BIM en renders (Bestand › Exporteren, los van Opslaan/Ctrl+S): CAD (DXF R12, plattegrond met wanden/sparingen/gevelbekleding/kozijnen met draaicirkel, ruimtes, inrichting, dakrand, elektra en echte maatvoering, plus vier gevels als lijntekening met verborgen lijnen weg; lagen PL-/AZ-, 1:1 mm, afgestemd op 1:50; in CAD op te slaan als DWG), BIM (IFC4 met alleen de bouwconstructie: stijlen, regels, vloer- en dakbalken, stalen nokbalk, palen, spaanplaat/OSB/cementplaat en elektra per leiding, gegroepeerd per unit en element met Pset_Tectum en kleur per soort) en Render (OBJ + MTL + texturen in een ZIP voor Blender, volledige afgewerkte woning, kleuren lineair, PBR); schoorsteen tegen een buitenwand (ChimneyModel: sparing in wand en dak met raveelwerk, steenstrip/stuc, verslepen langs de gevel); kozijnen koppelen met een eigen schakelaar; kozijnindeling (deurblad, zij-/bovenlicht, schuifbladen) gedeeld tussen 3D, plattegrond en aanzicht
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 20:00:32 +02:00
MachielandClaude Opus 5.5 86fcd57b96 v0.6.3: modellen Waal (12,85 × 7 m, flauw zadeldak dat aan de oostkop 1,5 m doorloopt als veranda), Maas (9,2 × 9,2 m, woningdak met inpandige veranda in de noordwesthoek) en Rijn (L-vorm 13 × 10 m, zadeldak als twee lessenaars op de naad, vleugel met plat dak, steenstrips met schoorsteenstrook, kookeiland, logeerkamer, spots in de boeidelen); overkapping per unit (dak verlengen voorbij de gevel) met palen (PostModel: hout, maat, h.o.h., op de plattegrond/PDF en in de kosten); kleur schakelaars/wcd's (wit, antraciet, zwart); gevellampen naast openingen en per vrij wandstuk gelijk verdeeld, nooit in een opening; logobord niet meer onder een unit bij een voordeur in een binnenhoek
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:26:06 +02:00
MachielandClaude Opus 5.5 b137a458d4 v0.6.2: dakaansluiting L/T (vleugel met nokdak loopt het hoofddak in met kilkepers, of de kop wordt een schild met hoekkeper; eigen dakdeel en PDF-blad per unit, ook in de kosten), model IJssel (L-vorm met zadeldaken in riet), unit max 4,7 m breed; mansarde vervallen (oude ontwerpen worden een zadeldak met dezelfde nok); gevelbekleding volgt voorbij het wandeinde de daklijn (geen blok meer boven een steil dakvlak) en bij een bolle daklijn per punt de bovenkant van het dak; gevellampen standaard min. 500 mm h.o.h. (geen samengevoegde lamp meer boven een smal raam)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 10:19:43 +02:00
MachielandClaude Opus 5.5 bd084e4a96 v0.6.1: standaardmodellen uit één lijst (HouseModel.MODELS) voor Snel nieuw en het venster Nieuw, gedeelde bouwstenen (modelKit) voor Amstel en nieuw model Wetering (10,5 × 4,8 m, twee units zonder naadwand, hoekkeuken, badkamer, slaapkamer met kast); keukenblok met kookplaat (plek instelbaar) en spoelbak aan/uit, kookplaat ook in de kosten van een keukenblok
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 00:53:24 +02:00
MachielandClaude Opus 5.5 ceda0b554d v0.6.0: ruimtes (verfemmer: functie, netto m², vloerafwerking, FIBO-wandpanelen, eigen verfkleur, vals plafond, ruimtestaat op de PDF), inrichting (sanitair, keuken, kookeiland, kasten, bed, zithoek, boiler; slepen met snappen op het wandvlak, draaien, kosten), kozijnen met deurrichting, glasdeur en schuifdeuren (inbouw/opbouw, deuren open in de loopmodus) plus dagkanten, gevel stucwerk en wandstukken splitsen met eigen gevel, dak over de hele woning met overkapping, geschilderd plafond, model Amstel als nieuw ontwerp, kosten en prijzen uit kosten/intern.csv en kosten/leveranciers.csv (CostCsv); easter egg verwijderd; overbodige comments opgeschoond (alleen copyright, uitzonderingen en valkuilen blijven)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 00:34:27 +02:00
MachielandClaude Opus 5.5 b5510d56c7 v0.5.3: elektra-buizen min. 50 mm uit elkaar (gebundeld alleen naar de meterkast), vloer-wcd met leiding door de vloer, elektra op de PDF-bladen per wand/vloer/dakvlak, kosten elektra (buis + draad per meter, boorgaten 90 s geteld op stijlen/regels/balken, dozen, groepenkast, keuring), dakbeschot OSB 18 mm bovenop de sporen, felsplaten als dakbedekking
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 20:54:49 +02:00
MachielandClaude Opus 5.5 e1a688728c v0.5.2: elektra (meterkast 3×25 A, schakelaars met letters op hun lampen, wcd, apparaatgroepen incl. perilex, groepenverklaring met fasen/aardlek, leidingen naar de meterkast met strekkende meters per type, PDF-blad + plattegrond, verplaatsbaar door slepen, bouwfase Elektra met installatiebuizen in 3D); ribbon, bouwfasen, kozijnen, kostenmodel en eerdere ongecommitte wijzigingen
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 18:40:11 +02:00
MachielandClaude Opus 5.5 8cdfa21f46 v0.4.17: openingen met schuine bovenzijde (hoogte links/rechts, volg dakhelling), 9 sleeppunten in het vooraanzicht; regelwerk, beplating, doek, steen en latwerk volgen de schuinte (columnMinusRects met schuine uitsparingen)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 20:01:54 +02:00
MachielandClaude Opus 5.5 23bfe153a2 v0.4.16: PDF-aanzichten (vlakke render) met legenda afwerking en afmetingen, zaaglijst/zaagmachine eigen blad, infopaneel afmetingen, lopen (Shift+T) met camera-menu, zachter licht, naadwanden volgen koppeling, boeideel over de gevel (gevel tot bovenkant dak), thumbnails riet/vloer
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 22:29:57 +02:00
MachielandClaude Opus 5.5 12c2579471 v0.4.15: gevelbekleding per woning (rabat/steen, override per wand), stenen trasraam (110 mm, 181 texturen), riet per unit, vloerafwerking, verfkleur binnen, boeideelkleur, gevel tot onder dakrand, binnenhoek-fixes; testontwerp als standaard
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 19:47:49 +02:00
MachielandClaude Opus 5.5 7d91416004 v0.4.14: schuin dak met loodrechte kopse kanten, import met naadwanden, weergave Vloerplan
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 17:24:38 +02:00
MachielandClaude Opus 5.5 94a5215f82 v0.4.13: opbouw buitenwand boven lager dak, latwerk-raster per gevel, dakrand 80 mm boven dakleer, lage rand loopt door
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 15:33:47 +02:00
MachielandClaude Opus 5.5 373c2c2fb7 v0.4.12: dak volgt wandvorm (plat/lessenaar/zadel), dakrand per hoogte, naadwand midden of geheel in unit A/B
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 14:43:42 +02:00
MachielandClaude Opus 5.5 001206a108 README opgeschoond: korte opzet met bulletpoints, geen changelog meer
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 13:41:01 +02:00
MachielandClaude Opus 5.5 9126588df7 v0.4.10: wandhoogtes gekoppeld, middenpunt (nok), binnenspots langs naadwanden
- WallModel: optioneel middenpunt (heightMid, topLine), bovenregels in verstek;
  stijlen, openingen, beplating, doek, latwerk, BOM, 2D en PDF volgen de knik
- wand-editor: schakelaar "Middenpunt (nok)" + nokhoogte, links/rechts = goothoogte
- UnitModel.syncWallHeights: tegenoverliggende wand gespiegeld, haakse wanden
  vlak op de hoekhoogtes; wallPieces met nok per stuk
- LightingModel.computeIndoor: raster vanaf binnenzijde eigen naadwanddeel

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 13:35:21 +02:00
MachielandClaude Opus 5.5 9bd7faeaa6 v0.4.9: naadwanden (2 delen, deur), kopbalken op naden, isolatie niet meer getekend
- HouseModel: naadwand per naad (ensureSeamWalls bij nieuwe woning en unit toevoegen),
  twee delen met beplating alleen aan de kamerzijde, openingen gespiegeld
- WallModel: buitenzijde 'geen', thicknessOf eenzijdig
- FloorModel: kopbalken (rims) voor vloer en dak op naden, ook in PDF en totalen
- isolatie: 3D-lagen en filter verwijderd, berekening blijft

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 13:13:07 +02:00
MachielandClaude Opus 5.5 f163f4deb1 v0.4.8: gevellampen tellen vanaf de zichtbare afgewerkte hoek
- bedekte gevelstukken (wandstuk in de naad, binnenhoek L) afgetrokken via voetafdruk
- uiteinden verlengd met afwerking (+ skinExt bij tussenpassende wanden)
- groupFacadeRuns accepteert overlap

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:54:41 +02:00
MachielandClaude Opus 5.5 448c2b1289 v0.4.7: lampen niet meer door muren, buiten overdag gedimd, binnenspots feller
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:47:08 +02:00
MachielandClaude Opus 5.5 5ecf3e0c2a v0.4.6: binnenspots per unit, omgeving als keuzemenu (Ontwerp/Dag/Nacht), lampen 15% zachter
- LightingModel.computeIndoor: plafondraster per unit (800-1500 h.o.h., 600 van wand/naad)
- 3D, plattegrond, render, totalen en PDF
- tegelvloer 20% groter; gras volledig verwijderd

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:44:06 +02:00
MachielandClaude Opus 5.5 7ae76fe390 v0.4.5: tegelvloer met witte rand i.p.v. gras, Lucht geen/dag/nacht, Render met daglicht + lampen
- core/skybox.js: tegelvloer (tiles.jpg) passend om het object, rand 100x25 mm wit
- nacht-panorama; nacht = 15% omgevingslicht + lampen 100%
- Render-knop met camera-icoon: echte lampen in het gekozen licht
- gras verwijderd (bestanden lokaal bewaard, uit git)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:34:19 +02:00
MachielandClaude Opus 5.5 9ed9cee2e0 v0.4.4: gras kleurgecorrigeerd naar panorama-grasgroen, belichting gecompenseerd
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:13:41 +02:00
MachielandClaude Opus 5.5 f8da490640 v0.4.3: lucht op de grond (grounded skybox) met gras en schaduw; webserver verplicht
- core/skybox.js: panorama op de grond geprojecteerd (port GroundedSkybox),
  grastextuur in cirkel rond het object met overvloeiing, zon met schaduw,
  camera niet onder de grond
- woning: maaiveld als instelling (standaard 350 mm onder bovenkant vloer)
- assets opgeschoond (alleen grass.jpg + skybox.webp), skybox-data.js weg
- start.sh + melding bij file://

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:07:35 +02:00
MachielandClaude Opus 5.5 3a4b9608c0 v0.4.2: iconen gerepareerd, lucht-achtergrond (skybox) met toggle
- bootstrap-icons: @font-face correct ingebed (selector .bi::before was stuk)
- core/skybox.js + assets/skybox-data.js (lazy), knop Lucht in alle 3D-weergaven
- woning: met lucht aan raster en sandwichpanelen onzichtbaar

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 11:58:07 +02:00
MachielandClaude Opus 5.5 3591fad220 v0.4.1: UI opgeschoond — tabbladen, iconen, uniforme labels, T-cyclus
- core/ui-kit.js: gedeelde velden/schakelaars/tabs/specificatiekaarten
- Bootstrap Icons lokaal (css/vendor, font ingebed)
- Woning- en unit-instellingen in tabbladen, labels gestandaardiseerd
- Specificaties onder 3D als kaarten
- T: standaard -> 3D groot -> alleen render -> standaard

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 11:51:18 +02:00
809 changed files with 23413 additions and 3260 deletions
+527 -222
View File
@@ -1,237 +1,542 @@
# 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.
Configurator voor mantelzorgwoningen: wand, vloer en woning (gekoppelde units)
met 2D, 3D, specificaties en PDF-tekenbladen.
Copyright © 2026 Machiel Heinen. Alle rechten
voorbehouden; gebruik uitsluitend met schriftelijke toestemming. Zie
[LICENTIE.md](LICENTIE.md). Elk bronbestand begint met deze copyright-kop.
Copyright © 2026 Machiel Heinen. Alle rechten voorbehouden; gebruik
uitsluitend met schriftelijke toestemming. Zie [LICENTIE.md](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
./start.sh # of: python3 -m http.server 8000
```
en open `http://localhost:8000`.
Open `http://localhost:8000`. Elke statische webserver volstaat; geen
build-stap. Direct openen via `file://` werkt niet (texturen/lucht).
## 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
index.html app-shell: bovenbalk (menu, documenten, opslaan), sneltoetsen, splashscreen
css/app.css alle stijl
js/vendor/ three.js r128, eigen OrbitControls, jsPDF, qrcode-generator 1.4.4 (MIT, Kazuhiko Arase; QR in de light-PDF),
model-viewer 4.3.1 (Apache-2.0, Google; UMD-bundel met eigen three.js, AR in de light-versie)
js/core/ gedeelde helpers: geometrie, weergavelagen (lagenmenu), menubalk, eigenschappenpaneel
(inspector.js), UI-kit (werkbalk, weergave, popovers), PDF-bladen,
DXF-schrijver (dxf-writer.js), IFC-schrijver (ifc-writer.js), OBJ-schrijver
(obj-writer.js), GLB-schrijver (glb-writer.js), ZIP (zip-writer.js), labels, camerageheugen,
skybox, licentie, logo
js/wall/ WallModel (logica) + wand-PDF + wand-editor
js/floor/ FloorModel (logica) + vloer-PDF + vloer-editor
js/roof/ RoofModel: dak (plat/lessenaar/zadel) + dakrand (boeidelen/daktrim)
PostModel: palen onder een overkapping/veranda (dak per unit te verlengen), of een dichte
zijwand op een vrije hoek
js/house/chimney-model.js ChimneyModel: schoorsteen tegen een buitenwand (hol, sparing in de wand zoals een raam,
ook over een naad, zonder hout erin; sparing in het dak met raveelwerk (stijlen, balken, kreupele
balken), de beplating eindigt op het kader; onderbreekt de dakrand; een nokbalk stopt ervoor;
buiten steenstrip/stuc, binnen als de wanden of eigen; in de plattegrond
te verslepen langs de buitengevel)
js/lighting/ LightingModel: gevellampen, boeideel-spots, binnenspots
js/elektra/ ElektraModel + ElektraPdf: meterkast, schakelaars (letters), wcd, groepen, leidingen
js/sandwich/ SandwichModel: sandwichpanelen rondom
js/room/ RoomModel: ruimtes (verfemmer), functie, netto m², afwerking, vals plafond
js/interior/ FixtureModel: inrichting (sanitair, keuken, kasten, meubels, boiler)
js/unit/ UnitModel: 1 vloer + 4 wanden, naden, wandstukken
js/house/ HouseModel (woning) + woning-PDF + CAD-export (house-dxf.js) + BIM-export (house-ifc.js) + woning-editor
js/cost/ CostModel (kostenberekening), posten + noodwaarden, CostCsv (CSV's), venster Kosten & tijden
js/app.js menubalk, versienummer, actieve editor
js/crm.js koppeling met de Van Emous CRM (alleen in de Docker-stack, zie "CRM")
light.html light-versie (modelpagina's), los te openen: light.html?model=amstel
js/light/ LightModel (keuzes op een model toepassen, indelingscontrole, kerncijfers), LightPdf (klant-PDF) + light-UI
css/light.css stijl light-versie, alles onder .tectum-light
json/defaults/ referentie-JSON's (niet runtime ingeladen)
kosten/ intern.csv (eigen waarden) + leveranciers.csv (live prijzen), bij het starten ingeladen
assets/ logo, texturen, skybox
```
## Bewuste keuzes / bekende beperkingen
## Uitgangspunten
- **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
via `file://` door browser-CORS-beleid. Dit was expliciet een vereiste
("gewoon via een index file"), dus is hier bewust voor gekozen.
- **`json/defaults/*.json` worden niet gefetcht.** Om dezelfde reden (fetch()
van lokale bestanden werkt ook niet betrouwbaar via `file://`): de
standaardwaarden van "Nieuw" staan hardcoded in `wall.js`/`floor.js` zelf,
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 in
`state.project` en gelden voor alle bladen.
- **Standaarden (WallModel).** Muurbalk 38 x 235 mm (stijlen én regels),
ingekocht in 3600/4200/4800/5400 mm; een zaagplan (`planStockCutting` in
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`) in `app.js`.
Conventie: laatste cijfer per kleine iteratie, middelste per mijlpaal
(aangegeven in chat), eerste bij live-gang.
- **Eén bron per logica.** Rekenwerk en 3D-opbouw zitten alleen in de
`*Model`/`*Pdf`-modules; editors en woning hergebruiken die.
- **Geen ES-modules, geen CDN.** Gewone `<script>`-tags in vaste volgorde
(zie `index.html`), alle libraries lokaal.
- **Assen/zijden.** Bovenaanzicht boven = noord: voor = noord, achter = zuid,
links = west, rechts = oost (interne sleutels blijven voor/achter/…).
- **Hoogtes** gelden vanaf bovenkant vloer (loopvlak).
- **Weergavelagen** (`ViewLayers`): regelwerk, elektra, beplating, vochtdoek,
latwerk, gevelbekleding, kozijnen, dakbedekking, afwerking, verlichting,
inrichting, ruimtes, dak en maten, elk los aan/uit; de snelkeuze Fase zet
alles tot en met een bouwfase aan (de volgorde in de hal). Lagen die aan
beide zijden zijn ingesloten worden niet
gebouwd (stijlen tussen spaanplaat en doek, latten en doek achter de rabat,
sporen tussen plafond en dakbedekking). Specificaties en totalen rekenen
altijd met alle lagen.
- **Invoer volgt de logica:** de dakvorm is een eigenschap van de unit
(plat/lessenaar/zadel, richting, goot- en nokhoogte of helling); de
wanden volgen.
## Functionaliteit
- **Wand:** openingen (raam/deur/voordeur) met ankers, ook boven elkaar
(raam boven een deur; stijlen ertussen van dorpel tot dorpel), regelwerk
38x235 met dubbele hoekstijlen en een dubbele stijl naast deuren, zaagplan
op handelslengtes, spaanplaat binnen, vochtdoek (met kruislat en trasraam)
of cementplaat buiten.
- **Elektra** (`elektra/`): meterkast (3×25 A) bij de voordeur, schakelaars
met letter (A binnen, B buiten, per unit een eigen; dezelfde letter bij de
lampen erop), dubbele wcd's per unit, apparaten met eigen groep (kookgroep
perilex, wasmachine, droger, warmtepomp, optioneel oven/vaatwasser).
Groepenverklaring met fasen en aardlekschakelaars, leidingen via stijlen
en plafond naar de meterkast (strekkende meters per type, draad, buis,
steekverbinders op module-naden), materiaallijst en eigen PDF-blad.
Buizen minstens 50 mm uit elkaar (gebundeld alleen het laatste stuk naar
de meterkast). Nooit door een raam of deur (`makeOpeningTest`): een
stijgleiding boven/onder een opening (wcd onder een raam) gaat eerst op
dezelfde hoogte opzij tot naast de opening, langs dezelfde wand met een
deur of raam ertussen via het plafond, gevellampen om de gevelhoeken heen,
en uit elkaar schuiven van buizen eindigt nooit in een opening. Vloer-wcd's met leiding door de vloer. Elektra ook op de
PDF-bladen per wand, vloer en dakvlak (plafond). Alles verplaatsbaar door
te slepen in de plattegrond. Kosten (groep Elektra): buis + draad per
meter, boorgaten (geteld op stijlen, regels en balken), dozen,
afmonteren, groepenkast en keuring.
- **Kozijnen** (`wall/kozijn-model.js`): per opening een vulling (geen, raam
met vast glas en optioneel ventilatierooster, of deur met dorpel en
optionele glasstrook of als glasdeur; zij- en bovenlicht vullen de rest van een grote
opening), kleur buiten en binnen (wit, grijs, antraciet, zwart). Volgt de
maat van de opening, ook een schuine bovenzijde. Deur: kant van het blad,
scharnierzijde en draairichting (naar binnen/buiten); openslaande deuren
met zijlichten = twee deuren naast elkaar. Koppelen: een opening die tegen
zijn buur aan staat (zelfde onderkant en hoogte, samen max. 2850 mm) vormt
daarmee één sparing zonder stijlen, dagkanten, latten of kozijnstijlen
ertussen; twee draaideuren worden stolp (bladen tegen elkaar), anders één
gedeelde tussenstijl. Schuifdeur: 1 of 2 bladen
(uit elkaar), in de wand of op de wand aan een rail (binnen- of
buitenzijde), glazen of dicht blad. In de plattegrond (app en PDF) een
draaicirkel per deur en de schuifrichting per schuifdeur; in de loopmodus
gaan deuren open (dubbele schuifdeur samen). Dagkanten (afgewerkte
fase): binnen een geschilderde omranding, dagkantplaten tot het kozijn en
een vensterbank onder ramen; buiten een omranding in de kozijnkleur en
een waterslag onder ramen (`WallModel.build3D`).
- **Plafond:** in de afgewerkte fase is de onderkant van het dak
geschilderd in de plafondkleur (Binnen › Wanden › Plafond), zolang
"Geschilderd" aan staat; anders kale OSB.
- **Dakvorm/wandhoogte:** per unit een dakvorm (Unit › Dakvorm: plat,
lessenaar, zadel of wolfsdak, met schuiven en hellingshoek).
Daaruit volgen de wanden: de kopgevels krijgen de daklijn (bij een
wolfsdak afgeknot op het wolfseind, met
daarboven driehoekige wolfseinden met de dakhelling tot de nok, met een
rechte nok ertussen), de haakse wanden staan vlak op de goothoogte. Het
bovenste deel van een wolfsdak is gewoon houtwerk: sporen, hoekkepers,
nokbalk en kopbalken (ook in zaaglijst, specificaties en kosten).
Een dubbel lessenaardak (twee units, elk hoog aan hun gezamenlijke naad,
op de mm gelijke goot, nok en hoogte op de naad: samen een zadeldak)
krijgt net als een zadeldak een stalen nokbalk onder de naad; één
lessenaar of twee die zo niet aansluiten niet. Staat er een schoorsteen
op de nok, dan stopt elke nokbalk vóór de schoorsteen.
Goot en nok gelden over de volle vloermaat (goot boven de buitenkant van
de gevel); staat de kopgevel tussen de haakse wanden, dan loopt zijn
daklijn daar precies op aan. Het wolfseind schaalt mee met goot en
nok (verhouding). De PDF heeft voor een wolfsdak een eigen blad met het
bovenste deel (bovenaanzicht houtwerk + stuklijst).
Grenzen (`UnitModel.LIMITS`): nok max 5 m, goot / plat dak max 3 m (vanaf
bovenkant vloer tot onderkant dak), unit max 4,7 x 14 m. Platte daken van verschillende hoogte krijgen elk hun eigen
boeideel (versprongen, het lage loopt door tot onder het hoge). Wijzig je een
wandhoogte in de wand-editor, dan geldt dezelfde regel vanuit die wand.
De daklijn van een wand hoort bij de wand zonder naden: loopt een wand
door een naad langer door (bijv. de kopgevel naast een gekoppelde unit),
dan blijven nok en knikken op hun plaats (`UnitModel.topLineOn`).
- **Dakaansluiting (L/T):** staat een unit met nokdak (zadel of
wolfsdak) met zijn nok haaks op de langszijde van een buur met nokdak
(vleugel tegen hoofdvolume), dan loopt de vleugel het hoofddak in tot
zijn nok, met kilkepers in de binnenhoeken (bij gelijke goot, nok en
overspanning onder 45°); het
wolfseind van de vleugel aan de naad vervalt. Ligt de vleugel gelijk met
een kop van het hoofdvolume, dan wordt die kop een schild in de vlakken
van de vleugel (hoekkeper, de goot loopt door; de kopgevel staat dan op
goothoogte, een wolfseind daar vervalt). Een vleugel die in een wolfseind
van het hoofdvolume zou steken sluit niet aan. Elke unit houdt zijn eigen
dakdeel (sporen, kreupele sporen, kepers, knik- en nokbalken; stalen
nokbalk alleen over de eigen nok) met een eigen PDF-blad
(`HouseModel.roofJoins`, `RoofModel.computeJoinedRoof`). Niet bij dak
over de hele woning; dakramen in zo'n dakdeel doen nog niet mee.
- **Overkapping:** bij een dak over de hele woning met `cover` loopt het
dak door tot de omhullende rechthoek waar geen unit staat (bijv. een
terras naast een kortere module), met een afgewerkte onderplaat in de
kleur van het boeideel (`HouseModel.coverExtensions`). Palen
(Woning › Dak › Palen overkapping) komen onder de vrije dakrand; met
"Zijwand" krijgt een vrije hoek geen paal maar een gestuukte wand van
200 mm van de dakhoek terug tot de gevel, langs de zijkant van de
overkapping (bij een hoek tussen twee vrije randen de kant met de kortste
weg naar de gevel); in 3D, plattegrond, PDF, DXF en kosten
(`PostModel`, `dak.zijwandM2`/`dak.zijwandMontage`). Ligt de buitenkant
in het vlak van een gevel, dan loopt die bekleding (felsplaten, rabat,
steen) erover door, gelijk met de gevel en tot onder de dakrand.
Bij een overkapping (veranda, inpandig of uitpandig: het dak van een unit
steekt buiten zijn vloer, `HouseModel.hasCover`) is er geen wolfsdak: de
keuze verdwijnt en een bestaand wolfsdak wordt een zadeldak met dezelfde
goot en nok.
- **Dak over de hele woning:** eigenschappen Woning › Dak › "Over hele woning": één
dakvorm (zelfde invoer als per unit) over de omhullende rechthoek van alle
units; een wolfsdak alleen bij een rechthoek (bij een L-/T-vorm zouden
de wolfseinden kilkepers vragen, dan wordt het een zadeldak), bijv. een
grote wolfskap over twee units naast elkaar. Elke unit
houdt zijn eigen dakdeel (dekken, bovenste deel van het wolfsdak geknipt
op de unit, PDF-bladen, kosten); de wanden van alle units volgen het
woningdak. De daken per unit blijven bewaard (`roof.unitWalls`) en komen
terug als je het weer uitzet.
- **Vloer:** balken, cirkelvormige doorvoeren, OSB, optioneel chassis;
in de woning een vloerafwerking (textuur, bijv. visgraat).
- **Woning:** units koppelen aan een zijde (uitlijning + verschuiving); op
naden vervallen de buitenwanden en komt een naadwand met deur: midden op
de naad in twee delen (één per unit), of als één binnenwand geheel in unit
A of B. De hoogte volgt per deel de daklijn van zijn unit. Staat een unit
met een hogere daklijn tegen een lager dak, dan krijgt zijn buitenwand aan
de naadzijde een opbouw vanaf de bovenkant van het lage dak (ramen daar
teken je op die buitenwand) en stopt de naadwand op die hoogte. Loopt het
lage dak langs de naad schuin, dan loopt de naadwand door en krijgt het
uitstekende stuk buitenafwerking (vochtdoek + latwerk).
Binnenwanden teken je in de plattegrond.
- **Dak:** per unit opgebouwd als gespiegelde vloer + dakleer, in de vorm
die de wanden aangeven: plat, lessenaar (schuine kopgevels) of zadel
(nok). Elk dakvlak is een eigen dek met de balken als sporen en een eigen
PDF-blad; doorvoeren gaan naar het vlak waarin ze vallen. Opbouw:
plafondplaat (OSB) binnen, sporen, dakbeschot (OSB 18 mm) bovenop en
daarop de bedekking per unit: dakleer, of bij een hellend dak riet
(180 mm, 3,8 kg/m²) of felsplaten (staande naad, zink/antraciet/zwart);
de dakrand schuift dan mee omhoog. De dakrand
(boeidelen/daktrim, spots) loopt als één rand door en volgt de helling.
Is een dak langs de naad minstens een boeideelhoogte hoger dan het
aangrenzende, dan krijgt het een eigen rand rondom (boven het lage dak
zonder spots). De rand van het lage dak loopt dan door tot de gevel van
het hoge, of langs een zijgevel tot de volle overstek (onder de hoge
rand). Boeideel en daktrim steken 80 mm boven het dakleer uit. Hebben
dak én gevel onder een rand felsplaten, dan komt er geen boeideel: de
dakplaat zet om over de rand, net vóór de gevelbekleding en zonder
opstand (`RoofModel.FELS_EDGE`, zetwerk zit in de prijs van de
felsplaten); een boeideel ernaast stopt gelijk met de buitenkant van zo'n
rand (ook naast daktrim). Onder de boeidelen zit op de gevel een
ventilatierooster van 40 mm (direct onder de onderplaat, op de
gevelbekleding; niet boven een veranda), zwart/antraciet/wit
(`RoofModel.VENT`, Woning › Dak › Boeideel; kosten `dak.ventRoosterM`).
- **Gevel:** gevelbekleding per woning, met override per wand en per
wandstuk: rabat (vochtdoek + kruislat + rabat 12 mm, kleur per woning,
getekend als plankentextuur die over naden doorloopt), steen (181
texturen), stucwerk (pleisterlaag 15 mm op cement-gebonden plaat, kleur
per woning, `WallModel.STUC`) of felsplaten (staande naad, banen van
500 mm, zink/antraciet/zwart; opbouw als verticale rabat, kleuren gedeeld
met de felsplaten op het dak, `WallModel.FELS`; kosten `gevel.felsM2` en
`gevel.felsMontage`). Een zijde kan gesplitst worden (wand ›
Wandstukken › Splitsen op, gemeten vanaf de linker vloerhoek van buitenaf):
elk stuk wordt een eigen wand-element en kan een eigen gevel krijgen
(bijv. stuc links, hout rechts). Steen is overal een
steenstrip op een wit isolatieblok, samen 110 mm (`WallModel.STONE`).
Het trasraam (cementplaat of een eigen steen) komt onder beide, dus
twee stenen kan. Op een stenen trasraam onder rabat, felsplaten of stuc
(minder ver uitstekend) komt een afdekker: zetwerk 5° aflopend met een
neus van 25 mm over de steen, onderbroken bij openingen, zwart/antraciet/wit
(`WallModel.TRAS_CAP`, `TRIM_COLORS`; kosten `gevel.afdekkerM`). Latwerk, doek en metselwerk lopen per gevel door over
unit-naden. Sandwichpanelen rondom, 600 mm de grond in.
- **Ruimtes** (`room/room-model.js`): elk door wanden afgesloten gebied is
een ruimte, bepaald als een verfemmer: alles wat bereikbaar is zonder door
een wand te gaan (deuren en ramen tellen als wand). Exact op het raster van
de wandvlakken, dus de netto vloer tot op de mm; kiertjes tot 30 mm tussen
wanden worden dichtgezet. Gereedschap *Ruimte vullen* (Start/Binnen): kies
een functie (woonkamer, keuken, slaapkamer, badkamer, toilet, hal, ...) en
klik in de plattegrond; of selecteer een gebied en kies daar de functie
(nog eens klikken = de unit eronder). Per ruimte: naam, vloerafwerking
(o.a. tegels), FIBO-wandpanelen (decor, tot een hoogte of tot het plafond),
eigen verfkleur en een vals plafond op een vaste hoogte (alleen waar het
dak hoger ligt; wandafwerking en binnenspots volgen). Laag in de
plattegrond (Lagen › Ruimtes), label met netto m², in de structuur,
het rapport, de kosten (vals plafond, FIBO) en op de PDF-plattegrond met
een ruimtestaat. Het zaadpunt hoort bij een unit en schuift mee.
- **Inrichting** (`interior/fixture-model.js`): zwevend toilet (wandcloset
aan een voorzetwand), fontein, badmeubel met spiegel, inloopdouche
(douchegoot, glaswand, regendouche), keukenblok (spoelbak, hoge kast met
koelkast en oven, vaatwasser, bovenkasten), kookeiland met inductieplaat,
kledingkast, bed, eettafel met stoelen, bank met chaise longue, fauteuil,
salontafel, tv-meubel, boiler en wasmachine. Gereedschap Inrichting (I): kies
een stuk in de werkbalk en klik in de plattegrond; slepen, bij een wand snapt de rug op
het wandvlak (Alt = vrij), D = draaien, Del = verwijderen. Per stuk maten
en opties (front, plek spoelbak, glaswand links/rechts, ...). In 2D, 3D
(afgewerkte fase), de PDF-plattegrond, de structuur en de kosten (groep
Inrichting; los meubilair telt niet mee). Het stuk hoort bij een unit en
schuift mee.
- **Verlichting:** boeideel-spots of gevellampen (per gevel verdeeld,
override per wand) en binnenspots in een raster per unit.
- **Indeling** (zelfde patroon als CAD/BIM-pakketten; elke functie op één plek):
bovenbalk met menu Bestand (nieuw, openen, opslaan, exporteren,
projectgegevens, kosten & tijden) · Beeld · Help, de geopende ontwerpen als
tabs en de knop Opslaan; links de structuur (groepen in-/uitklapbaar en
onthouden; de groep met de selectie klapt vanzelf open); in het midden een werkbalk met
gereedschap (Selecteren V, Binnenwand W, Ruimte R, Inrichting I, met de
opties van het actieve gereedschap ernaast; Unit toevoegen) en weergave
(Lagen, Omgeving, Doorsnede X, Render, Lopen L, Rapport 4, 2D + 3D / 2D /
3D met 1/2/3); rechts het eigenschappenpaneel: de selectie (unit,
wandstuk, binnenwand, ruimte, inrichting, elektra) met kruimelpad terug,
of zonder selectie de woning (kerncijfers en inklapbare secties Gevel,
Dak, Binnen, Verlichting, Elektra, Constructie); onderin een statusbalk
met de hint van het gereedschap en meldingen. Wand- en vloer/dak-editor
hebben dezelfde indeling (werkbalk boven, paneel met tabbladen en
Resultaat rechts; binnen de woning met "← Woning" of Esc terug). Help ›
Sneltoetsen (?) toont alle toetsen. Rapport toont transport per unit,
gewicht, afmetingen, kosten, hout en plaatwerk in plaats van de
plattegrond, als masonry (kaart in de kortste kolom, leesvolgorde blijft).
- **3D en plattegrond:** één lagenmenu (Lagen in de werkbalk, met bouwfase
als snelkeuze) voor 3D en plattegrond; plattegrond zoomt met het
scrollwiel en de knoppen rechtsonder (F = passend), verschuiven met
slepen; Doorsnede (wanden afgesneden op een instelbare hoogte, schuif in
de werkbalk, snede wit afgedekt), binnenzijde in een verfkleur (afgewerkte
fase), omgeving Ontwerp/Dag/Nacht, Render met lampen als echte
lichtbronnen.
- **Transport:** per unit buitenmaat (incl. gevelafwerking), hoogte en
gewicht (vloer/wanden/dak) met een indicatieve breedteklasse.
- **Uitvoer:** JSON opslaan/openen en een samenhangende PDF (aanzichten
noord/oost/zuid/west als vlakke render met legenda afwerking, plattegrond,
vloeren, wandstukken, binnenwanden, totalen).
- **CAD-export (DXF):** Bestand › Exporteren › CAD (DXF); los van
Opslaan/Ctrl+S. DXF R12 (AC1009), opent in elk
CAD-pakket (AutoCAD, BricsCAD, DraftSight, LibreCAD, …); DWG maakt het
CAD-pakket zelf met Opslaan als (echte DWG schrijven vergt een GPL- of
commerciële bibliotheek). Modelruimte 1:1 in mm: plattegrond met noord
boven en de zuidwesthoek van de units op 0,0, eronder de vier gevels in een
2×2-raster (maaiveld als basis). Plattegrond: wanden per stuk als gesloten
polylijn, onderbroken bij sparingen die onder het snijvlak (1500 mm) beginnen
(hogere gestreept), stijlzone en gevelbekleding als eigen lagen, kozijnen
(raam: kader + glaslijn; deur: stijlen, blad en draaicirkel als boog;
schuifdeur: bladen, pijlen, rail), ruimtegrenzen als gesloten polylijn met
naam/m²/plafond, inrichting, dakrand, palen, schoorsteen, verlichting,
elektra, naden en elementcodes. Gevels: dezelfde vlakken als de
PDF-aanzichten (`HousePdf.viewProjections`) als lijntekening met verborgen
lijnen weg, kozijnen met kader, blad, zij-/bovenlicht en glas
(`KozijnModel.viewLines`). Maatvoering als echte DIMENSION (maatstijl
TECTUM): ketting per buitenwandstuk langs de sparingen, totaal per stuk en
van de woning, hoogtes maaiveld/peil/top per gevel. Lagen `PL-*`
(plattegrond), `AZ-*` (aanzichten), `MAATVOERING`, `TEKST`; tekst,
maatvoering en lijntypes afgestemd op 1:50 (`$LTSCALE`/`DIMSCALE` 50).
- **BIM-export (IFC):** Bestand › Exporteren › BIM (IFC), ook in Woning ›
Uitvoer. IFC4 met alleen de bouwconstructie: hout (stijlen/regels als
IfcMember, vloerbalken als IfcBeam, dakbalken als IfcMember), stalen
nokbalk, palen, platen (spaanplaat, OSB, cementplaat als IfcPlate) en
elektra (buis per leiding, inbouw-/lasdozen, meterkast); geen
gevelafwerking, latwerk, isolatie, kozijnen, dakbedekking of inrichting.
Geometrie uit de 3D-opbouw zelf (`HouseIfc`: fase *elektra* voor alle balken
en leidingen, fase *beplating* voor de platen; herkend aan het materiaal),
als driehoeksnet. Opbouw: unit › element (A-W1, A-V1, A-D) › onderdelen;
binnenwanden en elektra los in de bouwlaag. Per onderdeel `Pset_Tectum`
(element, onderdeel, afmeting, lengte, materiaal). Kleur per soort (op het
vlak en het materiaal): stijl lichthout, regel oranje, vloerbalk bruin,
dakbalk roodbruin, paal donkerbruin, stalen nokbalk staalblauw, spaanplaat
groen, OSB geel, cementplaat grijs; elektra in de app-kleuren
(`HouseIfc` COLORS). X = oost, Y = noord,
Z = 0 op peil; zuidwesthoek van de units = 0,0 (zelfde als de DXF).
- **Render-export (OBJ):** Bestand › Exporteren › Render (OBJ), ook in Woning ›
Uitvoer. Voor een sfeerimpressie: alleen wat in de afgewerkte woning te zien
is (dak, dakrand, lampen, ruimtes, inrichting; los van de gekozen lagen,
doorsnede en weergave-opties; zonder buizen en dozen, binnenste vloerbalken,
latten en isolatie achter de gevel, lichtkegels, logobord, grond en lucht)
als ZIP met `.obj`, `.mtl`, `textures/*.png` (rabat, steen, riet, tegels) en
`<naam>_lampen.py`: in Blender uitvoeren importeert de OBJ en zet elke lamp
(gevellamp, dakrandspot, binnenspot) als echte spotlight met dezelfde plek,
richting en kegel als in de app (`LightingModel.lightSources`). Meters, Y omhoog (de
standaard OBJ-import van Blender zet dat goed: noord = +Y), oorsprong op
maaiveld onder het midden. Kleuren omgerekend van sRGB naar lineair (de app
heeft geen kleurbeheer, Blender wel), PBR via `Pr`/`Pm`/`d`/`Ke` (ruwheid,
metaal, doorzichtigheid glas, gloed lampen); textuurherhaling zit in de
UV's (`ObjWriter`).
## Light-versie (modelpagina's)
Beperkte configurator voor de websitepagina van één model (later in de HUGO-build; nu los via
`light.html?model=<sleutel uit HouseModel.MODELS>`). Inbedden: de stylesheets en scripts uit `light.html`
plus `<div class="tectum-light" data-model="amstel"></div>` (mount vanzelf), of
`TectumLight.mount(el, { model, frames, url, modelViewer, save })`. De engine hoeft niet naast de pagina te staan:
texturen, kleurstalen en `kosten/*.csv` laden via `tectumUrl()` (`js/core/geometry.js`) vanaf de map van de scripts
(bijv. `/configurator/` op een modelpagina van de site); paden in de data blijven relatief.
- **Rekent als de configurator** (zelfde `HouseModel.computeParts`, totalen en `CostModel`), maar toont
alleen: indicatieve prijs incl. btw (afgerond op € 100), buitenmaten, bouwhoogte, bruto/leefbaar m²,
inhoud en gewicht. Geen uren, zaaglijst, inkoop of kostenopbouw.
- **Weergave:** 3D (afgewerkt, dag-omgeving), Doorsnede (wanden op een instelbare hoogte, standaard 1,5 m en hoogstens de laagste goot of de hoogte van een plat dak, afgesneden en wit afgedekt
met `HouseModel.sectionCaps`, dezelfde als de configurator; dak, dakrand, palen en lampen weg) en een
2D-plattegrond (ruimtes met netto m², wanden, kozijnen met draairichting, inrichting, dakrand, buitenmaten).
- **Keuzes:** per unit breedte, diepte, goothoogte en dakvorm met richting (lessenaar: hoge kant noord/zuid/
west/oost; zadel- en wolfsdak: nok noord–zuid of west–oost); bij een hellend dak de nokhoogte (lessenaar:
hoge kant, met de helling eronder; de goot omhoog neemt de nok mee), bij een wolfsdak ook de hoogte van het
wolfseind (bij een dak over de hele woning één keer), dakbedekking, gevelbekleding (hout met richting, felsplaten, stuc, steenstrips; kleur),
het accent van het model (de afwijkende gevel; of geen), trasraam (geen of steen, met hoogte; een cementplaat-trasraam van het model wordt geen), boeidelen of daktrim
(met kleur boeidelen; een model met beide houdt zijn indeling tot je kiest), zetwerk-kleur (afdekker trasraam en
ventilatierooster), binnenspots aan/uit en het type buitenverlichting. Wolfsdak over de hele
woning alleen als de units samen een rechthoek vormen en nooit bij een overkapping (zoals de configurator). Geen openingen,
binnenwanden, inrichting of elektra; die volgen het model.
- **Keuzes op een schone kopie:** `LightModel.build` past de keuzes elke keer toe op het model zelf; wat niet
afwijkt blijft precies zoals in het model. Bij een andere maat schuiven binnenwanden mee met hun unit en
schuift wat tegen de oost- of zuidgevel staat (binnenwand-eindpunt, inrichting) mee met die gevel (`BAND`).
Bij een andere hoogte gaan de binnenwanden van die unit evenveel mee. Een andere dakvorm dan die van het
model krijgt de helling uit `LightModel.PITCH` (lessenaar 10°, zadel 30°, wolfsdak 35°).
- **Kaders:** standaard `UnitModel.LIMITS` (maat 2,4–14 m, max 4,7 m in één richting; hoogte 2,4–3 m), per
model te beperken in `LightModel.FRAMES` of per pagina met `frames` (zelfde vorm; `null` = maat staat vast).
- **Indelingscontrole** (`LightModel.check`): een keuze waarbij ramen of deuren niet meer passen
(verschoven, ingeklemd, te hoog of over een naad), een binnenwand buiten de units valt, inrichting door
een gevel steekt, ruimtes verdwijnen of units overlappen, wordt geweigerd; vergeleken met het model zelf.
Bij een maat wordt de dichtstbijzijnde maat gezocht die nog past.
- **Indeling:** paneel als accordeon (Afmetingen, Dak, Gevel, Verlichting; één open, de kop vat de keuze samen),
kerncijfers en prijs met PDF-knop onderaan. Responsief op de breedte van de tool zelf (container queries; in de
site in een Bootstrap col-12): vanaf 720 px naast elkaar, smaller 3D boven en de keuzes eronder met prijs en
PDF vast onderin beeld. Stijl alles onder `.tectum-light` (Bootstrap-reboot geneutraliseerd); Bootstrap Icons
nodig (`css/vendor/bootstrap-icons.min.css`). Het scrollwiel scrolt de pagina, tenzij je in de 3D hebt
geklikt of Ctrl/⌘ ingedrukt houdt. Zijwaarts schuiven: rechts of middelste knop slepen, Shift/Ctrl/⌘ +
slepen, of de pijltjestoetsen met de muis boven de 3D. Touch: één vinger draaien, twee vingers knijpen/schuiven (eigen
OrbitControls, geldt ook voor de configurator).
- **Opslaan = PDF** (`LightPdf`): voorblad "Uw woningontwerp" (beeld uit de 3D-weergave, kerncijfers, keuzes
in woorden via `LightModel.describe`, indicatieve prijs, contactgegevens en een QR-code naar de modelpagina
op de site, of `data-url`/`url` van de pagina), dan aanzichten en plattegrond
(`HousePdf.generate(state, { customer: true, doc })`: zonder onderdelenlijst, elementcodes, elektra en
kosten) en als laatste het stappenplan van de site ("Hoe verloopt het traject?") met een blok over maatwerk
met de eigen software (keuken op maat, indeling, ramen en deuren). Contact en stappen staan
in `LightPdf.COMPANY` en `STEPS`.
- **Eigen opslaan** (`save: { label, icon, onSave }`): vervangt de PDF-knop, bijv. "Ontwerp aanvragen" op de site.
`onSave` krijgt `{ design, label, key, info, choices, url }`: `design` is de house-design-JSON zoals de
configurator die opslaat (de CRM maakt daar het gekozen model van), `info` de kerncijfers met prijs, `choices` de
keuzes in woorden. Zonder `save` (en via `el.tectumLight.design()`) hetzelfde ontwerp.
- **AR / schermvullend:** knop rechtsboven in de weergave. Op een telefoon of tablet: het ontwerp als GLB
(`GlbWriter`, afgewerkte woning zoals in 3D, één primitive per materiaal, texturen als JPEG/PNG tot 1024 px,
lichtbundels weg; maaiveld onder het midden = oorsprong, `HouseModel.groundOrigin`) in model-viewer, over de
hele pagina, met de knop "Bekijk in je tuin" (ware grootte; `ar-modes="webxr scene-viewer quick-look"`, op iOS
maakt model-viewer zelf de USDZ). model-viewer wordt pas bij de eerste keer geladen
(`js/vendor/model-viewer-umd.min.js` naast `js/light/`, of `modelViewer`/`data-model-viewer`). AR vraagt
https; Scene Viewer (Android zonder WebXR) heeft bovendien een publieke URL van de GLB nodig, een blob-URL
werkt daar niet. Op de desktop: de weergave schermvullend (Fullscreen API; het scrollwiel zoomt dan direct).
Per ontwerp wordt de GLB één keer gemaakt; `el.tectumLight.glb()` geeft `{ blob, url, stats }` (op
`light.html` de testknop GLB).
## CRM (woningen van leads en klanten)
Alleen in de Docker-stack (`../docker`), waar Tectum op `tectum.<domein>` achter het wachtwoord staat. Caddy zet
`api/crm/*` daar door naar de CRM (`/api/tectum/*`) met de sleutel `TECTUM_CRM_KEY`; de browser ziet die nooit.
- **Nieuw** toont onder de standaardmodellen de woningen uit de CRM (zoeken op woning, naam, relatie of plaats);
kiezen opent de nieuwste versie in een eigen tab (wolkje in de tab, naam "woning · vN").
- **`?woning=<id>`** opent die woning direct (de knop "Bewerken in Tectum" bij een woning in de CRM).
- **Opslaan in CRM** (bovenbalk, Bestand, Ctrl+S in een CRM-tab) vraagt wat er veranderd is en zet het ontwerp als
nieuwe versie bij de woning in de CRM. Staat er intussen een nieuwere versie (iemand anders), dan vraagt Tectum
eerst of het toch moet. **Downloaden (JSON + PDF)** doet in een CRM-tab wat Opslaan anders doet.
- Sluiten van een CRM-tab met wijzigingen die nog niet in de CRM staan vraagt om bevestiging.
Zonder stack (`start.sh`) bestaat `api/crm/` niet en is van de CRM niets te zien.
## Kosten en prijzen (CSV)
Alle waarden van het kostenmodel staan in twee CSV-bestanden in `kosten/`, die
de app bij het starten ophaalt. Elke waarde staat op één plek; de CSV's zijn
leidend en de app bewaart niets in de browser.
- `kosten/intern.csv`: eigen waarden: tijden, uurloon, bezetting, kosten per
uur, opslagen, marge (alles behalve prijzen).
- `kosten/leveranciers.csv`: alle inkoopprijzen (bijv. uit API-scripts van
leveranciers), ook constructiehout per balkmaat.
- `js/cost/cost-defaults.js`: welke posten er zijn (labels, eenheden, keuzes)
en noodwaarden voor wat een CSV mist.
```
# intern.csv
code;omschrijving;eenheid;waarde
arbeid.uurloon;Uurloon productie (all-in);€/u;45
zagen.methode;Zaagmethode;;robot
# leveranciers.csv
code;omschrijving;eenheid;prijs;leverancier;artikelnummer;bijgewerkt
elektra.wcdEnkel;Wandcontactdoos enkel met randaarde;€/st.;6,00;Groothandel X;123456;2026-10-09
hout.balk.38x235;Constructiehout vuren C24 38×235;€/m;4,91;Houthandel Y;;2026-10-09
```
- Verplicht: `code` en `waarde` (of `prijs`), excl. btw; `6,00`, `6.00`,
`1.234,50` en `€ 6` mogen; bij een keuze de sleutel of de tekst.
Scheidingsteken `;`, `,` of tab; regels met `#` worden overgeslagen.
- `code` = `<groep>.<sleutel>` uit `cost-defaults.js`, of `hout.balk.<b>x<h>`
voor constructiehout per balkmaat in €/m (zonder balkmaat: m³-prijs × volume).
- `omschrijving` is de naam van de post in de app (leeg = die uit `cost-defaults.js`).
- `eenheid` is optioneel; ingevuld moet die gelijk zijn aan die van de post,
anders wordt de regel geweigerd.
- Een prijs in intern.csv of een tijd in leveranciers.csv wordt geweigerd
("hoort in …"). Meerdere regels met dezelfde code in leveranciers.csv
(leveranciers): de laagste prijs telt.
- Onbekende codes (bijv. onderdelen die de app nog niet rekent) en fouten staan
bovenaan in Kosten & tijden.
- Kosten & tijden: **Toepassen** geldt tot herladen (om te proberen);
**intern.csv downloaden** om het bestand in `kosten/` te vervangen.
Prijsvelden staan vast. Bij Leveranciers: **Sjabloon** (alle prijscodes),
**Tijdelijk laden** (tot herladen of **Terug naar server**).
## Bekende beperkingen
- DXF: geen arceringen en geen lijndiktes (R12); kleuren per laag (ACI), dus
pendiktes via de plotstijl. Geen doorsnede en geen dakaanzicht. Eenheid
staat niet in het bestand: in CAD op millimeters zetten (UNITS) als het
pakket erom vraagt.
- OBJ: lichtbronnen alleen via het meegeleverde Blender-script, geen
reliëf-/normaalkaarten; glas als doorzichtig materiaal, in Blender eventueel
op Glass BSDF zetten.
- IFC: onderdelen zijn driehoeksnetten (niet parametrisch); geen
verbindingsmiddelen, isolatie of bekabeling (alleen buizen).
- Tijdelijk (verwijderen voor productie): zaagmachine-overzicht (zaagmeters bij
2400 m/u, zaagsneden, hoeken) in de app en op het totalenblad (`SAW_M_PER_H`).
- Tijdelijk: een nieuwe woning is het voorbeeldontwerp "Vlinderwoning"
(92 m², drie units, vlinderdak met riet + platte tuinkamer, ook als
`json/premade/vlinderwoning.json`); uit te zetten met `TEST_DEFAULT` in
`js/house/house-model.js`. Bij het starten opent model **Amstel**
(`HouseModel.createAmstel`, naar `examples/ontwerp_amstel.pdf`): 11,24 ×
7,2 m, twee modules onder één plat dak dat over het terras doorloopt,
stucwerk wit met verticaal hout aan de slaapkamerkant, binnenwanden,
dubbele schuifdeur tussen woonkamer en hal, en complete inrichting.
Langer maken: beide units breder (alles is vanaf de westgevel gemaat).
Model **Wetering** (`HouseModel.createWetering`, naar
`examples/ontwerp_wetering.pdf`): 10,5 × 4,8 m, twee units van 2,6 en
2,2 m zonder naadwand (open woonkamer over de volle diepte), verticaal
rabat grijs, plat dak met zwart boeideel, hoekkeuken met kookplaat,
badkamer, slaapkamer met kledingkast. Model **IJssel**
(`HouseModel.createIJssel`, naar `examples/ontwerp_ijssel.pdf`): L-vorm
14 × 4,6 m met een vleugel van 4,6 × 3 m, twee units met zadeldak en
riet die met een kil en een hoekkeper op elkaar aansluiten, stucwerk wit,
openslaande deuren in de westgevel. Model **Waal**
(`HouseModel.createWaal`, naar `examples/ontwerp_waal.pdf`): 12,85 × 7 m,
flauw zadeldak dat aan de oostkop 1,5 m doorloopt als veranda op eiken
palen (Overkapping per unit). Model **Maas** (`HouseModel.createMaas`,
naar `examples/ontwerp_maas.pdf`): vierkant 9,2 × 9,2 m, flauw zadeldak
over de hele woning; de overkapping maakt van de noordwesthoek een
inpandige veranda (2,5 × 4,6 m) op eiken palen. Model **Rijn**
(`HouseModel.createRijn`, naar `examples/ontwerp_rijn.pdf`): L-vorm
13 × 10 m, hoofdvolume met flauw zadeldak (twee lessenaars die op de naad
de nok vormen) en een vleugel met plat dak, steenstrips rondom met een
schoorsteen (800 mm, hart op de naad) in de oostgevel, kookeiland, logeerkamer en
apart toilet in de vleugel. Model **Reest** (`HouseModel.createReest`,
naar `examples/ontwerp_reest.pdf`): 12,9 × 7,85 m, hoofdvolume
11,5 × 4,8 m onder één lessenaarsdak (hoog aan de noordgevel, twee units
van 3,4 en 1,4 m met lessenaars in hetzelfde vlak) dat aan de westkop
1,4 m doorloopt als overkapping bij de voordeur, dicht met een witte
zijwand; aanbouw met plat dak (toilet, berging, entree met open doorgang
naar de woonkamer, daktrim i.p.v. boeidelen); zuidgevel en dak in
antraciet felsplaten (zuidrand zonder boeideel, de felsplaten lopen over
de zijwand door), verder verticale rabat. Model **Vecht** (`HouseModel.createVecht`): U-vorm
13 × 9,5 m, drie units (slaapvleugel west, tussenlid met entree, leefvleugel oost) met de holte open naar
het noorden; de vleugels lessenaars die naar de holte aflopen, het tussenlid plat op dezelfde goot, de
overkapping van het tussenlid dekt de holte (palen niet nodig); zwarte verticale rabat, wit stucwerk aan de
holte. De standaardmodellen staan in
`HouseModel.MODELS`; Bestand › Snel nieuw en het venster Nieuw worden
daaruit opgebouwd (nieuw model = één regel plus een `create`-functie die
`modelKit` gebruikt). De L-woning (8 × 3,6 m + 4,5 × 3,6 m) blijft
beschikbaar als "Woning L-vorm".
- Netto m² per ruimte telt de hele vloer, ook onder een laag schuin dak
(geen NEN 2580-correctie voor hoogte < 1,5 m).
- Units kunnen niet gedraaid worden.
- Getekende binnenwanden volgen de dakvorm (nog) niet.
- De dak-editor toont het dek in de plattegrond (niet per schuin dakvlak).
- Geen schaduw per lamp in de render (browserlimiet).
- Eigen OrbitControls: roteren/zoomen/pannen, geen damping.
## Versie
`APP_VERSION` in `js/app.js`: laatste cijfer per iteratie, middelste per
mijlpaal (met git-tag), eerste bij live-gang. De changelog staat in git.
+9 -2
View File
@@ -1,2 +1,9 @@
Bestemmingsmap voor toekomstige assets: GLB-modellen (ramen/deuren),
texturen/bumpmaps, e.d. Nog leeg.
Assets voor de 3D-weergave en de PDF:
- logo.svg / logo-animated.svg logo (splash, about); PDF-logo staat als data in js/core/logo-data.js
- skybox.webp equirectangulair panorama dag (4096x2048), "Lucht: Dag" (core/skybox.js)
- skybox-night.webp equirectangulair panorama nacht (4096x2048), "Lucht: Nacht"
- tiles.jpg tegeltextuur (1024x1024) voor de ronde vloer onder het object
- textures/buitenmuur/ steen voor het trasraam: "<code> - Witte voeg.jpg" (2062x1125, 2 mm/px,
naadloos), voorvertoning in thumb/32|64|128/*.png (WallModel.TRASRAAM_STONES)
- textures/vloer/ vloerafwerking (FloorModel.FINISHES), bijv. visgraat_001.jpg (1500x1500, tegel 3 m); thumb/32|64|128/*.png
- textures/dak/ dakbedekking: riet_<nr>.jpg (1024x1024, tegel 1 m); nummers in RoofModel RIET.nrs; thumb/32|64|128/*.png
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 523 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 715 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 698 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 753 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 598 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 909 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 711 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 786 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 936 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 656 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 723 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 743 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 813 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 749 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 837 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 981 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 709 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 708 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 798 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 831 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 636 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 548 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 762 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 452 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 887 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 759 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 470 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 645 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 904 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 813 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 925 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 860 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 865 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 924 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 835 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 981 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 787 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 556 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 505 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 494 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 523 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 538 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 598 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 537 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 772 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 957 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 736 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 459 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 528 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 846 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 853 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 562 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 642 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 637 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 941 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 767 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 801 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 924 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 616 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 591 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 647 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 761 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 666 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 633 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 644 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 570 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 896 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 746 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 871 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 830 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 883 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 914 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 958 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 809 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 976 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 979 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 907 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 990 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 935 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 920 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 771 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 960 KiB

Some files were not shown because too many files have changed in this diff Show More