From dcd455eda25d680344556a7189fb7a2ab47ba8cb Mon Sep 17 00:00:00 2001 From: jessikitty Date: Fri, 31 Jul 2026 15:21:58 +1000 Subject: [PATCH] Add ES module: presets + Three.js footprint outline/plane helpers --- setFootprints.js | 71 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 setFootprints.js diff --git a/setFootprints.js b/setFootprints.js new file mode 100644 index 0000000..ab56b12 --- /dev/null +++ b/setFootprints.js @@ -0,0 +1,71 @@ +// setFootprints.js +// LEGO Hidden Side set footprint presets for the Newbury Exhibit layout editor. +// Units: centimetres (1 Three.js unit = 1 cm). width = X extent, depth = Z extent. +// Fan/tribute project; not affiliated with or endorsed by the LEGO Group. +// Source: brickset.com/sets/theme-Hidden-Side (published model dimensions W x D x H; +// footprint = the two horizontal axes). + +export const SET_FOOTPRINTS = [ + { setNumber: "70418", name: "J.B.'s Ghost Lab", width: 13, depth: 18, height: 9, year: 2019 }, + { setNumber: "70420", name: "Graveyard Mystery", width: 14, depth: 32, height: 10, year: 2019 }, + { setNumber: "70421", name: "El Fuego's Stunt Truck", width: 10, depth: 10, height: 17, year: 2019 }, + { setNumber: "70422", name: "Shrimp Shack Attack", width: 19, depth: 32, height: 10, year: 2019 }, + { setNumber: "70424", name: "Ghost Train Express", width: 14, depth: 61, height: 15, year: 2019 }, + { setNumber: "70425", name: "Newbury Haunted High School", width: 30, depth: 43, height: 26, year: 2019 }, + { setNumber: "70427", name: "Welcome to the Hidden Side", width: 17, depth: 22, height: 13, year: 2020 }, + { setNumber: "70428", name: "Jack's Beach Buggy", width: 10, depth: 11, height: 8, year: 2020 }, + { setNumber: "70429", name: "El Fuego's Stunt Plane", width: 22, depth: 22, height: 8, year: 2020 }, + { setNumber: "70430", name: "Newbury Subway", width: 15, depth: 26, height: 14, year: 2020 }, + { setNumber: "70431", name: "The Lighthouse of Darkness", width: 29, depth: 22, height: 18, year: 2020 }, + { setNumber: "70432", name: "Haunted Fairground", width: 28, depth: 35, height: 27, year: 2020 }, + { setNumber: "70433", name: "J.B.'s Submarine", width: 21, depth: 19, height: 10, year: 2020 }, + { setNumber: "70434", name: "Supernatural Race Car", width: 19, depth: 11, height: 7, year: 2020 }, + { setNumber: "70435", name: "Newbury Abandoned Prison", width: 19, depth: 30, height: 15, year: 2020 }, + { setNumber: "70437", name: "Mystery Castle (closed)", width: 34, depth: 31, height: 27, year: 2020 }, + { setNumber: "70437o", name: "Mystery Castle (open)", width: 45.5, depth: 26, height: 27, year: 2020 } +]; + +// Lookup by set number. +export function getFootprint(setNumber) { + return SET_FOOTPRINTS.find(s => s.setNumber === setNumber) || null; +} + +// Dropdown label helper: "70425 — Newbury Haunted High School (30 × 43 cm)". +export function footprintLabel(fp) { + return `${fp.setNumber} — ${fp.name} (${fp.width} × ${fp.depth} cm)`; +} + +// Build a THREE.LineLoop outlining the footprint on the table plane (Y = 0), +// centred on origin. Pass in your THREE namespace so this stays import-map friendly. +// Returns an object3D you can add to the scene and reposition via .position. +export function makeFootprintOutline(THREE, fp, { color = 0x51eaf1, y = 0.05 } = {}) { + const hw = fp.width / 2; + const hd = fp.depth / 2; + const pts = [ + new THREE.Vector3(-hw, y, -hd), + new THREE.Vector3( hw, y, -hd), + new THREE.Vector3( hw, y, hd), + new THREE.Vector3(-hw, y, hd), + new THREE.Vector3(-hw, y, -hd) + ]; + const geom = new THREE.BufferGeometry().setFromPoints(pts); + const mat = new THREE.LineBasicMaterial({ color }); + const loop = new THREE.Line(geom, mat); + loop.userData.setNumber = fp.setNumber; + loop.userData.footprint = { width: fp.width, depth: fp.depth }; + return loop; +} + +// Filled semi-transparent plane version (useful as a placement guide beneath the build). +export function makeFootprintPlane(THREE, fp, { color = 0x51eaf1, opacity = 0.12, y = 0.02 } = {}) { + const geom = new THREE.PlaneGeometry(fp.width, fp.depth); + const mat = new THREE.MeshBasicMaterial({ + color, opacity, transparent: true, side: THREE.DoubleSide, depthWrite: false + }); + const mesh = new THREE.Mesh(geom, mat); + mesh.rotation.x = -Math.PI / 2; // lay flat on the table + mesh.position.y = y; + mesh.userData.setNumber = fp.setNumber; + mesh.userData.footprint = { width: fp.width, depth: fp.depth }; + return mesh; +}