Kiosk-Bourbon-Tree is a procedurally generated 3D museum exhibit built with Three.js and Vite, designed to run fullscreen on a Raspberry Pi touchscreen kiosk. Rather than loading a pre-modeled tree, it grows an oak entirely from code at runtime: a stochastic L-system produces a branching grammar, a 3D turtle walks that grammar to build tapered branch geometry, and foliage is scattered across the branch tips as instanced geometry — bark and leaves are both shaded with hand-written GLSL noise instead of image textures.
Museum visitors touch the screen to wake the kiosk from its idle attract-mode animation, rotate and regrow the tree, and browse exhibit facts about the bourbon lineage it represents, before the kiosk automatically resets itself for the next visitor.
The tree is (re)built once at boot — no models or textures are loaded, only generated:
flowchart LR
LS[LSystem.js] -->|branch string| TB[TreeBuilder.js]
TB -->|tip transforms| LG[LeafGenerator.js]
MAT[Materials.js] -.->|shaders| TB
MAT -.->|shaders| LG
TB --> SC[Scene.js]
LG --> SC
SC --> RN[Renderer.js]
HardwareInputs.js normalizes touch/pointer activity and feeds it to
StateMachine.js, which drives which UI overlay is visible:
stateDiagram-v2
[*] --> ATTRACT
ATTRACT --> INTERACTIVE: touch
INTERACTIVE --> TIMEOUT_WARNING: idle timeout
TIMEOUT_WARNING --> INTERACTIVE: touch
TIMEOUT_WARNING --> ATTRACT: warning expires
INTERACTIVE --> ATTRACT: Reset button
Kiosk-Bourbon-Tree/
├── .github/workflows/
│ └── deploy.yml # CI/CD: builds on push, deploys via a self-hosted runner on the Pi
├── kiosk-scripts/
│ ├── setup-pi.sh # One-time Raspberry Pi OS provisioning (X11, Chromium, nginx, autologin)
│ └── autostart.sh # Launches fullscreen Chromium in kiosk mode on boot
├── src/
│ ├── procedural/ # Generates the oak tree from code — no models or textures
│ │ ├── LSystem.js # Stochastic L-system grammar → branch string
│ │ ├── TreeBuilder.js # 3D turtle walk → tapered tube geometry
│ │ ├── LeafGenerator.js # Scatters instanced foliage at branch tips
│ │ └── Materials.js # Procedural bark/leaf shaders (embedded GLSL noise)
│ ├── graphics/ # Three.js scene, renderer, and animation
│ │ ├── Scene.js # Camera, lights, ground; assembles the tree
│ │ ├── Renderer.js # WebGLRenderer tuned for Raspberry Pi
│ │ └── Animator.js # Wind sway + branch-growth reveal
│ ├── kiosk/ # Visitor interaction state
│ │ ├── StateMachine.js # ATTRACT → INTERACTIVE → TIMEOUT_WARNING
│ │ ├── IdleTimer.js # Timer primitive backing the state machine
│ │ └── HardwareInputs.js # Normalizes touch/pointer input
│ ├── components/ # DOM UI overlays
│ │ ├── AttractScreen.js # Idle-state "Touch to Explore" screen
│ │ ├── ControlsOverlay.js # Rotate / Grow / Angle / Reset buttons
│ │ └── InfoPanel.js # Paginated exhibit-fact card
│ ├── utils/
│ │ └── PiPerformance.js # FPS-driven quality scaler (pixel ratio, leaf count)
│ ├── config.js # Kiosk-tunable settings (tree shape, colors, timeouts)
│ ├── main.js # Entry point — wires everything together, owns the render loop
│ └── style.css
├── index.html
├── vite.config.js
└── package.json