Files
hydro-builder-app/README.md
2026-06-13 17:36:44 -07:00

142 lines
6.0 KiB
Markdown
Raw 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.
# Hydro Builder
An interactive, browser-based 3D builder for hydroponic / water-flow systems.
Design lattice towers, grow walls, pipe networks, pumps, reservoirs and custom
water paths — with live, approximate flow simulation.
Built with **React + TypeScript + Vite**, **React Three Fiber / Drei**,
**Zustand**, and **TailwindCSS**.
![Hydro Builder](docs/screenshot.png)
## Quick start
```bash
npm install
npm run dev # → http://localhost:5173
```
```bash
npm run build # typecheck + production build (dist/)
npm run preview # serve the production build
npm run typecheck # tsc only
```
On first launch the app loads a working demo: reservoir → pump → riser →
overhead return → emitter spraying back into the tank, plus a grow tower,
tray and lattice to play with. Your work autosaves to the browser and is
restored on the next visit.
## Using the builder
| Action | How |
|---|---|
| Place a part | Click it in the left library, then click the ground (Shift-click stamps copies). Or drag it from the library onto the canvas. |
| Move a part | Drag it in the scene. In Front/Side views, dragging moves vertically too. |
| Raise / lower | `E` / `Q` (or edit Y in the inspector) |
| Rotate | `R` (90° around Y), Shift-`R` reverse, or inspector fields/buttons |
| Duplicate / delete | `D` / `Delete`, or inspector buttons |
| Undo / redo | `⌘Z` / `⇧⌘Z` (or toolbar) |
| Measure | Toolbar 📏, then click two points |
| Snap to grid | Toolbar ⌗ (0.25 ft grid) |
| Connect pipes | Drop a part near another part's connector — it snaps. Green dot = joined, amber = open. |
| Views | Toolbar: 3D orbit / Top / Front / Side (2D orthographic) |
| Water animation | Toolbar 💧 Flow |
| Save / Load | Toolbar — named projects in browser storage |
| Export / Import | Toolbar — design JSON file |
## How the simulation works
The system is treated as a **graph**:
- **Nodes** — connection points; connectors that touch are merged (union-find).
Every flow-carrying part also gets an internal node so 3-way tees, tanks,
towers etc. work uniformly.
- **Edges** — part bodies (pipes, elbows, valves, …), each with a hydraulic
resistance.
- **Pump** — pressure source. It checks its inlet reaches a reservoir, then
traverses downstream collecting resistance, static head (highest point above
the pump), open ends, dead ends and loops.
Approximate delivered flow:
```
Q = rated_GPH × headFactor × resistanceFactor
headFactor = clamp(1 head / maxHead, 0, 1)
resistanceFactor = 1 / (1 + R / 30)
R(pipe) ≈ length / diameter⁴
R(elbow) ≈ 1.2 × (angle/90) / diameter²
R(valve) ≈ 0.3 + restriction(% open); closed = blocks flow
```
Diagnostics surfaced in the bottom panel: missing source, disconnected pump,
pump too weak for the elevation (head ≥ max head), bottlenecks, open pipe
ends (leaks), dead ends, closed valves, loops. Click a diagnostic to select
the offending part. Flow direction is rendered as animated arrows; flowing
pipes tint blue and the rate scales arrow speed.
This is deliberately simple steady-state math — not CFD — and is designed to
be swapped out later (see below).
## Project structure
```
src/
├── types.ts # Shared domain types (parts, sim, project file)
├── parts/
│ └── catalog.ts # ★ Part catalog: defaults, params, connectors
├── store/
│ └── builderStore.ts # Zustand store + undo/redo (BuilderState)
├── simulation/
│ └── flowSimulator.ts # Graph build + pump physics + warnings
├── utils/
│ ├── connectors.ts # World-space connector math, snap logic
│ ├── serializer.ts # Save/load/export/import (ProjectSerializer)
│ ├── demoProject.ts # Starter scene
│ └── dragState.ts # Transient drag context
├── components/
│ ├── SceneCanvas.tsx # R3F canvas, cameras, grid, drag plane, measure
│ ├── PartMesh.tsx # Geometry for every part type + selection/drag
│ ├── FlowArrows.tsx # Animated flow-direction arrows
│ ├── Toolbar.tsx # Project actions, tools, view presets
│ ├── PartLibrary.tsx # Left sidebar
│ ├── PropertiesPanel.tsx # Right sidebar inspector
│ └── StatusPanel.tsx # Bottom simulation status
├── App.tsx # Layout, shortcuts, autosave, drag-drop
└── main.tsx
```
Conventions: world units are **feet** (1 grid cell = 0.5 ft), pipe diameters
in **inches**, flow in **GPH** (shown with L/h). Rotations are radians (XYZ
euler) in state, degrees in the UI.
## How to extend
**Add a new part type** (e.g. a UV filter):
1. Add `'uvFilter'` to `PartType` in `src/types.ts`.
2. Add a catalog entry in `src/parts/catalog.ts` — defaults, inspector params
and `getConnectors()`. Add it to a category in `CATEGORIES` and (if it
carries water) to `FLOW_PARTS`.
3. Add a mesh case in `src/components/PartMesh.tsx`.
4. Give it a resistance in `partResistance()` in
`src/simulation/flowSimulator.ts`.
That's it — placement, snapping, drag, save/load, inspector and simulation
pick it up automatically.
**Improve the physics**: everything lives in `flowSimulator.ts`. The graph
build is separate from the flow estimate, so you can replace the single-pass
estimate with e.g. Hardy-Cross iteration or a linear solver over the same
graph without touching the UI.
**Planned extension points** (the architecture already supports them):
- *Nutrient dosing* — add a `doser` part + per-edge concentration tracking in
the simulator (it already knows flow per part).
- *Plant growth zones / lighting / timers* — new part categories; timers can
gate `partResistance()` (a valve already shows how blocking works).
- *Bill of materials* — iterate `useBuilder.getState().parts` and group by
type/params; the catalog has labels and units.
- *Parts marketplace / AI assistant* — the project JSON (`ProjectFile`) is a
complete, validated serialization format for sharing and generation.