diff --git a/public/admin/layout.html b/public/admin/layout.html
index 1ef7bde..4096c06 100644
--- a/public/admin/layout.html
+++ b/public/admin/layout.html
@@ -14,6 +14,7 @@ import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { TransformControls } from 'three/addons/controls/TransformControls.js';
import { anchorWorldMatrix } from '/js/ar/pose.js';
+import { SET_FOOTPRINTS, footprintLabel, footprintToBuilding } from '/js/set-footprints.js';
import { api, requireAuth, styles, nav } from './admin.js';
document.head.insertAdjacentHTML('beforeend', ``);
await requireAuth();
@@ -37,6 +49,7 @@ app.innerHTML = `${nav('layout')}
+
@@ -55,7 +68,14 @@ app.innerHTML = `${nav('layout')}
purple = ghost paths: drag the spheres, cone shows walk direction
-`;
+
+
+
Import Hidden Side set
+
Adds a to-scale footprint (a building box) at the view centre. Drag it into place,
+ then set its height/yaw in the panel. Footprints in cm; not affiliated with the LEGO Group.
+
+
+
`;
let scene = await api('/api/scene');
scene.anchors ||= []; scene.buildings ||= []; scene.spawns ||= []; scene.paths ||= [];
@@ -274,6 +294,23 @@ document.querySelectorAll('[data-add]').forEach(b => b.onclick = () => {
buildAll(); panel();
});
+// ---------- import set footprint ----------
+const setModal = document.getElementById('setModal');
+const setList = document.getElementById('setList');
+setList.innerHTML = SET_FOOTPRINTS
+ .map((fp, i) => ``).join('');
+document.getElementById('importSet').onclick = () => setModal.classList.add('open');
+setModal.querySelector('.close').onclick = () => setModal.classList.remove('open');
+setModal.onclick = e => { if (e.target === setModal) setModal.classList.remove('open'); };
+setList.querySelectorAll('[data-fp]').forEach(b => b.onclick = () => {
+ const fp = SET_FOOTPRINTS[+b.dataset.fp];
+ const t = orbit.target;
+ scene.buildings.push(footprintToBuilding(fp, [t.x, 0, t.z]));
+ sel = { kind: 'building', index: scene.buildings.length - 1 };
+ setModal.classList.remove('open');
+ buildAll(); panel();
+});
+
// ---------- property panel ----------
const side = document.getElementById('side');
function field(label, val, oncommit, opts) {
@@ -340,6 +377,8 @@ function panel(rebuild = true) {
h += field('height', o.size[1], v => o.size[1] = v);
h += field('depth', o.size[2], v => o.size[2] = v);
h += field('yaw °', o.yawDeg || 0, v => o.yawDeg = v, { step: 1 });
+ if (o.setNumber) h += `
Imported footprint · Hidden Side set ${o.setNumber}.
+ Size is the published build; adjust height/yaw freely.
`;
} else if (sel.kind === 'pathpoint') {
h = `
path ${sel.index} · point ${sel.sub + 1}/${o.points.length}
`;
h += textField('path id', o.id, v => o.id = v);