Files
wireless-docs/docs/ARCHITECTURE.md
2026-09-10 14:09:25 -04:00

498 lines
14 KiB
Markdown
Raw Permalink 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.

# Architecture Documentation
This document explains the architecture of the EID Wireless documentation system and its interactive diorama renderer.
---
## Overview
The EID Wireless documentation is a **text-first** technical resource that uses interactive 3D visualizations (dioramas) as *supplemental* learning tools. The core principle is: **readers should be able to understand the concepts without interactives, but gain deeper insight through them**.
This is achieved through a hybrid architecture:
1. **Typst** generates static HTML documents from `.typ` source files
2. **Custom JavaScript renderer** provides interactive dioramas embedded in those pages
3. **Vite** bundles everything together for development and production
The dioramas are not the primary content—they're visual aids that appear *after* conceptual explanations and serve to reinforce understanding through visualization.
---
## Architecture Goals
### Primary Goal: Text-First Documentation
The documentation system prioritizes readable, searchable, accessible text content. Interactive dioramas:
- Are **optional** and **degrade gracefully** (pages work without JavaScript)
- Are **out-of-the-way** (don't interfere with reading flow)
- Are **supplemental** (don't contain core information that isn't in text)
- Are **mobile-friendly** (scrolling behavior is preserved by default)
### Secondary Goals
1. **Accurate Minecraft rendering** - Dioramas must faithfully represent block states, rotations, and redstone behavior
2. **Efficient rendering** - Multiple dioramas can appear on a single page; rendering must be performant
3. **Easy authoring** - Content creators should focus on concepts, not graphics programming
4. **Version independence** - Documentation should work across different Minecraft versions
---
## System Architecture
### High-Level Flow
```
Typst Source (.typ files) ──▶ HTML + JavaScript ──▶ Browser
│
└─▶ Interactive Dioramas (WebGL)
```
### Components
#### 1. Typst Document Generator
**Role**: Converts `.typ` source files into HTML pages
**Key Files**:
- `main.typ` - Main entry point, defines document structure
- `lib.typ` - Library functions (`diorama()`, `callout()`, etc.)
- `content/*.typ` - Documentation chapters
- `typst.toml` - Package metadata
**Responsibilities**:
- Compile `.typ` files into HTML using `tinymist` language server
- Embed interactive elements via `#show` directives
- Generate navigation between pages
**Key Pattern** - Diorama Embedding:
```typ
#show raw.where(lang: "mc-diorama"): it => diorama(
orbit: true,
pan: true,
autoplay: true,
it.text,
)
```
This directive tells Typst to:
1. Find all `mc-diorama` code blocks
2. Wrap them in the `diorama()` function
3. Pass block content as the world definition
#### 2. World Definition System
**Role**: Defines Minecraft scenes using a timeline-based domain-specific language
**Format**:
```
p x y z block_type properties
t time
```
Where:
- `p` places or modifies blocks at coordinates
- `t` advances the timeline
- Properties are `key=value` pairs (e.g., `facing=east`, `powered=true`)
**Example**:
```
p 0 0 0 dropper facing=up triggered=false
p 0 1 0 dropper facing=up triggered=false
t 2
p 0 0 0 triggered=true
t 4
p 0 0 0 triggered=false
```
This format is designed to be:
- **Human-readable** - Easy to write and debug
- **Concise** - Minimal boilerplate
- **Timeline-aware** - Changes occur at specific game ticks
#### 3. WebGL Renderer (Engine)
**Role**: Renders Minecraft blocks as 3D models using WebGL
**Key Files**:
- `src/engine.js` - Main renderer class
- `src/world.js` - World state management
- `src/diorama.js` - Camera and view management
- `src/math.js` - Matrix operations (orthographic projection, look-at, etc.)
**Architecture**:
```
Engine (singleton)
├── Dioramas (multiple per page)
│ ├── Canvas (2D context for offscreen rendering)
│ └── Frame (world timeline state)
└── Resources (blockstates, models, textures)
├── Cache (async resource loading)
├── Blockstate Handler (parses JSON blockstate definitions)
├── Model Handler (builds geometry from models)
└── Texture Handler (atlas textures into single canvas)
```
**Key Features**:
- **Instanced rendering** - Thousands of blocks rendered efficiently
- **Lazy updates** - Only re-renders when content changes
- **View culling** - Skips rendering for off-screen dioramas
- **Texture atlasing** - Packs all textures into single texture for batch rendering
#### 4. Controller System
**Role**: Handles user interaction with dioramas
**Key Files**:
- `src/controller.js` - SpacetimeController class
- `src/components.js` - Custom HTML elements
**Features**:
- **Orbit controls** - Rotate view (left drag)
- **Pan controls** - Move view (middle drag or shift+left)
- **Zoom controls** - Scale view (right drag or ctrl+left)
- **Timeline autoplay** - Auto-play animations with configurable speed
- **Mobile support** - Touch gestures with scroll delegation
- **State preservation** - Camera position and timeline state can be reset
**Mobile-Specific Behavior**:
- Default browser scroll is preserved (diagram doesn't capture scroll)
- Touch interaction requires deliberate engagement (200ms timeout)
- 1-finger touch: orbit (don't interfere with scroll)
- 2-finger touch: pan + zoom (pinch gesture)
#### 5. Build System
**Role**: Integrates Typst output with JavaScript rendering
**Key Files**:
- `vite.config.js` - Vite configuration
- `mise.toml` - Development tool configuration
- `dist/` - Production output directory
**Workflow**:
```bash
# Development
mise run dev # Runs Vite dev server + Typst watch
# Build
mise run build # Compile Typst + bundle with Vite
```
**Vite Configuration**:
- `root: .typ-bundle` - Typst-generated HTML is the Vite root
- `publicDir: public` - Static assets served from Minecraft assets
- Alias `/src` → `src/` - JavaScript modules accessible from HTML
- Watch mode monitors both `.typ` and `src/**/*` files
---
## Data Flow
### 1. Document Compilation
```
Typst Source (.typ)
↓ (tinymist)
HTML + Scripts
↓ (Vite bundling)
dist/index.html
```
### 2. World Parsing
```
mc-diorama Code Block
↓ (World constructor)
World Object
├── events[] - Timeline events (changes at each tick)
├── initialState - Block state at t=0
└── labels - Named timeline positions
```
### 3. Frame Playback
```
World Object
↓ (WorldFrame)
Frame Object
├── blocks[] - Current block state
├── currentTime - Timeline position
└── listeners[] - Callbacks on state change
```
### 4. Rendering Pipeline
```
Frame State Change
↓
Engine.updateAll()
├── Parse blocks → Blockstates → Models
├── Build geometry (positions, normals, UVs)
├── Update texture atlas
└── Create instanced meshes (VBOs)
Frame State Change (again)
↓
Engine.render()
├── Check visibility (cull off-screen dioramas)
├── Update camera matrices (orthographic projection)
├── Draw instanced meshes (WebGL)
└── Copy to 2D canvas (for HTML display)
```
### 5. Resource Loading
```
Request Blockstate/Model/Texture
↓
Cache.getAsync()
├── Check if already loading → return promise
├── Check if already loaded → return data
└── Kick off fetch + prepare fallback
Fetch Complete
↓
Handler.process()
├── Parse JSON (blockstate/model)
├── Build geometry (model)
└── Return structured data
↓
Cache.onResolve() → Engine.requestUpdate()
```
---
## User Experience: What Users Actually See
Dioramas appear as interactive 3D diagrams within the documentation:
```
┌─────────────────────────────────────┐
│ Text explanation of redstone... │
│ (this is the primary content) │
├─────────────────────────────────────┤
│ ┌───────────────────────────────┐ │
│ │ [Diorama: 3D interactive │ │
│ │ view of the mechanism] │ │
│ │ │ │
│ │ (click/drag to interact) │ │
│ └───────────────────────────────┘ │
│ Caption: "Figure 1: Mechanism" │
└─────────────────────────────────────┘
```
**Key UX Principles**:
1. **Dioramas are after the text** - Readers understand conceptually first, then visualize
2. **Dioramas don't steal scroll** - Default browser scroll works; interaction requires deliberate action
3. **Mobile-first interaction** - Touch gestures don't interfere with page navigation
4. **Progressive enhancement** - Pages work without JS; dioramas add value when JS is available
### Camera System
Dioramas use **orthographic projection** (not perspective) because:
1. Redstone mechanisms are small and detailed
2. Orthographic preserves proportions
3. Better for technical diagrams
4. Easier to measure distances
**Camera Parameters**:
- `target` - Point camera looks at (world coordinates)
- `radius` - Distance from target
- `theta` - Horizontal rotation angle (degrees)
- `phi` - Vertical rotation angle (degrees)
**Matrix Calculation**:
1. Convert spherical coordinates to Cartesian (eye position)
2. Calculate view direction and up vector
3. Build view matrix via `mat4LookAt()`
4. Build orthographic projection matrix based on radius and aspect ratio
5. Combine: `viewProj = projection × view`
### Instanced Rendering
Each unique block variant gets its own instanced mesh:
```
Geometry (positions, normals, UVs, tints, shades)
↓
Instance Data
├── Matrix[] (16 floats each) - World transformation
└── Color[] (3 floats each) - Redstone power tint
↓
GPU Buffer (VBO)
↓
DrawElementsInstanced()
```
This allows thousands of blocks to be rendered in a single draw call.
### Texture Atlasing
All block textures are packed into a single canvas:
```
16×16px blocks
↓
Atlas Canvas (256×256px default)
├── Cell 0: block_0.png
├── Cell 1: block_1.png
├── Cell 2: block_2.png
└── ...
↓
UV Map
├── u, v (cell position)
└── du, dv (cell size)
```
Texture loading is **asynchronous** but **synchronous fallback** is provided:
- Renderer immediately gets UV coordinates
- Texture data loads in background
- Fallback texture (black silhouette) shown until loaded
---
## Interactive Element Design
### Accessibility First
Dioramas must work without JavaScript:
```html
<!-- Without JS: plain text world definition -->
<mc-diorama>
<script type="text/mc-world">
p 0 0 0 dropper...
</script>
</mc-diorama>
<!-- With JS: interactive canvas -->
<mc-diorama>
<canvas width="800" height="600"></canvas>
</mc-diorama>
```
### Performance Optimizations
1. **Lazy rendering** - Only update when content changes
2. **Visibility culling** - Skip off-screen dioramas
3. **State preservation** - Only rebuild meshes when blocks change
4. **Texture batching** - Single texture bind for all blocks
5. **Instanced drawing** - One draw call per block type
### Mobile-First Interaction
**Touch Handling**:
- 200ms delay before engaging (allows scroll detection)
- 1-finger: orbit (doesn't interfere with page scroll)
- 2-finger: pan + zoom (pinch gesture)
- Touch doesn't block page scroll unless clearly interacting
**Scroll Delegation**:
```javascript
canvas.addEventListener('touchstart', e => {
// Check if user is trying to scroll
if (maxTouchDistance < 10px) {
// Let browser handle scroll
return;
}
// Engage diorama interaction
e.preventDefault();
});
```
---
## Extensibility
### Adding New Block Types
1. **Blockstate JSON** - Define block variants in `public/assets/minecraft/blockstates/`
2. **Model JSON** - Define geometry in `public/assets/minecraft/models/`
3. **Texture PNG** - Add texture image in `public/assets/minecraft/textures/`
The system automatically discovers and loads these assets.
### Adding New Diorama Features
The controller system is designed for easy extension:
```javascript
class SpacetimeController {
constructor(diorama, options = {}) {
this.opts = {orbit: true, pan: true, zoom: true, ...options};
// Add new options here
}
}
```
New features can be added as optional behaviors without breaking existing dioramas.
---
## Development Workflow
### Running Locally
```bash
mise run dev
# Opens browser at localhost:5173
# Automatically reloads on changes to .typ or src/**/*
```
### Building for Production
```bash
mise run build
# Compiles Typst to .typ-bundle/
# Bundles with Vite to dist/
```
### Debugging
**Enable debug redraw**:
```javascript
window.mcEngine.debug_redraw = true;
// Highlights regions that are being redrawn
```
**Check resource loading**:
```javascript
window.mcEngine.cache.data
// Shows all loaded resources
```
**Inspect frame state**:
```javascript
const frame = document.querySelector('mc-diorama').frame;
console.log(frame.blocks, frame.currentTime);
```
---
## Future Architecture Changes
The JavaScript API is intentionally unstable. Planned changes:
1. **Component system** - Move from custom elements to framework components
2. **WebAssembly rendering** - Potential Rust/WASM renderer for better performance
3. **TypeScript migration** - Improve type safety and IDE support
4. **Animation system** - More sophisticated timeline interpolation
5. **Shader effects** - Enhanced visual feedback (glows, particles, etc.)
These changes won't break the Typst authoring experience—the diorama content format will remain the same.
---
## References
- Typst documentation: https://typst.app/docs
- WebGL2 documentation: https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API
- Minecraft Java Edition documentation: https://minecraft.wiki/w/Java_Edition
- Instanced rendering: https://learnopengl.com/Advanced-OpenGL/Instancing