feat: Add comprehensive design documentation for Krates
- Canvas: Infinite zoomable workspace with LOD and navigation - Spotlight: Fuzzy search with type filters and view shortcuts - Krate: Window group container with non-overlapping placement - Detail Window: YAML/Describe/Logs/Shell views with maximize - Top Bar: Cluster info, user presence, admin toggle - Admin Drawer: Multi-user presence and spectate functionality - Minimap: Browse and navigate canvas overview - Collection Window: List/tree views with filtering and sorting - Shell/Logs: Real-time terminal and log streaming - Backend: Go service with K8s API, WebSocket handlers, CRDT sync - Architecture: Full project structure and tech stack
This commit is contained in:
105
design/canvas.md
Normal file
105
design/canvas.md
Normal file
@@ -0,0 +1,105 @@
|
||||
# Canvas Feature Specification
|
||||
|
||||
## Overview
|
||||
The canvas is the infinite zoomable/pannable workspace where krates live. It serves as the primary interaction surface for exploring Kubernetes clusters.
|
||||
|
||||
## Core Responsibilities
|
||||
- Render an infinite 2D workspace (12000×8000px world)
|
||||
- Handle camera navigation (pan/zoom)
|
||||
- Manage Level of Detail (LOD) based on zoom level
|
||||
- Display a CAD grid overlay
|
||||
- Coordinate global interactions (space panning, spotlight trigger)
|
||||
|
||||
## Technical Requirements
|
||||
|
||||
### Viewport & World Layer
|
||||
- Full viewport (`position: fixed; inset: 0`)
|
||||
- Background color: `#0b0e13`
|
||||
- World layer: 12000×8000px div transformed via `translate(camX, camY) scale(zoom)`
|
||||
- All krates/windows are absolutely positioned children
|
||||
|
||||
### Grid Overlay (CSS background-image)
|
||||
- Fine grid: 34px spacing, rgba(125,145,175,.04)
|
||||
- Coarse grid: 170px spacing, rgba(125,145,175,.075)
|
||||
- Both X and Y repeating linear gradients
|
||||
|
||||
### Camera State
|
||||
```typescript
|
||||
interface CanvasState {
|
||||
camX: number; // world-to-screen X offset
|
||||
camY: number; // world-to-screen Y offset
|
||||
zoom: number; // 0.16 – 2.2; default 0.92
|
||||
flying: boolean; // true during animated camera transitions
|
||||
dragging: boolean; // true during pan drag
|
||||
collapsed: boolean; // LOD: true when zoom < 0.4
|
||||
spacePanning: boolean; // true while space is held
|
||||
}
|
||||
```
|
||||
|
||||
## Navigation
|
||||
|
||||
### Scroll Wheel
|
||||
- ** Default **: Pan canvas
|
||||
- ** Ctrl/⌘ + scroll **: Zoom canvas (intercepted via wheel event with `e.ctrlKey || e.metaKey`)
|
||||
|
||||
### Space + Drag Panning
|
||||
- Critical: must work even when shell window has keyboard focus
|
||||
- Implementation:
|
||||
- `document.addEventListener('keydown', handler, { capture: true })` on space
|
||||
- Set "panning" flag, prevent default on body
|
||||
- Forward `mousemove` to canvas pan handler
|
||||
- Release on `keyup` for space
|
||||
- Do NOT use `e.stopPropagation()` - allow event propagation
|
||||
|
||||
### Click/Typed Key Triggers
|
||||
- ** Click on empty canvas **: Open spotlight
|
||||
- ** Type any key **: Open spotlight with that character pre-seeded
|
||||
|
||||
### Zoom Levels / LOD
|
||||
- ** zoom > 0.5 **: Normal view — krates expanded, all windows visible, draggable
|
||||
- ** zoom < 0.4 **: Collapsed view — krates become 230px wide overview cards, no windows rendered
|
||||
- ** Hysteresis**: Collapse at 0.4, re-expand at 0.5 (prevents flickering)
|
||||
|
||||
### Animations
|
||||
- CSS `transform` with `transition` only for programmatic "fly" animations: `.52s cubic-bezier(.22,.8,.28,1)`
|
||||
- During user scroll/drag: `transition: none` for immediacy
|
||||
|
||||
## UI Components
|
||||
|
||||
### Top Bar
|
||||
- Position: `absolute; top: 0; left: 0; right: 0; z-index: 10; height ~56px`
|
||||
- Layout: `display: flex; align-items: center; padding: 13px 18px`
|
||||
- Background: none (transparent)
|
||||
- Left side: Logo pill, cluster pill, krate count pill
|
||||
- Right side: Synced pill, admin button, roster avatars
|
||||
|
||||
### Bottom Hint Bar
|
||||
- Position: `absolute; right: 18px; bottom: 18px`
|
||||
- Shows keyboard hints (status bar)
|
||||
|
||||
### Zoom Pill
|
||||
- Position: `absolute; left: 18px; bottom: 18px`
|
||||
- Displays current zoom percentage
|
||||
|
||||
### Minimap
|
||||
- Position: `absolute; right: 18px; bottom: 64px`
|
||||
- Size: 180×120px
|
||||
- Shows all krates as small rectangles
|
||||
- Viewport indicator rectangle showing current view frustum
|
||||
- Click anywhere to fly camera to that world position
|
||||
|
||||
## Interaction Summary
|
||||
| Interaction | Behavior |
|
||||
|---|---|
|
||||
| Scroll wheel | Pan canvas |
|
||||
| Ctrl/⌘ + scroll | Zoom canvas |
|
||||
| Space + drag | Pan canvas (even over windows/shells) |
|
||||
| Click empty canvas | Open spotlight |
|
||||
| Type any key | Open spotlight pre-seeded |
|
||||
| Minimap click | Fly camera to position |
|
||||
|
||||
## Gotchas
|
||||
1. **Space pan over shells**: Must intercept with `{ capture: true }`, prevent default, but don't stop propagation
|
||||
2. **Ctrl/⌘+scroll**: Use `{ capture: true }` on canvas wheel handler to intercept before window scroll containers
|
||||
3. **Camera transitions**: Only animate during programmatic fly, not user gestures
|
||||
4. **LOD state**: Use stable boolean `collapsed` in state, not derived from `zoom` on every render
|
||||
Reference in New Issue
Block a user