Generator: raise the early bot-win-rate floor to ~0.97 (near-guaranteed first
stages), widen the early move-buffer margin, and delay score-chase/line-sprint
objectives until stage 9/13 so the opening stretch is pure clear-a-gem. Result:
stage 1 now 16 moves (was 11), stages 1-9 all simple gems at 90-99% bot win.
Preserves theme.bgm=season_001; manifest SHA regenerated. Settings tag -> build 4.
- activeSeason now returns the first season (Season 1 'First Bloom') so a new
player starts at spring instead of the newest season.
- Bundle the owner-picked CC0 tracks menu.mp3 + season_001.mp3 (BGM now audible).
- Settings footer shows 'v1.0.0 (build 3)' so test builds are identifiable.
180 tests green, analyze clean.
MusicService (looping audioplayers player, independent of SFX) driven by the
active season theme's new 'bgm' key; switches track on season change, pauses on
app background, all failures swallowed. Separate Music on/off toggle in Settings
(persisted, independent of SFX). Season packs carry bgm keys (menu/season_001/
season_002), manifest regenerated. Assets slot assets/audio/bgm/ ready — drop in
menu.mp3/season_001.mp3/season_002.mp3 (CC0) and it plays; silent until then.
180 tests green, analyze clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
On device the floating top-left X (48px IconButton) overlapped the HUD moves
chip. Move it into the column flow above the HUD, left-aligned, so it never
collides. Found via on-device test build.
Replaces the TODO_REAL_* ad-unit placeholders with the owner's real AdMob
console ids (publisher pub-5605900229781491) and the native AdMob app ids
(iOS ~8397095848, Android ~8257495040) in place of the Google sample ids.
Debug builds still serve Google test ads via kDebugMode; release builds now
use the real units.
Step-by-step owner guide to register the AdMob apps + 6 ad units, create the
remove_ads IAP in both stores, and the exact values to send back so the
TODO_REAL_* ad ids and native AdMob app ids get swapped in.
The flutter_test default font draws every glyph as a box, so the wordmark was
unreadable. Load the OFL Titan One TTF via FontLoader in the generator and
render 'Block Seasons' + tagline with it; fit the text within the 1024 width.
Font used only by the asset generator, not bundled in the app.
Adds PressableScale (0.94 squish on tap-down) around the Adventure
FilledButton, Classic OutlinedButton, and each season-map stage node.
Replaces all in-app MaterialPageRoute pushes with a gentle fade+scale
PageRouteBuilder (320ms in, 240ms out) via a new fadeRoute helper.
Introduces AppIconMark (navy gradient field + 2×2 glossy blocks reusing
paintGlossyTile) and a testWidgets generator that writes icon.png,
icon_background.png, and icon_foreground.png to assets/icon/ for the
upcoming flutter_launcher_icons task.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
AdMob ads (interstitial/rewarded/banner) with a pure-Dart frequency policy,
a compliant UMP->ATT->init consent flow, and a remove_ads non-consumable IAP
with Restore. Single repo-backed ownership source (adsRemovedProvider); all
ad/IAP/consent failures swallowed. Runs on Google test ids today; owner swaps
real ids by config. 169 tests green; opus final review passed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
iapServiceProvider was lazy and only read by Settings, so the purchase stream
attached only after opening Settings — deferred/interrupted/restored
transactions wouldn't be delivered or completed until then. Read it in the
post-frame callback so the stream is live for the whole session.
On a cold start the consent flow is still running when home first builds, so
createBanner returns null and the slot stayed empty until a rebuild. AdService
now exposes an isReady ValueNotifier; BannerAdSlot listens and retries its load
once MobileAds finishes initializing. Verified: analyze clean, 169 tests green.
pod install for google_mobile_ads added Google-Mobile-Ads-SDK 12.14.0 and a
[CP] Copy Pods Resources build phase. Tracking both keeps the build
reproducible (follow-up to 245a065).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Firebase Analytics SDK initialized on the iOS simulator; debug build renders
gameplay and (per system log) disables GA4 collection. Evidence for the
analytics wiring milestone.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
setAnalyticsCollectionEnabled(kReleaseMode) after Firebase init so the native
SDK's automatic events (session_start, screen_view) stay out of production
analytics in debug too — not only our custom events. Verified on simulator:
release builds collect, debug builds do not.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
flutterfire configure registered the iOS/Android apps under project
block-seasons and generated firebase_options.dart + native config. main()
now initializes Firebase and routes analytics through FirebaseAnalyticsBackend
in release builds (console logger in debug, so dev traffic never pollutes
GA4). Firebase init is guarded — failure falls back to the debug logger
rather than blocking startup.
firebase.json keeps the existing Hosting config and gains the FlutterFire
platform section. Client config files are committed (they ship in the binary;
Firebase security is enforced by rules, not config secrecy).
flutter analyze clean, all 161 tests green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
firebase_core 4.x bundles the Firebase iOS SDK which requires iOS 15.0+.
Sets the Podfile platform and the three Xcode build configs accordingly.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds firebase_core + firebase_analytics and a FirebaseAnalyticsBackend that
adapts the existing AnalyticsBackend interface to GA4. Kept in its own file
so the typed AnalyticsService and DebugAnalyticsBackend stay free of the
firebase dependency (unit tests never pull in platform channels).
Not yet wired into main() — that needs lib/firebase_options.dart from
flutterfire configure (owner step). All 161 tests still green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
firebase init hosting wired to project block-seasons, public dir = deploy.
Generated season payload (deploy/content/) and CLI cache (.firebase/) are
gitignored — content/ is the source of truth, regenerated by the deploy
script in docs/firebase-hosting-guide.md.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>