Devlog
This is glemy's real decision log, not a curated highlight reel — every entry states what was tried, what was rejected and why, and how the outcome was actually verified. Newest first.
- #0067Publish glemy 0.1.0 to Hex
- #0066Declare javascript as gleam.toml's default target, discovered as a real gleam publish blocker
- #0065Set Hex-publish metadata (0.1.0, BSD-3-Clause) and audit the public API surface, informed by glemy-games as a real external consumer
- #0064Extract the three reference games into a new glemy-games repository
- #0063Dedupe a Shell-side pattern into game_ffi.mjs's setElementVisibilityMessage, mirroring decision 0062's Core-side reasoning one layer up
- #0062Decompose wall-handling into caller-parameterized Core primitives (resolve_axis/resolve_high_only), parameterize physics.update's wall step, instead of leaving it unused by 2 of 3 games
- #0061Close out RM-034: circle-vs-Rect detection generalizes to Core, wall/landing restitution policy does not (three games, three distinct answers)
- #0060Wire the platformer's rendering/input (glemy/game_platformer), verified via a new browser-check using captured-GPU-uniform position checks
- #0059Build the platformer's pure game logic (glemy/games/platformer), confirming a third distinct wall/landing policy and a real Landed-event design bug found by direct testing
- #0058Promote circle-vs-Rect detection and the x-fraction/rect-to-CSS helpers from games/breakout into Core, at RM-034's second real caller
- #0057Fix the Breakout stable-channel deploy crash and replace decision 0046's manual-only stable promotion with CI-gated automatic promotion
- #0056Extend tools/decisions with a roadmap subcommand to validate and manage docs/development-plan.jsonl (RM-028)
- #0055Add Breakout to glemy-website's game catalog, generalizing game_card into a parameterized component at its second real caller
- #0054Phase 3 (playtesting/tuning): empirical multi-exchange verification confirms Breakout's constants are sane; subjective feel-tuning deferred to the user's own hands-on play
- #0053Wire Breakout's rendering/input (glemy/game_breakout), redesign Brick with a stable id for DOM reconciliation, and extract shared browser-check bootstrap at its second real caller
- #0052Build Breakout's pure game logic (glemy/games/breakout, rect/brick/paddle) with rectangles kept entirely outside physics, and confirm physics.update does not generalize to a second genre
- #0051Split glemy/game.gleam into glemy/game_tiers.gleam plus a shared game_ffi.mjs, in preparation for a second game runner
- #0050Add physics/bounds.clamp_x and physics.settle_all, reject a bounds.y_from_top helper, and fix a real float.clamp/bounce_axis divergence on degenerate bounds
- #0049Extend the Core API with three small utility modules (cooldown, stopwatch, random) and physics.entity_count, and reject a generic PreviewQueue abstraction
- #0048Rename pe to physics, pair render colors with entities instead of a parallel list, give render.Canvas a public constructor, and fix doc-comment drift left by decision 0047
- #0047Formalize the Core API surface and introduce the glemy/games/<name>/ convention, moving all Suika-specific rule logic out of pe
- #0046Split the live demo into pinned stable and always-latest edge release channels, promoted via a committed ref file
- #0045Content-hash glemy-website's built static assets: style.css per-file, the play-demo build as one renamed directory
- #0044Generalize pe's SoundEvent into GameEvent, returned as #(Model, List(GameEvent)) from tick rather than carried as a Model field
- #0043Restructure docs/development-plan.md into a status-tracked, item-based living roadmap, replacing prose narrative that required full rewrites
- #0042Establish a project-level Technical Architecture Document: engine/game boundary, deployment/live-demo strategy, and versioning policy
- #0041The project's public website (goals, devlog, live demo) lives in a separate glemy-website repo, not this one
- #0040Systematic DevOps tooling organization: a researched taxonomy (kind, packaging weight, fixture placement, discoverability) for tools/, not an ad hoc layout
- #0039Formal modularization thresholds (ARCHITECTURE.md), grounded in SRP/cohesion research not line-count alone -- and one real extraction the audit found: pe/collision_sweep.gleam
- #0038Zero-unexpected-warnings gate: fixed the one real dead import, enforced the rest via a checked-in baseline diff, not a silent policy
- #0037Clamp dt inside pe.tick: a real, confirmed entity-entity tunneling risk after decision 0032 raised speed, made worse by zero dt clamping in the game loop
- #0036Merge visual feedback: a whole-canvas brightness flash, not a per-position particle burst
- #0035Added drop/merge sound effects: synthesized via Web Audio, not audio files -- and a new Model.sound_events field so the decision of what happened stays pure and testable
- #0034Two-ahead tier queue and a next-tier UI swatch, matching the genre's standard 'next fruit' preview
- #0033Added a visible danger-line indicator: a CSS overlay, not a WebGPU-rendered entity
- #0032Fall was still too slow after decision 0029's bounce fix -- fixed the real drag mismatch (velocity_damping) plus raised gravity, roughly halving real fall time
- #0031Architecture cleanup: deleted the unused glemy/cs compute-shader layer, added ARCHITECTURE.md as the standing rule set
- #0030Render the drop preview circle Model.preview_x was tracking but never actually drawing
- #0029Root-caused 'falls too fast, hard to predict' to fully elastic restitution (1.0), not gravity -- lowered to 0.1 to match a real reference-game clone
- #0028Fixed a genuine resonance bug in decision 0027's resting-contact threshold: replaced the hard velocity cutoff with a smooth restitution ramp plus a Box2D-style time-based sleep backstop
- #0027Fixed a real, previously-documented-as-acceptable bug: entities visibly crossed the play area boundary before bouncing, because radius was never subtracted from the bounce comparison
- #0026Fixed silent black-screen failures: dev server now sends no-cache, and the game loop reports errors visibly instead of dying silently
- #0025Phase 8 (playtesting/tuning): empirical verification confirms the constants are sane; subjective feel-tuning deferred to the user's own hands-on play
- #0024HTML overlay UI: score and game-over text, format computed in Gleam, only non-branching DOM writes in FFI
- #0023Danger line / game over: plain continuous-time threshold, tick freezes once lost
- #0022Drop mechanic: cursor-follow preview, cooldown-gated drop, randomized next tier -- and gleam_stdlib already has a cross-target float.random(), no new FFI needed
- #0021Fixed a real latent bug: click-to-spawn passed raw viewport pixels through as world coordinates, unconverted
- #0020Per-entity render color is tier-driven, single source of truth in tier.color, sent to the shader as a vec4 uniform
- #0019Same-tier overlapping entities merge into the next tier instead of bouncing, one pair per sweep pass
- #0018Collision physics is now mass-aware (proportional to area), superseding the equal-mass simplification
- #0017Entity.tier is the authoritative discrete identity; radius is tier-derived data
- #0016Standing rule: JS FFI code must be minimal and every Gleam-callable export must be wrapped by Gleam
- #0015Present via a native GPUCanvasContext under Deno, not TypeScript+Playwright, for maximum type safety
- #0014Cap max_entities rather than build broad-phase collision culling
- #0013Standing rule: use every tool's type safety to the maximum extent available
- #0012Headless WebGPU verification does work in this sandbox -- decision 0011's conclusion was wrong
- #0011This dev sandbox cannot run real-browser WebGPU, even headless and even in software
- #0010Present the game runner's frames via Canvas2D putImageData, not a WebGPU canvas context
- #0009Build a type-safe Gleam CLI tool for decisions.jsonl instead of ad-hoc Python
- #0008Move JavaScript-target testing from Node to Deno; drop the webgpu npm package
- #0007Circle-circle collision assumes equal mass regardless of radius; no per-entity mass field yet
- #0006Use a plain EventTarget for io's testing fallback, not jsdom
- #0005Centralize WebGPU device acquisition in one shared module (gpu_ffi.mjs), not per-FFI-file
- #0004Model game entities as a plain immutable List(Entity) in pe, not an ECS
- #0003No bundler for the browser build; raw Gleam ESM output plus a hand-written index.html
- #0002Restructure into a single glemy package with 4 target modules (io, pe, cs, render), rooted at the repo root
- #0001Install Erlang/OTP via asdf (build from source), not the RabbitMQ PPA