Pick a crate of lager, shandy or cider and we will knock 50% off a box of crisps. Take the crate
The mechanism

Render the season. Then, if it turns up, render the weather.

The whole layer is one rule expressed twice: the seasonal default is computed at build time from the server clock and is always correct, and every live value hydrates in afterwards without ever being allowed to block the first paint.

The rule

The degradation rule, in four steps.

  1. Build time: the season is stamped into the HTML

    dse_season() reads the server month and returns spring, summer, autumn or winter. That value is written onto the root element as data-season and onto the body as a season- class before a byte leaves the server.

    The CSS for all four states ships in the same stylesheet. Switching state is one attribute redefining two custom properties, which costs nothing and cannot fail.

    No request, no fetch, no flash of the wrong colour.

  2. First paint: the page is already complete

    At this point the palette is right, the illustration set is right, the ambient line is the seasonal default, and every placeholder occupies exactly the box its live value will occupy.

    If the visitor closes the tab here they have seen a correct page. That is the bar.

  3. After first paint: live values hydrate in place

    Weather, crop stage and yield are fetched after the page is interactive and replace their placeholders in the same boxes. There is no layout shift because there is no new content, only better content in an existing slot.

    Each has a cache in front of it. Fifteen minutes for the weather, an hour for the yield, twenty-four hours for the crop stage.

  4. On failure: nothing happens, visibly

    If a feed times out, errors, or returns nonsense, the placeholder simply stays. No spinner, no error state, no retry loop, and above all no stale reading presented as current.

    If the weather API is down the site looks like the season it is. Most people would not notice, and the ones who did would be looking at a page that was still entirely usable.

    The failure mode of this layer is: it looks slightly less clever.

01/ 03
The build

Three implementation decisions that make it work.

The season is server-side, everything else is not

Putting the season in JavaScript would mean a flash of the wrong palette on every cold load, on every page, forever. Putting it server-side costs one function call and removes the problem entirely.

Everything else is deliberately client-side, because everything else is optional.

Season
Server-side, always
Live values
Client-side, optional

Placeholders are the same shape as the real thing

The ambient line has a seasonal default of the same length as a weather line. The ticker has five lines whether or not the weighbridge is talking. The crop-stage illustration has a seasonal default frame.

That is why hydration causes no reflow: nothing is being inserted, only replaced.

Layout shift
None
Spinners
None

One function owns all five inputs

Every live number on this site is produced by a single PHP function that currently returns deterministic seeded values. Nothing else in the theme reads a feed.

Replacing the placeholders with the Met Office, the weighbridge and the ops entry means rewriting that one function. That is the entire integration surface.

Integration points
One
Files that read a feed
One
The numbers

Caching, in full.

Time to live

Date and season
no TTLSystem clock, server-side
Weather at OX7
15 minMet Office DataPoint or equivalent
Crop growth stage
24 hFarm ops entry
Live yield
1 hWeighbridge, or an ops entry when the bridge is down
Series window
no TTLManual flag

Why those numbers

Weather, 15 minutes
Nobody needs to know it started raining ninety seconds ago
Yield, 1 hour
The weighbridge produces a number every few loads, not continuously
Crop stage, 24 hours
A growth stage that changed in an hour would be a data error
Season, no TTL
It is the clock
Series window, no TTL
It is a flag a person sets, and it changes four times a year

Failure behaviour

Timeout
Placeholder stays. No retry storm
Error response
Placeholder stays. Logged, not surfaced
Stale cache
Served, and only until the TTL expires
Expired and unreachable
Falls back to the seasonal default, not to the stale value

The last row is the one that matters. An expired reading is worse than no reading, because a wrong temperature presented confidently is a lie and an absent one is merely quiet.

All five

What each input changes, and what happens without it.

InputWhat it changesTTLWithout it
Date and season Field palette and illustration set no TTL Cannot happen
Weather at OX7 Sky treatment and ambient copy 15 min Seasonal sky, seasonal line
Crop growth stage Beast and crop illustration stage, Plotting status 24 h Seasonal default stage
Live yield The ambient ticker 1 h That ticker line is omitted
Series window Second-screen mode no TTL Defaults to closed

The one rule, stated once more

Live data must never block first paint. The seasonal default renders at build time and is always correct; live values hydrate afterwards or they do not. If the weather API is down, the site simply looks like the season it is.

The five feeds

The layer, in four lines

Build time

The season, stamped server-side.

Runtime

Weather, crop stage and yield, hydrated after paint.

Failure

Placeholder stays. No spinner, no error, no stale value.

One function

The entire integration surface.

The two palettes it moves between.

One follows the season. The other deliberately does not.

Next along the route

The field palette

Carry on
Basket Book the pub Plot a field Join the list Bother us

Snooping, briefly.

We use a small number of cookies to keep your basket upright and to work out which pages people actually read. We do not sell anything about you to anyone, because that would be a rotten way to behave.

Read the detail