ATL
- Image blocks become timelines: picture steps with dissolve, parallel, contains,
finite repeat, time, function f(trans, st, at), calls of other transforms with
arguments, on hover/idle events for buttons. Animations stop when their element
leaves the page
- Pictures defined by an expression (get_face_path("base")) are drawn at show time
- Purely graphical hints (shader, mesh, gl_*, u_*) are accepted and dropped
Colour
- matrixcolor and im.matrix.* as 5x5 matrices combined with `*`, applied through SVG
filters; im.MatrixColor/Scale/Crop/Blur/Composite and Text/Image as values
Python
- match statement, re/copy/time/datetime/defaultdict/functools.partial, more
str/dict methods, Character(...) created by code
- narrator("..."), Character calls, renpy.say and renpy.show/hide with expressions in
Python blocks become script nodes
- Audit follows reachability: functions and classes nothing refers to (custom
statement lexers, unused tools) no longer block an import
Docs: README and ARCHITECTURE now describe a multi-engine library (GameMaker and
QSP planned). Tests for the new runtime pieces.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Converter
- screens.py parses the screen language: containers (fixed, frame, vbox, hbox,
grid, vpgrid, viewport, button, has), widgets (text, textbutton, imagebutton,
add, bar ...), if/for/use/transclude, default, python, key, timer, on, inline ATL,
conditional properties, and decompiled forms (unparenthesised operators,
glued property values, comma separated actions)
- style statements, call/show/hide screen operators and Python-level
renpy.show_screen are translated; only screens the game shows are audited,
unused stock screens no longer block an import; undefined screens do
- ATL values may be computed at run time and transforms take parameters
(at blink(0.2, 0.3)); blur property
Player
- screens.ts builds the DOM from the IR and rebuilds it on state changes;
buttons with idle/hover/selected/insensitive states, tooltips, sounds, modal
screens, timers and keys that survive re-rendering, saved with the save file
- Actions: Jump, Call, Return, SetVariable, Toggle*, SetScreenVariable, Show, Hide,
ToggleScreen, Function, Play, Notify, If, Language, ShowMenu, OpenURL ...
- Crop/LiveCrop/Solid/Frame/Transform/DynamicDisplayable values, crop property,
globals(), renpy.variant/change_language/seen_image, transition stubs
Tests: screen parser and runtime (linkedom DOM), screens fixture compiled from
tests/fixtures/screens.rpy. Docs: docs/SCREENS.md.
Twisted-Thoughts now passes the strict compatibility check.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Python sandbox
- try/except/else/finally, raise (incl. re-raise), assert, for/while ... else
- Multi-generator and dict comprehensions
- Builtin exception hierarchy; user exceptions subclass it
- Inside try, missing keys/indexes, division by zero, attribute access on None
and unknown names raise Python exceptions; lookups stay lenient elsewhere
- int()/float() raise ValueError on non-numeric strings
ATL
- converter/atl.py: set/move (linear, ease, easein, easeout), pause, repeat,
parallel, choice, block, on show/hide and named transforms become a timeline
shipped as game.json "atl"; Move() becomes a linear slide
- player/atl.ts: timeline runner wired into the renderer; `on hide` plays
before the picture is removed
- function, time, contains, matrixcolor and expressions still block the import
Tests: exceptions/ATL fixtures and runtime tests, converter ATL tests; README
and ARCHITECTURE updated.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Add immutable revisions, PGVN editor, asset replacement, merge and rebase workflows, authenticated media delivery and reachability GC. Harden the script interpreter, pin unrpyc and remove tracked build metadata. Include current compatibility checks, Naninovel import and regression tests.
- every script node gets a permanent id, say nodes a Ren'Py-style tid
- all languages from the game's tl/ are imported at conversion: dialogue blocks
matched by their source-location comment or by label + original text,
`translate strings` become a per-language strings table
- source language from config.language or detected from the dialogue
- manifest stores locales/<lang>/<module>.json and strings.json; game.json
lists sourceLang and available locales with progress
- player: language picker in main menu and settings, fallback to source,
__(), [var!t] and _preferences.language
- parser: `default` with init priority, and one bad statement no longer drops
the whole file
- docs/LOCALIZATION.md: design for translations, publishing and mods
Line endings of several converter/player files go back to LF: an earlier
commit accidentally stored them as CRLF.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- FastAPI backend: admin bootstrap with forced credential change, admin-created
users with one-time generated passwords, roles as permission sets
- Games and versions with content-addressed blob storage; forks copy only the
manifest, so mods share assets with the original
- Worker: archive/RPA extraction, unrpyc for .rpyc, own .rpy parser, Python
subset translated via ast, media converted to WebP/Opus/WebM
- React panel (library search, game page, upload, users, roles) and a
framework-free web player with saves, history, skip/auto, transitions
- docker compose: postgres, backend, worker, nginx on a single HTTP port
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>