Cultivar UI

Svelte frontend for the Grove5 Cultivar appliance.

A thoughtful friend who checked in on your grow while you were busy, and wants to tell you about it over coffee. Warm, specific, calm, quietly knowledgeable. Never anxious. Never condescending.

Grove5 — Open source software, honest hardware.


What it is

The Cultivar UI runs on the QRB2210 Linux side of the Arduino UNO Q, served as static files by cultivar-daemon. It connects to the daemon via WebSocket for real-time sensor data and REST for history.

Designed for a tablet or desktop browser. The appliance serves it locally — no cloud, no accounts, no ads.

Stack

  • Svelte — compiled to vanilla JS, no virtual DOM
  • TypeScript — full type safety via cultivar-types
  • Vite — build tooling
  • D3 — sweep visualizations (radar, heatmap)

Current bundle: 242 KB JS / 73 KB gzip — lean by design.

Structure

src/
├── lib/
│   ├── charts/
│   │   ├── ColonizationCurve.svelte
│   │   └── LineChart.svelte
│   ├── reference/
│   │   ├── contaminants.ts      # 15 contaminants with causes + remediation
│   │   ├── species.ts           # 27 species with climate envelopes + CO2 tolerances
│   │   └── index.ts
│   ├── twin/
│   │   ├── CultivarTwin.svelte  # dual-chamber physical twin
│   │   ├── MushroomBag.svelte
│   │   └── BagHeroCard.svelte
│   ├── ui/
│   │   ├── ChartPanel.svelte
│   │   ├── InfoHint.svelte
│   │   └── TopBar.svelte
│   ├── store.svelte.ts          # reactive app state
│   ├── types.ts                 # from cultivar-types
│   └── mock.ts                  # mock data for development
└── routes/
    ├── Overview.svelte           # main dashboard
    ├── BagDetail.svelte          # per-bag detail view
    ├── Reference.svelte          # field guide
    └── Onboarding.svelte

Views

Overview

The main dashboard. Shows:

  • Cultivar Rhythm — narrative summary + actionable task list
  • Current Status — dual-chamber physical twin with bag states
  • Environment — temp, humidity, CO2, air quality with 1h/6h/24h history

Field Guide

  • 27 species with climate envelopes, CO2 tolerances, flush patterns
  • 15 contaminants with visual ID, causes, remediation

Bag Detail

  • Per-bag colonization progress, vision snapshots, stage history

Development

npm install
npm run dev        # dev server at localhost:5173 (uses mock data)
npm run build      # build to dist/ for daemon to serve
npm run preview    # preview built output

Mock vs live data

mock.ts provides realistic data for UI development without a running daemon. The store switches to WebSocket automatically when VITE_DAEMON_URL is set:

# Dev against live daemon
VITE_DAEMON_URL=http://localhost:8000 npm run dev

Environment variables

Variable Default Description
VITE_DAEMON_URL `` (mock mode) Daemon base URL
VITE_WS_URL derived from VITE_DAEMON_URL WebSocket URL

WebSocket integration

The store connects to ws://{daemon}/ws and handles typed messages:

// store.svelte.ts
ws.onmessage = (event) => {
  const msg: WsMessage = JSON.parse(event.data)
  switch (msg.type) {
    case 'payload':   updateEnvironment(msg.chamber_id, msg.data)
    case 'anomaly':   addAnomaly(msg.data)
    case 'baseline':  updateBaseline(msg.chamber_id, msg.data)
    case 'heartbeat': // keepalive
  }
}

Deployment

Built output at dist/ is served directly by cultivar-daemon:

npm run build
# daemon auto-serves dist/ at http://cultivar.local:8000

Design system

  • Colors: charcoal (#1C1C1C) + sage green (#7A9E7E) — two color system
  • Typography: ITC New Baskerville serif (headings) + system sans (body)
  • Voice: warm, specific, calm — "Harvest day." not "HARVEST READY ✅"

License

MIT — Grove5

S
Description
Svelte frontend hosted directly on Cultivar. A thoughtful friend who checked in on your grow while you were busy, and wants to tell you about it over coffee. Warm, specific, calm, quietly knowledgeable. Never anxious. Never condescending.
Readme MIT
2.1 MiB
0 Stars 1 Watchers 0 Forks
Languages
Svelte 74.2%
TypeScript 23.9%
CSS 1.7%
JavaScript 0.1%