Layers (config.layers, onlayer, add_layer, show_layer_at, camera with perspective), the
game's config.custom_text_tags called like Ren'Py does (the built-in {bt}/{fi}/... copies
are gone), built-in {font} {alpha} {k} {cps} {a} {rb}/{rt} {space} {alt} {image}, FontGroup,
mouse displayable, renpy.fetch, preferences backed by the player's settings, Color class,
Render.subsurface/zoom, `default obj.attr` on provided objects, and a repaint loop that
survives text being laid out again.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
onlayer on show/hide/call screen and `camera <layer>` reach the player, `perspective`
is an ATL property now, RotateMatrix/OffsetMatrix/ScaleMatrix, Text.set_text and
renpy.fetch are accepted. The text-effect modules of That New Teacher are no longer
skipped (only the shader-based wave tag is).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Each letter is moved by one animation loop with the formulas of BounceText, FadeInText, ScareText and
GlitchText (fi follows the text speed, bt keeps its phase while a line is typed out, glitch cuts the text
into strips that jump sideways). Flatten and `at Flatten` isolate their children as one picture, screens
get the 3D turns, matrixtransform and blend of their widgets, and RotateMatrix/OffsetMatrix/ScaleMatrix
exist in Python.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
rendertransform.ts follows RenderTransform from accelerator.pyx: the same matrices in the same order, with
transform_anchor measuring the anchor in the child. Scene images are laid out from it (left/top plus a
matrix3d with origin 0 0), so rotation turns about the picture's centre and the box grows to its diagonal
as in Ren'Py; xpan/ypan are a wrapped shift of a repeating background, xtile/ytile repeat it, blend and a
fully additive picture become mix-blend-mode. Checked in a real browser page and by unit tests of the math.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
These properties were treated as GPU hints and silently discarded. The converter now carries xpan, ypan,
xtile, ytile, xrotate, yrotate, zrotate, zpos, zzoom, blend, additive, transform_anchor, rotate_pad,
matrixanchor, matrixtransform, fit, maxsize and crop_relative into the timelines.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Named stores (PyNamespace: dotted access, functions that see their own store first, restored after a
save is loaded), real generators run step by step (next, send, yield as an expression), len/bool through
__len__/__bool__, os/calendar/itertools/pygame_sdl2 helpers, Skip and ToggleLocalVariable actions,
text tags {glitch} and {wave} and plain display of explode/gradient/ruby, SnowBlossom and anim.Blink,
RoundedCorners as a transform, transforms listed in `at`, ATL choice weights that are flags, and
renpy.image_size from the converter's picture sizes.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
`init phone register` becomes a default (the group chat) plus a function of library calls that runs with
the other defaults of a new game (phone_register.py). `init/python [early|hide] in some.store` wraps its
code in an in_store node and `default some.store.name` may name a store; yield works as an expression
(generator functions are marked gen); `import x as y`, `transform -150 name(...)`, `init:` with if/else,
`config.special_namespaces` lines, `at` lists and tuples, transforms made by Python functions, `choice`
weights that are expressions, `__len__`/`__bool__`, and the whitelist for os, calendar, itertools,
pygame_sdl2 and the new runtime. The converter also records the size of every picture it converts
(`imageSizes`) so `renpy.image_size` answers without loading.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The Phone library's own statement parsers (ll.require, ll.keyword ... in 01statements.rpy) run while
Ren'Py reads scripts, so the converter reads `init phone register` itself and the file is skipped. Also
skipped: the old-save fixer (it reads Ren'Py's pickled saves), the shader blur patched into Transform,
and the text-effect modules that draw letters through the render API (the player has its own text
tags). One misspelt call in the library (`charcter`) is recorded as a defect of the original build.
The game now passes the strict check and converts fully (14236 files, 3.3 GB).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Text fields (`input`) with InputValue classes games can extend, continue/break in screen loops, Confirm,
CaptureFocus/ClearFocus/InvertSelected, generator functions and iter/next, starred tuple items,
renpy.file and json over data files loaded before the game starts, renpy.Container and
register_sl_displayable, DiamondBox layout, ConditionSwitch/DynamicImage/Animation, renpy.show(what=...),
callable transforms (`store.move_in(0.3)`), call_in_new_context as a call, im.matrix/im.Image/
MatrixColor, colorsys, fnmatch, FontGroup, persistent._clear and small renpy helpers.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
`init -490 screen`, `import x as y` and `from m import A as B`, classes with @renpy.pure, pickle hooks
on classes, `*` items in tuples and lists, generator functions (yield statements; the player runs them
to the end), multi-line expressions that need brackets, Null() and Animation() images, images given as
expressions (`"path/{}.png".format(x)`, f-strings), window statements in init, `offset` in ATL, input
widgets with their values and the focus/confirm actions, `continue` and `break` in screens, `drag`
and DiamondBox-style `fixed` with cell_size, `getattr(...)()` calls, transforms called with arguments,
and the whitelist for the new runtime. JSON files of a game are shipped as data files. Also fixes
blocking_names failing on a call of a call during full conversion.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
goodluke skips the author's developer tools (save export, scene browser and launcher, state panel, seed
tool: they read files and start programs, and nothing outside atlas/dev calls them) and the outline
shader demo, and waives two defects of the original: a jump to the label composer_scene that was never
written, and a call to a debug helper that is not defined and sits behind a flag that is False.
SaintlyCorruption needs only its fingerprint. Both now pass the strict check and convert fully.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Games write their own displayables with render(), renpy.Render, blit, fill, canvas() and renpy.redraw.
render.ts keeps a tree of placed pieces (child renders, ordinary displayables, fills and drawing
commands) and turns it into DOM elements that stay put between redraws; pointer events reach event()
as pygame-style objects, and a returned value ends the interaction. Shaders and GPU properties are
accepted and ignored. The converter whitelists the calls and methods and accepts `import pygame`.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The build (fingerprint of its scripts) skips third-party code written against Ren'Py's render API
(colour picker demo, Kinetic Text Tags, cps_preview) and waives its one missing test screen. Converter:
xpan/ypan/matrixtransform/matrixanchor are skipped like other GPU hints, `if renpy.has_live2d()` in an
init block keeps only its else branch, `crop(...)xpos` and `crop (1, 2, 3, 4)` parse, `drag` is a screen
container, `at icon["at"]` becomes a dynamic entry, and the whitelist gains Matrix, Move, absolute and
the no-op helpers. The game now passes the strict check and converts fully (3272 files, 288 MB).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
screens: `drag` with draggable True moves with the pointer (the place is kept while the screen is
shown); `at icon["at"]` picks a transform that Python code stored in a dict (transform names now
evaluate to a reference); PreviewSlowText and Move(...) exist as values. Python: Matrix([16 numbers])
for matrixcolor, renpy.has_live2d() is false, renpy.fetch fails like a missing network (games catch
it), cache.get_total_size and the texture helpers are no-ops.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Letters of these custom tags animate one after another (CSS). A closing tag now closes the style that
it opened (with anything left open inside) instead of popping whatever was on top, and an unknown tag
that has a closing tag later shows its text plainly and stays balanced.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
MIST's cutscene screen has a 0.1s timer that changes a variable, and every change rebuilt the whole
screen: the <video> restarted each time and "Skip" was replaced between press and release, so the
click never landed. Videos (Movie(play=...) and the movie channel picture) are now kept per shown
screen and resumed if the browser paused them, and a redraw requested while a pointer is down waits
for its release.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Games with their own save screens work: FileAction/FileSave/FileLoad/FileDelete/FilePage*, FileLoadable,
FileTime, FileSaveName, FileJson and friends use browser slots (a slot has no screenshot). Added
renpy.has_image/has_screen/list_files/get_mouse_pos/log/jump_out_of_context/random.seed,
renpy.translation.translate_string, type/id/vars/Flatten/LiveComposite/Composite, bare defaultdict/
deepcopy, md5/sha256 (checked against test vectors), uuid4, time.monotonic, re.compile().fullmatch,
math.isfinite and `{**a, "k": v}`. The converter whitelists them and accepts the hashlib/uuid imports.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
ATL: `ease(1.0) zoom 1.3`, `ease (0.1)xpos 0.5`, `ease(0.1)rotate 5` and `pause(1.5)` take the duration
in brackets; `offset (x, y)` becomes xoffset/yoffset; lines starting with shader, mesh, u_*, blend or
transform_anchor are skipped as GPU hints. thelewdesthouse drops from about 1400 to 111 rejections.
Screens: `for x index k in seq`, `add"x"` without a space, and `onlayer name` after show/call screen
(the layer is ignored, every screen lives in one layer). Transforms named with a capital letter and
declared in another file are resolved by the prescan, and `__("Name") "text"` is a translatable speaker.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
gui/journal_icon.png in that build is a text note ("PLACEHOLDER: Download a journal icon...") with an
.svg next to it, so Ren'Py cannot load it either. A build can now list placeholder files by path and
SHA-256; only an exact match is skipped and the report carries a non-blocking warning. The full
conversion of the game (2898 files, 2.77 GB) now finishes without failed media.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
`frame at (a if cond else b)` is kept as a choice that the player resolves each time the screen is
drawn. An ATL line splits at top-level commas into separate statements, so `zoom 1.2, 0.2` is a zoom
followed by a 0.2s pause, as Ren'Py compiles it (two-value properties such as `pos 0.5, 0.5` stay
whole). The inert events deselected/unselected, which Ren'Py never sends, are accepted. With the
build profile for The Only Doe 0.05 the game now passes the strict script check.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
sleep.rpy tests `... before_sleeping=2` (assignment) in an elif; sleep.rpyc holds the same text, so
Ren'Py cannot compile that branch either. Builds can now carry exact-line patches pinned by the
SHA-256 of the line and the build fingerprint; this one restores `==2`. Anything else stays strict.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Screens get an invisible mousearea that reports the pointer entering and leaving without taking
clicks. datetime.date/datetime/timedelta support construction and date arithmetic. dir() lists the
game's variables, renpy.style.rebuild() is a no-op, and renpy.image_size answers only for pictures
the browser already holds (otherwise an IOError the game can catch).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Ren'Py's own _hide_windows label hides the dialogue window until the player clicks. Games call it
directly between scenes, and one of them 531 times. Other labels stay unsupported.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
renpy.random/random get choices, sample, randrange and Random(seed); frozenset, iter and hash
are builtins. User classes may define __hash__ (dict keys), __iter__, __getitem__ and
__contains__; the converter accepts them instead of rejecting the whole class, which
removes the Perk/Skill/Status wall in SaintlyCorruption.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
show text _("...") and literal screen texts are listed in Names and menu; typing in search switches the filter from To do to All; the translator is told how stutters are spelled.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Decorative Ren'Py tags cannot survive translation mid-word; retry without them when the translator rejects the answer.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Total shown right away, lines saved per poll, retry reasons in the card; layout fix of the options row.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The run is recorded at every page and picked up from the translator's finished job; one run across tabs via Web Locks.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Language picker with search and SVG flags, real pagination with locate, one global machine translation run shown next to uploads.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Shared translator session, game description/genres as optional context, live header progress.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Translator panel in the translation editor and a /translator setup page. The browser talks to
local-translator directly; the server only receives lines marked as machine.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- Each ready version gets a "Languages" dropdown next to Play: the original language
first, then translations with their completion; picking one starts the version in
that language
- The game header gets the same dropdown, aggregated over published, ready versions.
Each language points at the version that has it best (most complete, the main
version on a tie); an original language counts as complete
- The old row of language tags linking to the translation editor is replaced
- Backend: versions carry source_name (the name of the original language)
- pages/languages.ts holds the aggregation logic with tests; LanguageMenu closes on
outside click and Escape
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- Music, sound and voice volumes are shared by all games by default; a game that
has never been launched with its own volumes plays with the shared ones
- The sound section of the player settings has a "own volume for this game" switch:
turning it on starts from the current values and then the sliders change only this
game, turning it off removes the override and returns to the shared volumes
- The override belongs to the game (game_id from /api/versions/{id}), so forks and mods
share it; it falls back to the version id when the id is unavailable
- Reading speed and auto delay stay shared
- volume-store.ts keeps the storage logic (damaged data ignored, values clamped,
unavailable storage tolerated) and has its own tests
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- math: sin/cos/tan/asin/acos/atan/atan2, exp, log, log10, fabs, fmod, modf, trunc,
hypot, degrees, radians, isnan, isinf, copysign, e
- renpy.curry, get_showing_tags, run(action), pop_call; _preferences.get_mute/get_volume
- The compatibility check knows these names
Removes a few more blockers in TheFixer and That_New_Teacher; the rest are custom
systems of those games (AlphaMask wardrobe, custom statements) and authoring defects.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- pyparse.ts: parser for expressions and simple statements built at run time, producing
the sandbox's own IR; backs eval() and exec() (e.g. exec("persistent." + var + " = 0"))
- Replay/EndReplay and renpy.end_replay: the engine stashes the full game state, runs the
label with the given scope and restores everything when it ends; locked replays are
insensitive. Save loading shared as applySave()
- Screen actions are callable (MainMenu(confirm=False)())
- jump main_menu_screen is Ren'Py's own label: it opens the player's main menu
- Screens: a closing quote ends the word before a letter ("text"size 15) but not before
an operator ("a"+b); Text(...) pictures in image blocks
- README: current capabilities and limits of the Ren'Py support
Strict compatibility check on the local collection: Tomie, Twisted-Thoughts, Hooked,
iNSight-of-you and SomethingBetter pass; TheFixer (custom AlphaMask wardrobe, missing
labels) and That_New_Teacher (custom statements, Render API) do not.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>