Lil Beasties

lil-beasties forgejo

Notes

Project Page 1
  • Lil Beasties project-lil-beasties

    Vision

    A monster music game for kids — choose monsters, place them on islands, and hear them perform together. Each monster plays a different musical part (beat, bass, melody, harmony, percussion, vocal). Complete performances to win new monsters and unlock new islands. Built with Rails 8 + Phaser 4. Duolingo aesthetic. Deploy through the pal-e pipeline, wrap for App Store with Hotwire Native.

    User Stories

    Key Story Note Role Success Metric
    perform Perform Music Kid Place 3 monsters, hear them play music together
    progress Progress Through Islands Kid Complete island 1, win monster, unlock island 2
    play-anywhere Play Anywhere Player Same progress on phone and desktop

    Architecture

    1. Domain Model — monsters with musical parts, islands as levels, placement grid
    2. Data Flow — Rails API + Phaser game loop + audio layering (to be created)
    3. Deployment — k3s + ArgoCD + Harbor (to be created)

    Key decisions:

    • Rails 8 monolith — game state, auth, API all in one app
    • Phaser 4 in Stimulus controllers — sprites, game loop, audio, touch input at 60fps
    • Six musical parts (beat, bass, melody, harmony, percussion, vocal) — same BPM/key, any combo works
    • One monster per part per island — no stacking, enforced by Placement validation
    • Earn monsters through performance, not purchase — progression drives collection
    • Islands are levels — each one is a new stage for building a new song
    • Island-first landing — kids see their current island immediately after login
    • Hotwire Native for iOS App Store wrapper
    • Keycloak for auth (existing platform SSO)

    Board

    board-lil-beasties

    Status

    2026-06-06: Tone.js audio stack documented (PR #9 merged). Phaser handles visuals only, Tone.js owns AudioContext + Transport for beat-synced loop playback. All docs aligned: architecture, user-stories, music-theory. Issues #1-3, #7 updated with part/sound/vibe terminology + Tone.js references. Next: scaffold Rails app (Issue #1).

    Milestones

    Milestone Issues Gate Status
    M1: Playable prototype #1 Scaffold + #2 Phaser island + #3 Sprites Place 3 monsters on an island, hear them play music Not started
    M2: Progression loop #7 Island progression + monster rewards Complete island 1, win monster, unlock island 2 Not started
    M3: Ship it #4 Keycloak auth + #5 Deploy pipeline Live on cluster, accessible via Tailscale Funnel Not started

    Repos

    Repo Platform Role Status
    lil-beasties Forgejo Rails 8 + Phaser 4 monolith Active
Architecture 1
  • Domain Model: Lil Beasties arch-domain-lil-beasties

    Domain Model: Lil Beasties

    Diagram

    erDiagram
        Player ||--o{ PlayerMonster : owns
        Player ||--o{ Island : "progresses through"
        Monster ||--o{ PlayerMonster : "instance of"
        PlayerMonster ||--o{ Placement : "placed as"
        Island ||--o{ Placement : contains
    
        Player {
            string username
            string uid
            string provider
            integer current_level
        }
    
        Monster {
            string name
            enum musical_part
            integer level_unlocked
            string sprite_key
            string sound_key
        }
    
        PlayerMonster {
            references player_id
            references monster_id
            datetime acquired_at
        }
    
        Island {
            string name
            string theme
            integer level_number
            integer grid_width
            integer grid_height
            boolean completed
            references player_id
        }
    
        Placement {
            references player_monster_id
            references island_id
            integer grid_x
            integer grid_y
        }
    

    Components

    Component Purpose Notes
    Player User account linked to Keycloak SSO uid/provider from OmniAuth. current_level tracks progression.
    Monster Shared catalog -- each monster is a (part, sound, vibe) tuple musical_part (enum) = role in the song. sound_key = audio loop variant. sprite_key = visual personality. Multiple vibes per part. level_unlocked controls when it enters the catalog.
    PlayerMonster Ownership join -- player has earned this monster Created when player completes an island. First monster chosen at game start via audition.
    Island A performance stage -- the level the kid plays Completed when 3+ of 6 parts are filled. Each island has a visual theme. Created sequentially as player progresses.
    Placement A monster placed at a grid position on an island Unique constraint on [island_id, grid_x, grid_y]. Enforces one monster per musical_part per island.

    Musical Parts

    Every monster has three properties: part (role in the song), sound (audio loop variant), and vibe (visual personality). Multiple monsters can share a part but have different sounds and vibes. All audio: 120 BPM, C major, 4-bar seamless loops. One monster per part per island — no stacking. See docs/music-theory.md in repo for the full audio design.

    Part Sound Monster Vibe
    beat Kick, snare pattern Stompy rock monster
    bass Low-end groove Big round belly monster
    melody Lead tune Singing bird-like monster
    harmony Chords, pads Floaty cloud monster
    percussion Shakers, clicks, fills Spiky bug monster
    vocal Oohs, ahhs, chants Little mouth monster

    Gameplay Loop

    flowchart TB
        START[Game start] --> CHOOSE[Choose first monster]
        CHOOSE --> ISLAND[Go to Island 1]
        ISLAND --> PLACE[Place monsters on grid]
        PLACE --> PERFORM[Monsters play their parts together]
        PERFORM --> COMPLETE{Enough parts filled?}
        COMPLETE -->|No| PLACE
        COMPLETE -->|Yes| WIN[Win new monster!]
        WIN --> NEXT[Unlock next island]
        NEXT --> ISLAND2[Go to new island]
        ISLAND2 --> PLACE
    

    Key Decisions

    • Part / sound / vibe model: Six parts define the roles; sound and vibe are paired variants within each part. Kids pick personality, the system guarantees musicality.
    • One per part per island: Prevents stacking. Gives the kid a reason to collect different types. Enforced at the Placement level.
    • Audition before placing: Kids preview a monster's sound before committing to a placement.
    • 3 of 6 to complete: Minimum viable song is beat + bass + melody. All 6 is the goal but not required.
    • Earn, don't buy: Monsters are rewards for completing islands. No shop, no coins.
    • Islands are levels: Each island has a theme. Completed when 3+ parts are filled. Unlocks the next island.
    • Monster as catalog: Shared table, seeded on deploy. level_unlocked controls catalog growth. Starts with 6 (one per part), grows to multiple vibes per part.
    • Grid-based placement: Integer x/y on a fixed grid. Uniqueness constraint is the collision detection.
    • Client-side rendering: Phaser runs on the user's device (WebGL/Canvas). Rails serves game state via API.
    • No user table — Keycloak owns identity: Player stores uid/provider from OmniAuth. No passwords, no emails.
    • project-lil-beasties — parent project page
    • arch-dataflow-lil-beasties — how data moves at runtime (to be created)
    • arch-deployment-lil-beasties — where services run (to be created)
    • story-lil-beasties-perform — performing music on islands
    • story-lil-beasties-progress — earning monsters and unlocking islands
    • story-lil-beasties-play-anywhere — cross-device play
User Story 3
  • Progress Through Islands story-lil-beasties-progress

    ## story: Progress Through Islands ### Role Kid (Lucas's child) ### Key progress ### Want As a **kid**, I want to **complete islands by filling musical parts and unlock new islands** ### So That So that **I can earn new monster vibes and build new songs** ### Acceptance Criteria - Islands are levels with a level_number and theme - Placing enough monsters (3+ of 6 parts) completes the island - Completing an island rewards a new monster (new vibe for an existing part) - Completing an island unlocks the next island - Later islands unlock more vibes per part -- kids gain expressive range as they progress - Player's current_level tracks progression - Monster.level_unlocked controls catalog growth across levels ### Success Metric Complete island 1, win monster, unlock island 2. ### Related Architecture - `arch-domain-lil-beasties` -- Island.level_number, Island.completed, Monster.level_unlocked ### Related - `project-lil-beasties` -- parent project page - `board-lil-beasties` -- project board - `docs/music-theory.md` in repo -- completion threshold, catalog growth

  • Perform Music story-lil-beasties-perform

    ## story: Perform Music ### Role Kid (Lucas's child) ### Key perform ### Want As a **kid**, I want to **place monsters on an island and hear them play music together** ### So That So that I can **compose my own songs by choosing which monsters perform** ### Acceptance Criteria - Player can browse available monsters per part, each with a distinct sound and vibe - Player can audition a monster (tap preview, monster opens mouth, plays a sample) - Player can place a monster on an island grid slot for its part - Each placed monster plays its audio loop; loops layer together (120 BPM, C major) - One monster per musical part per island (no stacking the same role) - Multiple vibe options per part give kids a choice within each role - Monsters play idle and singing animations at 60fps - Touch input works for placing/moving monsters on mobile ### Success Metric Place 3 monsters, hear them play music together. ### Related Architecture - `arch-domain-lil-beasties` -- Monster.musical_part, Monster.sound_key, Monster.sprite_key, Placement, Island ### Related - `project-lil-beasties` -- parent project page - `board-lil-beasties` -- project board - `docs/music-theory.md` in repo -- part/sound/vibe model, audio constraints

  • Play Anywhere story-lil-beasties-play-anywhere

    story: Play Anywhere

    Role

    Player (kid or parent)

    Key

    play-anywhere

    Want

    As a player, I want to play on my phone or computer with my progress saved

    So That

    So that I can pick up where I left off on any device

    Acceptance Criteria

    • Player can log in via Keycloak SSO
    • Island progress and monster collection persist across sessions and devices
    • App is deployed and accessible via browser
    • Responsive design works on mobile and desktop
    • Health check endpoint returns 200

    Success Metric

    Player completes island 1 on phone, opens desktop, sees the same progress and collection.

    • arch-deployment-lil-beasties — k3s + ArgoCD deployment
    • arch-domain-lil-beasties — Player entity, Keycloak integration
    • project-lil-beasties — parent project page
    • board-lil-beasties — project board
Review 2
  • Verdict: APPROVED

    Re-review of board item #1329 after refinement. Previous review (review-1329-2026-06-05) returned NEEDS_REFINEMENT with 5 findings. All 5 have been addressed.

    Previous Findings Resolution

    • [x] Database conflict -- RESOLVED. Issue now says "PostgreSQL for dev via docker-compose per rails-base pattern." Constraints section updated. Aligns with rails-base/docker-compose.yml (postgres:17-alpine).
    • [x] Dockerfile clarification -- RESOLVED. File Targets entry now reads: "Dockerfile -- production container only (dev uses docker-compose with Harbor base image, no Dockerfile needed)." AC updated to "Production Dockerfile builds successfully."
    • [x] Multi-database clarification -- RESOLVED. Constraints section now says "Multi-database (Solid Cache/Queue/Cable) is production config -- dev uses single PostgreSQL database." Matches rails-base/docs/multi-database.md.
    • [x] Architecture note -- RESOLVED. arch-domain-lil-beasties note created with full ER diagram (Mermaid), Components table, Key Decisions, and Related links. Active status, tagged architecture. Project page Architecture section links to it.
    • [x] Story note -- RESOLVED. story-lil-beasties-collect note exists (was created with the project, predating the first review). Contains Role, Key, Want, So That, Acceptance Criteria, Success Metric, Related Architecture. Active status, tagged user-story. Project page user-stories table links to it correctly.

    Template Completeness

    • [x] Type -- Feature
    • [x] Lineage -- Standalone
    • [x] Repo -- ldraney/lil-beasties
    • [x] User Story -- present, well-formed
    • [x] Context -- thorough, includes data model relationships and UX flow
    • [x] File Targets -- 12 files listed (11 to create + 1 Dockerfile for production)
    • [x] Acceptance Criteria -- 11 criteria, all verifiable
    • [x] Test Expectations -- 4 test items + run command (docker compose run web rails test)
    • [x] Constraints -- 5 constraints, clear boundaries
    • [x] Checklist -- present
    • [x] Related -- references project-lil-beasties and arch-domain-lil-beasties

    Traceability

    • [x] story:collect label -- Collect Monsters
    • [x] story note verified -- story-lil-beasties-collect exists in pal-e-docs, active, properly structured
    • [x] story entry on project page -- project-lil-beasties user-stories table has "collect" row linking to story-lil-beasties-collect
    • [x] arch:rails-monolith label -- present on board item
    • [ ] arch note partial -- arch-domain-lil-beasties exists (domain model), but no arch-rails-monolith note exists. The label references "rails-monolith" as the architecture component, but the backing note covers the domain model, not the monolith architecture itself. This is a minor naming mismatch -- acceptable for a greenfield project where the domain model IS the first architectural artifact. Non-blocking advisory: consider creating arch-rails-monolith when deployment architecture is defined (ticket #5), or relabel to arch:domain-lil-beasties.
    • [x] Forgejo issue -- https://forgejo.tail5b443a.ts.net/ldraney/lil-beasties/issues/1, open

    File Targets

    • [x] All 12 file targets are new files to create -- repo contains only README.md (confirmed via Forgejo API). Greenfield scaffold.
    • [x] docker-compose.yml -- source template confirmed at ~/rails-base/docker-compose.yml (postgres:17-alpine, Harbor ruby-rails-build image, port 9999)
    • [x] Dockerfile -- clarified as production-only. No template in rails-base (confirmed: ~/rails-base/Dockerfile does not exist), so agent must write from scratch. Acceptable -- production Dockerfile is project-specific.
    • [x] Rails models, controller, views, routes, seeds -- standard rails generate targets

    Repo Placement

    OK -- Forgejo issue filed on ldraney/lil-beasties, ticket targets same repo. Single-repo scope.

    Dependencies

    • No blocking dependencies -- this is the first ticket on the board (standalone, foundational).
    • Board item #1330 (Integrate Phaser 4 + first island scene) depends on this ticket -- needs Rails app and islands#show view.
    • Board item #1332 (Keycloak auth integration) depends on this ticket -- issue references "auth wiring comes in #4, stub for now."
    • Dependencies are implicitly documented in constraints ("Root route must redirect to login if unauthenticated (auth wiring comes in #4, stub for now)"). Sufficient for a greenfield project.

    Acceptance Criteria

    • [x] All 11 criteria are concrete and agent-verifiable
    • [x] Test commands are real: docker compose run web rails test
    • [x] Multi-database now correctly scoped to production config
    • [x] No missing criteria for the stated scope

    Blast Radius

    • Greenfield project -- no existing consumers affected.
    • Database conflict resolved -- now aligned with rails-base platform standard (PostgreSQL for dev).
    • No downstream risks for this scaffold ticket.

    Decomposition Assessment

    • 12 file targets in 1 repo, 11 acceptance criteria, 4 test expectations
    • Borderline by raw numbers, but this is a rails new scaffold -- most files are generated by rails commands, not hand-written
    • Agent workflow is sequential: copy docker-compose, rails new, generate models, configure routes, write seeds, write tests
    • No decomposition needed -- a single focused agent pass with rails generators can complete this

    Recommendations

    No action needed. All previous findings resolved. One non-blocking advisory noted in Traceability (arch label naming mismatch).

  • Verdict: NEEDS_REFINEMENT

    Template Completeness

    • [x] Type -- Feature
    • [x] Lineage -- Standalone
    • [x] Repo -- ldraney/lil-beasties
    • [x] User Story -- present
    • [x] Context -- present, thorough
    • [x] File Targets -- 12 files listed
    • [x] Acceptance Criteria -- 11 criteria
    • [x] Test Expectations -- 4 test items + run command
    • [x] Constraints -- present
    • [x] Checklist -- present
    • [x] Related -- present

    Traceability

    • [x] story:collect label -- Collect Monsters
    • [x] story entry on project-lil-beasties user-stories table -- "collect" row exists, links to story-lil-beasties-collect
    • [ ] story note MISSING -- story-lil-beasties-collect note does not exist in pal-e-docs. [SCOPE] Create story note story-lil-beasties-collect.
    • [x] arch:rails-monolith label -- Rails monolith component
    • [ ] arch note MISSING -- no arch-rails-monolith note found in pal-e-docs. [SCOPE] Create architecture note arch-rails-monolith.
    • [x] Forgejo issue -- https://forgejo.tail5b443a.ts.net/ldraney/lil-beasties/issues/1, open

    File Targets

    • [x] All 12 file targets are new files to create -- repo currently contains only README.md. Greenfield scaffold, no existing-file verification needed.
    • [ ] Dockerfile -- ISSUE: rails-base/docs/starting-a-new-project.md says "No Dockerfile needed for dev" and uses docker compose with a pre-built ruby-rails-build image from Harbor. If the ticket intends a production Dockerfile, this needs clarification. [BODY] Clarify whether Dockerfile is for production only, or remove if dev uses docker-compose with base image.

    Repo Placement

    OK -- Forgejo issue filed on ldraney/lil-beasties, ticket targets same repo. Single-repo scope.

    Dependencies

    • No blocking dependencies -- this is the first ticket on the board (standalone, foundational).
    • Board item #1330 (Integrate Phaser 4 + first island scene) depends on this ticket -- it needs the Rails app and islands#show view to mount Phaser onto.
    • Board item #1332 (Keycloak auth integration) depends on this ticket -- the issue references "auth wiring comes in #4, stub for now."
    • Dependencies are implicitly documented in the constraints section ("Root route must redirect to login if unauthenticated (auth wiring comes in #4, stub for now)") but not explicitly listed as blocked-by/blocks relationships.

    Acceptance Criteria

    • Criteria are concrete and verifiable by an agent.
    • "App boots and passes rails test" is a real, runnable command.
    • However: AC says "Multi-database configured: primary + solid_cache + solid_queue + solid_cable" but the rails-base multi-database doc shows this as a production-only concern. Dev uses a single database. The AC should clarify this is production config only.

    Blast Radius

    • Greenfield project -- no existing consumers affected.
    • Constraint conflict: ticket says "Use SQLite for dev, PostgreSQL for prod" but rails-base pattern uses PostgreSQL for both dev and prod via docker-compose. The docker-compose.yml in rails-base runs a PostgreSQL container for dev. Using SQLite for dev would diverge from the platform standard and could cause dev/prod parity issues. [BODY] Resolve database conflict: align with rails-base pattern (PostgreSQL for dev via docker-compose) or document why SQLite is preferred for this project.

    Decomposition Assessment

    • 12 file targets in 1 repo
    • 11 acceptance criteria
    • 4 test expectations
    • Estimated agent work: well beyond 5 minutes -- generating a full Rails app, creating 5 models with migrations, seeds, routes, controller, view, Dockerfile, and database config is substantial.
    • However: this is a rails new scaffold + model generation. Most file targets are generated by rails commands (rails new, rails generate model), not hand-written. The agent workflow is sequential: generate app, generate models, configure routes, write seeds. This can be done in a single focused pass if the agent runs rails generators inside docker compose.
    • Recommendation: borderline. The high file/AC count is inflated because rails new generates most of them. A skilled agent running generators can complete this in one pass. No decomposition needed IF the scope conflicts below are resolved first.

    Recommendations

    • [SCOPE] Create story note story-lil-beasties-collect in pal-e-docs -- the project user-stories table links to it but it does not exist.
    • [SCOPE] Create architecture note arch-rails-monolith in pal-e-docs -- the board item has the label but no backing note.
    • [BODY] Resolve database conflict in Constraints section: ticket says "Use SQLite for dev" but rails-base platform pattern uses PostgreSQL for dev via docker-compose. Pick one and update the ticket.
    • [BODY] Clarify Dockerfile file target: rails-base says "No Dockerfile needed for dev" and uses a pre-built Harbor image. If this is a production Dockerfile, label it as such. If not needed, remove from file targets.
    • [BODY] Clarify multi-database AC: specify this is production config; dev uses single database per rails-base/docs/multi-database.md.
Board 1
Repos 1
  • lil-beasties
    active