Initial Dansori character workspace
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from datetime import date
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import Image
|
||||
|
||||
|
||||
ROOT = Path(r"D:\Work_AI\Dansori")
|
||||
APP = ROOT / "DansoriEQ" / "src" / "DansoriEQ.App"
|
||||
HOST = APP / "Assets" / "Live2DHost"
|
||||
PUPPET = APP / "Assets" / "Characters" / "Puppets" / "LeeSoriV2"
|
||||
PLAN = ROOT / "DansoriEQ" / "docs" / "LIVE2D_CHARACTER_INTEGRATION_PLAN.md"
|
||||
|
||||
|
||||
def update_characters() -> None:
|
||||
path = HOST / "characters.json"
|
||||
data = json.loads(path.read_text(encoding="utf-8-sig"))
|
||||
for character in data["characters"]:
|
||||
if character.get("id") == "leesori":
|
||||
character["puppet"] = {
|
||||
"rig": "../Characters/Puppets/LeeSoriV2/rig.json",
|
||||
"imageBase": "../Characters/Puppets/LeeSoriV2/Images/",
|
||||
}
|
||||
break
|
||||
path.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
||||
|
||||
|
||||
def update_css() -> None:
|
||||
path = HOST / "style.css"
|
||||
css = path.read_text(encoding="utf-8")
|
||||
old = """#puppet {
|
||||
display: none;
|
||||
right: 10%;
|
||||
bottom: 1%;
|
||||
width: 80%;
|
||||
height: auto;
|
||||
aspect-ratio: 1086 / 1448;
|
||||
transform-origin: 50% 100%;
|
||||
filter: drop-shadow(0 20px 24px rgba(0, 0, 0, .46));
|
||||
animation: puppetRootIdle 3.8s ease-in-out infinite;
|
||||
}"""
|
||||
new = """#puppet {
|
||||
display: none;
|
||||
right: 17.5%;
|
||||
bottom: -20%;
|
||||
width: 65%;
|
||||
height: auto;
|
||||
aspect-ratio: 365 / 1058;
|
||||
transform-origin: 50% 100%;
|
||||
filter: drop-shadow(0 20px 24px rgba(0, 0, 0, .46));
|
||||
animation: puppetRootIdle 3.8s ease-in-out infinite;
|
||||
}"""
|
||||
if old not in css:
|
||||
raise RuntimeError("Expected #puppet CSS block was not found.")
|
||||
path.write_text(css.replace(old, new), encoding="utf-8")
|
||||
|
||||
|
||||
def make_css_qa() -> None:
|
||||
src = Image.open(PUPPET / "leesori_v2_source.png").convert("RGBA")
|
||||
width, height = 390, 600
|
||||
stage = Image.new("RGBA", (width, height), (16, 16, 18, 255))
|
||||
target_w = int(width * 0.65)
|
||||
target_h = int(target_w * src.height / src.width)
|
||||
resized = src.resize((target_w, target_h), Image.Resampling.LANCZOS)
|
||||
right = int(width * 0.175)
|
||||
bottom = int(height * -0.20)
|
||||
x = width - target_w - right
|
||||
y = height - target_h - bottom
|
||||
stage.alpha_composite(resized, (x, y))
|
||||
stage.convert("RGB").save(PUPPET / "qa_view_390x600_css_selected.png")
|
||||
|
||||
|
||||
def update_plan() -> None:
|
||||
entry = f"""
|
||||
|
||||
### {date.today().isoformat()} - New Sheet LeeSoriV2 Conversion
|
||||
|
||||
User correction:
|
||||
|
||||
- The previous LeeSoriExtended puppet solved clipping but used the old LeeSori design.
|
||||
- The authoritative new design sheet is:
|
||||
- `Characters_Build_Docs/LeeSori_Profile/03_Assets/Reference/sori_sheet.png`
|
||||
|
||||
Changed:
|
||||
|
||||
- Created `LeeSoriV2` from the new sheet's front full-body pose without AI identity drift.
|
||||
- Extracted alpha-clean source and overlap puppet parts:
|
||||
- base, legs, chest, left/right arms, left/right hands, head.
|
||||
- Replaced the app preview image with the new sheet-based LeeSori.
|
||||
- Switched `characters.json` to:
|
||||
- `../Characters/Puppets/LeeSoriV2/rig.json`
|
||||
- `../Characters/Puppets/LeeSoriV2/Images/`
|
||||
- Updated WebView framing for the new tall sheet ratio:
|
||||
- `right: 17.5%`
|
||||
- `bottom: -20%`
|
||||
- `width: 65%`
|
||||
- Framing goal: upper-body biased view for idle/work states while keeping head and both hands visible. Full body remains available in the source/rig for later state-specific framing.
|
||||
|
||||
QA artifacts:
|
||||
|
||||
- `src/DansoriEQ.App/Assets/Characters/Puppets/LeeSoriV2/qa_source_black.png`
|
||||
- `src/DansoriEQ.App/Assets/Characters/Puppets/LeeSoriV2/qa_view_390x600_upper_bias.png`
|
||||
- `src/DansoriEQ.App/Assets/Characters/Puppets/LeeSoriV2/qa_view_390x600_css_selected.png`
|
||||
|
||||
Next:
|
||||
|
||||
- Build and run in WPF to verify real WebView framing.
|
||||
- If this sheet-based puppet is accepted, add state-specific animation tuning and then generate Haruka/Isabel/Noeul with the same source-first process.
|
||||
"""
|
||||
text = PLAN.read_text(encoding="utf-8")
|
||||
if "New Sheet LeeSoriV2 Conversion" not in text:
|
||||
PLAN.write_text(text.rstrip() + entry + "\n", encoding="utf-8")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
update_characters()
|
||||
update_css()
|
||||
make_css_qa()
|
||||
update_plan()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user