Case study · Frontend

reaktr.cc

Cost analytics for cultivated food, with an AI copilot built in.

Role
Designed and built all of it. Led a team of three researchers
Where
McDonald-Nandi Lab, UC Davis
Frontend
Next.js, React, Tailwind CSS, Chart.js
Year
2025. Live at reaktr.cc
reaktr.cc
reaktr landing hero: the headline Cultivated food analytics, reimagined, beside a tilted preview of the dashboard with cost cards, an OPEX donut and a cost breakdown

Summary

The cost of cultivated meat swings on a few dozen inputs: reactor size, doubling time, media price, labor. reaktr turns the lab's cost model into a dashboard anyone can tune, share by link and question in plain English.

  • 4

    bioreactor types to compare

  • 60+

    preset configurations

  • 7

    cost categories, each with its own chart

  • $26.73

    per kg for the 105,000 L baseline

My part

What I built

Every screen and service on this page is my work. I also ran the project for a team of three researchers in Jira.

Product and brand
The CultiVision product and its rebrand to reaktr.
Landing page
The redesign, with live analytics previews and the Wiz demo.
Dashboard
Parameters panel, result cards, OPEX and CAPEX charts including the nested doughnut, and the process flow diagrams.
Sharing and export
Share links that carry the whole configuration, chart and table downloads, CSV export and the full report.
Access control
The request form, email verification and expiring personal links.
Wiz
The retrieval-augmented assistant, its streaming API and the chat interface.

01 · Landing page

Show the numbers, not stock art

Every section of the redesigned landing page is built from the dashboard's real output, so a visitor sees the product before asking for access.

Features section with six feature cards for cost analysis, visualizations, bioreactor configurations, parameters, sharing and research-grade data
Features. Six cards on one hairline grid, with a scrolling ticker of the platform's numbers above.
Live analytics preview: an OPEX breakdown with bars and dollar amounts, key metric cards and a bioreactor comparison
Live analytics preview. The same breakdown, metrics and reactor comparison the dashboard produces.

02 · Product

Change an input, see the cost move

Parameters on the left, results on the right. Reactor, doubling time and cell density come as presets, and every cost input shows its base case underneath.

mcdonald-nandi-lab.github.io/cultivision
Dashboard: a parameters panel, four result cards for COGS, operating and capital expenses and facilities, an OPEX donut chart and a cost breakdown table
The dashboard. Four headline numbers, then a chart and a table for each cost type. Every chart and table has its own download button.
CAPEX distribution as a nested doughnut: the outer ring shows main capital categories and the inner ring breaks down direct fixed capital
Nested doughnut. The outer ring holds the capital categories and the inner ring splits the largest one, so a 93% slice still has detail.
Process flow diagram for the 105,000 liter stirred configuration: seed reactors feeding a production reactor and centrifuge
Process flow. Each configuration opens its own reactor train with the volumes for every stage.

03 · Product

Open to request, gated by link

Access is by request. Visitors fill in a short form, then get a personal link by email that expires after a few days. A three-step tracker shows where they are.

reaktr.cc/access
Request Access page: a three-step progress card and a form for name, email, affiliation, use case and terms
Request access. Required fields, a 20 to 500 character use case with a live counter, and terms to accept before sending.

04 · Mobile

The same tools at 390 pixels

The landing page stacks into one column and the copilot keeps its prompt chips. In the dashboard, parameters and charts stack, and each chart keeps its legend and download button.

Mobile landing hero with the headline and three call to action buttons
Hero
Mobile Wiz section with a sample conversation and prompt chips
Wiz
Mobile dashboard parameters panel with reactor, doubling time, density and cost inputs
Parameters
Mobile OPEX distribution donut with legend and the start of the breakdown table
OPEX
Mobile CAPEX nested doughnut with legend and chart guide
CAPEX

05 · Design system

Night navy and one mint signal

  • Ground#0A0F1A
  • Surface#0F1824
  • Raised#141F2E
  • Slate#7A95B0
  • Text#EEF2F7
  • Mint#00E5C3

Geist 900

Real data. Real decisions.

Black-weight headlines with tight tracking

Geist Mono

COGS W/ DEPR. · 105,000 L

Uppercase labels, pills and units

  • One phrase per headline goes mint. Everything else stays in the navy and slate range.
  • Both fonts load through next/font, so there's no layout jump when they arrive.
  • The dashboard still runs the earlier CultiVision look. Moving it onto this system is next.

06 · Tech

Two apps, one front door

  1. 1 · reaktr.cc

    Marketing site

    Next.js App Router with server components, built with Turbopack and served from Netlify.

  2. 2 · /access

    Request and verify

    A validated form, then a personal, expiring link sent by email.

  3. 3 · Dashboard

    Static Next.js export

    Hosted on GitHub Pages. Chart.js on canvas, Tailwind CSS v4 and the whole configuration kept in the URL.

  4. 4 · Wiz

    Streaming assistant

    Retrieval-augmented answers streamed back over its own API.

Share by URL

Only the inputs that differ from the defaults go into the link, so a shared URL stays short and opens the exact same analysis.

Export everything

Every chart and table has its own download, plus a full report, so the numbers can go straight into a slide or a paper.

Explain every term

Each cost line has an info tooltip, and each input shows its base case, for readers who aren't bioprocess engineers.

  • Next.js
  • React
  • TypeScript
  • Tailwind CSS
  • Chart.js
  • Turbopack
  • next/font
  • Netlify
  • GitHub Pages

07 · Code

Share links that only carry what changed

A shared link has to reopen the exact analysis without a database. The encoder keeps only the inputs that differ from the defaults and packs them into URL-safe base64.

Lightly trimmed. The decoder reverses it and merges onto the defaults, so old links survive new inputs.

export function encodeProductionCosts(costs: ProductionCosts): string {
  const changedParams: Record<string, number> = {};

  orderedKeys.forEach((key) => {
    const defaultValue = DEFAULT_PRODUCTION_COSTS[key];
    const currentValue = costs[key];

    if (Math.abs(currentValue - defaultValue) > 0.001) {
      changedParams[key] = currentValue;
    }
  });

  if (Object.keys(changedParams).length === 0) {
    return "";
  }

  return btoa(JSON.stringify(changedParams))
    .replace(/\+/g, "-")
    .replace(/\//g, "_")
    .replace(/=+$/, "");
}

08 · Performance

Measured on the live sites

Desktop Chrome, October 30, 2026, read from the browser's Performance API. Sizes are what travels over the network.

Landing page

reaktr.cc · Brotli
JavaScript in 20 chunks

363KB

CSS

11KB

requests

48

layout shift

0

Dashboard

GitHub Pages · gzip
JavaScript in 18 chunks

273KB

CSS

10KB

requests

20

layout shift

0

09 · Applied AI

Ask the dashboard a question

Not every visitor knows which chart answers their question. Wiz takes the question in plain English and answers from the configuration on screen.

Ask what drives cost and it ranks the categories with their share and dollar amount, then offers to model a change, like cutting media cost by 20%.

Answers are retrieval-augmented and stream in as they're written. Prompt chips under the input give first-time users a place to start.

Meet Wiz section: a chat window where Wiz breaks down what affects cost of goods sold, next to three capability cards
Wiz on the landing page, with the same answer format it gives inside the product.

10 · Next

What I'd ship next

  1. 01Move the dashboard onto the reaktr design system so the rebrand is complete end to end.
  2. 02Put the four headline results first on phones and fold the parameters into a drawer.
  3. 03Trim the landing page's 363 KB of JavaScript, starting with its three largest chunks.