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.

Classes

FeedEntry
A reproducible recipe for one theme: a generated (seed, family, engineVersion) 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).