Robert Nealan

Case study · 2025–now · My studio

The Wheelhouse

The Wheelhouse is Telluride’s community art and ceramics studio: wheels, kilns, a darkroom, letterpress and a MakerSpace, shared by local makers and open to members around the clock.

The problem

Community studios run on word of mouth and a group text. Members want to know whether the kiln is done before they drive over, newcomers want to know what a membership gets them, and the person running the place is also the person loading the kiln.

Where it started

I took over the Wheelhouse in 2024. It had members and a kiln, and no website at all. I'm the owner, the designer and the engineer. The site runs on Shopify Hydrogen with React Router, deployed to Oxygen's edge workers, so the clay shop and its cart sit on the same Storefront API as everything else.

What I built

Dorothea, the kiln that reports in

Dorothea is a Skutt KMT-1027 with a Bartlett controller on KilnLink. The page shows her temperature, the running program and an estimated unload time, and draws the firing curve as dots colored the way the inside of a kiln glows at each temperature. KilnLink gives the studio a single login, and the page polls while it's open, so the live endpoint sits behind a 20-second edge cache. However many people refresh during a glaze firing, KilnLink sees at most one request every 20 seconds. If KilnLink is down, the page shows the kiln as off instead of throwing.

A firing log from snapshots

KilnLink has no history endpoint, only the current state. So a small always-on Fly.io machine asks the site to archive a snapshot to S3 every ten minutes and rebuild the firing index every hour. The rebuild walks the archive and finds each firing from the controller's own start and end timestamps rather than its firing counter, whose timing I couldn't verify. A firing that started and finished entirely between two polls is dropped and counted, not invented. One that stopped early is flagged rather than shown as a short, cool firing.

Events from Markdown

Each event is a Markdown file with front matter, validated against a schema and tested. Paid events sell through Stripe Payment Links, and the page reads each link's remaining seats so a sold-out class says so. If Stripe can't be reached the button quietly falls back to email. Free events take RSVPs on the site, with a confirmation from Resend, and support recurring dates, invite-only events and per-event social previews.

An estimator that agrees with itself

The MakerSpace sells 3D printing, Cricut and laser cutting, and ceramic firing. The services page prices a job live as you change filament, sheets, minutes or rush. The client and the server import the same pure pricing module, so the total you see is the total the server recomputes when you send the request. The public endpoint has a honeypot and an in-memory rate limiter, which is enough for a studio's inbox.

A clay shop with a cart

The four clay bodies we keep on the shelf have product pages with the supplier's specs, sold by the 25 lb block through Shopify with a real cart. Until a product is published to the storefront, its page still renders and offers an email link instead of Buy.

Memberships, and what comes next

Memberships, a resources hub with the guest waiver, and a members' vendor form for the holiday markets are on the site today. This week the studio's memberships, billing and door codes move onto Collective, the platform I built from running this place.

Next case study

Kismet Health

Telehealth built for pediatrics