skatemakerpro/js/export.js
type-two d68fa84f92 Kit thumbnails + prop colliders
js/kitthumbs.js renders each kit GLB to a 128x96 sprite once (offscreen
renderer, framed by bounding sphere), POSTs to /api/kit-thumb, and all 52
are committed under assets/kit_thumbs/ so every checkout gets instant thumbs;
the generator only runs for props without one (future kit drops). KIT drawer
shows them with category groups and filter.

js/colliders.js derives world-space colliders from kit manifest hints +
a table for builtin props (bins, planters, trunks, fences...). Test ride
resolves circle-vs-box/circle push-out — you scrub and stop instead of
riding through furniture. Exports gain an additive COLLIDERS array for
bookquoy to adopt when its player is ready; existing contract untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-03 21:13:36 +10:00

55 lines
2.2 KiB
JavaScript

// SKATEMAKER PRO — exports. A park leaves here two ways:
// 1. park.json — the native data format
// 2. level.<name>.js — a drop-in for BOOKQUOY: exports the exact interface
// bookquoy's js/level.js has (heightAt, normalAt, BOUNDS,
// RAILS, GAPS, LETTERS, SPAWN, buildLevel). Ship it with
// parkmath.js + parkbuild.js + assets/uploads/.
function download(name, text, type = 'application/octet-stream') {
const a = document.createElement('a');
a.href = URL.createObjectURL(new Blob([text], { type }));
a.download = name;
a.click();
setTimeout(() => URL.revokeObjectURL(a.href), 5000);
}
const slug = park => (park.name || 'park').toLowerCase().replace(/[^\w]+/g, '_');
export function downloadParkJSON(park) {
download(slug(park) + '.json', JSON.stringify(park, null, 1), 'application/json');
}
import { propColliders } from './colliders.js';
export function generateLevelJS(park, kitMap = {}) {
const colliders = propColliders(park, kitMap);
return `// ${park.name} — generated by SKATEMAKER PRO ${new Date().toISOString().slice(0, 10)}
// Drop-in for BOOKQUOY: copy this file + parkmath.js + parkbuild.js (+ assets/uploads/)
// into bookquoy/js/ and point main.js/player.js imports at it. Same contract as level.js:
// heightAt(x,z) is the single source of truth for visuals AND collision.
import { makeHeightAt, makeNormalAt, flattenRails } from './parkmath.js';
import { buildParkScene } from './parkbuild.js';
export const PARK = ${JSON.stringify(park, null, 1)};
export const BOUNDS = PARK.bounds;
export const RAILS = flattenRails(PARK);
export const GAPS = PARK.gaps;
export const LETTERS = PARK.letters;
export const SPAWN = PARK.spawn;
export const heightAt = makeHeightAt(PARK);
export const normalAt = makeNormalAt(heightAt);
// world-space prop colliders (bins, planters, trunks) — adopt when the player is ready
export const COLLIDERS = ${JSON.stringify(colliders)};
export function buildLevel(scene) {
const { ground, letterMeshes } = buildParkScene(scene, PARK);
return { ground, letterMeshes };
}
`;
}
export function downloadLevelJS(park, kitMap) {
download('level.' + slug(park) + '.js', generateLevelJS(park, kitMap), 'text/javascript');
}