Files
hidden-side-footprints/setFootprints.js
T

72 lines
4.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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;
}