Skip to content

feat: console music command with 8-bit soundtrack - #1

Merged
jjsnack merged 11 commits into
mainfrom
feat/console
Jul 27, 2026
Merged

feat: console music command with 8-bit soundtrack#1
jjsnack merged 11 commits into
mainfrom
feat/console

Conversation

@jjsnack

@jjsnack jjsnack commented Jul 27, 2026

Copy link
Copy Markdown
Owner

What

Adds a music command to the floating console, plus a subcommand refactor of the console command style.

  • music — synthesises a calm C-major pentatonic 8-bit tune live with WebAudio (no audio files, no deps). Triangle lead + sine bass pad.
    • music play / music stop / music volume <0-10>
    • bare music prints a usage block
  • theme — refactored to the same subcommand style: theme list / theme set <mode>, bare theme prints usage
  • help — reformatted to aligned name : description
  • CLAUDE.md — documents the theme + the console command style all future commands must follow

Self-check (node assets/js/console.js) covers every new branch and passes.

🤖 Generated with Claude Code

jjsnack and others added 6 commits July 28, 2026 00:30
Dependency-free terminal widget on the homepage. Launcher button opens a
draggable floating window (~80x24), dockable to the bottom quarter. Commands:
theme, history, clear, close, help. On open it shows the site title as a
Bulbhead FIGfont banner (parser + font embedded, no npm dep). Progressive
enhancement: launcher and window stay hidden without JS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EBF9sk8L2MdbSC1Pbz9tkH
theme + music now use the subcommand pattern (bare cmd prints usage block).
music synthesises a square-wave chiptune via WebAudio, with play/stop/volume.
Add CLAUDE.md documenting the theme and console command style.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jjsnack

jjsnack commented Jul 27, 2026

Copy link
Copy Markdown
Owner Author

Frontend review

Solid overall — no-dep vanilla JS, pure run() core with a self-check, progressive enhancement done right (launcher + window ship hidden, JS unhides), XSS-clean (textContent everywhere), WebAudio uses the correct lookahead-scheduler pattern. Self-check passes. Findings ranked.

Accessibility

1. ASCII banner is announced to screen readers — real defect. .console__log is role="log" aria-live="polite". At init the figlet <pre> banner is appended inside it (console.js:273) with no aria-hidden, so a screen reader reads decorative ASCII art character-by-character. Fix: art.setAttribute("aria-hidden","true").

Correctness / robustness

2. music play lies if audio is blocked. console.js:239 writes ♪ music on unconditionally; ctx.resume()'s promise is never inspected (console.js:187). User-gesture triggered so usually fine, but a blocked context claims music plays silently. A .catch writing a failure line closes it. (low)

3. voice param vol shadows module-level vol. console.js:163 — inner vol is per-note gain, outer is master volume used by setVolume. Same name, two meanings, one scope apart. Rename param to gain. (footgun, not a bug)

4. var history shadows window.history. console.js:144. Harmless but a smell in a 300-line IIFE.

Performance

5. Whole figfont base64'd into every page. console.html:6 embeds {{ $font.Content | base64Encode }} — ~6KB base64 in every page's HTML, re-parsed client-side per load. site.Title is known at build time, so the banner could be rendered server-side in Hugo, dropping both the embedded font and the parseFig/banner JS (~40 lines). Bigger refactor — flagging.

Dead code

6. a.console__line:hover matches nothing. main.css targets anchor lines, but write() only ever creates divs — no path renders an <a>. Delete it.

Design — passes

Monochrome, single --accent tint, disciplined; fits the text-first brief, avoids AI-default looks. Real responsive handling (min(84ch, calc(100vw-2rem)), banner isolated in overflow-x:auto). No gratuitous motion. Subcommand usage: style matches the documented convention.

Verdict

Ship-worthy after #1 (one line). #6 is a free deletion. #2#5 are follow-ups, not blockers.

jjsnack and others added 5 commits July 28, 2026 08:17
The banner <pre> lives inside .console__log, which is role="log"
aria-live="polite". Without aria-hidden a screen reader announces the
decorative ASCII art character-by-character. Mark it hidden.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bgxxw4baXATznPYP4ARHzW
- music play now reports "blocked by the browser" instead of claiming
  "♪ music on" when AudioContext.resume() rejects. on() returns a promise
  so the caller can tell success from failure.
- rename voice()'s per-note gain param vol -> peak (was shadowing the
  module-level master vol used by setVolume).
- rename local history array -> cmdHistory (was shadowing window.history).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bgxxw4baXATznPYP4ARHzW
write() only ever creates <div> lines — no code path renders an anchor,
so this selector matched nothing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bgxxw4baXATznPYP4ARHzW
The figfont was base64-encoded into a data-font attribute on every page
(~6KB of HTML each). Publish it as a fingerprinted resource and fetch it
once at runtime instead — cached across the whole site, and the banner
render moves off the initial HTML payload. Falls back to no banner if the
fetch fails; the console still works.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bgxxw4baXATznPYP4ARHzW
@jjsnack
jjsnack merged commit 9eb6464 into main Jul 27, 2026
1 check passed
@jjsnack
jjsnack deleted the feat/console branch July 27, 2026 22:26
@jjsnack

jjsnack commented Jul 27, 2026

Copy link
Copy Markdown
Owner Author

Issues all fixed with Claude.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant