Add polished README and UI screenshot
This commit is contained in:
322
README.md
322
README.md
@@ -1,141 +1,235 @@
|
|||||||
# Hydro Builder
|
# Hydro Builder
|
||||||
|
|
||||||
An interactive, browser-based 3D builder for hydroponic / water-flow systems.
|
Hydro Builder is a browser-based 3D builder for laying out pumps, reservoirs, pipe runs, fittings, towers, trays, and return lines with live water-flow feedback.
|
||||||
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**,
|
It is built for fast iteration:
|
||||||
**Zustand**, and **TailwindCSS**.
|
|
||||||
|
|
||||||

|
- click-to-place parts
|
||||||
|
- drag to reshape runs
|
||||||
|
- snap connectors pipe-to-pipe
|
||||||
|
- switch between builder, x-ray, water, and 3D views
|
||||||
|
- inspect pump output, head, open ends, and system health while you build
|
||||||
|
|
||||||
## Quick start
|

|
||||||
|
|
||||||
|
## What this repo contains
|
||||||
|
|
||||||
|
- `frontend`: React + TypeScript + Vite app in the repo root
|
||||||
|
- `backend`: lightweight Express API in `server/index.js` with SQLite persistence
|
||||||
|
- `simulation`: in-browser flow and diagnostics for pumps, restrictions, head, loops, and open drains
|
||||||
|
|
||||||
|
## Linux quick start
|
||||||
|
|
||||||
|
These instructions assume Ubuntu or Debian first. Equivalent packages work on Arch, Fedora, or other distros.
|
||||||
|
|
||||||
|
### 1. Install system dependencies
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install -y git curl build-essential python3 make g++
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Install Node.js 20
|
||||||
|
|
||||||
|
Use Node 20 LTS. The app is Vite-based and that is the sane floor here.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
|
||||||
|
sudo apt install -y nodejs
|
||||||
|
node -v
|
||||||
|
npm -v
|
||||||
|
```
|
||||||
|
|
||||||
|
You want Node `20.x` or newer.
|
||||||
|
|
||||||
|
### 3. Clone and enter the project
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://gitea.thetempleofdoom.com/drjones/hydro-builder-app.git
|
||||||
|
cd hydro-builder-app
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Install JavaScript dependencies
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm install
|
npm install
|
||||||
npm run dev # → http://localhost:5173
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 5. Create your local env file
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run build # typecheck + production build (dist/)
|
cp .env.example .env
|
||||||
npm run preview # serve the production build
|
|
||||||
npm run typecheck # tsc only
|
|
||||||
```
|
```
|
||||||
|
|
||||||
On first launch the app loads a working demo: reservoir → pump → riser →
|
Minimum local env:
|
||||||
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
|
```dotenv
|
||||||
|
PORT=3000
|
||||||
| Action | How |
|
JWT_SECRET=change-this-for-real-use
|
||||||
|---|---|
|
STRIPE_SECRET_KEY=sk_test_replace_me
|
||||||
| 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,
|
Notes:
|
||||||
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
|
- `PORT` is for the backend API server.
|
||||||
be swapped out later (see below).
|
- `JWT_SECRET` should be changed for any non-throwaway environment.
|
||||||
|
- `STRIPE_SECRET_KEY` is only needed if you are testing billing or checkout flows.
|
||||||
|
|
||||||
|
## How to run it
|
||||||
|
|
||||||
|
You have three useful ways to start the app.
|
||||||
|
|
||||||
|
### Frontend only
|
||||||
|
|
||||||
|
Use this when you are working on the builder UI, 3D scene, layout, snapping, or water visualization.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Open:
|
||||||
|
|
||||||
|
- [http://localhost:5173](http://localhost:5173)
|
||||||
|
|
||||||
|
### Backend only
|
||||||
|
|
||||||
|
Use this when you are debugging auth, saved projects, payments, or SQLite behavior.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run server
|
||||||
|
```
|
||||||
|
|
||||||
|
API runs on:
|
||||||
|
|
||||||
|
- [http://localhost:3000](http://localhost:3000)
|
||||||
|
|
||||||
|
SQLite database file:
|
||||||
|
|
||||||
|
- `server/database.sqlite`
|
||||||
|
|
||||||
|
### Frontend and backend together
|
||||||
|
|
||||||
|
This is the normal local setup.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev:all
|
||||||
|
```
|
||||||
|
|
||||||
|
That starts:
|
||||||
|
|
||||||
|
- Vite frontend on `5173`
|
||||||
|
- Express backend on `3000`
|
||||||
|
|
||||||
|
## Build commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run typecheck
|
||||||
|
npm run build
|
||||||
|
npm run preview
|
||||||
|
```
|
||||||
|
|
||||||
|
What they do:
|
||||||
|
|
||||||
|
- `typecheck`: TypeScript validation only
|
||||||
|
- `build`: production build into `dist/`
|
||||||
|
- `preview`: serve the production build locally
|
||||||
|
|
||||||
|
## Builder workflow
|
||||||
|
|
||||||
|
This app is only useful if the editing loop is fast. The current interaction model is:
|
||||||
|
|
||||||
|
### Place and connect
|
||||||
|
|
||||||
|
- click a part in the left library, then place it in the scene
|
||||||
|
- drag a part near another connector to snap
|
||||||
|
- green connectors mean joined
|
||||||
|
- amber connectors mean open
|
||||||
|
|
||||||
|
### Manipulate runs
|
||||||
|
|
||||||
|
- drag a body or gizmo to move a selected part
|
||||||
|
- double-click plumbing to grab the full run
|
||||||
|
- selected pipes expose stretch handles
|
||||||
|
- drag connector dots to snap endpoints
|
||||||
|
- use front or side views for vertical edits
|
||||||
|
|
||||||
|
### Tune flow
|
||||||
|
|
||||||
|
- select a pump
|
||||||
|
- adjust rated flow and max head in the inspector
|
||||||
|
- switch to `Water` mode to isolate active flow behavior
|
||||||
|
- use `Flow` to animate movement through the system
|
||||||
|
|
||||||
|
### Diagnose problems
|
||||||
|
|
||||||
|
The bottom diagnostics area will surface issues like:
|
||||||
|
|
||||||
|
- disconnected pump inlet
|
||||||
|
- open drain / leaking end
|
||||||
|
- dead-end branch
|
||||||
|
- head too high for the selected pump
|
||||||
|
- closed or restrictive path
|
||||||
|
- loop or return behavior
|
||||||
|
|
||||||
## Project structure
|
## Project structure
|
||||||
|
|
||||||
```
|
```text
|
||||||
src/
|
.
|
||||||
├── types.ts # Shared domain types (parts, sim, project file)
|
├── src/ # React app, store, simulation, 3D scene, UI
|
||||||
├── parts/
|
├── server/ # Express API + SQLite bootstrap
|
||||||
│ └── catalog.ts # ★ Part catalog: defaults, params, connectors
|
├── docs/ # screenshots and design notes
|
||||||
├── store/
|
├── dist/ # production build output
|
||||||
│ └── builderStore.ts # Zustand store + undo/redo (BuilderState)
|
├── package.json
|
||||||
├── simulation/
|
└── README.md
|
||||||
│ └── 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
|
Important files:
|
||||||
in **inches**, flow in **GPH** (shown with L/h). Rotations are radians (XYZ
|
|
||||||
euler) in state, degrees in the UI.
|
|
||||||
|
|
||||||
## How to extend
|
- `src/App.tsx`: top-level app shell
|
||||||
|
- `src/components/SceneCanvas.tsx`: 3D scene and camera behavior
|
||||||
|
- `src/components/PartMesh.tsx`: part rendering and direct manipulation
|
||||||
|
- `src/store/builderStore.ts`: state, selection, undo/redo
|
||||||
|
- `src/simulation/flowSimulator.ts`: flow graph and pump logic
|
||||||
|
- `src/parts/catalog.ts`: part definitions and connector metadata
|
||||||
|
|
||||||
**Add a new part type** (e.g. a UV filter):
|
## Troubleshooting on Linux
|
||||||
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
|
### `npm install` fails building native modules
|
||||||
pick it up automatically.
|
|
||||||
|
|
||||||
**Improve the physics**: everything lives in `flowSimulator.ts`. The graph
|
Make sure these exist:
|
||||||
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):
|
```bash
|
||||||
- *Nutrient dosing* — add a `doser` part + per-edge concentration tracking in
|
sudo apt install -y build-essential python3 make g++
|
||||||
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).
|
### Port 5173 or 3000 is already in use
|
||||||
- *Bill of materials* — iterate `useBuilder.getState().parts` and group by
|
|
||||||
type/params; the catalog has labels and units.
|
Find and kill the process:
|
||||||
- *Parts marketplace / AI assistant* — the project JSON (`ProjectFile`) is a
|
|
||||||
complete, validated serialization format for sharing and generation.
|
```bash
|
||||||
|
lsof -i :5173
|
||||||
|
lsof -i :3000
|
||||||
|
kill -9 <pid>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Backend starts but auth or save features fail
|
||||||
|
|
||||||
|
Check:
|
||||||
|
|
||||||
|
- `.env` exists
|
||||||
|
- `JWT_SECRET` is set
|
||||||
|
- `server/database.sqlite` is writable
|
||||||
|
|
||||||
|
### Water or 3D rendering looks broken
|
||||||
|
|
||||||
|
Check:
|
||||||
|
|
||||||
|
- browser console errors
|
||||||
|
- WebGL is enabled in the browser
|
||||||
|
- you are on a current Chrome, Chromium, or Firefox build
|
||||||
|
|
||||||
|
## Current reality
|
||||||
|
|
||||||
|
This is not CFD and it is not a full hydraulic solver. It is a fast builder with approximate flow behavior intended to make pipe-to-pipe editing, pump sizing, and obvious routing mistakes easy to see.
|
||||||
|
|
||||||
|
That is the right tradeoff for this app right now.
|
||||||
|
|||||||
BIN
docs/hydro-builder-ui.png
Normal file
BIN
docs/hydro-builder-ui.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 950 KiB |
Reference in New Issue
Block a user