[object Object]

← back to Ventura Bus 3d

add /models-preview.html: orbit-camera grid of all 8 sourced GLBs

6a8f84b95dac4ed7b0c340d7beb1edd6272a055f · 2026-05-10 09:01:19 -0700 · Steve Abrams

Files touched

Diff

commit 6a8f84b95dac4ed7b0c340d7beb1edd6272a055f
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Sun May 10 09:01:19 2026 -0700

    add /models-preview.html: orbit-camera grid of all 8 sourced GLBs
---
 public/models-preview.html | 124 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 124 insertions(+)

diff --git a/public/models-preview.html b/public/models-preview.html
new file mode 100644
index 0000000..91438ef
--- /dev/null
+++ b/public/models-preview.html
@@ -0,0 +1,124 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<title>Ventura Bus 3D — Model Preview</title>
+<style>
+  :root { --bg:#0b0d12; --fg:#e6eaf2; --muted:#8a93a6; --card:#141821; --accent:#ff8c00; }
+  *{box-sizing:border-box} html,body{margin:0;background:var(--bg);color:var(--fg);font:14px/1.4 -apple-system,system-ui,sans-serif}
+  header{padding:18px 22px;border-bottom:1px solid #20242f;display:flex;align-items:baseline;gap:14px;flex-wrap:wrap}
+  h1{margin:0;font-size:18px;letter-spacing:.02em}
+  header .meta{color:var(--muted);font-size:12px}
+  header a{color:var(--accent);text-decoration:none}
+  .grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:14px;padding:18px}
+  .card{background:var(--card);border:1px solid #20242f;border-radius:8px;overflow:hidden;display:flex;flex-direction:column}
+  .stage{aspect-ratio:1/1;background:linear-gradient(180deg,#161a24 0%,#0d1018 100%);position:relative}
+  .stage canvas{display:block;width:100%;height:100%}
+  .meta-row{padding:10px 12px;border-top:1px solid #20242f;display:flex;justify-content:space-between;align-items:baseline}
+  .name{font-weight:600}
+  .role{color:var(--muted);font-size:12px}
+  .size{font-variant-numeric:tabular-nums;color:var(--muted);font-size:12px}
+  .credit{padding:6px 12px 12px;font-size:11px;color:var(--muted)}
+  .credit a{color:#7eb1ff;text-decoration:none}
+  .controls{position:absolute;bottom:6px;right:8px;font-size:10px;color:var(--muted);user-select:none}
+</style>
+</head>
+<body>
+<header>
+  <h1>Ventura Bus 3D — sourced vehicle models</h1>
+  <div class="meta">8 glTF binary models · all CC-BY 3.0 · drag to orbit · scroll to zoom</div>
+  <div class="meta">↩ <a href="/">main scene</a> · <a href="/models/ATTRIBUTION.md">ATTRIBUTION.md</a></div>
+</header>
+<div class="grid" id="grid"></div>
+
+<script type="importmap">
+{
+  "imports": {
+    "three": "https://unpkg.com/three@0.160.0/build/three.module.js",
+    "three/addons/": "https://unpkg.com/three@0.160.0/examples/jsm/"
+  }
+}
+</script>
+<script type="module">
+import * as THREE from 'three';
+import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
+import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
+
+const MODELS = [
+  { file:'bus-metro-articulated.glb', name:'bus-metro-articulated', role:'Metro orange articulated (stand-in)', credit:'Bus by Poly by Google', url:'https://poly.pizza/m/9Rj7a89ypPQ' },
+  { file:'bus-ladot-dash.glb',         name:'bus-ladot-dash',        role:'LADOT DASH (stand-in)',              credit:'Montreal Bus by Nick Ladd', url:'https://poly.pizza/m/fFCCghvRImG' },
+  { file:'bus-school.glb',             name:'bus-school',            role:'School bus',                         credit:'Schoolbus by Poly by Google', url:'https://poly.pizza/m/8xacyNqdJ3t' },
+  { file:'car-sedan.glb',              name:'car-sedan',             role:'Sedan',                              credit:'Car by Quaternius', url:'https://poly.pizza/m/Cz6yDaUcM9' },
+  { file:'car-suv.glb',                name:'car-suv',               role:'SUV',                                credit:'SUV by Quaternius', url:'https://poly.pizza/m/xsMtZhBkxL' },
+  { file:'car-sports.glb',             name:'car-sports',            role:'Sports car',                         credit:'Sports Car by Quaternius', url:'https://poly.pizza/m/1mkmFkAz5v' },
+  { file:'car-pickup.glb',             name:'car-pickup',            role:'Pickup truck',                       credit:'Pickup Truck by Quaternius', url:'https://poly.pizza/m/qn4grQgHm8' },
+  { file:'car-delivery-van.glb',       name:'car-delivery-van',      role:'Delivery van',                       credit:'Van by Poly by Google', url:'https://poly.pizza/m/aT_24cDaW1a' },
+];
+
+const grid = document.getElementById('grid');
+const loader = new GLTFLoader();
+const fmtKB = b => `${(b/1024).toFixed(0)} KB`;
+
+for (const m of MODELS) {
+  const card = document.createElement('div'); card.className = 'card';
+  const stage = document.createElement('div'); stage.className = 'stage';
+  const ctrl  = document.createElement('div'); ctrl.className = 'controls'; ctrl.textContent = 'orbit · zoom';
+  stage.appendChild(ctrl);
+  const meta  = document.createElement('div'); meta.className = 'meta-row';
+  meta.innerHTML = `<div><div class="name">${m.name}</div><div class="role">${m.role}</div></div><div class="size" data-size>—</div>`;
+  const credit = document.createElement('div'); credit.className = 'credit';
+  credit.innerHTML = `${m.credit} · <a href="${m.url}" target="_blank" rel="noopener">source</a> · <a href="https://creativecommons.org/licenses/by/3.0/" target="_blank" rel="noopener">CC-BY 3.0</a>`;
+  card.append(stage, meta, credit);
+  grid.appendChild(card);
+
+  // Per-card Three.js scene
+  const scene = new THREE.Scene();
+  scene.background = new THREE.Color(0x10141d);
+  const camera = new THREE.PerspectiveCamera(40, 1, 0.05, 200);
+  camera.position.set(6, 4.5, 7);
+  const renderer = new THREE.WebGLRenderer({ antialias: true });
+  renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
+  const sizeObs = new ResizeObserver(() => {
+    const r = stage.getBoundingClientRect();
+    renderer.setSize(r.width, r.height, false);
+    camera.aspect = r.width / r.height; camera.updateProjectionMatrix();
+  });
+  sizeObs.observe(stage);
+  stage.appendChild(renderer.domElement);
+
+  scene.add(new THREE.HemisphereLight(0xffffff, 0x223044, 0.9));
+  const sun = new THREE.DirectionalLight(0xffe7b3, 1.2); sun.position.set(5, 8, 4); scene.add(sun);
+  const grid2 = new THREE.GridHelper(20, 20, 0x2a2f3d, 0x1a1d27); grid2.position.y = -0.001; scene.add(grid2);
+
+  const controls = new OrbitControls(camera, renderer.domElement);
+  controls.enableDamping = true; controls.target.set(0, 0.6, 0);
+
+  // Track byte size via fetch HEAD
+  fetch(`/models/${m.file}`, { method: 'HEAD' }).then(r => {
+    const len = r.headers.get('content-length');
+    if (len) meta.querySelector('[data-size]').textContent = fmtKB(Number(len));
+  });
+
+  loader.load(`/models/${m.file}`, (gltf) => {
+    const root = gltf.scene;
+    const box = new THREE.Box3().setFromObject(root);
+    const size = new THREE.Vector3(); box.getSize(size);
+    const center = new THREE.Vector3(); box.getCenter(center);
+    const maxDim = Math.max(size.x, size.y, size.z) || 1;
+    const scale = 4 / maxDim;
+    root.scale.setScalar(scale);
+    root.position.sub(center.multiplyScalar(scale));
+    root.position.y += (size.y * scale) / 2;  // sit on grid
+    scene.add(root);
+  }, undefined, (err) => {
+    stage.style.background = '#3a1a1a';
+    ctrl.textContent = 'load error: ' + err.message;
+  });
+
+  let raf = 0;
+  function tick(){ controls.update(); renderer.render(scene, camera); raf = requestAnimationFrame(tick); }
+  tick();
+}
+</script>
+</body>
+</html>

← bcac288 add 8 CC-BY vehicle GLBs (3 buses + 5 cars) + ATTRIBUTION.md  ·  back to Ventura Bus 3d  ·  task #5: traffic.js — fixed-timestep bus + ambient car sim w 9e03e9b →