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>
This commit is contained in:
Machiel
2026-09-30 11:58:07 +02:00
co-authored by Claude Opus 5.5
parent 3591fad220
commit 3a4b9608c0
10 changed files with 121 additions and 6 deletions
+79
View File
@@ -0,0 +1,79 @@
/*!
* Tectum
* Copyright © 2026 Machiel Heinen.
* Alle rechten voorbehouden. Gebruik uitsluitend met schriftelijke toestemming.
* Zie LICENTIE.md.
*/
// ============================================================
// core/skybox.js — lucht-achtergrond (equirectangulair panorama) voor de
// 3D-weergaven, met een "Lucht"-knop in de 3D-werkbalk. De afbeelding
// (assets/skybox-data.js, gegenereerd uit assets/skybox.webp) wordt pas bij
// de eerste keer aanzetten geladen en daarna gedeeld. De keuze aan/uit wordt
// onthouden (localStorage, alleen gemak).
// Plain script (geen ES-module).
// ============================================================
window.Skybox = (() => {
const PREF_KEY = 'tectum.skybox';
let texturePromise = null;
function load() {
if (texturePromise) return texturePromise;
texturePromise = new Promise((resolve, reject) => {
const fromData = () => {
const img = new Image();
img.onload = () => {
const tex = new THREE.Texture(img);
tex.mapping = THREE.EquirectangularReflectionMapping;
tex.needsUpdate = true;
resolve(tex);
};
img.onerror = reject;
img.src = window.TECTUM_SKYBOX;
};
if (window.TECTUM_SKYBOX) return fromData();
const s = document.createElement('script');
s.src = 'assets/skybox-data.js';
s.onload = fromData;
s.onerror = reject;
document.head.appendChild(s);
});
texturePromise.catch(() => { texturePromise = null; });
return texturePromise;
}
function isOn() {
try { return localStorage.getItem(PREF_KEY) === '1'; } catch (e) { return false; }
}
function remember(on) {
try { localStorage.setItem(PREF_KEY, on ? '1' : '0'); } catch (e) { /* geen opslag: alleen deze sessie */ }
}
// Zet de achtergrond van `scene`: lucht als on, anders fallbackColor (hex).
// wanted() wordt na het laden nog eens gevraagd (knop intussen uitgezet?).
function apply(scene, on, fallbackColor, wanted) {
if (!on) { scene.background = new THREE.Color(fallbackColor); return; }
load().then(tex => { if (!wanted || wanted()) scene.background = tex; })
.catch(() => { scene.background = new THREE.Color(fallbackColor); });
}
// "Lucht"-knop in een 3D-werkbalk. onChange(on) bij elke klik (en niet bij
// aanmaken: de aanroeper leest de begintoestand met isOn()).
function createToggle(toolbar, onChange) {
const btn = document.createElement('button');
btn.type = 'button';
btn.className = 'btn-3d-toggle' + (isOn() ? ' active' : '');
btn.title = 'Lucht als achtergrond';
btn.innerHTML = '<i class="bi bi-cloud-sun"></i>Lucht';
btn.addEventListener('click', () => {
const on = !btn.classList.contains('active');
btn.classList.toggle('active', on);
remember(on);
onChange(on);
});
toolbar.appendChild(btn);
return btn;
}
return { load, isOn, apply, createToggle };
})();