engine/theme_feed library

The swipe feed (spec §5.2, §6.1, §6.2; design doc theme_feed.dart): a history stack where back returns the exact previous theme, next / previous, a hero every 8–12 new themes (seeded), a family filter, a 3-ahead prefetch hook, the lock, and the theme of the day.

Pure Dart and deterministic: the feed stores FeedEntry recipes, not specs. Step k of a feed (the k-th new theme) is a pure function of (feed seed, k, filter at the time), so ThemeFeed.upcoming can predict exactly what ThemeFeed.next will return. State round-trips through ThemeFeed.toJson / ThemeFeed.fromJson for persistence.

Engine v4 adds steering: ThemeFeed.steer sets a ThemeIntent, and every new theme after it is generated under it (no heroes), the first one centred on the intent. Entries carry their intent, so history keeps working after the intent changes.

Classes

FeedEntry
A reproducible recipe for one theme: a generated (seed, family, engineVersion , intent, centred) or a hero id.
FeedFilter
Which families the feed draws from (spec §6.1): "Surprise me" (every enabled family) or a chosen set.
ThemeCache
A small LRU of resolved specs, so prefetched themes are ready when the user swipes (generation is < 2 ms, but a commit frame should not pay it).
ThemeFeed
The swipe feed. Mutable; one per app (the theme controller owns it).

Constants

dailyEngineVersion → const int
Generator version the theme of the day uses: fixed, so every app version that has it shows the same theme on the same date (research §11.3). Bump deliberately.
dailyFamilies → const List<ThemeFamily>
Families the theme of the day rotates through under dailyEngineVersion (fixed: enabling new families must not change past or future days of this version).

Functions

localDayIndex(DateTime local) → int
Days since 1970-01-01 of the local calendar date of local (flips at local midnight; exact on the web).
themeOfTheDay(DateTime localDate) → FeedEntry
The theme everyone gets on localDate's calendar day: Rng.stream(localDayIndex, 'daily').

Typedefs

PrefetchHook = void Function(List<FeedEntry> upcoming)
Callback with the next themes the feed will show (prefetch them).