Context aware skills for TL Images Skill

This commit is contained in:
DazedAnon 2026-07-26 13:18:18 -05:00
parent ef7a3f8235
commit c41b84142a
9 changed files with 77 additions and 26 deletions

View file

@ -26,7 +26,8 @@ folder containing loose PNGs.
1. Use **Decrypt** for RPG Maker assets or **Make editable** for ordinary PNGs. Editable copies
mirror their game-relative paths under `.dazedtl/images/`.
2. Click **Copy skill** and paste the scoped bitmap-localization instructions into your coding
agent.
agent. The shared workflow automatically receives RPG Maker or Generic-specific guidance from
the active image profile.
3. Review the edited PNGs here.
4. Patch highlighted images, or clear highlights to patch every editable PNG.

View file

@ -1,16 +1,20 @@
# Localize Editable Bitmap UI
<task_context>
Translate player-visible source-language text embedded in the editable RPG Maker bitmap UI
assets under this folder, recursively:
Translate player-visible source-language text embedded in the editable bitmap UI assets for the
{{ENGINE_NAME}} image profile under this folder, recursively:
`{{EDITABLE_IMAGES_FOLDER}}`
Use this game project as read-only context for vocabulary, image usages, event data, plugins,
scripts, runtime coordinates, scaling, opacity, and dynamic values:
Use this game or project folder as read-only context for vocabulary, image usages, scripts, data,
runtime coordinates, scaling, opacity, and dynamic values:
`{{GAME_ROOT}}`
Apply this engine-profile guidance:
{{ENGINE_CONTEXT}}
Use this file as the authoritative glossary for every translation:
`{{VOCAB_FILE}}`
@ -26,10 +30,10 @@ backups and temporary candidates outside the editable image folder so they canno
patchable assets. Work through all editable PNGs without asking for confirmation unless a hard
safety rule below requires review.
Runtime assets may be read, decoded, or decrypted in memory or into an isolated temporary
directory when needed to reconstruct an editable image. This does not authorize modifying those
runtime assets. Prefer the project's own clean source layers over attempting to recover artwork
from a flattened text-bearing PNG.
Runtime assets may be read or decoded in memory or into an isolated temporary directory when
needed to reconstruct an editable image, when permitted by the engine-profile guidance. This does
not authorize modifying those runtime assets. Prefer the project's own clean source layers over
attempting to recover artwork from a flattened text-bearing PNG.
</task_context>
Translate embedded bitmap text by reconstructing the smallest safe UI regions and rendering
@ -110,9 +114,8 @@ clean version of every covered visual element. Check:
- Runtime images with matching prefixes, encounter numbers, abbreviations, or character names.
- Enemy battlers, recollections, cut-ins, gallery images, portraits, and layered battle sprites.
- Alternate pages or variants that reveal how the same composition is assembled.
- Event and script references that map an editable filename to a runtime encounter or asset.
- RPG Maker encrypted image files. Read the project encryption key and decode a copy in memory
or a temporary directory when required; never alter the encrypted original.
- Code, data, scene, or script references that map an editable filename to a runtime use.
- Additional runtime variants or source layers made accessible by the engine-profile guidance.
Build an explicit mapping from each editable variant to its clean source art. Preserve semantic
and progression differences: for example, use the enemy icon on introductory pages and the
@ -125,8 +128,8 @@ clone over, or cover the flattened artwork first.
### 5. Inspect runtime drawing logic
Search the read-only game project for every image filename and the code or event data that
displays it. Determine:
Search the read-only game or project folder for every image filename and any code, data, scene,
or script definition that displays it. Determine:
- Image position, scale, and runtime opacity.
- Runtime-drawn counters, percentages, names, or other values.
@ -248,7 +251,7 @@ effect stack and visual prominence.
### 11. Protect dynamic values
Reserve the exact runtime-drawn areas discovered from source code or event data. Test likely
Reserve the exact runtime-drawn areas discovered from available project or runtime data. Test likely
maximum values such as `0`, `99`, `100`, `999`, and any known project-specific maximum. Ensure
translated labels and suffixes cannot collide with right-aligned or centered runtime values.

View file

@ -37,6 +37,7 @@ An image profile exposes:
5. Creation of editable copies.
6. Runtime-file generation for patching.
7. Capabilities and actionable unsupported-operation errors.
8. A concise context block injected into the shared bitmap-localization skill.
Patch delivery is separate from engine encoding. The initial Git/GameUpdate
backend publishes engine-built files at their game-relative paths and adds exact
@ -62,6 +63,8 @@ later apply-only and export-folder backends.
- Generic mode exposes an image-folder selector constrained to the game root.
- Action wording follows capability: RPG Maker uses Decrypt for encrypted
assets; generic assets use Make editable.
- Copy skill injects the active engine name and profile guidance into one shared,
engine-neutral bitmap-localization workflow.
- The first release keeps the existing All/Editable filters. Baseline metadata
provides the foundation for later Modified/Conflict filters without making
every ordinary filter operation hash thousands of images on the UI thread.

View file

@ -45,6 +45,7 @@ from util.image_manager import (
detect_image_engine,
editable_workspace_root,
ensure_editable_workspace,
get_image_profile,
make_profile_assets_editable,
normalize_generic_image_root,
prepare_profile_assets_for_patch,
@ -1025,7 +1026,10 @@ class ImageManager(QWidget):
if self.game_root is None:
raise ValueError("Select a game folder first.")
game_root = Path(self.game_root).expanduser().resolve()
profile = get_image_profile(self.engine_id)
replacements = {
"{{ENGINE_NAME}}": profile.label,
"{{ENGINE_CONTEXT}}": profile.translation_skill_context,
"{{GAME_ROOT}}": str(game_root),
"{{EDITABLE_IMAGES_FOLDER}}": str(self._editable_image_root().resolve()),
"{{VOCAB_FILE}}": str(game_root / "vocab.txt"),

View file

@ -124,8 +124,8 @@ class SkillsTab(QWidget):
path=SKILLS_DIR / "image_translation.md",
hint=(
"Clipboard skill copied from the Image Manager for deterministic bitmap UI "
"localisation. Keep the {{GAME_ROOT}}, {{EDITABLE_IMAGES_FOLDER}}, and "
"{{VOCAB_FILE}} placeholders."
"localisation. Keep the {{ENGINE_NAME}}, {{ENGINE_CONTEXT}}, {{GAME_ROOT}}, "
"{{EDITABLE_IMAGES_FOLDER}}, and {{VOCAB_FILE}} placeholders."
),
is_json=False,
)

View file

@ -148,13 +148,13 @@ TLSYSTEMSWITCHES = False
JOIN408 = False
# Dialogue / Scroll / Choices (Main Codes)
CODE101 = True
CODE401 = True
CODE405 = True
CODE102 = True
CODE101 = False
CODE401 = False
CODE405 = False
CODE102 = False
# Optional
CODE408 = True
CODE408 = False
# Variables
CODE122 = False
@ -162,14 +162,14 @@ CODE122_VAR_MIN = 0
CODE122_VAR_MAX = 2000
# Plugins / Scripts
CODE355655 = False
CODE357 = False
CODE355655 = True
CODE357 = True
CODE657 = False
CODE356 = False
CODE320 = False
CODE324 = False
CODE325 = False
CODE111 = False
CODE111 = True
CODE108 = False
# ─── Plugin Manager ──────────────────────────────────────────────────────────
@ -201,7 +201,7 @@ HEADER_MAPPINGS_357 = {
"SceneGlossary": (["category"], None),
}
# Subset of HEADER_MAPPINGS_357 keys that should be processed (empty = none).
ENABLED_PLUGINS_357: set = {"DTextPicture"}
ENABLED_PLUGINS_357: set = {"BattleLogOutput"}
# All known code-355/655 script patterns. Enable entries via ENABLED_PATTERNS_355655.
PATTERNS_355655 = {

View file

@ -169,6 +169,8 @@ class ImageEngineDetectionTests(unittest.TestCase):
self.assertTrue(profiles[PROFILE_RPGMAKER_MVMZ].supports_encryption)
self.assertFalse(profiles[PROFILE_GENERIC].supports_encryption)
self.assertTrue(profiles[PROFILE_GENERIC].configurable_image_root)
self.assertIn("RPG Maker MV/MZ", profiles[PROFILE_RPGMAKER_MVMZ].translation_skill_context)
self.assertNotIn("RPG Maker", profiles[PROFILE_GENERIC].translation_skill_context)
def test_detects_rpgmaker_from_system_json_and_img(self):
with tempfile.TemporaryDirectory() as raw:

View file

@ -317,6 +317,9 @@ class RPGMakerImageManagerSelectionTests(unittest.TestCase):
self.assertIn(str(self.game_root), prompt)
self.assertIn(str(self.game_root / ".dazedtl" / "images" / "img"), prompt)
self.assertIn(str(self.game_root / "vocab.txt"), prompt)
self.assertIn("RPG Maker MV/MZ image profile", prompt)
self.assertIn("This is an RPG Maker MV/MZ project", prompt)
self.assertIn("`.rpgmvp` or `.png_`", prompt)
self.assertIn("authoritative glossary for every translation", prompt)
self.assertIn("deterministic raster backend", prompt)
self.assertIn("runtime value locations as protected keepout regions", prompt)
@ -329,6 +332,8 @@ class RPGMakerImageManagerSelectionTests(unittest.TestCase):
self.assertNotIn("{{GAME_ROOT}}", prompt)
self.assertNotIn("{{EDITABLE_IMAGES_FOLDER}}", prompt)
self.assertNotIn("{{VOCAB_FILE}}", prompt)
self.assertNotIn("{{ENGINE_NAME}}", prompt)
self.assertNotIn("{{ENGINE_CONTEXT}}", prompt)
self.assertIn(
"Copied image translation skill for 1 editable PNG",
self.manager.status_label.text(),
@ -440,6 +445,24 @@ class GenericImageManagerUITests(unittest.TestCase):
self.assertEqual(manager.image_list.count(), 1)
self.assertEqual(manager.assets[0].asset_id, "assets/images/ui/menu.png")
self.assertFalse((game_root / ".dazedtl").exists())
asset = manager.assets[0]
asset.plain_path.parent.mkdir(parents=True)
asset.plain_path.write_bytes(asset.runtime_plain_path.read_bytes())
manager._start_scan()
manager._scan_worker.wait(5000)
self.app.processEvents()
QApplication.clipboard().clear()
manager.copy_translation_button.click()
prompt = QApplication.clipboard().text()
self.assertIn("Generic / Loose Images image profile", prompt)
self.assertIn("manages loose PNG assets", prompt)
self.assertIn("without assuming a particular game engine", prompt)
self.assertNotIn("RPG Maker", prompt)
self.assertNotIn(".rpgmvp", prompt)
self.assertNotIn("{{ENGINE_NAME}}", prompt)
self.assertNotIn("{{ENGINE_CONTEXT}}", prompt)
finally:
for worker in list(manager._thumbnail_workers):
worker.wait(5000)

View file

@ -84,6 +84,7 @@ class ImageEngineProfile:
label: str
configurable_image_root: bool
supports_encryption: bool
translation_skill_context: str
supported_extensions: tuple[str, ...] = SUPPORTED_PLAIN_EXTENSIONS
@ -93,12 +94,26 @@ IMAGE_ENGINE_PROFILES = (
"RPG Maker MV/MZ",
configurable_image_root=False,
supports_encryption=True,
translation_skill_context=(
"This is an RPG Maker MV/MZ project. Runtime images normally live under `img/` or "
"`www/img/`. Inspect event commands, plugins, and scripts for image placement, "
"scaling, opacity, dynamic values, and filename-dependent behavior. Encrypted "
"`.rpgmvp` or `.png_` assets may be decoded read-only with the encryption key from "
"`System.json`; never modify an encrypted runtime original."
),
),
ImageEngineProfile(
PROFILE_GENERIC,
"Generic / Loose Images",
configurable_image_root=True,
supports_encryption=False,
translation_skill_context=(
"This profile manages loose PNG assets without assuming a particular game engine. "
"Search available code, data, scenes, and asset references for runtime usage when "
"they exist. If placement, scaling, opacity, or dynamic-value behavior cannot be "
"established, preserve suspicious blank regions and report the uncertainty. Do not "
"attempt archive extraction, bundle rebuilding, or format conversion."
),
),
)