Context aware skills for TL Images Skill
This commit is contained in:
parent
ef7a3f8235
commit
c41b84142a
9 changed files with 77 additions and 26 deletions
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue