Move all root .py files into playscii/ package directory. Rename playscii.py to app.py, add __main__.py entry point. Convert bare imports to relative (within package) and absolute (in formats/ and games/). Data dirs stay at root.
3.8 KiB
playscii - ascii art and game creation tool (v9.18)
desktop GUI app using SDL2 + OpenGL. NOT a web app, no server component. originally from https://heptapod.host/jp-lebreton/playscii (mercurial). we maintain our own git repo.
running
just run launch the app (uv run python -m playscii) just check lint gate (ruff check + format) just lint ruff check --fix + ruff format just typecheck ty check (601 errors, legacy code, not in check gate) just test pytest (no tests yet, not in check gate)
project structure
python source organized as playscii/ package (~50 .py files) data directories (charsets/, palettes/, etc.) live at repo root formats/ and games/ also at root (loaded dynamically via importlib)
playscii/ init.py package marker main.py entry point for python -m playscii app.py main application, SDL2/OpenGL setup (was playscii.py) art.py art/canvas management, the core data model ui*.py ~20 UI modules (dialogs, panels, menus, toolbar, etc.) game_.py game engine (objects, rooms, world, HUD) renderable.py rendering pipeline (sprites, lines, framebuffer)
formats/ import/export handlers (ANS, ATA, BMP, EDSCII, PNG, GIF, TXT) games/ bundled example games (crawler, fireplace, flood, maze, shmup, etc.) charsets/ 30+ classic computer character sets (.char + .png) palettes/ color palette definitions shaders/ GLSL shader files artscripts/ art animation scripts (.arsc files) art/ sample ASCII art (.psci files) docs/ documentation and design notes ui/ UI image resources
dependencies
runtime: appdirs, numpy, Pillow, PyOpenGL, PySDL2, packaging system: libSDL2, libSDL2_mixer (must be installed on the OS) dev: ruff, pytest
gotchas
package structure: all python source now lives in playscii/ package. files use relative imports (from .art import ...). formats/ and games/ use absolute imports (from playscii.art import ...). data directories stay at root since the app uses CWD-relative paths to load charsets, shaders, etc.
art scripts and exec(): art.py imports random at module level with a noqa comment. art scripts (.arsc files) are loaded via exec() in art.py's scope. they use random without importing it themselves. do NOT remove that import even though ruff flags it as unused. same pattern may apply to other "unused" imports in art.py — check before removing anything.
pdoc detection: app.py has a contextlib.suppress block that tries to import pdoc. the import MUST stay inside the suppress block. if it gets moved or removed, pdoc_available becomes unconditionally True and the help menu breaks when pdoc isn't installed.
SDL2 init ordering: many modules import from app.py's namespace or expect SDL2 to be initialized before they run. import order in app.py matters — E402 is disabled for this reason.
mutable default arguments: B006 is disabled. many functions use mutable defaults (lists, dicts). changing these could alter behavior since some code may rely on the shared mutable state. do not "fix" these without testing.
variable naming: E741 is disabled. single-letter vars (l, x, y, z, i, r, g, b) are everywhere in the math/rendering/game code. this is intentional.
ruff config
rules: E, F, I, UP, B, SIM 13 rules are explicitly ignored (see pyproject.toml for rationale) line-length: 88, formatter handles what it can
when adding new code, write it clean. the ignored rules are concessions to legacy code, not a style guide for new work.