Repository navigation
Releases: darkcodelabs/hakcd-v4
Release list
HAKCD v0.1.33 — all placeholders replaced
First fully-authored HAKCD build. All 5 outstanding placeholders replaced with 23Studios visual_pack_factory v3.1 OpenRouter output (gemini-2.5-flash-image + gemini-3-pro-image-preview).
V3 visual contract validator: 0 FAIL, 0 WARN, 44 entries, 0 placeholders.
Sideload: download the zip, extract, drop hakcd.pdx on your Playdate via USB or open in Simulator.
Replaced assets:
- coin_locked.png (48×48)
- hakcd-table-24-24.png (192×192 tileset, 8×8 grid)
- lockpick_body.png (240×100, Pope-style cylinder lock)
- portraits/newb.png (48×56, head + hoodie + cowlick)
- newb-table-32-32.png (256×32 walk cycle strip)
pdxinfo: 0.1.32 → 0.1.33. Stays below the 0.2.0 enforcement gate; V3 stays in WARN mode for future re-validation.
v0.1.31 — Phase V2 visual_spec.lua
Phase V2 of visual recovery. 44 assets declared: 14 final / 5 placeholder / 23 generated / 2 debug. 1 readability fail (newb_table). visual_spec.assert_id / is_final / placeholders / failing_readability helpers live. V3 validator next.
HAKCD v0.1.30 - Phase V1 Visual Style Guide
Phase V1 - Visual Style Guide + Reference Library Scaffold
Foundational visual recovery sprint. Documentation + version bump only;
no .lua source touched, no assets regenerated, no validators modified.
What ships
docs/style_guide.md- the sacred visual contract (12 sections):
purpose, character scale, perspective, black-mass rule, line weight,
dithering rules, dither pattern catalog, UI placement, hardware
readability, banned methods, reference games, acceptance / sign-off.docs/reference/README.md- reference library scaffolding + workflow.docs/reference/playdate_reference_games.md- per-game detail for the
six visual targets.docs/reference/{characters,rooms,ui,palettes,games}/- stub
directories ready for V4-V8 reference imagery.
Versioning note
Mission brief specified 0.1.27 -> 0.1.28, but v0.1.29 (Phase V9 hardware-
review scaffold) already shipped on main ahead of V1. V1 sequenced to
v0.1.30 to avoid a backwards version.
Rules enumerated
12 (style guide sections 1-12).
Banned methods declared
4 (ImageMagick primitive draw commands, concept auto-shrink resize,
global ordered-dither as output filter, text-label baking into sprites).
Reference games documented
6 (Mars After Midnight, Pick Pack Pup, Crankin's Time Travel Adventure,
Casual Birder, Saturday Edition, Demon Quest 85).
HAKCD v0.1.29 — Hardware Review Workflow (Phase V9)
Phase V9 — Hardware Review Workflow
Scaffolds tools/hardware_review/ as the human-in-the-loop gate every visual
asset must pass before claiming art_status='final'.
What landed
tools/hardware_review/README.md— workflow spec (6 sections: overview,
layout, capture script, hardware photo requirements, PASS/FAIL/WIP rubric,
v0.2.0 build-blocking rule)tools/hardware_review/capture_screenshots.sh— Simulator capture driver
with manual-protocol fallback (Linux Simulator does not expose scriptable
capture in SDK 3.0.6)tools/hardware_review/per_version_template.md— per-release signoff
template (table + scene-level review + overall verdict)tools/hardware_review/v0.1.29/{simulator,device}/— first-version capture
directories ready to populate
Workflow
sideload -> capture (9-scene minimum) -> photograph (arm's length, finger for
scale, no flash glare) -> sign off in SIGNOFF.md against commit SHA with
reviewer handle + ISO date + per-asset PASS/FAIL/WIP verdict.
Scenes captured per session
TitleScene, BedroomScene, ComputerScene, ModemScene, PhoneScene,
PlaygroundScene, LockpickScene, TysonScene, CoinVaultScene.
Blocking rule (activates at v0.2.0)
Once visual_spec.lua exists AND validate_visuals.sh checks human_reviewed +
art_status AND pdxinfo version >= 0.2.0: build FAILS if any
priority='critical' asset has human_reviewed != true OR
art_status == 'placeholder'. Until then, validator warns only.
Scope
pdxinfo bump + docs/scripts only. No .lua, no asset, no validator, no
Makefile changes. V3 owns the validator extension.
v0.1.27 — Phase 14 Hardware Performance Pass
Phase 14 — Hardware Performance Pass
Final phase of the hakcd-v4 canon-first migration sprint. Targets real Playdate hardware (rev A/B), implements the prioritized fixes from `docs/hardware_perf_audit_notes.md`.
Fixes shipped
- SFX preload — `sound_manifest.preload_sfx()` builds one cached sampleplayer per path at boot. Eliminates per-shot `sampleplayer.new()` cost (cross-cutting audit FAIL).
- CoinVault grid bake — 4x6 grid rendered to a single offscreen image, blitted in one draw call instead of ~96 per frame. Cursor highlight drawn on top per-frame. Re-bake gated on coin-status fingerprint (audit fix #1, biggest single perf win).
- CoinVault asset cache — `coins.json` parse + 9 coin images + portrait moved to module-scope cache. Re-entering CoinVault is now zero-IO (audit fix #2).
- Bedroom + Playground tilemap cache — `LDtk.create_tilemap` + `get_empty_tileIDs` + `get_entities` cached at module scope. Per-enter cost is now just sprite-shell construction (audit fix #3).
- Newb overlap allocation — replaced `self.newb:overlappingSprites()` with manual rect-intersect against `self.hotspots`. Zero per-frame Lua table alloc (cross-cutting audit WARN).
- DebugOverlay — new `source/systems/DebugOverlay.lua`. 100x60 top-right HUD (FPS / SCN / SPR / NWB / MEM), toggled via `debug overlay` system menu item.
Deferred (next pass)
- Lockpick + Tyson static-chrome bakes (audit #7, #8)
- Pre-format strings on state transitions (audit #9)
- Phone/Computer/Modem chrome split (audit #10)
- Progression deferred save coalescing (audit #11)
- gameWillPause music pause hook (audit #12)
- Title/SpriteTest exit() music stop (audit #13)
Build
- Validator: 9/9 PASS, 21/21 asset gates PASS
- `.pdx` size: ~68 MB
- pdxinfo: 0.1.27 / buildNumber 27
v0.1.26 — Phase 13 playtest checklist adopted
Phase 13/14. tools/playtest_checklist.md (drafted v0.1.15 in 27305d6) formally adopted as playtest gate. Covers SceneRouter (Phase 11) + Progression flag migration (Phase 12). Next: Phase 14 hardware perf pass against 13 prioritized fixes in docs/hardware_perf_audit_notes.md.
v0.1.25 — Phase 11 SceneRouter
Phase 11: centralized scene routing via source/systems/SceneRouter.lua.
Every Noble.transition call site outside SceneRouter.lua now flows through SceneRouter.transition_by_id(canon_scene_id) (for canon-listed targets) or SceneRouter.transition(class) (pass-through for minigame return paths handed a class via launch args).
- 1 new file: source/systems/SceneRouter.lua (65 LoC)
- 11 scene/main files touched, 16 transition sites swapped
- Unknown scene_id prints [SceneRouter] warning and returns false instead of crashing
- pdxinfo bumped to 0.1.25 / 25 (Phase 12 landed 0.1.24 in parallel just ahead of this)
- Validator (9/9 canon graph checks) + pdc both green
v0.1.24 — Phase 12 progression migration
Phase 12 — scene flag reads/writes routed through canon-guarded Progression.get_flag / Progression.set_flag (Phase 8 wrappers). Every scene flag site references canon.state_flags..id; no bare strings, no direct Noble.GameData access from scene code.
Sites migrated:
- TysonScene: tyson_unlock read (enter) + write (commit_digit) → Progression API with canon lookup; removed legacy get_flags/set_flag helpers.
- PlaygroundScene / BedroomScene: no flag I/O present in current scenes (nothing to swap).
- CoinVaultScene: verify-only — coin__status already routes through Progression.coin_status → Progression.get_flag (post Phase 8).
Validator: 9/9 canon graph checks passed. .pdx 68167619 bytes. Save compat preserved — state.tyson_unlock round-trips via the same Noble.GameData['state'] table Phase 8 already wrote to.
v0.1.22 — Phase 10: Bedroom + Playground hotspots use canon lookups
Phase 10 — Room + Hotspot Canon Migration
Replaces bare hotspot string literals in BedroomScene.lua + PlaygroundScene.lua A-press dispatch with canon.objects.<id>.id / .launches / .transitions_to lookups. Hotspot id contract now lives in canon.lua, not in scene files.
Migrations
- BedroomScene A-press:
bed(uses.transitions_to→ PlaygroundScene),computer/modem/phone(use.launches). - PlaygroundScene A-press:
lockpick_station/tyson_cabinet/coin_vaultall route via_G[canon.objects.<id>.launches]with the existingreturn_scenehand-off. The six tier-2/3 placeholder hotspots (rfid_pedestal, payphone, ir_wall, gravity_arena, subghz_tuner, portal_pedestal) declarelaunches=nilin canon and fall into the existing placeholder dialog branch. - Spawn fallbacks now read
rooms_manifest.<room>.spawn_points[1]instead of inline(200, 168). LDtkplayer_spawnentity still wins — manifest is the floor.
Not migrated (deferred to Phase 11 SceneRouter)
- The explicit if/elseif dispatch chain remains — Phase 11 will fold it into a generic table-driven router.
walkable_boundsnot yet consumed by either scene (collision is fully handled by LDtk Solid enum +addWallSprites); the manifest field remains declarative-only.
Build
- Validator: 9/9 canon graph checks passed (no new ids introduced).
- pdc clean,
.pdx= 68,167,887 bytes (~65 MB), zip = 63,958,986 bytes. - Runtime behavior preserved.
Slot reshuffle note
Phase 9 (sprite-migration) landed at v0.1.21 (commit 7703b6d), so this Phase 10 commit slides to v0.1.22 rather than fight the already-pushed tag.
Commit: 76593ba
v0.1.21 — Phase 9 sprite migration
Phase 9 of the canon-first migration sprint.
What
source/sprites/Newb.lua now loads its 10-state FSM from the generated source/data/animations.lua manifest instead of inline addState literals. The manifest (per-character spec table with frames, frameDuration, loop, fallback, blocks_input, bible_anim_id) is the single source-of-truth, generated by tools/canon/generate_animations_manifest.js and linked back to the story bible. The Phase 7 continuity validator already gates this manifest against asset.frame_count on every build.
Why
Canon-first migration goal: animation specs live in declarative data, not scattered Lua call-sites. Future sprite changes are a manifest edit + regenerate, not a code patch. AnimatedSprite library stays generic — no fork.
Invariants preserved
- Same 10 states by same names (idle/walk x NSEW + interact + surprised)
- Same frame indices per state (verified against pre-migration Newb.lua)
- Same tickStep / loop semantics
- Spawn coords + collideRect + facing init unchanged
- updateMovement (d-pad + footstep SFX) untouched
- No imagetable load in update — init-only
Files
- source/sprites/Newb.lua — migrated to manifest loop
- source/pdxinfo — 0.1.20 -> 0.1.21