Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,14 @@ Quest stages may pin the FIRST tray via the stage's `tray` field (the
"opening break" design — see CONTRIBUTING_QUESTS.md); the generator
takes over from the second tray on.

**Quest gem stages** (`GameState.gemGoal` non-empty): gems ride on the
generated tray pieces rather than being pre-placed. After drawing a tray,
`assignGems` attaches gems to some pieces, drawing colors only from those
still needed (goal − collected); a color that's fully collected stops
spawning. A placed gem is collected when a line through it clears
(`GameState.trayGems` carries the pending gems per tray slot). Goals can
exceed what's ever on the board, and over-collecting is fine (win is ≥).

**Classic clear-focus** (`GameState.clearFocus`, set by the classic
controller): the same generator, turned up for maximum clears/combos.
Breakers are boosted ~9×, near-empty boards favor big/long pieces (to
Expand Down
18 changes: 13 additions & 5 deletions CONTRIBUTING_QUESTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,24 @@ Piece ids are the entries in `lib/models/piece_catalog.dart` (`single`,
|------|---------|
| `.` | empty cell |
| `0`–`7` | block in palette color 0–7 (red, green, orange, yellow, blue, purple, cyan, pink) |
| `r` `b` `p` `y` `g` | gold block holding a red / blue / purple / yellow / green **gem** |
| `r` `b` `p` `y` `g` | light tile holding a red / blue / purple / yellow / green **gem** |

Gems are collected when any completed line containing them clears.
Gems are collected when any completed line containing them clears. For a
gem GOAL you normally leave these out of the board entirely — gems come
from the tray (see Goals). The gem letters remain available if you want a
few decorative pre-placed gems, but they are not required and not counted
toward what's reachable.

### Goals

- Score: `{ "type": "score", "target": 700 }` — reach the score.
- Gems: `{ "type": "gems", "counts": { "red": 2, "purple": 3 } }` —
collect all listed gems. Every color you require must actually exist on
the board in at least that quantity.
- Gems: `{ "type": "gems", "counts": { "red": 8, "purple": 6 } }` —
collect *at least* the listed count of each color. Gems ride on the
generated tray pieces (spawned only for colors you still need), so the
goal does NOT depend on gems being pre-placed on the board — you don't
put gems in the board at all for a gem goal, and counts can be large.
Collecting more than the goal is fine. Once a color is fully collected
it stops appearing on new pieces.

### Rules the validator enforces

Expand Down
16 changes: 16 additions & 0 deletions PROGRESS.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,22 @@ lose-screen/80%-banner visual eyeballing during play, a CI workflow
- Session ended mid slice-D device verification at user request; all
code committed on `dev`, working tree clean, 43/43 tests green.

### 2026-07-16 — Gems ride on tray pieces (quest gem stages reworked)
- User: pre-placing all gems on the grid made stages swingy and capped
goals low. Now gems spawn on generated tray pieces (assignGems, ~50%
of pieces carry one, big pieces sometimes two), drawing only colors
still needed; a met color stops spawning; over-collecting is fine.
A placed gem is collected when a line through it clears.
- Model: GameState gains trayGems (per-slot cell→color) + gemGoal;
placement.stampWithGems; engine threads gems on place/refill; the
controller passes the goal; board renders placed gems in the piece
color (pre-placed stay light); tray pieces show their gems.
- Validator: dropped the "board must contain the goal's gems" rule
(obsolete); added a gem-count sanity range. All 20 gem stages had
their board gems stripped and goals raised (single 8 / two 6 / three 5).
- Workflow: per user, land on dev only from here — no auto-promote to
main (they promote later). See memory no-auto-promote-to-main.

### 2026-07-16 — Playtest round 5: 7 polish items
- Ghost dial-back: nearest-legal snap capped to a 1-cell radius (catches
grid-line straddling, no longer teleports onto far gaps; over occupied
Expand Down
2 changes: 2 additions & 0 deletions SAVE_MODEL.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ silently discarding progress.
"roundBestCombo": 7,
"allClears": 1, // this run; absent in old saves -> 0
"clearFocus": true, // classic mode's easy-clears dealing
"gemGoal": {"red": 8}, // quest gem stage target (else absent)
"trayGems": [{"0": "red"}, {}, {}], // gems on each tray slot (else absent)
"gems": {"red": 1} // collected this run (quest only)
}
```
Expand Down
6 changes: 3 additions & 3 deletions content/quests/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,21 @@
"title": "First Steps",
"release_date": "2026-07-01",
"file": "packs/starter.json",
"checksum": "770475f32eaa716e132fb1de37d1c3cf8cfa53904d018101e77e92a8969ffdfa"
"checksum": "8c70a5bdbc7a9a059ef8f106e7d70e5a3dd45f7664f511cd989f5d17f4aae400"
},
{
"id": "deep-dig",
"title": "Deep Dig",
"release_date": "2026-07-05",
"file": "packs/deep-dig.json",
"checksum": "8578afdf6304fd3fe8ca1281fb2b2387ab5de383b36b417278d2a437bc518a80"
"checksum": "eefa0748debb175ecb710141bb39e4b207fa3850162ad0b746b496c0615690b7"
},
{
"id": "treasure-trail",
"title": "Treasure Trail",
"release_date": "2026-07-26",
"file": "packs/treasure-trail.json",
"checksum": "f0b78a9ea566c9b5af0a410e06fb4f4e40b58931536ba329de4764f8c2facc9f"
"checksum": "c4e1c2d4edd1831459d9b263a5eb91739d50a3fc9eca2daa67af5553115af2b9"
}
]
}
94 changes: 47 additions & 47 deletions content/quests/packs/deep-dig.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,18 @@
"id": "d02",
"board": [
"........",
"..b.....",
"..3.....",
"........",
"........",
"3b33.333",
"44..44b4",
"3333.333",
"44..4434",
"44..4444",
"111...11"
],
"goal": {
"type": "gems",
"counts": {
"blue": 3
"blue": 8
}
},
"tray": [
Expand Down Expand Up @@ -75,19 +75,19 @@
"id": "d04",
"board": [
"........",
".g....r.",
".3....3.",
"........",
"........",
"3333.333",
"77g7.777",
"7737.777",
"777..777",
"1r11...1"
"1311...1"
],
"goal": {
"type": "gems",
"counts": {
"green": 2,
"red": 2
"green": 6,
"red": 6
}
},
"tray": [
Expand Down Expand Up @@ -121,19 +121,19 @@
{
"id": "d06",
"board": [
"...p....",
"...3....",
"........",
"........",
"000..000",
"3333.333",
"5p5...55",
"55p...55",
"5p5...55"
"535...55",
"553...55",
"535...55"
],
"goal": {
"type": "gems",
"counts": {
"purple": 4
"purple": 8
}
},
"tray": [
Expand Down Expand Up @@ -167,19 +167,19 @@
{
"id": "d08",
"board": [
"y.......",
"3.......",
"........",
"........",
"000..000",
"3333.333",
"444.y444",
"444.3444",
"444..444",
"4y44.444"
"4344.444"
],
"goal": {
"type": "gems",
"counts": {
"yellow": 3
"yellow": 8
}
},
"hard": true,
Expand Down Expand Up @@ -214,20 +214,20 @@
{
"id": "d10",
"board": [
"..r..b..",
"..3..3..",
"........",
"........",
"111...11",
"3r33.333",
"77..7r77",
"777.7b77",
"3333.333",
"77..7377",
"777.7377",
"........"
],
"goal": {
"type": "gems",
"counts": {
"red": 3,
"blue": 2
"red": 6,
"blue": 6
}
},
"tray": [
Expand Down Expand Up @@ -262,20 +262,20 @@
{
"id": "d12",
"board": [
".p....g.",
".3....3.",
"........",
"..g.....",
"..3.....",
"111...11",
"3g33.333",
"5p55.555",
"3333.333",
"5355.555",
"555..555",
"5p5.5555"
"535.5555"
],
"goal": {
"type": "gems",
"counts": {
"purple": 3,
"green": 3
"purple": 6,
"green": 6
}
},
"hard": true,
Expand Down Expand Up @@ -311,19 +311,19 @@
{
"id": "d14",
"board": [
"r.......",
"3.......",
"........",
"........",
"3333.333",
"7r..7777",
"7r.77777",
"00r00.00",
"0000r.00"
"73..7777",
"73.77777",
"00300.00",
"00003.00"
],
"goal": {
"type": "gems",
"counts": {
"red": 5
"red": 8
}
},
"hard": true,
Expand All @@ -336,23 +336,23 @@
{
"id": "d15",
"board": [
"r.......",
"3.......",
"........",
"........",
"3333.333",
"1b...111",
"111.g111",
"44y4..44",
"444..4p4"
"13...111",
"111.3111",
"4434..44",
"444..434"
],
"goal": {
"type": "gems",
"counts": {
"red": 1,
"blue": 1,
"purple": 1,
"yellow": 1,
"green": 1
"red": 5,
"blue": 5,
"purple": 5,
"yellow": 5,
"green": 5
}
},
"hard": true,
Expand Down
Loading
Loading