7.9 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
Definitely not an Impostor is a narrative-driven fantasy game built for TIC-80, a fantasy console. The game is written entirely in Lua. All source modules in inc/ are concatenated at build time into a single impostor.lua file that TIC-80 loads.
Build Commands
make build # Concatenate inc/**/*.lua into impostor.lua (order from impostor.inc)
make minify # Build then minify (downloads minify.lua if missing)
make lint # Run luacheck with source mapping to original files
make watch # Auto-rebuild on file changes in inc/
make export # Export minified game to HTML and .tic formats
make import_assets # Import PNG sprite/tile assets into the TIC-80 cartridge
make export_assets # Extract TIC-80 asset sections into inc/meta/meta.assets.lua
make docs # Generate documentation with ldoc
make clean # Remove build artifacts
To run the game locally: tic80 --fs=. impostor.lua
VSCode tasks are available for "Run TIC80", "Build & Run TIC80", "Export assets", and "Make build".
There is no test framework — validation is done via make lint (luacheck).
Important Workflow Note
Do not run git add or git commit — git operations are the user's responsibility.
Code Conventions (from GEMINI.md)
- Functions:
PascalCase(e.g.,UpdatePlayer,DrawHUD) - Variables:
snake_case(e.g.,player_x,game_state) - Constants:
SCREAMING_SNAKE_CASE(e.g.,MAX_SPEED) - Indentation: 2 spaces
- Tables: Always multi-line with one key-value pair per line
- Code sections: Delimited with
--- @section SectionNamecomments - TIC-80 APIs: Use
btn()for input,spr()for sprites,map()for tilemaps,Print.text()for text
Architecture
The game is a state machine driven by a window manager. The build order is defined in impostor.inc — 99 source files are concatenated in dependency order.
Main Loop
TIC() in inc/system/system.main.lua is TIC-80's per-frame callback. It:
- Initializes game state once on first call
- Updates mouse/context timing
- Delegates to the current active window handler
- Updates meters, timers, triggers, and glitch effects
- Draws UI overlays
Window Manager (inc/window/window.manager.lua)
Central UI state machine. Windows register with id, update(), and draw() handlers. Only one window is active at a time. All windows are declared in window.register.lua.
| Window | Purpose |
|---|---|
intro_title |
Title screen |
intro_ttg |
"Thanks To Grandma" credits |
intro_brief |
Game briefing |
menu |
Main menu |
game |
Main gameplay (screens + decisions) |
popup |
General popup overlay |
discussion |
NPC dialogue/conversation |
minigame_button_mash |
Button Mash minigame |
minigame_rhythm |
Rhythm minigame |
minigame_ddr |
DDR minigame |
game_over |
Game over / restart screen |
end |
End game choice screen |
continued |
Day-continued notification |
credits |
Credits roll |
controls |
Control scheme display |
audiotest |
Audio testing utility |
player_name |
3-character name entry before new game |
ascend_debug |
Debug utility: start at a specific ascension level |
Screen & Decision System (inc/screen/, inc/decision/)
- Screens are gameplay scenes. Registered with
Screen.register({id, name, decisions[], background, init, update, draw, exit}). They manage background maps and NPC sprite placement. - Decisions are player choices available on a screen. Registered with
Decision.register({id, label, condition, handle}). Aconditionfunction gates visibility;handledrives transitions (to new screens, dialogue, minigames).
Screens: home, office, work, toilet, walking_to_office, walking_to_home, mysterious_man, manager
Maps (inc/map/): bedroom, office, street — rendered via map.manager.lua.
Game Logic (inc/logic/)
| Module | Purpose |
|---|---|
logic.meter.lua |
Tracks ISM/WPM/BM stats (0–1000), combo multipliers, daily decay (20/day) |
logic.day.lua |
Day counter; ascension triggers at day 3, game over at day 100 |
logic.timer.lua |
Event scheduling/delayed callbacks, one-shot and repeating |
logic.trigger.lua |
Conditional event handlers with start/stop callbacks |
logic.discussion.lua |
Dialogue parsing, branching answers, NPC portrait rendering |
logic.minigame.lua |
Config and win-overlay for Button Mash, Rhythm, and DDR |
logic.focus.lua |
Circular reveal/hide overlay transitions (expanding/shrinking circle) |
logic.glitch.lua |
Visual glitch effect (random vertical stripes), toggled via Glitch.show()/hide() |
logic.commute_glitch.lua |
7-level glitch progression during ascension 7: corrupts sprite lists, remaps Norman to norman_echo, speeds up music, blocks/redirects decisions |
logic.codegenerator.lua |
Encodes player's 3-char name to a 6-char base-36 completion code shown on the end screen |
Global State (inc/init/)
init.context.lua: All runtime game state (current screen, meter values, progress flags). Persisted in memory bank 6. Key fields:player_name(3-char string),commute_glitch_level(0–7),talked_to_norman_echo,talked_to_true_sumphore,have_been_to_office,have_done_work_today.init.config.lua: Screen dimensions (240×136), palette colors, timing constants. Persisted in memory bank 7.init.ascension.lua: 9-level meta-progression system ("ASCENSION" letters progressively lit). Level 7 activates CommunteGlitch; level 9 unlocks the final "Break the cycle" decision.init.context_debug.lua:Context.new_game_debug(level)— starts a new game at a specific ascension level for testing.
Audio (inc/audio/)
audio.manager.lua: Music playback (no-restart if already playing). Named tracks:room_work(0),activity_work(1),mystery(2).audio.generator.lua/audio.songs.lua: Sound generation and song definitions.
Sprites (inc/sprite/)
sprite.manager.lua handles registration. Supports single and composite sprites with offset layers.
NPCs: norman, norman_echo (palette-remapped glitch variant of Norman, shown at commute glitch level 7), sumphore, pizza_vendor, and 10 developer archetypes (dev_boy, dev_buddy, dev_extrovert, dev_girl, dev_guard, dev_guru, dev_hr_girl, dev_introvert, dev_operator, dev_project_manager). Matrix characters: matrix_architect, matrix_neo, matrix_oraculum, matrix_trinity.
Discussions (inc/discussion/)
Branching dialogue files loaded by logic.discussion.lua. Each file defines one or more named dialogue trees (keyed strings with answer arrays that apply meter deltas).
| File | Dialogues |
|---|---|
discussion.sumphore.lua |
Sumphore conversations (glitch-aware variants at commute glitch level 7) |
discussion.coworker.lua |
Coworker coffee-chat variants per ascension level (disc_0, disc_1, disc_asc_1, disc_2, disc_asc_2, …) |
discussion.commute_glitch.lua |
8 commute glitch encounter variants (cg_0–cg_7) + truth/Sumphore variant |
discussion.truth.lua |
Dialogue with the "truth" mysterious man |
discussion.pizza_vendor.lua |
Pizza vendor interaction |
Input Utilities (inc/system/)
system.textinput.lua: 3-character uppercase letter selector. Supports next/prev letter cycling (A↔Z wrapping) and cursor navigation. Used byPlayerNameWindow.
Key Directories
inc/ Source modules (concatenated at build)
assets/ Game assets (sprites, tiles, SFX, music)
assets_src/ Source art (Aseprite files, PNGs for import)
docs/ Design documentation (mostly Hungarian)
tools/ Build utilities (musicator: MIDI→TIC-80 converter)
prompts/ Feature templates