|
1 | 1 | # car-visualizer |
2 | 2 |
|
3 | | -This is a test to demo the ThreeJS library with a 3D model of a car. |
| 3 | +A small demo that shows a 3D car viewer using three.js and a GLTF model (Ferrari F40). |
4 | 4 |
|
5 | | -Visit https://badgerloop-software.github.io/car-visualizer/ to view. |
| 5 | +View online |
6 | 6 |
|
7 | | -Citation for the 3D Model: |
8 | | -This work is based on "Ferrari f40" (https://sketchfab.com/3d-models/ferrari-f40-52a66c41cfcd4f999fb1b1c49bf24d70) by Black Snow (https://sketchfab.com/BlackSnow02) licensed under CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/) |
| 7 | +- The demo is automatically deployed to GitHub Pages: |
| 8 | + - https://badgerloop-software.github.io/car-visualizer/ |
| 9 | +- Changes pushed/merged to the repository's main branch will be picked up by GitHub Pages (depending on the repo's pages settings) and appear online after the site build completes. |
| 10 | + |
| 11 | +Run locally |
| 12 | + |
| 13 | +- Serve the folder (from project root): |
| 14 | + - python3 -m http.server 8000 |
| 15 | +- Open http://127.0.0.1:8000/index.html in your browser. |
| 16 | +- Note: the GLTF loader requires the files to be served over HTTP (don't open index.html with file://). |
| 17 | + |
| 18 | +User controls & UI |
| 19 | + |
| 20 | +- I — Toggle the Camera Info panel. Press once to open or close (works reliably regardless of element focus; click the viewer canvas if key events don't register). |
| 21 | +- H — Jump to the saved "Home" preset (if present). |
| 22 | +- C — Copy the current camera state to the clipboard (same as the "Copy" button in the panel). |
| 23 | +- Mouse controls (OrbitControls): |
| 24 | + - Left-drag: rotate |
| 25 | + - Middle/Alt+drag: pan |
| 26 | + - Wheel: zoom |
| 27 | +- After you stop interacting for ~1 second the camera will revert automatically to the current mode's preset (Home or Drive). |
| 28 | +- The camera is clamped so you can't look under the floor plane (prevents pitching below ground). |
| 29 | + |
| 30 | +Camera Info panel (press 'I') |
| 31 | + |
| 32 | +- Shows: |
| 33 | + - Pos: camera position (x,y,z) |
| 34 | + - Target: orbit target (x,y,z) |
| 35 | + - Distance: distance from camera to target |
| 36 | + - Azimuth & Polar angles in degrees |
| 37 | +- Buttons: |
| 38 | + - Copy — copies camera state JSON to clipboard (position, target, distance, azimuthDeg, polarDeg) |
| 39 | + - Set Home — saves your current view as preset named "Home" |
| 40 | + - Go Home — moves the camera to the saved Home preset |
| 41 | +- Preset manager inside the panel: |
| 42 | + - Select a preset, then Go / Set (save current) / Delete |
| 43 | + - Import — paste a JSON payload like: |
| 44 | + { |
| 45 | + "position": [x, y, z], |
| 46 | + "target": [x, y, z] |
| 47 | + } |
| 48 | + - Presets are stored in localStorage under the key: `cameraPresets` (the old `cameraHome` is migrated automatically if present). |
| 49 | + |
| 50 | +Park brake simulation & signals |
| 51 | + |
| 52 | +- There is a simulated brake button in the panel (label toggles between "Sim Brake Release" and "Sim Brake Enable"). |
| 53 | +- The viewer tracks a `park_brake` boolean state: 1 = engaged (Home), 0 = released (Drive). |
| 54 | +- Edge behavior: |
| 55 | + - 1 -> 0 (released) triggers transition to the Drive preset (if present). |
| 56 | + - 0 -> 1 (engaged) triggers transition to the Home preset (if present). |
| 57 | + |
| 58 | +Integration API (for parent application) |
| 59 | + |
| 60 | +- window.cameraAPI |
| 61 | + - setPreset(name, data?) — Save a preset. `data` is optional; when omitted the current view is saved. `data` expects { position: [x,y,z], target: [x,y,z] }. |
| 62 | + - getPreset(name) — Get saved preset object or null. |
| 63 | + - listPresets() — Returns array of preset names. |
| 64 | + - goToPreset(name, duration?) — Smoothly move to the preset (duration in ms). |
| 65 | + - animateTo(targetPosition, targetTarget, duration) — Animate to given THREE.Vector3 positions. |
| 66 | + - receiveVehicleSignal(signalName, value) — Forwards signals into the viewer. |
| 67 | + |
| 68 | +- Convenience globals: |
| 69 | + - window.receiveVehicleSignal(signalName, value) |
| 70 | + - e.g. window.receiveVehicleSignal('park_brake', 0) — triggers the park_brake handling. |
| 71 | + - window.setParkingBrakeState(value) |
| 72 | + - e.g. window.setParkingBrakeState(1) |
| 73 | + |
| 74 | +Implementation notes |
| 75 | + |
| 76 | +- Built with three.js r128 and uses `OrbitControls` + `GLTFLoader` for the model. |
| 77 | +- Presets are stored in localStorage as `{ <name>: { position: [...], target: [...] } }`. |
| 78 | +- The viewer auto-imports an example "Drive" preset (from demo data) on first run if no preset exists. |
| 79 | +- Camera is constrained so it cannot go underneath the ground plane and polar angle is limited to prevent under-floor views. |
| 80 | +- When user manipulates the camera, the viewer waits ~1s after interaction stops and then re-applies the current mode preset. |
| 81 | + |
| 82 | +Troubleshooting |
| 83 | + |
| 84 | +- Black screen: check DevTools console for errors and verify `ferrari_f40/scene.gltf` is present. If model fails to load a simple fallback car will be created. |
| 85 | +- Keys not registering: click the render canvas to give it focus, then press keys. |
| 86 | +- Copy to clipboard: uses the modern Clipboard API, with a textarea fallback if necessary. |
| 87 | + |
| 88 | +License / Model credit |
| 89 | + |
| 90 | +This work uses the Ferrari F40 model by Black Snow on Sketchfab, licensed under CC-BY-4.0. See `ferrari_f40/license.txt` for details. |
0 commit comments