41 Commits

Author SHA1 Message Date
airkjw 41b9a14c0c Merge Phase 3.5: commercial polish round
Glossy tiles + season theme system, juice kit, intro flow
(splash/season card/tutorial), serpentine journey map,
endless classic mode, redesigned home.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 07:39:27 +09:00
airkjw f9eaa3ae59 docs: polish round simulator screenshots (splash, season card, home)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 07:39:19 +09:00
airkjw c59454aa5f fix: center splash logo and wordmark (stack was sized to children)
Wrap AnimatedBuilder in SizedBox.expand so the Stack fills the full
Scaffold body; alignment: Alignment.center now centers within the whole
screen instead of within the wordmark-sized intrinsic box.

Adds a regression widget test (test/ui/splash_screen_test.dart) that
asserts the wordmark dx is within 1px of screen-center at 1500ms into
the animation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 07:37:54 +09:00
airkjw bf7720ebd3 fix: clear season flow when starting Classic so tutorial/theme can't leak
- Add SeasonFlowNotifier.clear() to null out the flow state
- Call clear() in HomeScreen's Classic button before startStage()
- Broaden tutorial-end guard to next.phase != GamePhase.playing (covers stuck)
- Add regression test: clear() resets flow to null

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 07:33:41 +09:00
airkjw 26adf98d73 fix: guard home buttons against double-tap double-push 2026-06-12 07:22:18 +09:00
airkjw 94e62d3e41 feat: redesigned home with adventure/classic entries and endless best
Add adventure/classic l10n keys; rewrite HomeScreen with SeasonBackground,
2×2 glossy logo mark, Adventure→SeasonMap + Classic→endless GameScreen buttons,
and conditional best-score caption. Update widget_test assertions accordingly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 07:18:42 +09:00
airkjw 5a84a47cd4 fix: keep HUD balance in endless via invisible moves chip
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 07:13:47 +09:00
airkjw fea8336391 feat: endless mode UI - game over card, best score, HUD 2026-06-12 07:06:30 +09:00
airkjw c5e9029cad test: relax endless survival bound to >30 (proves no cap, seed-robust) 2026-06-12 07:01:22 +09:00
airkjw 6c76837ab6 feat: endless score-attack mode in the engine
Add StageConfig.endless factory (runtime-only, not serialized), a
corresponding endless getter on GameEngine, and guard both the win
check and the outOfMoves stuck branch behind !_stage.endless so
endless runs can never be won or move-limited. Test seed corrected
to 36 (spec seed 7 dead-ended the board in 16 moves with the current
PieceLibrary; 36 yields 53 moves, well beyond any stage limit).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 06:53:02 +09:00
airkjw 2b44dcd812 fix: journey map season-complete styling, scroll callback guard, palette constant
- Guard addPostFrameCallback with !_autoScrolled so it only fires once per
  widget lifetime instead of on every LayoutBuilder rebuild.
- Derive seasonComplete flag; pass it into _node so the last stage uses
  gold "done" styling (not "current/next") when the season is fully 3-starred.
- Extract const Color(0xFF232B4A) to GamePalette.lockedNode.
- Remove warnIfMissed: false from tap call in season_map_screen_test; ensureVisible
  already guarantees hit-testing succeeds (confirmed: test still passes cleanly).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 23:30:22 +09:00
airkjw 78eb5c0639 feat: serpentine journey map with auto-scroll and glowing current node
Replaces the plain GridView with a Candy-Crush-style journey map:
dotted serpentine path, circular nodes (gold=done, glowing=current,
dark+lock=locked), glass header, auto-scroll to current stage.
Updates season_map_screen_test to use Key('stage_node_$i') finders.
2026-06-11 23:17:41 +09:00
airkjw 96304cc8a7 feat: serpentine map layout function 2026-06-11 23:12:29 +09:00
airkjw ee364cc2e2 fix: dismiss tutorial when the stage ends
A finished stage ends the tutorial; otherwise the overlay would sit
on top of the result card and leak into the next stage.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 23:11:13 +09:00
airkjw 963d0d5dd6 feat: first-play interactive tutorial overlay
Add TutorialOverlay widget (dim veil, message bubble, animated hand on
dragPiece step, skip button) and wire it into game_screen: start on
flow.index==0 when tutorialDone is false, forward onPlaced/onLineCleared
events unconditionally from fxTick handler, and compute hand-path
coordinates from board/tray RenderBox geometry.
2026-06-11 22:58:14 +09:00
airkjw 3d1f3b30c7 feat: tutorial step state machine with persistence
Adds TutorialNotifier (dragPiece → clearLine → explainHud → null) backed
by SaveRepository.markTutorialDone(); out-of-order events are silently
ignored. Registers tutorialProvider in providers.dart.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 22:50:49 +09:00
airkjw f97b4faad7 fix: bail to home when season list is empty on title card 2026-06-11 22:48:17 +09:00
airkjw 9fe1910d12 feat: season title card on cold start
Shows "SEASON 1 / First Bloom / N stages" over the season background for
~1.6s between splash and home; tap anywhere skips. Bails to home on
content-load error. Adds seasonLabel/seasonStages l10n keys (en + ko).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 22:43:20 +09:00
airkjw 3f34358137 refactor: splash nextScreen as constructor param instead of mutable static
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 22:39:04 +09:00
airkjw 189ab469af feat: logo-assembly splash screen and native launch colors
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 22:30:04 +09:00
airkjw 944c5733c9 fix: defensive keys and overflow guard in result overlay
- Add ValueKey(i) to each TweenAnimationBuilder in the star animation loop
  to prevent Flutter from reusing widget state during rebuild cycles
- Add maxLines: 2 and overflow: TextOverflow.ellipsis to the almostThere
  Text widget to prevent overflow in the loss-state progress message

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 22:27:14 +09:00
airkjw 677a09f8cb feat: staggered star reveal and near-miss progress ring
Stars on win now appear sequentially with elastic-bounce via
TweenAnimationBuilder (400/650/900 ms). Lost overlay shows a
CircularProgressIndicator ring with "87% complete!" (l10n:
almostThere) when objectiveProgress > 0.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 22:20:29 +09:00
airkjw f1b8052f77 fix: re-anchor effects clock when ticker drains (stale-clock freeze)
After Ticker.stop(), elapsed resets to zero on the next start(). _now was
left frozen at the old elapsed, so effects added after a drain captured a
stale start time and their progress() clamped to 0 forever — ticker never
stopped, second batch broken. Fix: reset _now = Duration.zero on drain.
Adds @visibleForTesting getters and a regression test that catches the
stale value directly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 22:16:51 +09:00
airkjw 8c3c2ae9a9 feat: juice kit - sparks, score popups, combo banners, confetti, haptics, shake
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 22:05:14 +09:00
airkjw d985d40f09 feat: persist tutorial completion and endless best score
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 21:25:55 +09:00
airkjw 6b796b6d1d perf: cache ThemeColors across frames; theme-tint leaf particles
Fix 1: Stop allocating ThemeColors on every animation frame by caching it in
_colors field and updating only when theme changes via didUpdateWidget.

Fix 2: Leaf particles now follow the season accent color instead of hardcoded
orange, maintaining visual consistency with theme changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 21:24:08 +09:00
airkjw 6e4d3b60df feat: procedural season background with drifting petals 2026-06-11 21:17:12 +09:00
airkjw d283bf6959 fix: include flash rows/cols in BoardPainter.shouldRepaint
The shouldRepaint override was omitting flashRows and flashCols comparisons,
which could cause the painter to skip redraws when these lists changed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 21:13:01 +09:00
airkjw 8739fc0e26 feat: glossy tile rendering and per-season theme colors
Introduces candy-gloss tile rendering (diagonal gradient + glass highlight
+ optional glow) via a shared paintGlossyTile() in tile_painter.dart,
applied to board filled-cells and tray/drag-overlay pieces. Adds
ThemeColors to palette.dart for UI-layer season color resolution, and
activeThemeProvider for one-call access to the active season's theme.
Regenerates the game_screen golden to reflect the new look.
2026-06-11 21:06:26 +09:00
airkjw 6bb1eac28c fix: tolerate num-typed JSON color entries in SeasonTheme 2026-06-11 21:02:23 +09:00
airkjw e866de189d feat: extend SeasonTheme with visual identity fields (ARGB ints)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 20:58:48 +09:00
airkjw a69120e46b docs: add Phase 3.5 commercial polish implementation plan
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 20:52:26 +09:00
airkjw 1397746845 Add Phase 3.5 commercial polish design spec
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 20:38:27 +09:00
airkjw 607278928b Add daily streak system and normalize bundle id to com.airkjw.blockseasons
Pure advanceStreak (1-day grace none, milestone flags at 3/7/14/30),
persisted in the save blob; StreakNotifier advances on every finished
attempt; home screen flame chip and milestone snackbar. Fix flutter
create's camelCased iOS bundle id and underscored Android application
id to the agreed lowercase form before any store registration.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 17:25:39 +09:00
airkjw 7bc26447f7 Wire season flow: map screen, progress save, win recording, next stage
SaveRepository (versioned JSON over prefs) with best-result merging and
unlock walking; ContentRepository loads the bundled pack; SeasonFlow/
Progress notifiers orchestrate stage start -> win record -> advance.
Season map grid with stars/locks, Home -> Map -> Game navigation,
close button, next-stage action on the win overlay.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 17:04:45 +09:00
airkjw 41c18c8bdd Add AutoPlayer bot, stage generator CLI, and calibrated Season 1 (60 stages)
Greedy bot with tray-survival lookahead and gem-line steering; generator
samples layouts along a difficulty curve, probes bot moves-to-win, sets
adaptive move budgets targeting win-rate bands, and derives star
thresholds from spare-move quantiles. Season 1 pack bundled in assets
with per-stage difficulty report.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 13:56:54 +09:00
airkjw ad6689b42f Add synthesized SFX and audio wiring
Pure-Dart WAV synthesizer (tool/gen_sfx.dart) generates place/clear/
combo/win/lose effects; AudioService player pool fires on placement,
line clears, combo streaks, and phase transitions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 13:28:02 +09:00
airkjw 3138fc4b08 Add playable core UI: board painter, drag-and-drop, HUD, result overlay
CustomPainter board with gems/ghost/clear-flash, finger-lifted drag
with snap preview, combo text effect, HUD chips, phase overlays with
rescue stubs, demo stage. E2E widget test drives a real drag gesture.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 13:19:34 +09:00
airkjw 62cbb4b16a Add objectives, stage config, and GameEngine session core
Sealed Objective types (clearGems/reachScore/clearLines) with JSON
round-trip; StageConfig with preset cells and star thresholds;
GameEngine orchestrating placement -> clear -> scoring -> objectives
with stuck detection, one-shot rescue (continue / +5 moves), and
deterministic per-attempt RNG. 100-game headless stress test and
pure-Dart architecture guard. 76 tests green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 13:11:31 +09:00
airkjw 0210c14858 Add pure-Dart engine core: RNG, grid, placement, line clear, scoring, piece generator
PCG32 seeded RNG; immutable 8x8 GridState with occupancy bitmask;
placement legality + anyPlacementExists; simultaneous row/col clears
with single-count gem credit; combo scoring with one-move grace;
weighted-bag generator with pity bias and depth-3 solvability nudge.
All TDD, 51 tests green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 13:05:55 +09:00
airkjw 40528238b2 Scaffold Block Seasons Flutter app
flutter create (com.airkjw.blockseasons, iOS+Android), Riverpod,
shared_preferences, audioplayers, gen-l10n EN/KO wiring, app shell
with Home -> Game placeholder.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 12:55:59 +09:00