쇼 HN: 클로드 코드 내부의 운명

hackernews | | 📰 뉴스
#anthropic #claude #오픈소스
원문 출처: hackernews · Genesis Park에서 요약 및 분석

요약

개발자는 클로드 코드 내에서 실제 '둠' 게임을 구동할 수 있는 시스템을 구현했습니다. 상태 표시줄은 ANSI 아트로 각 프레임을 렌더링하고, MCP 서버는 클로드가 게임을 플레이할 수 있는 API를 제공합니다. 사용자는 채팅창에 키를 입력하여 캐릭터를 조작할 수 있으며, 백그라운드 데몬이 게임 상태를 관리합니다.

본문

Play Doom inside Claude Code. The actual Doom engine renders to your status line, you move by typing keys into the chat box, and an MCP server lets Claude itself play the game. ┌───────────────────────────────────────────────┐ │ Claude Code │ │ │ │ you: wwwf │ │ claude: ... │ │ │ │ [ status line below renders real Doom here ] │ │ │ │ ┌─────────────────────────────────────────┐ │ │ │ DOOM E1M1 HP 87 ARM 0 PISTOL 34/200 │ │ │ │ ▓▓▓▓▓▓▓▓▓▓▓ █▓▓▓▓▓█ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ │ │ │ │ ▓░▒▒░▒▓░░▓▓ ▓░▒░░░▓ ▓▓▒▒░░▒▒▒░░░▒▒▓▓ │ │ │ │ ... (28 rows of chafa-rendered frame) . │ │ │ └─────────────────────────────────────────┘ │ └───────────────────────────────────────────────┘ Four native Claude Code surfaces cooperate to host a real Doom game: | Surface | Role | |---|---| Status line (refreshInterval: 1 ) | Renders each frame as ANSI art in the bottom bar | | UserPromptSubmit hook | Captures your keystrokes (w , a , s , d , f , ...) from the chat input | | MCP server | Exposes doom_look , doom_move , doom_state , etc. so Claude can play | Slash command /doom | Controls the daemon (start, stop, status, preset, render mode, gamma) | A background daemon holds the game state. Two daemon backends are provided: doomgeneric backend — real Doom. Built from doomgeneric, wrapped with a tick-on-demand controller. C + Makefile, requires a toolchain.stub backend — a pure-Node fake Doom that implements the same file contract. Works out of the box without compiling anything. Use it to verify the integration. ┌─────────────────────────────────────────┐ │ daemon (doomgeneric OR stub) │ │ ─ reads: /tmp/doom-in-claude/input.fifo│ │ ─ writes: frame.ansi, frame.png, │ │ state.json │ └──────┬────────────┬──────────────┬──────┘ │ │ │ ┌───────▼──┐ ┌──────▼─────┐ ┌─────▼──────┐ │Status │ │UserPrompt- │ │MCP server │ │line │ │Submit hook │ │(stdio) │ │(display) │ │(your keys) │ │(Claude's │ │ │ │ │ │ tools) │ └──────────┘ └────────────┘ └────────────┘ All four Claude Code surfaces are documented, stable extension points. The daemon is an ordinary background process. Requires: macOS or Linux, bash , node >= 18 , jq , perl (for the byte-stability normalizer), and (for real Doom) gcc /clang + make . Also recommended: chafa (brew install chafa ) — the default renderer. git clone https://github.com/erkandogan/doom-in-claude-code.git cd doom-in-claude-code ./install.sh The installer: - Copies the status line script, hook, slash command, and MCP server to ~/.claude/ . - Patches ~/.claude/settings.json to registerstatusLine ,hooks.UserPromptSubmit , and thedoom-in-claude MCP server. - Attempts to build the doomgeneric backend. If the build fails orgcc is missing, falls back to the stub backend. - Installs the doom-in-claude CLI to~/.local/bin/ . - Downloads the Freedoom WADs (GPL, free to redistribute). Uninstall with ./install.sh --uninstall . The default install gives you a playable Doom that's stable for most play sessions. A few tweaks make it more stable and more legible. None are strictly required. /doom start --gamma 0.7 - Default renderer: chafa with 256-color palette + ordered dither — half the per-cell SGR byte cost of TrueColor, drift-resistant under heavy scene changes (damage flashes, fireballs). This is the main drift mitigation and it's on by default. --gamma 0.7 : lifts Doom's dark corridor values out of the single "black cube entry" so walls and textures are legible. Without it, dark rooms can collapse to monochrome. Range 0.5–1.0, 0.7 is the sweet spot. Claude Code's Ink-based renderer maintains an internal cell-diff cache that can occasionally drift under heavy scene changes (big damage flashes, sudden full-screen color swaps). The default renderer's byte-stability + static anchor border + lower frame rate keep this rare. If you want it impossible, run Claude Code inside tmux — tmux re-parses ANSI into its own canonical grid and re-emits cleanly, absorbing any drift from Ink. Your ~/.tmux.conf : set -g default-terminal "tmux-256color" set -sa terminal-overrides ",xterm*:Tc" set -sa terminal-overrides ",iterm*:Tc" set -sa terminal-overrides ",kitty*:Tc" set -sa terminal-overrides ",ghostty*:Tc" set -sa terminal-overrides ",alacritty*:Tc" set -sa terminal-features ",*:RGB" set-environment -g COLORTERM "truecolor" Claude Code has a defensive clamp to 256-color when $TMUX is set. Without the following, Claude's own TUI colors look muted inside tmux: # Add to ~/.zshrc (or ~/.bashrc) export CLAUDE_CODE_TMUX_TRUECOLOR=1 This restores TrueColor for Claude's TUI. The Doom frame still renders in 256-palette regardless (that's intentional for drift resistance), but Claude's prompt / diff / syntax highlighting use the full gamut. See anthropics/claude-code#46146 for the env var reference. In a Claude Code session: /doom start --gamma 0.7 # start the daemon with recommended settings wwwasdw # type keys as a single prompt → you move /doom look # print the current frame /doom stop The hook interprets chat submits as Doom commands whenever the daemon is active: | Prompt | Action | |---|---| w / a / s / d | forward / strafe-left / back / strafe-right | q / e | turn left / turn right | f | fire current weapon | space or u | use (open door, press switch) | digits 1 ..7 | switch weapon | | a run of characters | each char is one action, executed in order (wwwf = walk 3 then fire) | rush , retreat , ... | named macros from ~/.claude/doom/macros.json | go | let n ticks elapse with no input (enemies move) | | anything else | passes through to Claude as normal | With the MCP server running, the full tool surface is: doom_state — game state JSON (hp, armor, weapon, ammo, position, killcount, map, tick)doom_look — current frame as PNG (Claude can see the scene)doom_move — send keysdoom_burst — send multiple key sequences in orderdoom_wait — advance N ticks with no inputdoom_macro — run a named macrodoom_start /doom_stop /doom_status — daemon lifecycle A prompt that reliably gets Claude through E1M1 is in docs/claude-play.md. You play; Claude watches via doom_state on each of your moves and comments in chat: "Shotgun behind you, two imps in the left corridor. Duck left before firing." Just ask Claude to watch while you play. /doom start [--render MODE] [--chafa-preset NAME] [--blocks-colors 256|full] [--gamma VALUE] [--cols N] [--rows N] | Mode | Native? | Notes | |---|---|---| chafa (default) | external | gold-standard quality; auto-selected if installed | blocks-hq | yes | area-averaged native C renderer, no external deps | timg | external | brew install timg — different color quantization | quadrant | yes | simpler native point-sampled blocks | sextant | yes | Unicode 13 sextants (2×3 subpixels, drift risk outside tmux) | sixel / kitty | — | image protocols; confirmed blocked by Ink | | Preset | Colors | Dither | Notes | |---|---|---|---| default / balanced | 256 | ordered 4×4 | recommended — drift-safe, good colors | detailed | 256 | ordered 2×2 | + preprocess + avg extractor, pair with --cols 160 | sextant-tmux | 256 | ordered | 2×3 subpixel density, requires tmux | rich | full | ordered | TrueColor gamut, moderate drift risk | vivid | full | diffusion | best first-frame colors, drift under heavy scenes | sharp / fast | 256 | none | flat colors, no dither noise | Applies a pre-quantization gamma curve: 1.0 darkens Zero byte-count cost — the LUT is per-pixel, not per-frame. Drift risk unchanged. --blocks-colors 256 switches the native renderer to xterm-palette output for the smallest possible byte stream (~78 KB frames). Default is TrueColor (138 KB). - Turn-based cadence. One Enter press per decision. You can't hold W to run — you type www + Enter. Usego N to auto-tick. - Passive refresh at 3.3 Hz. The daemon writes a new frame every 300 ms; the statusline reads on refresh + events. - ~28 rows × 120 cols of frame at default size, tunable via --cols /--rows . - Residual drift is possible under extreme scene changes. The internal mitigations (byte-stable cells, static black border, 256-palette default, fixed-width HUD) keep drift rare in normal play. If you want it impossible, run Claude Code inside tmux — tmux's grid-repair absorbs any remaining drift. - MCP screenshots cost tokens. doom_look returns a PNG (~1–2k tokens). Usedoom_state first,doom_look when stuck. Claude Code's TUI does not expose a "custom panel" API. Status lines, hooks, slash commands, and MCP are the documented extension surfaces. This project composes all four to create something that feels like a built-in Doom panel without patching the binary. A full rationale, including 15+ alternative approaches that don't work, is in docs/design.md. The stub backend is the reference contract. A new real-Doom backend (e.g., Chocolate Doom fork, WASM Doom) implements the same file interface: - Read tick-delimited commands from /tmp/doom-in-claude/input.fifo - Write an ANSI frame to frame.ansi after each tick - Write a PNG screenshot to frame.png - Write game state to state.json (see docs/state-schema.json) MIT. See LICENSE. Doom itself is not included. This project is not affiliated with id Software or Bethesda. Use Freedoom (GPL) for a legally redistributable WAD, or point the daemon at your own licensed doom.wad / doom2.wad .

Genesis Park 편집팀이 AI를 활용하여 작성한 분석입니다. 원문은 출처 링크를 통해 확인할 수 있습니다.

공유

관련 저널 읽기

전체 보기 →