feat: player runs the game's own text tags, layers and camera, real preferences and Color

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>
This commit is contained in:
mrleo1nidandClaude Sonnet 5.5 committed 2026-10-27 04:39:48 +03:00
1 parent 5da7ab1a90
commit a7034b3563
13 files changed
+1563 -710

No files matched your search

+4 -4
View File
@@ -41,15 +41,15 @@ test("highlight wraps glossary terms case-insensitively and escapes regex charac
assert.equal(highlight("plain", []), "plain");
});
test("custom tags: letters of {bt} and {sc} move, a closing tag closes only its own tag, unknown pairs stay plain", async () => {
test("tags the game does not run stay plain, and a closing tag closes only its own tag", async () => {
const { build } = await import("esbuild");
const { fileURLToPath } = await import("node:url");
const compiled = await build({ entryPoints: [fileURLToPath(new URL("../src/player/text.ts", import.meta.url))],
bundle: true, write: false, format: "esm", platform: "node", logLevel: "silent" });
const { parseText, plainText } = await import(`data:text/javascript;base64,${Buffer.from(compiled.outputFiles[0].text).toString("base64")}`);
const parsed = parseText("a{b}{bt=8}jump{/bt} still bold{/b} plain {chaos}odd{/chaos} end");
const styles = parsed.segments.filter((s) => s.kind === "text").map((s) => [s.text, !!s.style.b, s.style.fx ?? null]);
assert.deepEqual(styles, [["a", false, null], ["jump", true, "bt"], [" still bold", true, null], [" plain ", false, null],
["odd", false, null], [" end", false, null]]);
const styles = parsed.segments.filter((s) => s.kind === "text").map((s) => [s.text, !!s.style.b]);
assert.deepEqual(styles, [["a", false], ["jump", true], [" still bold", true], [" plain ", false],
["odd", false], [" end", false]]);
assert.equal(plainText(parsed), "ajump still bold plain odd end");
});