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>
- Unsupported ATL constructs in a transform now block the import only when the
transform is used (at clause, another transform, even before its definition).
Stock screens.rpy transforms for unused screens no longer fail games
- image blocks with one picture plus linear/ease/parallel/repeat keep their
animation (image-level ATL); the renderer also starts it
- Python: skip @gui.variant/@renpy.variant functions (inactive variants), treat
@renpy.pure as transparent, read renpy.store.x as x
- Accept renpy.transition, end_replay, block_rollback and music set_pause/set_pan
as presentation-only no-ops, and implement them in the player (set_pause and
set_pan were allowed by the converter but missing at runtime)
- Skip the 0x52-URM add-on directory (in-game console / save editor) when
parsing scripts and media
- Tests for lazy ATL warnings, moving images and variants
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>
- 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>
Checked against six real games (Ren'Py 7.5 and 8.x):
- nested labels and named menus become jump anchors inside label bodies
- call with arguments and labels with parameters (dynamically scoped)
- frame-by-frame ATL images, Movie frames, layeredimage, camera, Shake,
custom audio channels via register_channel, show text with expressions
- generator expressions in Python, no SyntaxWarning noise from decompiled code
Also:
- app.import_dir converts an unpacked game folder without changing it
- app.converter.analyze dry-runs the script part of the converter
- imports use their own "importing" status so a worker restart can't hijack them
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>