Climatique

Role

Solo end-to-end ⁠— product research, UX/UI, Cinema 4D modelling, rigging and Redshift rendering, a real-time three.js world, system architecture, FastAPI + pandas, React + Vite, data integrations and deployment

Client

Self-initiated product

Disciplines

Product Design · UX · Data · 3D · Motion

Year

2026

A household scheduler that ranks 30-minute windows across the next 48 hours using carbon, price, weather and comfort. It offers primary and backup times, with modelled kg CO₂ differences and UK electricity-price savings against a stated baseline.

Problem
The tools I reviewed show carbon forecasts or electricity prices, but do not combine them with weather and comfort into a named household schedule
Insight
Timing can change a task’s estimated carbon footprint; a named window and a stated baseline make that choice actionable
Solution
I built a planner scoring every 30-min slot over 48 h on carbon, price, weather and comfort, naming windows with modelled kg CO₂ differences in 3 cities and £ savings in the UK
Outcome
Live at climatique.app: the whole site is one small real-time planet whose sky, haze and robin follow the grid hour by hour, in 3 cities with 5 free data feeds. Savings are measured against the task’s own allowed hours, so the figures are small and defensible

From a grid forecast to a usable household schedule

An illustrative average-intensity calculation: a 4.2 kWh wash-and-dry cycle at 380 gCO₂/kWh is assigned about 1.6 kg CO₂; at 50 gCO₂/kWh, about 0.2 kg. These inputs demonstrate the calculation, not a promised daily range or measured household result. Average-grid accounting does not establish the marginal emissions actually avoided by shifting a task.

I reviewed eight tools before writing a line of code. NESO (formerly National Grid ESO) shows carbon intensity but has no price or scheduling. Octopus shows Agile prices but no carbon signal. Loop is historical only. Home Assistant requires hardware and technical setup. The gap: across the eight, none fuses carbon × price × weather × comfort into a named time window with a savings number ⁠— supplier-agnostic, hardware-free.

The gap is translation: a named window and an explicit comparison against a baseline, without specialist hardware

Climatique today: the whole front page is the planet, here on a London evening

Four weeks of research, no code ⁠— data sources, task profiling, scoring model design

November 2025 was research-only. Week 1: competitive audit of 8 tools and grid data source evaluation. Week 2: carbon API testing across UK, France and Belgium and data quality checks. Week 3: appliance energy profiling ⁠— real kWh draws for laundry, dishwasher, EV charging, ventilation. Week 4: scoring model design and architecture decisions.

For London, the app requests a 48-hour regional forecast from the UK Carbon Intensity API at 30-minute resolution. France (RTE éco2mix via ODRE) and Belgium (Elia ods192) publish actuals only, so I built a cyclical time-of-day proxy for their forward windows. Electricity Maps covers 50+ countries at 15-minute resolution but sits behind a paid tier. Open-Meteo handles weather for all three cities, free, no key required.

Belgium’s carbon input now comes from Elia ods192 actuals. The forward window uses a labelled time-of-day proxy, rather than the original weather-based carbon model.

From a data dashboard to a planet you can read

The interface went through three stages. The first organised city, priorities and task inputs around a large carbon-and-price chart. The October planner gave the recommendation a named time window and placed local conditions beside a rendered botanical meadow. Since 25 October the planner is the world itself: one full-screen planet, with the controls in glass panels over it. These screens show the design progression; they do not establish a measured improvement in usability.

Stage 1: the early dashboard, an archived iteration with illustrative forecast values

Stage 2, 10 October 2026: the planner beside a native Redshift meadow

A 4-axis scoring engine, a slide-window scheduler, and swappable data providers

The stack is deliberately minimal: FastAPI + Python backend, React + Vite frontend, pandas for the slot grid, SQLAlchemy over SQLite locally and Postgres in production. No message queue, no worker processes, no vector database. The optional Groq weekly brief is separate from the core planning request.

Each task receives a 0–⁠100 score per 30-minute slot. When price and task-specific weather data are both available, Green uses carbon 55%, price 10%, weather 35%; Save Money uses 10%, 55%, 35%; Balanced uses 33/⁠33/⁠34. Missing inputs use separate fallback weights. Comfort is a hard gate: a window that violates a constraint, such as rain during outdoor drying, is excluded. The sliding-window scheduler returns a primary window and a non-overlapping backup. A 48-hour horizon contains 96 half-hour slots per task, a small finite grid that supports an exact scan rather than a solver.

Provider calls are asynchronous (httpx) and cached per source. pandas joins the carbon, price and weather series, resamples hourly weather to half-hour slots and scores the grid: carbon, price and fit as vectorised columns, the weather sub-scores row by row. A timezone-aware index keeps local household hours separate from the UTC timestamps used by the feeds.

Named windows, real numbers, three cities ⁠— no hardware, no account required

Screens captured on 28 and 29 October 2026 from the live site with live data. The figures on them are that day’s forecast, not measured household savings. On the recommendation card the percentage compares grid intensity with the task’s earliest start; the kg and £ figures compare with the average of every allowed start and, for air-dried laundry, count the dryer you do not run, which is most of the saving.

climatique.app — live preview
Live demo
climatique.app
Open

Live ⁠— the dock shows the hour, its carbon, the UK generation mix and the next 48 hours; drag the sun or scroll, then ask for the cleaner hour

Input on the left, the answer on the right, the planet between them

On a phone the headline stacks above the planet and the top bar fits one row

The plan as a sheet; the percentage compares with the earliest start

Paris on 29 October: no grid forecast exists, so the card says the hours repeat recent days and how old the grid data is; no money figure without a price feed

Cost savings are UK-only: they come from Octopus Agile half-hourly prices, and France and Belgium have no equivalent free public price feed. The UI labels currency per city (£ vs €) so a figure is never misattributed. The overnight EV scheduler required two fixes ⁠— a naïve same-day constraint rejected post-midnight starts entirely, and a later code review surfaced a subtler bug that silently dropped the cleanest small-hours slots. The real fix gates on an absolute window-open instant, backed by a regression test. A reminder that “works on the happy path” and “is correct” are different claims.

The whole site is a tiny world that tells the time of the grid

The planet is the answer made visible. The sun stands where it really stands for the selected city, placed by an astronomical formula; the moon shows its phase to within about a day and the stars and meadow follow the season. Haze follows the absolute carbon intensity, clear at 30 gCO₂/kWh and full at 350, because the planner’s own score is relative to the 48-hour window and would make Paris’s very clean grid look smoggy. The relative score drives how much the flowers bloom instead.

Noon, clean air: a frame from the live world, not a render

The same code at 350 gCO₂/kWh or more: the haze shows how dirty the power is, not air quality

The robin is a European robin I modelled, rigged and animated in Cinema 4D, exported as glTF and compressed to about 319 KB as served. It lives by the planet’s clock: it pecks by day, sings at dawn and sleeps at night. When you ask for the cleaner hour it searches from its post while the plan loads, then flies a quick lap of the planet, lands and sings through the recommended window as the flowers bloom. Wind, rain and frost change its posture.

The robin on its post, close up in the live world

Around it: an opt-in soundscape generated on the spot with the Web Audio API (wind, rain, a grid hum that gets rougher with the haze, birds that follow the robin), a share postcard rendered by a second offscreen world, a short time-lapse that sweeps the world’s clock to the recommended hour, a generation-mix strip for London, and a /story page that explains where the numbers come from. A quality ladder protects the device: the world takes over from the poster only above 50 fps on desktop or 28 fps on a phone, steps the pixel ratio down when frames slow, and returns to the poster rather than stutter. The mobile profile stays under 380,000 triangles.

A living meadow, built in Cinema 4D and rendered with Redshift

The planet gives an abstract carbon signal a tangible, living form. I assembled the scene in Cinema 4D from botanical plant meshes: a continuous clover groundcover, grasses, lavender clusters, white daisies, small yellow flowers and pink clover heads. Variations in scale, rotation and grouping break up repetition while the low planting layer closes gaps in the spherical surface.

Final native Redshift frame ⁠— layered planting and soft directional light

Cinema 4D working viewport ⁠— lightweight previews keep the dense scene manageable

Multi-Instance cloners reuse the plant geometry instead of duplicating it across the sphere. A warm upper-left light, broad frontal bounce and soft sky fill separate flowers from the foliage. The wind animation bends the planting with varied phases while keeping roots anchored; the native loop contains 240 frames at 30 fps, rendered from a 1024 × 1024 source.

The 8-second Redshift wind loop, exported from the native frame sequence

The Redshift render was the planet’s first face. Today the poster you see before the real-time world starts, and the fallback if it cannot run, is a still of the live world itself. The live planet is a new three.js build rather than a conversion of the Redshift scene: procedural plants drawn as instances, wind in a vertex shader, and the meadow and cloud atlas grown in a web worker off the main thread.

The same visual system, from the planner to the smallest screen

The Seasons 700 headings, Manrope body text and Streamline Flex Line icons bring the product into one type, spacing and control system. Selected modes keep the same label wrapping and dimensions. Compact settings and task editing share a dialog with browser Back and focus recovery; the tour tracks the visible target as the layout changes. The 404 page uses the same identity and provides a clear route back.

10 October release: narrow-screen homepage ⁠— type hierarchy and native artwork remain readable

A real HTTP 404 with a clear return action

The October release passed automated keyboard, contrast, responsive, route and security checks in addition to the application tests. A short instrumented check on an iPhone 15 Pro confirmed the mobile renderer runs. Spoken VoiceOver/NVDA checks, finger scrolling with the moving Safari toolbar and broader loading-performance work remain open; this is an engineering and expert review, not a participant usability study or an accessibility certification.

Deleting my own model when the real data disagreed

Belgium originally used a weather-based carbon model because a free forward-looking feed was not available in the integration. The current provider instead reads Elia ods192 consumption-based actuals and builds a labelled time-of-day proxy for future slots. I removed the weather-based carbon path so it could not silently return as a fallback. The source is traceable, while the forward window remains a pattern estimate rather than a forecast from the grid operator.

A smaller decision runs through the whole scheduler. A slot that violates a hard constraint, such as rain during outdoor laundry drying, is excluded outright rather than penalised in the score. A penalty keeps a bad slot rankable and lets a good-looking total recommend something the user obviously cannot do. Exclusion is less elegant and harder to tune. It is also why recommendations survive contact with the weather.

The overnight EV scheduler is where that principle was hardest to hold. A naïve same-day constraint rejected post-midnight starts entirely, and a later code review surfaced a subtler bug that silently dropped the cleanest small-hours slots, which are the exact hours the feature exists to find. Both were fixed rather than tuned around. A scheduler that quietly skips the best answer is worse than one that admits it has none.

Smaller numbers I can defend

An audit on 28 October changed what the planner claims. Savings used to be compared with the UK evening peak, 17:00–⁠20:00, whatever the task; that made an overnight EV charge look like it saved 0.55 kg CO₂ and £1.43. Savings are now compared with the average of all the hours the task was allowed to run in, which brings the same charge to roughly 0.1 kg and about £0.01, depending on the day’s forecast. I withdrew the earlier annual estimate (~£184 and ~68 kg CO₂ for a London household) because it rested on the old baseline. Paris and Antwerp now say how old their grid data is, treat data older than 48 hours as stale, and the weekly outlook only ranks days that have a real forecast.

The 7-day outlook after the audit: only days inside the 48-hour forecast get a carbon score; the rest say “no carbon forecast” instead of guessing

What I would do differently: choose the honest baseline first and instrument the feedback loop earlier. Browser-scoped history supports “Followed” and “Not followed” responses with owner checks, but that does not establish real savings. Next: validate recommendations with participants, run a mock jury before award submissions, and investigate local price feeds for France and Belgium.

Build facts, updated 29 October 2026: a 6-month core build, then the real-time world from mid-October. 3 cities (London, Paris, Antwerp), 5 task types and 5 free-tier data sources. Lighthouse 12 mobile on production behind Cloudflare scored 78–⁠82 across eight runs on 28 October (LCP 3.3–⁠3.8 s); the 90 target is not met yet. Self-hosted on Coolify with internal Postgres and nightly database backups; no data subscription costs.

Sources

Next project
Wanderwort