GardenPin
A weekend build — from a Moleskine sketch to a working garden-planning app with companion-planting recommendations, offline mode, and a hand-rolled canvas grid.
Problem
Every spring I sketch a layout for my three raised beds in a notebook, lose it by July, and rebuild from memory the following year. Companion-planting matters — basil and tomatoes thrive together, basil and rue do not — but the rules live in a dozen scattered articles. There was no single tool that let me draw a bed, place plants, and see which neighbours would help or hurt.
Solution
A phone-friendly, offline-first web app where each raised bed is a top-down grid. Plants are dragged onto tiles; a companion-planting graph scores their neighbours in real-time. Sowing dates trigger watering and harvest reminders via the browser's Notification API. No accounts, no servers, no tracking — just a 32-character device ID in a cookie and an opt-in sync endpoint.
Tech Stack
Key Features
Companion-planting graph
84-plant catalogue with companion / antagonist edges encoded as a 612-row sparse adjacency table. Drag-and-drop scoring picks tiles where neighbours boost growth and avoid known antagonists.
Hand-rolled canvas grid
~140 lines of vanilla canvas: pan via pointer events, pinch-zoom around the cursor, plants render as coloured circles + emoji. No charting library, no map tiles, no SVG.
Offline-first by default
All user data lives in localStorage. A 32-character device ID lets you opt in to single-endpoint sync. No accounts, no passwords, no third-party trackers.
Reminders without a backend job
Sowing/watering/harvest events derived from plant data on the client. Browser Notification API fires within a 24-hour window. Anything past that is recomputed at next app open.
Timeline — 48 hours, in order
- Friday 19:00
Started with React Native + Mapbox. Three hours later: simulator certs unresolved, Mapbox demanding a credit card. Scrap.
- Friday 22:30
Reset. Plain Next.js 14 + canvas. Drew the first bed grid in 40 minutes.
- Saturday morning
Curated the 84-plant catalogue and the companion / antagonist relations. Detour through r/permaculture for weighting.
- Saturday afternoon
Drag-and-drop pin placement, neighbour scoring, score visualisation on hover.
- Saturday evening
Reminder generation from sowing dates. Web Notifications API wired up. First end-to-end run.
- Sunday
Polish: dark mode, keyboard navigation, exporting beds as PNG, deploy to Vercel. Ship.
Metrics
Screenshots
Bed editor — drag plants onto the grid
Screenshot coming with v1.1 release
Companion-planting score on hover
Screenshot coming with v1.1 release
Reminders feed — tomorrow’s tasks
Screenshot coming with v1.1 release
Dark mode, late-night planning
Screenshot coming with v1.1 release
What I learned
Friction is the enemy of weekend builds
The right stack is the one you can reach without burning a half-day on certs, billing accounts, or framework debates. I dropped React Native the second it cost me three hours.
Canvas beats charting libraries when the geometry is yours
I almost installed Konva. The whole map ended up in 140 lines of vanilla canvas, and I understand every pixel. Reach for a library when you'd be re-implementing it badly — not before.
Curate data before you build the visualisation
I started with the canvas and discovered halfway through Saturday that my plant data was incomplete. A weekend build doesn't have time for two passes — get the data right first, then make it pretty.
Skip backend cron jobs when client-side derivations work
Reminders are deterministic functions of your plant data. I generate them in the browser and use the Notification API — no worker, no queue, no infrastructure. Hobby apps reward this kind of simplification.
Want the full build journal?
Read the technical write-up