From d51e441b65b5356c41c7db8950da611537fde61b Mon Sep 17 00:00:00 2001 From: jessikitty Date: Fri, 24 Jul 2026 14:12:15 +1000 Subject: [PATCH] Preview: apply ghost height, keep name labels world-scale above scaled ghosts --- public/admin/preview.html | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/public/admin/preview.html b/public/admin/preview.html index 247d438..fd15c53 100644 --- a/public/admin/preview.html +++ b/public/admin/preview.html @@ -129,29 +129,34 @@ function buildStatics(scene) { // ---------- live ghosts ---------- const active = new Map(); // uid -> { rec, group, label } let followUid = null; +let ghostHeight = 4; // cm, from scene.ghostHeightCm const clockSamples = []; let clockOffset = 0; async function addGhost(rec) { if (active.has(rec.uid)) return; const group = await buildGhost(rec, gradients, modelManifest); + group.userData.setHeight(ghostHeight); const label = textSprite(rec.name, COLORS[rec.color] || '#fff'); - label.position.y = 28; - group.add(label); - scn.add(group); + label.scale.set(20, 5, 1); + scn.add(group); scn.add(label); // label stays world-scale, outside the scaled group active.set(rec.uid, { rec, group, label }); renderList(); } function removeGhost(uid) { const e = active.get(uid); if (!e) return; - scn.remove(e.group); + scn.remove(e.group); scn.remove(e.label); active.delete(uid); if (followUid === uid) followUid = null; renderList(); } const net = new ExhibitNet(); -net.on('scene', m => buildStatics(m.scene)) +net.on('scene', m => { + buildStatics(m.scene); + ghostHeight = m.scene.ghostHeightCm || 4; + for (const e of active.values()) e.group.userData.setHeight(ghostHeight); + }) .on('active', async m => { for (const uid of [...active.keys()]) removeGhost(uid); for (const rec of m.ghosts) await addGhost(rec); @@ -208,12 +213,14 @@ fit(); (function loop(t) { requestAnimationFrame(loop); const now = Date.now() + clockOffset; - for (const { rec, group } of active.values()) { + for (const { rec, group, label } of active.values()) { ghostTransform(rec, now, _tmp); group.position.copy(_tmp.position); group.rotation.y = _tmp.rotationY; group.userData.setOpacity(_tmp.opacity * 0.92); group.userData.tick(t / 1000); + label.position.set(_tmp.position.x, _tmp.position.y + ghostHeight + 3, _tmp.position.z); + label.material.opacity = _tmp.opacity; } if (followUid && active.has(followUid)) orbit.target.lerp(active.get(followUid).group.position, 0.08); orbit.update();