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();