Initial Dansori EQ workspace

This commit is contained in:
eKeerar
2026-07-04 10:34:46 +09:00
commit 5369ab8525
1350 changed files with 327985 additions and 0 deletions
+62
View File
@@ -0,0 +1,62 @@
{
"permissions": {
"allow": [
"Bash(dir \"D:\\\\Work_AI\\\\DansoriEQ\")",
"Read(//c/Program Files/**)",
"Read(//c/Program Files \\(x86\\)/dotnet//**)",
"Bash(/c/Program Files/dotnet/dotnet.exe *)",
"PowerShell(& \"C:\\\\Program Files \\(x86\\)\\\\dotnet\\\\dotnet.exe\" --version)",
"PowerShell(& \"C:\\\\Program Files \\(x86\\)\\\\dotnet\\\\dotnet.exe\" --info 2>&1 | Select-Object -First 20)",
"PowerShell($env:PATH = [System.Environment]::GetEnvironmentVariable\\(\"PATH\", \"Machine\"\\) + \";\" + [System.Environment]::GetEnvironmentVariable\\(\"PATH\", \"User\"\\); & dotnet --version)",
"PowerShell(dotnet new sln *)",
"PowerShell(dotnet sln add *)",
"PowerShell(dotnet build *)",
"PowerShell(dotnet test *)",
"PowerShell(dotnet restore *)",
"PowerShell(dotnet run *)",
"PowerShell(Stop-Process *)",
"Bash(dotnet build *)",
"PowerShell(Remove-Item *)",
"PowerShell(Get-Process *)",
"PowerShell(Get-Item \"D:\\\\Work_AI\\\\DansoriEQ\\\\src\\\\DansoriEQ.App\\\\bin\\\\Debug\\\\net8.0-windows\\\\DansoriEQ.App.dll\" | Select-Object LastWriteTime, @{N='SizeKB';E={[math]::Round\\($_.Length/1KB,1\\)}})",
"Bash(awk '{print $5, $9}')",
"Bash(awk '{print $5, $6, $7}')",
"Bash(exit 1)",
"Bash(mkdir -p 00_sheets sori dan _overview)",
"Bash(mv \"ChatGPT Image 2026년 7월 2일 오전 12_51_09 \\(1\\).png\" 00_sheets/sori_sheet.png)",
"Bash(mv \"ChatGPT Image 2026년 7월 2일 오전 12_51_09 \\(2\\).png\" 00_sheets/dan_sheet.png)",
"Bash(mv \"ChatGPT Image 2026년 7월 2일 오전 03_28_37 \\(1\\).png\" sori/sori_body_apose.png)",
"Bash(mkdir -p _rejected)",
"Bash(mv dan/dan_part_head_v1_restyle.png _rejected/dan_part_head_v1_thickoutline.png)",
"Bash(mv \"ChatGPT Image 2026년 7월 2일 오전 03_45_50 \\(1\\).png\" dan/dan_part_head.png)",
"Bash(mv \"ChatGPT Image 2026년 7월 2일 오전 03_45_50 \\(2\\).png\" sori/sori_avatar_a_neutral.png)",
"Bash(mv \"ChatGPT Image 2026년 7월 2일 오전 03_45_50 \\(3\\).png\" sori/sori_avatar_b_blink.png)",
"Bash(mkdir -p duo)",
"Bash(mv \"ChatGPT Image 2026년 7월 2일 오전 03_55_41 \\(1\\).png\" sori/sori_idle.png)",
"Bash(mv \"ChatGPT Image 2026년 7월 2일 오전 03_55_41 \\(2\\).png\" sori/sori_present.png)",
"Bash(mv \"ChatGPT Image 2026년 7월 2일 오전 03_55_42 \\(3\\).png\" sori/sori_happy.png)",
"Bash(mkdir -p \"src/DansoriEQ.App/Assets/Characters\")",
"Bash(cp Characters/sori/sori_avatar_a_neutral.png \"src/DansoriEQ.App/Assets/Characters/\")",
"Bash(cp Characters/sori/sori_avatar_b_blink.png \"src/DansoriEQ.App/Assets/Characters/\")",
"Bash(cp Characters/sori/sori_avatar_c_talk.png \"src/DansoriEQ.App/Assets/Characters/\")",
"Bash(cp Characters/sori/sori_avatar_d_wink.png \"src/DansoriEQ.App/Assets/Characters/\")",
"Bash(python -m pip install --quiet Pillow)",
"Bash(python -c \"import PIL; print\\('PIL ok', PIL.__version__\\)\")",
"Bash(python -c ' *)",
"Bash(python -c \"import numpy, scipy; print\\('numpy',numpy.__version__,'scipy',scipy.__version__\\)\")",
"Bash(python -m pip install --quiet numpy scipy)",
"Bash(python -c \"import numpy, scipy; print\\('ok numpy',numpy.__version__,'scipy',scipy.__version__\\)\")",
"Bash(python tools/make_transparent.py Characters/sori Characters/dan Characters/duo)",
"Bash(cp Characters/sori/sori_avatar_*.png Characters/dan/dan_avatar_*.png Characters/dan/dan_thumbsup.png Characters/sori/sori_happy.png \"src/DansoriEQ.App/Assets/Characters/\")",
"Bash(python -m pip install --quiet rembg onnxruntime)",
"Bash(echo \"---exit:$?---\")",
"Bash(python -c \"import rembg; print\\('rembg ok'\\)\")",
"Bash(rm -f Characters/dan_thumbsup.png Characters/sori_present.png)",
"Bash(rm -f Characters/_opaque_backup/dan_thumbsup.png Characters/_opaque_backup/sori_present.png)",
"Bash(cp Characters/sori/sori_avatar_*.png Characters/dan/dan_avatar_*.png Characters/dan/dan_thumbsup.png Characters/sori/sori_happy.png Characters/sori/sori_idle.png Characters/dan/dan_idle.png src/DansoriEQ.App/Assets/Characters/)",
"Bash(python -c \"from PIL import Image; im=Image.open\\('src/DansoriEQ.App/Assets/Characters/sori_idle.png'\\); print\\('sori_idle', im.mode, 'corner alpha', im.load\\(\\)[0,0][3]\\)\")",
"Bash(cp Characters/duo/duo_backtoback.png \"src/DansoriEQ.App/Assets/Characters/\")",
"Bash(python -c \"from PIL import Image; im=Image.open\\('src/DansoriEQ.App/Assets/Characters/duo_backtoback.png'\\); print\\('duo', im.mode, im.size\\)\")"
]
}
}
+80
View File
@@ -0,0 +1,80 @@
# Dansori EQ
> **말로 빚는 소리.** 자연어 AI로 이어폰/헤드폰 EQ를 만들어 **Equalizer APO**에 적용하는 Windows 앱.
> 코드 식별자: **DansoriEQ** · 표시명: **Dansori EQ** · 경로: `C:\Users\ekeer\DansoriEQ`
---
## ⚡ 핸드오프 요약 (반드시 먼저 읽기)
이 프로젝트는 **설계 + 대량의 선(先)생성 코드**가 이미 존재한다. **"아직 코드 없음"이 아니다.**
이전(토의) 세션에서 핵심 사용자 여정과 부가기능 대부분을 **코드 레벨로 배선**해 두었고, 다만
**아직 한 번도 컴파일/실행되지 않았다.** 다음 단계는 **빌드 + 실환경 연동**이다.
- 앱은 APO/AI키 없이도 **미리보기 모드**로 파이프라인이 도는 구조다(생성 config를 파일로 기록).
- 남은 일은 대부분 **실제 빌드/실행 환경**이 있어야 진행된다(아래 "다음 세션 첫 작업").
## 먼저 읽을 순서
1. `README.md` — 개요·기능·빌드·구조
2. `docs/PREBUILT.md`**선생성 파일 목록 + 교체/연결 지점**(가장 중요)
3. `docs/DEV_PLAN.md` — 마일스톤 M0~M15, 체크박스(`[x]`선구현 / `[ ]`남음)
4. `docs/SCENARIO.md` — 요구사항 + **핵심 사용자 여정**(§4.5)
5. `docs/ARCHITECTURE.md` — 스택·데이터흐름·DB/AI/APO/공유(.tweq) 스키마
6. `docs/TYPOGRAPHY.md` — 폰트 규칙(최소 12·최대 24, 가독성 우선)
7. `mockups/gallery.html` — 전체 UI 목업(브라우저로 열기)
## 다음 세션 첫 작업 (순서)
1. **솔루션·빌드·테스트**
```
dotnet new sln -n DansoriEQ
dotnet sln add src/DansoriEQ.Core/DansoriEQ.Core.csproj
dotnet sln add src/DansoriEQ.App/DansoriEQ.App.csproj
dotnet sln add tests/DansoriEQ.Core.Tests/DansoriEQ.Core.Tests.csproj
dotnet restore ; dotnet build ; dotnet test
```
2. **컴파일 오류 수정** — 선생성 코드는 미검증. 특히 WPF 시그니처(`EqGraphControl`,
Win32 P/Invoke), XAML, 패키지(WPF-UI/LiveCharts2는 아직 미추가) 확인.
3. **실환경 연동**
- **APO**: 실제 config 쓰기 + 최초 1회 승격(Include+ACL). 지금은 미리보기(`NullApoWriter`).
- **AI**: 실제 키로 프롬프트 루프 검증. provider/model은 `AppSettings`(AI 관리 화면)에서 선택됨.
- **DB**: `DesignProfileDbService`(스텁) → `SqliteProfileDbService`로 교체 + 사이드바 바인딩.
4. **마감(M5/M6)**: WPF-UI(Fluent/Mica) 테마 + 테마전환, MVVM 바인딩, 헤더 버튼 정리, 패키징/아이콘.
## 핵심 교체/연결 지점 (dev)
- **DB**: `SqliteProfileDbService`(App/Profiles) — `Search()`=사이드바, `LoadEq(id)`=프로파일 base EQ,
`UpdateAsync`=AutoEq zip 다운로드(무겁다 → curated 서브셋 권장).
- **AI**: `AiProviderFactory.Create(store)` 가 provider 생성. 프롬프트창(`MainWindow.SendPromptAsync`)은 이미 연결.
- **APO**: `ApoWriterFactory` 가 설치 감지 → 실제/미리보기 자동 선택.
- **크로스피드**: `ApoRenderer` 상단 메모대로 **저역통과+딜레이** 정식 구현 필요(현재 플레이스홀더).
- **DefaultDeviceSwitcher**: IPolicyConfig(**undocumented COM**) vtable 검증 필요.
## 절대 제약 (유지)
- 아름다운 모던 **Fluent GUI**(단순/텍스트 UI ✗, 웹앱 ✗) · **EQ 그래프** 포함
- **저권한**: 최초 1회만 승격, 이후 무승격
- 프로파일 목록 **IEM/헤드폰 분리** · 라이선스 배포불가 소스는 **배포 빌드 제외**(UI엔 병합 표시)
- **AutoEQ 베이스 + 귀로 AI 미세조정**(측정 마이크 없음) · **DAC/앰프는 EQ 대상 아님**
- **API 키는 런타임에 사용자 제공**(DPAPI 암호화 저장) · 초보자 친화 최우선
## 선구현 범위 (코드 레벨 완료, 미컴파일)
- **Core**: EQ 수학(RBJ)·모델·`ApoRenderer`(+이펙트)·`PreampCalculator`·프리셋(`.tweq`)·
AI(`IAiEqProvider`·4개 provider·`EqDelta(+Effects)`·파서·프롬프트/스키마)·스위칭 규칙/평가·AutoEqParser
- **App 창**: MainWindow(그래프·**AI 프롬프트 실배선**·Undo/Reset·바이패스+프리셋전환 핫키·볼륨패널·가변40밴드)
+ Settings/DbManager/Effects/PresetLibrary/Command/ApoSetup/**AiManager**/**SwitchRules**/PresetInfo/도움말드로어
- **App 서비스**: Apo(추상화+미리보기+installer/setup), Ai(4 provider+factory+**계정모델조회**+**Ollama설치/모델pull**),
Audio(NAudio 볼륨/**출력장치전환**·Windows볼륨 양방향 동기화), Switching(**앱+장치 감지→프리셋 자동전환**, 런타임 리로드),
Profiles(**SQLite 실저장소**+AutoEq import + 디자인 스텁), Security(DPAPI), Input(전역 핫키)
- **테스트**: Filter 수학 / AutoEqParser / PresetSerializer / ApoRenderer 이펙트
- **AI 제어**: EQ + **이펙트(크로스피드/밸런스/베이스)를 자연어 한 문장으로** 동시 제어
## 범위 결정 사항
- **스피커 확장 제외**(측정 기반이 정석인데 그 트랙은 안 함).
- **로컬 AI = Ollama만**(무인 자동설치 확실). LM Studio/GPT4All 등은 `LocalRuntime.cs` 메모의 "추후 테스트 후보".
- 서라운드/리버브는 향후(M13). `.tweq` 확장자 유지.
## 컨텍스트 (왜 이 앱인가)
사용자는 하이엔드 오디오 보유자(iFi Pro iDSD/iCAN Signature, SMSL DO400 등). Luxsin X8의 "AI EQ"에
관심 → X8은 DAC/앰프가 기존 플래그십과 중복이라 비효율 → **X8의 AI EQ 경험만 소프트웨어로 재현**.
하드웨어 PEQ 역분석(FiiO K13)은 리스크로 폐기 → **Equalizer APO + AI(클라우드/로컬)** 조합으로 확정.
## ⚠️ 이 시점에서 남은 것은 대부분 실환경 의존
빌드·컴파일 검증 · APO 실적용 · AI 키/네트워크 · NAudio/Win32/winget/Ollama · SQLite/AutoEq 다운로드 ·
MVVM 바인딩 · Fluent 테마. **여기서부터는 개발 세션(실행 환경 필요)에서 진행한다.**
+43
View File
@@ -0,0 +1,43 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{85A9F4A8-568F-4C38-8031-FBA5F8A87DB3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DansoriEQ.Core", "src\DansoriEQ.Core\DansoriEQ.Core.csproj", "{1073017D-A29B-4F5B-AC18-7400F1F93694}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DansoriEQ.App", "src\DansoriEQ.App\DansoriEQ.App.csproj", "{22808FF0-F093-417A-8EDC-58B284717BA5}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{B1D0028E-E5FF-4824-851F-B0010A1665B3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DansoriEQ.Core.Tests", "tests\DansoriEQ.Core.Tests\DansoriEQ.Core.Tests.csproj", "{AD991DC9-1440-4AD6-89FC-33F227240891}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1073017D-A29B-4F5B-AC18-7400F1F93694}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1073017D-A29B-4F5B-AC18-7400F1F93694}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1073017D-A29B-4F5B-AC18-7400F1F93694}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1073017D-A29B-4F5B-AC18-7400F1F93694}.Release|Any CPU.Build.0 = Release|Any CPU
{22808FF0-F093-417A-8EDC-58B284717BA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{22808FF0-F093-417A-8EDC-58B284717BA5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{22808FF0-F093-417A-8EDC-58B284717BA5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{22808FF0-F093-417A-8EDC-58B284717BA5}.Release|Any CPU.Build.0 = Release|Any CPU
{AD991DC9-1440-4AD6-89FC-33F227240891}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AD991DC9-1440-4AD6-89FC-33F227240891}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AD991DC9-1440-4AD6-89FC-33F227240891}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AD991DC9-1440-4AD6-89FC-33F227240891}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{1073017D-A29B-4F5B-AC18-7400F1F93694} = {85A9F4A8-568F-4C38-8031-FBA5F8A87DB3}
{22808FF0-F093-417A-8EDC-58B284717BA5} = {85A9F4A8-568F-4C38-8031-FBA5F8A87DB3}
{AD991DC9-1440-4AD6-89FC-33F227240891} = {B1D0028E-E5FF-4824-851F-B0010A1665B3}
EndGlobalSection
EndGlobal
+76
View File
@@ -0,0 +1,76 @@
# Dansori EQ
> **말로 빚는 소리.** 이어폰·헤드폰에 딱 맞는 EQ를, 자연어로 만드는 Windows 앱.
> Equalizer APO 위에서 동작하며, AI가 "보컬 가까이 · 저음 단단히" 같은 문장을 파라메트릭 EQ로 바꿔 즉시 적용합니다.
코드 식별자: `DansoriEQ` · 표시명: **Dansori EQ**
---
## 이게 뭔가요
Luxsin X8의 "AI EQ" 경험을 **소프트웨어로 재현**한 도구입니다. DAC/앰프를 새로 사지 않고, **PC의 Equalizer APO** 를 통해 소리를 보정합니다.
- **AutoEQ 프로파일**을 베이스로 로드하고, 그 위에 **AI가 취향(델타)** 을 얹습니다.
- 클라우드 AI(Claude/ChatGPT/Gemini)뿐 아니라 **로컬 AI(Ollama, 오프라인)** 도 선택 가능.
- 만든 EQ는 `.tweq` 파일로 **공유**하고, 받은 사람은 **불러와서 재편집**할 수 있습니다.
> DAC/앰프는 EQ 대상이 아닙니다(주파수 응답이 평탄). 유효 변수는 **트랜스듀서(이어폰/헤드폰) + 귀 + 취향** 입니다.
## 주요 기능
- 🎙 **자연어 AI EQ** — "치찰음 줄여줘", "따뜻하게" → 파라메트릭 EQ 생성·적용·설명
- 📊 **인터랙티브 그래프** — 드래그(Fc/Gain)·휠(Q)·더블클릭 추가·우클릭 삭제, **가변 밴드(최대 40)**
- 🎚 **이펙트** — 크로스피드·좌우 밸런스·베이스 부스트
- 📚 **프리셋 라이브러리 + 공유(.tweq)** — 저장·전환·내보내기/가져오기(대상 기기·AI 히스토리 포함)
- 🔀 **앱/장치 자동 전환** — 게임 실행 시 게이밍 프리셋 등
-**핫키** — Ctrl+Alt+B(바이패스), Ctrl+Alt+[ / ](프리셋 전환)
- 🔊 **볼륨/출력장치 제어** — 그래프 옆에서 Windows 볼륨과 동기화, 출력장치 전환
- 🧩 **AI 관리** — 로컬 런타임(Ollama) 자동설치·모델 다운로드·계정 모델 선택·저장공간 안내
-**온보딩 도움말** — 오른쪽 슬라이드 패널 + API 키 발급 공식 링크
## 동작 원리
```
기기 선택 → 베이스 EQ 로드
→ 자연어 입력 → AI(클라우드/로컬) → EqDelta(JSON)
→ 그래프/이펙트 반영 → APO config 렌더 → Equalizer APO 라이브 리로드
```
## 기술 스택
.NET 8 · WPF · (WPF-UI Fluent 예정) · 커스텀 그래프 컨트롤 · SQLite(Microsoft.Data.Sqlite) · NAudio(볼륨/장치) · DPAPI(키 암호화) · Anthropic/OpenAI/Gemini/Ollama REST
## 프로젝트 구조
```
DansoriEQ/
├─ src/DansoriEQ.Core/ # 순수 로직(EQ 수학·모델·APO 렌더·AI 스키마·프리셋·스위칭)
├─ src/DansoriEQ.App/ # WPF 앱(창·컨트롤·서비스: Apo/Ai/Audio/Switching/Profiles …)
├─ tests/DansoriEQ.Core.Tests/ # 단위테스트(Filter 수학·파서·직렬화·이펙트 렌더)
├─ docs/ # SCENARIO / ARCHITECTURE / DEV_PLAN / TYPOGRAPHY / PREBUILT
└─ mockups/ # gallery.html (전체 화면 비주얼 목표)
```
## 빌드 & 실행 (개발 세션)
```powershell
dotnet new sln -n DansoriEQ
dotnet sln add src/DansoriEQ.Core/DansoriEQ.Core.csproj
dotnet sln add src/DansoriEQ.App/DansoriEQ.App.csproj
dotnet sln add tests/DansoriEQ.Core.Tests/DansoriEQ.Core.Tests.csproj
dotnet restore
dotnet build
dotnet test
dotnet run --project src/DansoriEQ.App
```
- APO 미설치 PC에서도 **미리보기 모드**로 실행됩니다(생성된 config를 `%LOCALAPPDATA%\DansoriEQ\preview_apo_config.txt`에 기록).
- 실제 적용하려면 Equalizer APO 설치 후 `config.txt``Include: ai_eq.txt` 연결(앱의 최초 설정에서 안내).
## 상태
**설계 + 선(先)생성 코드 단계.** 대부분의 화면·서비스·로직이 작성되어 있으나 **아직 컴파일 검증 전**입니다.
남은 작업(실환경 연동·MVVM 바인딩·Fluent 테마·마감)은 `docs/DEV_PLAN.md`, 선생성 목록은 `docs/PREBUILT.md` 참조.
## 문서
- `docs/SCENARIO.md` — 요구사항/핵심 사용자 여정
- `docs/ARCHITECTURE.md` — 스택·데이터 흐름·DB/AI/APO/공유 스키마
- `docs/DEV_PLAN.md` — 마일스톤·잔여 작업
- `docs/TYPOGRAPHY.md` — 타이포그래피 규칙(가독성 우선)
- `docs/PREBUILT.md` — 선생성 코드 목록·교체 지점
- `mockups/gallery.html` — 전체 UI 목업
## 라이선스
미정(TBD). AutoEQ 등 측정 데이터는 각 출처 라이선스를 따르며, 배포 불가 소스는 배포 빌드에서 제외합니다(`--exclude-restricted`).
+172
View File
@@ -0,0 +1,172 @@
# ARCHITECTURE
## 1. 기술 스택 (확정)
| 영역 | 선택 | 이유 |
|---|---|---|
| 런타임 | **.NET 8** | 최신 LTS, 네이티브 Windows |
| UI | **WPF + WPF-UI (lepoco)** | Fluent Design System / Mica·다크모드 / WinUI 감성. 텍스트 UI 아님 |
| 차트 | **LiveCharts2** | 애니메이션되는 아름다운 EQ 커브. (대안: ScottPlot=정적·경량) |
| MVVM | **CommunityToolkit.Mvvm** | 소스제너레이터 기반, 보일러플레이트 최소 |
| DB | **SQLite (Microsoft.Data.Sqlite)** | 로컬 프로파일 인덱스 |
| AI | **Anthropic REST (HttpClient)** 또는 `Anthropic.SDK` NuGet | 구조화 출력(tool use) |
| 패키징 | **MSIX 또는 velopack/single-file** | 배포. 라이선스 제외 옵션과 연동 |
> WPF-UI가 Mica 배경 + Fluent 컨트롤 + 다크테마를 제공해 목업(`mockups/main_window.html`)의
> 룩앤필을 네이티브로 재현할 수 있다. 그래프는 LiveCharts2의 `CartesianChart`로 로그 X축(주파수)
> + 선형 Y축(dB), 영역 그라데이션 채우기.
## 2. 컴포넌트 구성
```
DansoriEQ.sln
├─ DansoriEQ.App (WPF, WPF-UI) ── Views/ViewModels, 그래프, 프롬프트 독
├─ DansoriEQ.Core (class lib)
│ ├─ Profiles/ ProfileRepository, AutoEqParser, DbUpdater
│ ├─ Eq/ EqState, Filter(model), ApoRenderer, PreampCalculator
│ ├─ Ai/ ClaudeClient, EqPromptBuilder, EqDeltaSchema
│ └─ Apo/ ApoLocator, ApoConfigInstaller(승격 1회), IncludeWriter
└─ DansoriEQ.Setup (elevated helper, 최초 1회 UAC — 아래 4장)
```
## 3. 데이터 흐름
```
프로파일 선택 → ProfileRepository.Load(id) → EqState(base)
→ ApoRenderer → IncludeWriter.Write(ai_eq.txt) → APO 라이브 리로드 → 그래프 갱신
프롬프트 입력 → EqPromptBuilder(현재 EqState + 헤드폰 메타 + 요청)
→ ClaudeClient(tool use, EqDeltaSchema) → EqDelta(JSON)
→ EqState.Apply(delta) → PreampCalculator → ApoRenderer → IncludeWriter → APO
→ AI 설명 텍스트를 응답 패널에 표시 / 히스토리 스택 push
```
## 4. APO 연동 & 저권한 전략 (중요)
문제: APO의 `config.txt``C:\Program Files\EqualizerAPO\config\` 아래라 쓰기에 승격 필요.
매번 승격은 "저권한" 원칙 위반.
**채택 방식 — "1회 승격 설정, 이후 무승격":**
1. **최초 실행 설정 마법사**(DansoriEQ.Setup, UAC 1회):
- APO 설치 경로 탐지: 레지스트리 `HKLM\SOFTWARE\EqualizerAPO``InstallPath`.
- 사용자 쓰기 가능한 EQ 파일 준비. **권장:** `config` 폴더 내 `ai_eq.txt`를 만들고
**그 파일(또는 폴더)에 현재 사용자 쓰기 ACL 부여**(icacls). 그리고 `config.txt`
`Include: ai_eq.txt` 한 줄 추가(중복 방지 검사).
- 완료 플래그 저장(`%LOCALAPPDATA%\DansoriEQ\setup.json`).
2. **이후 실행**: 앱은 `ai_eq.txt`만 갱신 → **승격 불필요**. APO가 저장 즉시 리로드.
> ⚠️ **M1에서 검증할 스파이크:** APO `Include:`가 절대경로를 허용하는지 확인.
> - 허용 O → `ai_eq.txt`를 `%APPDATA%\DansoriEQ\`에 두고 절대경로 Include(ACL 불필요, 가장 깔끔).
> - 허용 X(상대경로만) → 위 4-1의 config 폴더 내 파일 + ACL 부여 방식으로.
> 두 경로 모두 "1회 승격, 이후 무승격"을 만족. 스파이크 결과로 하나 확정.
APO 필터 문법(렌더 타깃):
```
Preamp: -6.0 dB
Filter 1: ON PK Fc 3000 Hz Gain 3.0 dB Q 1.20
Filter 2: ON LSC Fc 90 Hz Gain 4.0 dB Q 0.70
Filter 3: ON HSC Fc 10000 Hz Gain -1.5 dB Q 0.70
```
- 타입 매핑: PK=peaking, LSC=low-shelf, HSC=high-shelf, (LP/HP 확장 가능).
- **Preamp = -(양의 게인 총합) 또는 최소 -(최대 양의 게인) − 여유 1dB.** 클리핑 방지 필수.
## 5. 프로파일 DB & 라이선스 분리
### 폴더 레이아웃
```
data/
├─ profiles/
│ ├─ open/ ← 재배포 허용(퍼미시브) 소스. 배포 빌드에 포함
│ └─ restricted/ ← 재배포 불가 소스. 배포 빌드에서 제외
├─ manifest.json ← 소스별 {name, license, distributable, url, commit}
└─ dansorieq.db ← SQLite 인덱스(open+restricted 모두 인덱싱)
```
### 원칙
- **수집(개발 중 1회):** AutoEQ repo를 zip/clone로 확보 → 파싱 → 소스 라이선스에 따라
`open/` 또는 `restricted/`로 분류 저장 → SQLite에 upsert.
- **UI:** DB를 조회할 때 **라이선스 구분 없이 병합**해서 보여준다(IEM/헤드폰만 구분).
- **배포:** 패키징 시 `--exclude-restricted` 옵션 → `restricted/` 폴더와 해당 DB 행 제외.
(개인 사용 로컬 빌드는 전체 포함.)
- DB 스키마:
```sql
CREATE TABLE headphone(
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
brand TEXT,
type TEXT CHECK(type IN ('iem','headphone')) NOT NULL,
source TEXT, -- 측정/소스명
license TEXT, -- 예: 'CC-BY', 'restricted'
distributable INTEGER, -- 0/1 (UI에선 필터하지 않음)
target TEXT, -- 예: 'Harman IE 2019'
preamp_db REAL,
filters_json TEXT, -- [{type,fc,gain,q}]
raw_text TEXT, -- 원본 ParametricEQ.txt
updated_at TEXT
);
CREATE INDEX ix_hp_type ON headphone(type);
CREATE INDEX ix_hp_name ON headphone(name);
```
### 앱 내 업데이트
- "DB 업데이트" → 최신 소스(zip) 재확보 → 파싱 → **upsert(변경분만)** → manifest commit/날짜 갱신.
- UI 하단에 `N profiles · 최신: YYYY-MM-DD` 표시.
## 6. AI 레이어 스키마 (구조화 출력)
`EqDelta` (Claude가 tool use로 반환):
```json
{
"preamp_db": -6.0,
"filters": [
{ "type": "PK", "fc": 3000, "gain": 3.0, "q": 1.2, "enabled": true },
{ "type": "LSC", "fc": 90, "gain": 4.0, "q": 0.7, "enabled": true }
],
"explanation": "보컬 존재감을 위해 3kHz +3dB…",
"replace": false // false=현재 상태에 병합, true=전체 교체
}
```
시스템 프롬프트 요지:
- 역할: 파라메트릭 EQ 전문가. APO 제약(타입 PK/LSC/HSC, Fc 2020000Hz, Gain ±12dB 권장,
Q 0.36) 안에서만 출력.
- 입력으로 **현재 EqState + 헤드폰 모델/타입 + 사용자 요청** 제공 → 요청을 delta로 반영.
- 오디오 상식 힌트(보컬≈2–5kHz, 저음 단단히≈4080Hz 무게+150250Hz 뭉침 컷, 치찰음≈68kHz).
- **Preamp 안전값 계산 규칙 명시.**
- 런타임 모델: 기본 **Claude Sonnet**(요청당 25k 토큰), 옵션으로 Opus.
## 7. 오픈 이슈 → DEV_PLAN 참조
- APO Include 절대경로 허용 여부(스파이크).
- AutoEQ repo 구조/소스 라이선스 최신 상태 확인(수집 스크립트에서).
- 다중 출력 장치별 APO config 타깃팅(고급 옵션, MVP 이후).
## 8. EQ 프리셋 공유 포맷 (.tweq)
사용자가 만든 EQ를 다른 사용자와 공유하기 위한 파일. **JSON**, 확장자 `.tweq`.
```json
{
"format": "dansorieq.eq",
"version": 1,
"app_version": "0.1.0",
"created_utc": "2026-07-01T12:00:00Z",
"author_note": "밝고 보컬 중심 튜닝",
"target": {
"name": "Truthear x Crinacle Zero",
"brand": "Truthear",
"type": "iem",
"source": "AutoEQ",
"target_curve": "Harman IE 2019"
},
"eq": {
"preamp_db": -6.0,
"filters": [
{ "type": "PK", "fc": 3000, "gain": 3.0, "q": 1.2, "enabled": true }
]
},
"history": [
{ "role": "user", "text": "보컬 가까이, 저음 단단히", "ts": "..." },
{ "role": "ai", "text": "3kHz +3dB, 180Hz -2.5dB…", "ts": "..." }
]
}
```
- **내보내기**: 현재 EqState + 대상 기기 메타 + 대화 히스토리(간략)를 직렬화해 저장.
- **가져오기**: 검증(format/version, 값 범위 클램프, 크기 상한) → **정보 패널(대상 기기 / 히스토리 / 작성자 노트) 표시** → EQ 적용.
- **라이선스 안전**: 파일엔 측정 데이터가 아니라 **기기 이름/메타만** 포함 → 재배포 문제 없음.
- **보안**: history 텍스트는 **표시 전용**(실행/링크 처리 안 함), 항목 수·길이 상한, API 키 미포함.
## 9. 설정 & Claude API 키 관리
- **별도 설정 화면**(WPF-UI NavigationView: Home/EQ ↔ Settings).
- 섹션: [AI · API 키] / [테마] / [APO] / [데이터베이스].
- **API 키**: 등록 / 삭제 / 교체, "연결 테스트", **DPAPI 암호화 저장**(`%LOCALAPPDATA%\DansoriEQ`).
- **모델 선택**: 기본 Claude Sonnet / 옵션 Opus.
- 키 미등록 시 프롬프트 독 비활성 + 등록 안내.
+89
View File
@@ -0,0 +1,89 @@
# BRAND CHARACTERS — Dansori 마스코트 설정 (실제 이미지 기준)
> **기준**: `docs/Image/` 에 업로드된 확정 일러스트(듀오 브랜드 아트 + 온보딩 STEP 시리즈).
> 이전 버전의 상상 설정은 폐기하고, **실제 그림 속 두 인물의 외형을 그대로 문서화**한다.
> 일러스트레이터/이미지 생성 AI는 이 문서 + `docs/Image/` 레퍼런스를 함께 사용해 **동일 인물**을 유지할 것.
> **이름 확정**: 여캐 **이소리**(李소리 / Lee Sori) · 남캐 **이단**(李단 / Lee Dan).
> ※ 이름은 앱 곳곳에 **반드시 노출할 필요는 없음**(내부 설정/카피 톤 기준). 표시 브랜드명 **DANSORI**, 태그라인 **FEEL EVERY DETAIL**.
> 📎 성격·말투·의상/헤어 베리에이션·활용 시나리오 등 **확장 프로필**은 `docs/CHARACTER_PROFILES.md` 참조.
> 📌 `docs/Image/Girl Character.jpg`(기모노 브라운헤어)는 **여캐(이소리)의 "동양풍 얼굴" 참고용일 뿐** —
> **복장·소품·헤어컬러는 참고하지 않는다**(이소리의 확정 외형은 아래 §2: 민트 단발 등).
## 0. 방향 (필독)
- **성인 2인 콤비**(아시아계). 여 20대 중후반 / 남 20대 후반~30대 초반.
- 스타일: **모던 애니메·세미리얼 일러스트**, 성인 비율(약 7등신), 선명한 라인 + 네온 글로우.
- 톤: 자신감·활기·세련. **치비/아기같음 금지.** 다크 UI 위에서 **민트·시안 네온이 튀게.**
- 콤비 케미: **동료·파트너십**(연인 아님). 여=아이디어 제안, 남=정밀 튜닝.
## 1. 브랜드 컬러 (일러스트에서 추출)
| 용도 | 색 | 비고 |
|---|---|---|
| 여캐 시그니처(민트/틸) | `#38E0C4` 계열 | 헤어·재킷·글로우 |
| 남캐 시그니처(시안/블루) | `#4CC2FF` 계열 | 스트릭·헤드폰·지퍼 |
| 배경(딥네이비) | `#141418` ~ `#0E1A24` | 그라데이션 |
| 텍스트/화이트 | `#F2F3F5` | 후디·로고 |
| 네온 액센트 | 민트→시안 그라데이션 | 음파·음표·EQ 글로우 |
## 2. 여자 캐릭터 — 이소리 (Lee Sori)
- **역할**: AI 어시스턴트 페르소나 — "이렇게 들려드릴게요!" 소리를 상상/제안하는 쪽.
- **외형(확정)**:
- **헤어**: **민트/틸 그린 단발**(턱선 길이, 볼륨 있는 뱅). 끝이 살짝 뻗침.
- **눈/얼굴**: 갈색 눈, 큰 눈웃음, 밝고 자신감 있는 표정. **동양풍 얼굴형**(`Girl Character.jpg` 얼굴 참고 — 복장 아님).
- **체형(업데이트)**: **글래머러스한 성인 여성 실루엣** — 풍성한 가슴과 잘록한 허리의 **아워글래스 상체**, 세련되고 자신감 있게. *성인 캐주얼-시크 범위 내에서 우아하게(노출·선정성 지양, 품위 유지).*
- **헤드폰**: **은색/화이트 온이어**(하우징에 DANSORI 음파 로고), 케이블 민트.
- **의상**: **화이트 크롭 후디** + **민트/블랙 트랙 재킷** + **블랙 트랙팬츠(민트 사이드라인, 드로스트링)**.
- *DANSORI 워드마크*는 **히어로/마케팅 아트에만** 넣고, **모듈 에셋(리깅/아바타)엔 넣지 않음**(로고는 앱이 얹음).
- *소매 EQ 막대 그래픽*은 **선택**(단순 스트라이프도 OK — AI가 자주 단순화하며, 마스코트엔 깔끔한 편이 나음).
- **악세서리**: 블랙 초커 + **틸 젬 펜던트**.
- **시그니처 제스처**: 손바닥을 펴 **손끝에서 음파·음표·홀로그램 파티클**이 피어오름(“소리를 손에 쥔다”).
- **말투 예**: *"이 소리, 딱이죠?"*, *"보컬 한 발 앞으로 당겨볼게요."*
## 3. 남자 캐릭터 — 이단 (Lee Dan)
- **역할**: 정밀 튜너 — 소리의 아이디어를 **정확히 마무리**하는 엔지니어.
- **외형(확정)**:
- **헤어**: **짧은 다크(블랙) 텍스처 헤어 + 시안/블루 스트릭**(앞머리·윗머리 포인트).
- **눈**: 진한 눈매, 시원한 미소/살짝 개구진 자신감.
- **헤드폰**: **블루/시안 오버이어**(목에 걸침), 케이블 시안.
- **의상**: **네이비/블랙 후디+보머 재킷**(블루 지퍼) + **화이트 티** + **블랙 팬츠**. *소매 페이더/슬라이더 디테일은 선택*(지퍼만도 OK).
- **악세서리**: **블랙 스마트워치**(시안 글로우 다이얼).
- **시그니처 제스처**: **홀로그램 EQ 슬라이더/노브(60·250·1K·4K·12K, Bass, Reverb)**를 손끝으로 조작. 엄지척.
- **말투 예**: *"여기 살짝만 다듬으면 완벽해요."*, *"좋아, 미세 조정할게."*
## 4. 로고 / 그래픽 모티프
- **로고**: 스타일라이즈드 **"ID" 모노그램 + 재생 삼각형 + EQ 막대**(민트→시안). 워드마크 **DANSORI**(대문자 트래킹 넓게) + 태그라인 **FEEL EVERY DETAIL**(시안, 작게).
- **반복 모티프**: soundwave(음파선), 음표, EQ 막대/페이더, 홀로그램 패널, 파티클 별.
## 5. 듀오 케미 / 대표 포즈
- **등을 맞댄 백투백**(여=음파 손짓 / 남=EQ 조작) — 가장 대표 키비주얼.
- **헤드폰 한 짝씩 나눠 끼고 마주보기** / 케이블이 둘을 잇기 → *"함께 = Dansori"*.
## 6. 일관성 주의 (중요)
- 현재 업로드 배치마다 **얼굴·헤어 길이·표정이 미묘하게 다름**(특히 여캐 단발 길이).
-**일관성 시트 확보 완료**: `Characters/` 폴더(이소리·이단 턴어라운드+표정 6종, 투명 배경). 브랜드 설정 일치 확인.
→ **이후 모든 신규 컷은 이 시트를 레퍼런스로 첨부**해 동일 인물 유지. 상세 계획: `docs/CHARACTER_UI_INTEGRATION.md`.
## 7. 이미지 생성 AI 프롬프트 (실제 인물 유지용)
**[여 · 이소리]**
```
Asian young adult woman, mid-to-late 20s, anime semi-real illustration, ~7 heads adult proportions,
glamorous confident figure with a fuller bust and an elegant hourglass upper body (tasteful, adult
casual-chic — not revealing), mint/teal green bob hair, brown eyes, bright confident smile,
silver/white on-ear headphones, white cropped hoodie, mint-and-black track jacket, black track pants
with mint side stripe, black choker with teal gem pendant, mint (#38E0C4) neon accents, clean bold
lines, output a PNG with a fully TRANSPARENT background (alpha), no white, no scene
```
**[남 · 이단]**
```
Asian young adult man, late 20s / early 30s, anime semi-real illustration, ~7 heads adult proportions,
short dark textured hair with a cyan/blue streak, confident grin, blue/cyan over-ear headphones around
neck, navy-black hoodie+bomber with blue zippers and mixer-fader sleeve details, white tee, black pants,
black smartwatch with cyan dial, adjusting a holographic EQ slider panel, cyan (#4CC2FF) neon accents,
deep navy background, clean bold lines
```
**[듀오]**
```
two Asian audio-app mascots back-to-back: a mint-haired confident woman (mid-20s) with soundwaves from
her palm, and a cyan-streak-haired friendly man (early 30s) adjusting holographic EQ sliders; adult
proportions, modern anime semi-real, mint + cyan neon on deep navy, brand "DANSORI — FEEL EVERY DETAIL",
energetic partner chemistry, NOT chibi, NOT children
```
+190
View File
@@ -0,0 +1,190 @@
# CHARACTER PROFILES — 이소리 · 이단 상세 프로필 (활용 확장판)
> `BRAND_CHARACTERS.md`가 **확정 외형 바이블**이라면, 이 문서는 두 캐릭터를 **다양한 상황·굿즈·표정·의상·헤어**로
> 폭넓게 활용하기 위한 **확장 프로필**이다. 이미지 생성 AI 프롬프트 스니펫 포함.
> 원칙: **시그니처(브랜드 핵심 룩)는 고정, 베리에이션은 확장 영역에서 허용.**
---
## 0. 브랜드 일관성 원칙 (베리에이션 허용 범위)
- **시그니처 룩(고정)** = 브랜드 핵심 접점에서 **항상 동일**: 앱 아이콘/스플래시, AI 아바타, 온보딩, 스토어.
- 이소리 = **민트/틸 단발** + 화이트 크롭후디/트랙재킷. 이단 = **다크헤어+시안 스트릭** + 네이비 후디.
- **베리에이션 룩(허용)** = 확장 영역에서 다양화: 스티커/이모지, 시즌 이벤트, 마케팅, 테마 스킨, 로딩 미니컷.
- **얼굴/체형/성격은 언제나 동일**. 바뀌는 건 **헤어·의상·표정·포즈·소품**뿐. → "같은 사람이 스타일만 바꾼 것".
- 팁: 앱의 **강조색 테마(M5)와 헤어 컬러를 연동**하면 베리에이션이 브랜드 안에서 자연스럽다(§3-B 참고).
---
## 1. 이소리 (Lee Sori) — "소리를 상상하는 AI 어시스턴트"
### 1-1. 기본 프로필
| 항목 | 내용 |
|---|---|
| 이름 | 이소리 (李소리 / Lee Sori) — *"이 소리" 말장난 뉘앙스* |
| 나이/인상 | 20대 중후반, 아시아계, **동양풍 얼굴**(`Girl Character.jpg` 얼굴 참고) |
| 체형 | **글래머러스 아워글래스 상체**(풍성한 가슴·잘록한 허리), 품위 있는 성인 실루엣(노출 지양) |
| 역할 | **AI 어시스턴트/보컬리스트 감성** — 소리를 상상하고 제안 |
| 성격 | 밝고 에너지 넘침, 말이 빠르고 다정, 호기심 많음, 사람을 잘 챙김 |
| 톤 | 따뜻·활기·긍정. "이렇게 들려드릴게요!" |
| 시그니처 컬러 | 민트/틸 `#38E0C4` |
### 1-2. 말투 / 보이스 (앱 카피 예)
- 제안: *"이 소리, 딱이죠?"*, *"보컬 한 발 앞으로 당겨볼게요."*
- 처리중: *"지금 딱 맞는 소리 찾는 중…"*
- 성공: *"완성! 이대로 들어보세요 🎧"*
- 빈 상태: *"어떤 소리를 원하세요? 말만 해요."*
- 에러/실패: *"앗, 잠깐 꼬였어요. 다시 해볼게요!"*
### 1-3. 표정 레퍼토리
큰 눈웃음(기본) · 활짝 웃음 · 윙크 · 집중(살짝 진지) · 놀람(반짝) · 뿌듯 · 장난스러움 · 차분한 미소.
### 1-4. 포즈 / 제스처
손바닥 펴 음파 띄우기(시그니처) · 검지로 "이거!" 포인팅 · 헤드폰 한쪽 만지며 듣기 · 두 손 하이(기쁨) ·
윙크+따봉 · 팔짱+자신감 · 손끝 튕겨 EQ 생성 이펙트.
### 1-5. 의상 베리에이션 (얼굴·체형 고정)
| 룩 | 설명 | 용도 |
|---|---|---|
| **시그니처** | 화이트 크롭후디 + 민트/블랙 트랙재킷 + 블랙 트랙팬츠 | 브랜드 핵심(고정) |
| 스트리트 | 오버사이즈 후디 + 캡 + 스니커즈 | 캐주얼/마케팅 |
| 스튜디오 | 심플 티 + 헤드폰 풀착용 + 데님 | 작업/집중 씬 |
| 코지 | 니트 스웨터 + 담요, 머그컵 | 야간/편안 모드, 로딩 |
| 시즌(여름) | 반팔 + 라이트 톤 | 여름 이벤트 |
| 시즌(겨울) | 패딩/머플러(민트 포인트) | 겨울/연말 |
| 파티/이벤트 | 홀로그램 포인트 재킷 | 출시·축하 |
### 1-6. 헤어 — **컬러 & 스타일 베리에이션** (요청 반영)
> **원칙**: 시그니처는 민트 단발 유지. 아래는 확장/시즌/테마용. 헤어가 바뀌어도 **얼굴·헤드폰·분위기는 동일**.
**A) 헤어 컬러 팔레트**
| 컬러 | HEX | 무드 | 추천 용도 |
|---|---|---|---|
| **민트 틸 (시그니처)** | `#38E0C4` | 밝음·상쾌 | 브랜드 기본(고정) |
| 아쿠아 시안 | `#4CD9E8` | 시원·테크 | 이단과 톤 매치, 듀오컷 |
| 라벤더 퍼플 | `#B79CFF` | 드리미·야간 | 다크/야간 테마, 릴랙스 |
| 코랄 핑크 | `#FF8FB1` | 플레이풀·귀염 | 스티커·이벤트 |
| 선셋 오렌지 | `#FFB454` | 활기·여름 | 여름 시즌 |
| 로즈 골드 | `#F5C2A0` | 세련·프리미엄 | 프리미엄/굿즈 |
| 딥 네이비 블루 | `#3A5BD9` | 차분·포멀 | 포멀/집중 씬 |
| 스노우 화이트+민트 그라데 | `#EAF7F2``#38E0C4` | 몽환·하이엔드 | 스플래시/프리미엄 |
| 내추럴 블랙/브라운 | `#2B2B33` / `#5A3E2B` | 리얼·동양풍 | 오프브랜드/현실 톤(굿즈) |
> **강조색 연동 아이디어**: 앱 테마 강조색을 바꾸면 이소리 헤어도 같은 계열로(예: 강조색=퍼플 → 라벤더 헤어).
**B) 헤어 스타일 베리에이션**
| 스타일 | 설명 | 무드 |
|---|---|---|
| **단발 밥 (시그니처)** | 턱선 길이, 볼륨 뱅 | 기본·발랄 |
| 포니테일 | 높게 묶음, 잔머리 | 활동적·스포티 |
| 하프업 | 반묶음 | 캐주얼·친근 |
| 롱 스트레이트 | 어깨 아래 생머리 | 우아·차분 |
| 웨이비 미디엄 | 굵은 웨이브 | 세련·트렌디 |
| 브레이드 | 사이드 땋기 | 디테일·개성 |
| 픽시컷 | 짧고 시크 | 쿨·미니멀 |
| 번(올림머리) | 헤드폰과 조화 | 작업·집중 |
> 세트별 복붙 요청문(헤어 컬러/스타일·의상·시즌): **`docs/IMAGE_GEN_VARIATIONS.md`**.
**C) 헤어 베리에이션 이미지 생성 프롬프트 (예)**
```
[이소리, same face/character as reference], change ONLY hairstyle & color to: {lavender purple #B79CFF, long
wavy medium hair}. Keep identical East-Asian face, brown eyes, silver on-ear headphones, and overall vibe.
modern anime semi-real, transparent background, character only, NO text.
```
---
## 2. 이단 (Lee Dan) — "소리를 정밀하게 다듬는 튜너"
### 2-1. 기본 프로필
| 항목 | 내용 |
|---|---|
| 이름 | 이단 (李단 / Lee Dan) |
| 나이/인상 | 20대 후반~30대 초반, 아시아계 |
| 역할 | **사운드 엔지니어/정밀 튜너** — 아이디어를 정확히 마무리 |
| 성격 | 침착하고 유쾌, 잘 웃음, 손이 야무진 프로, 든든한 동료/형 |
| 톤 | 안정·신뢰·여유. "여기 살짝만 다듬으면 완벽." |
| 시그니처 컬러 | 시안/블루 `#4CC2FF` |
### 2-2. 말투 / 보이스 (앱 카피 예)
- 마무리: *"좋아, 미세 조정할게."*, *"여기만 다듬으면 완벽해요."*
- 처리중: *"디테일 잡는 중… 거의 다 됐어요."*
- 성공: *"완성! 이거예요 👍"*
- 안내: *"원하면 더 정밀하게 갈 수도 있어요."*
- 에러: *"음, 값이 좀 튀네요. 다시 잡을게요."*
### 2-3. 표정 레퍼토리
시원한 미소(기본) · 개구진 자신감 · 집중(눈매 진지) · 만족 끄덕임 · 놀람 · 껄껄 웃음 · 차분한 프로페셔널.
### 2-4. 포즈 / 제스처
홀로그램 슬라이더/노브 조작(시그니처) · 따봉 · 팔짱+미소 · 헤드폰 목에 걸고 손짓 · 검지로 포인트 ·
손목 스마트워치 확인 · "OK" 손사인.
### 2-5. 의상 베리에이션
| 룩 | 설명 | 용도 |
|---|---|---|
| **시그니처** | 네이비/블랙 후디+보머(블루 지퍼·페이더 디테일)+화이트 티 | 브랜드 핵심(고정) |
| 스트리트 | 보머 재킷 + 캡 + 스니커즈 | 캐주얼 |
| 스튜디오 | 롤업 셔츠/후디 + 헤드폰 풀착용 | 작업 씬 |
| 테크 | 미니멀 지퍼업 + 스마트워치 강조 | 정밀/엔지니어 |
| 시즌(겨울) | 패딩/후드(시안 포인트) | 겨울 |
| 포멀캐주얼 | 블레이저+티 | 발표/프리미엄 |
### 2-6. 헤어 — 컬러 & 스타일 베리에이션
**A) 컬러**
| 컬러 | HEX | 용도 |
|---|---|---|
| **다크+시안 스트릭 (시그니처)** | `#20242C` + `#4CC2FF` | 기본(고정) |
| 블루 틴트 다크 | `#1E3A5F` | 야간/테크 |
| 애쉬 실버 | `#C9CED6` | 시크/프리미엄 |
| 딥 네이비 | `#2B3A67` | 포멀 |
| 내추럴 블랙 | `#1C1C22` | 리얼/오프브랜드 |
| 시안 풀컬러 | `#4CC2FF` | 이벤트/포인트 |
**B) 스타일**
| 스타일 | 무드 |
|---|---|
| **텍스처 크롭 (시그니처)** | 트렌디·자신감 |
| 슬릭백 | 프로·세련 |
| 언더컷 | 샤프·모던 |
| 미디엄 웨이비 | 편안·캐주얼 |
| 비니 착용 | 스트리트 |
| 짧은 버즈+스트릭 | 스포티 |
---
## 3. 듀오 / 관계 · 활용 시나리오
### 3-1. 케미
- **이소리(아이디어) → 이단(정밀 마무리)** 워크플로우의 인격화. 동료·파트너십(연인 아님).
- 대표: 백투백(소리=음파 손짓 / 단=EQ 조작), 헤드폰 한 짝씩 나눠 끼고 마주보기.
- 티키타카 대사: 소리 *"보컬 앞으로!"* → 단 *"좋아, 미세 조정할게."*
### 3-2. 앱 상황별 등장 (누가·어떤 표정/포즈)
| 상황 | 캐릭터 | 연출 |
|---|---|---|
| 스플래시/About | 듀오 백투백 | 등장+음파 |
| 온보딩 3단계 | 소리+단 반신 | 단계별 제스처 |
| AI 처리중 | **이소리** 손끝 음파 | 루프(Lottie) |
| AI 응답 아바타 | **이소리** 원형 얼굴 | 말하기/윙크 |
| 로딩(다운/적용) | 소리 or 단 소형 | 이퀄 펄스 |
| 성공 토스트 | **이단** 따봉 | 팝인+체크 |
| 바이패스(EQ off) | 둘 헤드폰 벗음 | 상태 전환 |
| 빈 상태 | **이소리** 안내 | 정지+부유 |
| 에러 | 소리 or 단 | 머쓱 표정 |
### 3-3. 굿즈/확장
스티커팩(표정·헤어 베리에이션) · 이모지 · 스플래시 · 로딩 미니컷 · 시즌 테마 스킨 · 프로필 프레임.
---
## 4. 금지 / 가드레일
- 얼굴형·눈·나이감·체형 **변경 금지**(같은 인물 유지). 바뀌는 건 헤어/의상/표정/포즈/소품뿐.
- 치비·아기화 금지. 과도한 노출·유치한 캣이어 등 금지(플레이풀은 세련된 선에서).
- 시그니처 접점(아이콘/아바타/온보딩/스플래시)은 **민트 이소리 / 시안 이단 고정.**
- 베리에이션은 스티커·시즌·마케팅 등 **확장 영역에서만.**
## 5. 참고
- 확정 외형·컬러코드: `BRAND_CHARACTERS.md`
- UI 배치·포맷(Lottie): `CHARACTER_UI_INTEGRATION.md`
- 이미지 생성 요청문: `IMAGE_GEN_REQUESTS.md`
+155
View File
@@ -0,0 +1,155 @@
# CHARACTER UI INTEGRATION — 마스코트 UI 결합 계획
> 목표: `docs/Image/`의 두 마스코트(민트 여캐 "소리" · 시안 남캐 "단이", `BRAND_CHARACTERS.md`)를
> **실제 앱(WPF, 다크/Mica)에 역동적으로 결합**한다. 이 문서는 ①현재 자산 평가 ②UI 배치 매핑
> ③파일 포맷 결정(GIF/동영상/Lottie/PNG) ④이미지 생성 AI 의뢰 컨셉 목록을 정리한다.
---
## 1. 현재 자산 평가
`docs/Image/`에는 **완성도 높은 "전체 화면 장면"**이 이미 있다:
- 듀오 브랜드 아트, 온보딩 STEP 1~3, 로딩("소리 튜닝 중…"), 성공("튜닝 완료"), 바이패스("EQ 바이패스").
- 각 장면의 **wpf_gifs**(2~2.5MB) / **video_like_gifs**(2.8~3.4MB, 더 부드러움) 애니메이션 버전 존재.
### 좋은 점
- 캐릭터 디자인·컬러·분위기가 브랜드와 완벽히 일치. **스플래시/스토어/마케팅 비주얼로 즉시 사용 가능.**
### 인앱 사용의 문제 (그대로는 못 얹음)
1. **텍스트가 그림에 구워짐**(한글 UI 문구·STEP 라벨·버튼). → 현지화 불가, DPI 스케일 시 흐림,
`TYPOGRAPHY.md`(최소 12·최대 24) 규칙과 폰트 불일치. **텍스트는 WPF가 실시간 렌더해야 함.**
2. **불투명 전체 배경** → 다크/Mica 위에 겹쳐 쓸 수 없음. 레이아웃(1400×860 가로형)과 안 맞음(세로형 풀블리드).
3. **장면 통짜** → 캐릭터만 분리 불가. 실제 앱은 **캐릭터(투명 배경) + 라이브 UI**로 합성해야 함.
4. **GIF 한계**: 다크 그라데이션에서 색밴딩, 알파(투명) 불가, 용량 큼.
> 결론: 현재 장면들은 **스플래시/마케팅 전용**으로 보관. 인앱용은 **"캐릭터만 투명 배경"**으로 재의뢰한다.
---
## 2. UI 배치 매핑 (실제 앱 화면 기준)
| # | 앱 위치 | 등장 | 연출 | 에셋 형태 |
|---|---------|------|------|-----------|
| A | **스플래시 / About** | 듀오(백투백) | 등장 페이드+음파 루프 | (기존 장면 재사용 OK) 또는 투명 듀오 PNG |
| B | **온보딩 / 도움말 드로어(3단계)** | 소리+단이 반신 | 스텝별 슬라이드 인 | **투명 PNG 컷아웃** + 라이브 WPF 텍스트 |
| C | **AI 프롬프트 처리중**("AI가 듣는 중") | 소리(손끝 음파) | 손끝 음파 **루프 애니** | **Lottie** (소형, 코너) |
| D | **AI 응답 말풍선 아바타** | 소리 얼굴 | 정지/살짝 눈깜빡 | **원형 투명 PNG** (표정 2~3종) |
| E | **로딩**(AutoEQ 다운/EQ 적용) | 소리 or 단이 소형 | 헤드폰 이퀄 펄스 루프 | **Lottie** + 라이브 진행바 |
| F | **성공 토스트**(EQ 적용/튜닝 완료) | 단이 엄지척 | 팝인+체크 | **투명 PNG**(+WPF 스토리보드 팝) |
| G | **바이패스(EQ OFF) 상태** | 둘 헤드폰 벗음 | 상태 전환 | **투명 PNG**(활성/바이패스 2컷) |
| H | **빈 상태**(프로파일/프리셋 없음) | 소리 안내 제스처 | 정지 | **투명 PNG** |
| I | **헤더/사이드바 워터마크** | 로고 모노그램 | 정지 | **SVG/PNG** |
> 핵심 원칙: **캐릭터는 이미지, 텍스트·패널·그래프·버튼·진행바는 전부 WPF 라이브 요소.**
> 그림 속 홀로그램 EQ/말풍선은 "분위기"일 뿐, 실제 조작 UI는 우리 컨트롤이 담당.
---
## 3. 파일 포맷 결정 (GIF vs 동영상 vs Lottie vs PNG)
### 결론 요약
| 용도 | 권장 포맷 | 이유 |
|------|-----------|------|
| 정지 캐릭터(아바타·빈상태·온보딩 컷·성공/바이패스) | **투명 PNG-24 (알파)** | 선명, 가벼움, DPI별 @1x/@1.5x/@2x |
| 루프 마이크로 애니(AI 처리중·로딩·음파 펄스) | **Lottie (.json 벡터)** | 초경량, 벡터라 무한 선명, 색 틴트·루프 자연스러움 |
| 화려한 래스터 루프가 꼭 필요할 때 | **애니메이션 WebP / APNG** | 알파 지원(투명), GIF보다 고화질·소용량 |
| 불투명 전체화면 스플래시/인트로(1회) | **MP4/WebM (불투명)** | 리치하지만 알파 오버레이엔 부적합 |
| ❌ 지양 | **GIF** | 256색 밴딩(다크 그라데이션에 치명), 알파 없음, 용량 큼 |
### "GIF로? 동영상으로?" 직접 답
- **둘 다 최적이 아님.** 실제로 앱에 **역동적으로** 얹는 최선은:
**정지 투명 PNG + WPF 자체 애니메이션(Storyboard: 페이드/살짝 떠오름/스케일/글로우 펄스)**
90%를 커버한다. 추가 에셋·라이브러리 없이 "살아있는" 느낌을 낸다.
- 더 리치한 **손끝 음파/헤드폰 이퀄 펄스** 같은 반복 모션은 **Lottie**로 별도 제작(작고 선명·테마 틴트 가능).
- **동영상(MP4)** 은 **불투명 스플래시** 한 곳에만. WPF `MediaElement`는 **알파 채널 영상 지원이 빈약**해
캐릭터 오버레이용으로는 비추천.
- **GIF는 쓰지 말 것**(특히 이 다크·네온 그라데이션에서 밴딩이 눈에 띔). 굳이 래스터 루프면 **WebP/APNG.**
### WPF 재생 방법 / 필요 패키지 (메모)
- **투명 PNG**: 기본 `Image` 컨트롤. 추가 패키지 불필요.
- **WPF 스토리보드**: 기본 제공(`DoubleAnimation`, `RenderTransform`). 추가 불필요.
- **Lottie**: WPF는 기본 미지원 → 라이브러리 필요. 후보: **`SkiaSharp.Skottie`**(Skia 기반, 유지보수 양호) /
`LottieSharp`. dev 세션에서 하나 채택해 PoC.
- **애니메이션 GIF/WebP**: 기본 미지원 → `WpfAnimatedGif`(GIF) / WebP는 별도 디코더. (지양하므로 후순위)
- **성능**: 캐릭터는 큰 이미지이므로 **표시 크기에 맞춘 다운스케일본**을 쓰고, 안 보일 땐 언로드.
---
## 4. 이미지 생성 AI 의뢰 컨셉 목록
> ⚠️ **이미지 생성 AI는 "정지 이미지"만 만든다.** 애니메이션(Lottie/영상)은 별도 모션 작업.
> 따라서 AI에는 **① 일관성 고정용 캐릭터 시트 → ② 포즈/표정별 투명 배경 컷** 순으로 의뢰한다.
> 프롬프트 베이스는 `BRAND_CHARACTERS.md` §7. 공통 조건: **transparent background, character only, no text,
> no UI panels, consistent same character, high-res ≥2048px.**
### STEP 1 — 일관성 고정 (먼저)
- **캐릭터 시트(각 1장)**: 정면·3/4·측면 턴어라운드 + 표정 6종(기본/미소/웃음/집중/윙크/놀람).
→ 이걸 레퍼런스로 걸어 이후 컷의 **동일 인물** 유지.
### STEP 2 — 배치용 컷 (투명 배경)
**여캐 "소리"**
- `sori_idle` 반신 기본(살짝 미소) — 온보딩/빈상태
- `sori_present` 손바닥 펴고 손끝 음파 — AI 제안/처리중(C의 정지 베이스)
- `sori_happy` 두 손 하이(기쁨) — 성공
- `sori_face_round` 원형 얼굴 크롭 표정 3종 — AI 아바타(D)
- `sori_headphones_off` 헤드폰 벗는 컷 — 바이패스(G)
**남캐 "단이"**
- `dan_idle` 반신 기본(자신감 미소) — 온보딩
- `dan_tune` 홀로그램 슬라이더 조작(패널은 뺀 손동작만) — 튜닝/로딩(E 베이스)
- `dan_thumbsup` 엄지척 — 성공(F)
- `dan_headphones_off` 헤드폰 벗는 컷 — 바이패스(G)
**듀오**
- `duo_backtoback` 백투백 대표 포즈(투명) — 스플래시/About(A)
### STEP 3 — (선택) 모션
- C/E의 손끝 음파·헤드폰 펄스는 위 정지 컷을 바탕으로 **Lottie 재제작**(모션 디자이너 또는 image-to-video 툴).
- 저비용 대안: 정지 PNG + **WPF 스토리보드**(글로우 펄스/부유)만으로 시작.
### 규격 (전달용)
- 배경 투명(알파) PNG, 캐릭터만, **텍스트/로고/패널 없음**.
- 캔버스 여백 최소, 캐릭터 꽉 차게. 세로 반신 ~2048px, 원형 아바타 ~1024px.
- 3종 DPI 다운스케일본(@1x/@1.5x/@2x) 또는 원본 1장(앱에서 다운스케일).
- 컬러: 소리=민트 `#38E0C4`, 단이=시안 `#4CC2FF`, 라인 선명.
---
## 5. 제작 우선순위 / 로드맵
1. **캐릭터 시트로 일관성 고정**(STEP 1) — 가장 먼저. (배치마다 얼굴 다른 문제 해소)
2. **투명 PNG 핵심 5컷**: `sori_face_round`(아바타) · `sori_present` · `dan_thumbsup` · `duo_backtoback` · 바이패스 2컷.
3. **WPF 결합 PoC**: `Image` + 스토리보드로 온보딩/아바타/성공 토스트에 정적+모션 배선.
4. **Lottie 도입 검토**(SkiaSharp.Skottie) → AI 처리중·로딩 루프.
5. 스플래시는 기존 듀오 장면(불투명) 재사용 가능.
## 6. 열린 결정
- [x] **캐릭터 이름 확정**: 여 **이소리(Lee Sori)** · 남 **이단(Lee Dan)**. (이미지 직접 노출은 선택)
- [x] `Girl Character.jpg` = **이소리 "동양풍 얼굴" 참고용**(복장/헤어컬러 참고 아님).
- [x] **애니메이션 범위 확정: "최대한 Lottie"**.
→ 캐릭터 = **파츠 컷아웃 리깅으로 Lottie화**(AI가 만든 투명 파츠 사용), 모션 FX(음파·EQ바·파티클·로딩) =
**순수 벡터 Lottie**. PNG+스토리보드는 **폴백/저부하 화면**에만 제한적으로.
→ 이미지 생성 AI 요청문: **`docs/IMAGE_GEN_REQUESTS.md`**.
→ WPF Lottie 재생 라이브러리 PoC 필요(후보: **SkiaSharp.Skottie** / LottieSharp).
## 6-B. Lottie로 "직접(벡터)" 만들 모션 FX (이미지 생성 AI 아님)
> 아래는 이미지 생성 AI가 아니라 **AE/Bodymovin·Figma·LottieLab로 벡터 제작**(또는 무료 Lottie 에셋 커스터마이즈).
> 캐릭터 컷아웃 뒤/주변에 합성해 "캐릭터가 소리를 다루는" 장면을 완성한다.
- `fx_soundwave_loop` : 손끝에서 퍼지는 **음파 링/파형**(민트→시안) 무한 루프.
- `fx_eq_bars_loop` : 5~7개 **EQ 막대**가 위아래로 튀는 루프(로딩·처리중).
- `fx_particles_loop` : 반짝이는 별/음표 파티클 상승 루프.
- `fx_glow_ring_pulse` : 캐릭터 뒤 **글로우 링** 맥동(성공/강조).
- `fx_loading_progress` : 이퀄라이저형 진행 인디케이터.
- `fx_check_success` : 체크마크 그려지는 성공 애니.
## 7. Lottie vs PNG + WPF 스토리보드 (의사결정용 비교)
| 항목 | 투명 PNG + WPF 스토리보드 | Lottie (.json 벡터) |
|------|--------------------------|---------------------|
| 정체 | 정지 그림 + WPF가 위치/투명도/크기/회전만 애니 | 디자이너가 만든 **그림 자체가 움직이는** 벡터 애니 |
| 표현력 | 페이드·부유·확대·글로우·흔들림 등 **단순 트랜스폼** | 팔 움직임·음파 퍼짐·표정 변화 등 **본격 모션** |
| 제작 | 개발자가 XAML만(추가 그림 불필요) | **모션 디자이너/툴 필요**(AE→Bodymovin 등), 별도 제작 |
| 앱 무게 | 매우 가벼움(기본 기능) | 라이브러리 필요(SkiaSharp.Skottie 등) + json |
| 선명도 | 이미지라 DPI별 다운스케일 필요 | 벡터라 **무한 선명**, 색 틴트 쉬움 |
| 적합 | 아바타·온보딩 컷·성공 토스트·빈상태 | AI "듣는 중" 음파·로딩 이퀄 펄스 등 **주목 루프** |
| 비용/속도 | 낮음/빠름(바로 가능) | 높음/느림(에셋 제작 선행) |
> 권장: **PNG+스토리보드로 먼저 전체 배선** → 눈에 띄어야 할 1~2곳만 **Lottie로 승격**.
+163
View File
@@ -0,0 +1,163 @@
# DEV PLAN
> **개발 세션 진행 로그는 `PROGRESS.md` 참조.** 아래 체크박스의 `[x]`는 선구현 또는 dev 세션 완료.
> **다음 최우선 작업: 그래프 도트(노드) 위치 정상화 (`PROGRESS.md` ▶ 참조).**
## 마일스톤
### M0 — 스파이크/검증 (0.5일)
- [ ] APO `Include:` 절대경로 허용 여부 확인 → 저권한 전략 확정(ARCHITECTURE §4).
- [ ] AutoEQ repo 최신 구조 + 소스별 라이선스 확인 → open/restricted 분류 규칙 확정.
- [ ] WPF-UI + LiveCharts2 스켈레톤에서 Mica + 로그축 차트 렌더 PoC.
### M1 — 솔루션 스캐폴딩 (0.5~1일)
- [ ] `DansoriEQ.sln` + App/Core/Setup 프로젝트.
- [ ] WPF-UI 테마(다크 Fluent) 적용, 목업 레이아웃(사이드바/메인/AI독) 정적 배치.
- [ ] 설정 저장소(%LOCALAPPDATA%\DansoriEQ) + API 키 보관(DPAPI 암호화).
### M2 — 프로파일 DB (1~1.5일)
- [ ] AutoEQ 수집 스크립트(개발용, 1회) → open/restricted 분류 → SQLite 적재.
- [x] (선구현) **`SqliteProfileDbService`**(스키마·GetInfo·Search·LoadEq·Upsert·ImportFromFolder·UpdateAsync=AutoEq zip 다운로드). `AutoEqParser` 있음. [ ] (dev) 사이드바 바인딩 + DesignStub→Sqlite 교체.
- [ ] 사이드바: IEM/헤드폰 그룹 분리, 검색, 선택. (라이선스 구분 없이 병합 표시)
- [ ] "DB 업데이트" 기능(zip 재확보→upsert→날짜 표시).
- [ ] **가져오기 자동 매칭**: `.tweq` 가져올 때 대상 기기를 로컬 DB와 매칭(`FindMatch`) →
있으면 연결, **없으면 "DB 업데이트로 받기" 안내**(가져오기 미리보기 창에서 DbManager 연결).
### M3 — EQ 엔진 + APO (1일)
- [ ] `EqState`/`Filter` 모델, `ApoRenderer`, `PreampCalculator`.
- [ ] `ApoLocator`(레지스트리), `ApoConfigInstaller`(최초 1회 승격), `IncludeWriter`(무승격).
- [ ] 프로파일 선택→베이스 EQ 로드→APO 적용→그래프 반영 왕복.
- [x] (선구현) **시작 시 APO 탐색 → 없으면 설정창(자동설치/경로지정/미리보기)**. `ApoSetupWindow`·
`ApoInstaller`·`AppSettings`. ※ APO 무인설치는 불가(장치 선택+재부팅) → 설치파일 실행까지만.
- [x] (선구현) **APO 미설치 시 미리보기 writer**(`NullApoWriter`)로 파이프라인 동작.
### M4 — AI 레이어 (1일)
- [x] (선구현) `ClaudeClient` + **`IAiEqProvider` 추상화** + `EqDeltaParser`(공유). `EqPromptBuilder`.
- [x] (선구현) **프롬프트창 → 활성 provider → `EqDeltaApplier` → APO 적용 + 설명 출력** 실배선.
- [x] (dev) **Gemini 무료 API로 자연어→EQ 적용 동작 확인**(PROGRESS.md). 되돌리기/리셋 배선됨. [ ] 응답 품질 평가(사용자 추후), 히스토리 UI.
### M5 — 그래프 시각화 + 테마 (1.5일)
- [ ] LiveCharts2로 현재 EQ 합성 곡선 + 타깃 곡선 + 필터 노드.
- [ ] 애니메이션 전환, Preamp/활성 토글 연동.
- [ ] **테마 전환**: Dark / Light / System(윈도우 추종) — WPF-UI ApplicationThemeManager.
- [ ] **강조색(Accent) 프리셋 5종 내외**(기본=틸/시안) + '윈도우 강조색 추종' 옵션 + 설정 저장.
- [ ] **그래프 색을 테마·강조색 리소스에 바인딩**(라이트 모드에서도 자연스럽게).
- [ ] 인터랙티브 노드 편집은 M7로 분리(아래).
### M6 — 마감/패키징 (1일)
- [ ] 최초 설정 마법사 UX, 예외/권한 실패 폴백 안내.
- [ ] 패키징 + **`--exclude-restricted` 배포 옵션**(restricted 폴더/행 제외).
- [ ] 아이콘/브랜딩, 기본 프리셋, README.
- [x] (선구현) **도움말 드로어**(❓ 도움말 → 오른쪽 슬라이드): 3단계 온보딩 + 버튼 안내 +
**API 키 발급 공식 링크**(Claude/OpenAI/Gemini). 설정의 각 키 행에도 '키 발급 방법' 링크.
### M7 — 인터랙티브 그래프 EQ 편집 (fast-follow, +1.5~2.5일)
> MVP(M1~M6) 출시 후 붙이는 최우선 확장. 가장 무거운 UI 파트라 분리한다.
> AI 없이 순수 수동 편집만 하려는 사용자도 이걸로 커버된다.
- [ ] **커스텀 WPF 에디터 컨트롤**(Canvas 기반) 또는 LiveCharts2 곡선 위 드래그 오버레이(Thumb/Adorner).
※ LiveCharts2 기본 포인트 드래그로는 폴리시가 부족 → **전용 컨트롤 권장**.
- [x] 인터랙션: 노드 좌우=Fc / 상하=Gain / 휠=Q / 더블클릭=밴드 추가 / 우클릭=삭제. [ ] **노드 위치 정상화(다음 작업, PROGRESS.md ▶1)**, 타입 변경(팝업서 지원).
- [x] (dev) **필터 칩 더블클릭 → 자체 그래픽 편집 팝업**(`FilterEditWindow`): **전체 18종 필터 타입** + 컨텍스트 UI(Q/기울기/차수) + **Peace식 정밀 수치 입력** + 그래프 축 라벨. `Filter`/`FilterType`/`ApoRenderer` 확장.
- [x] (선구현) **가변 밴드 개수**(`List<Filter>`, 상한 `MaxBands=40`; Peace는 31). 그래프 더블클릭/우클릭 +
' 밴드 추가'/'전체 지우기' 버튼(`AddBand`/`ClearBands`).
- [ ] 드래그 중 **Fc/Gain/Q 실시간 수치 표시**.
- [x] (선구현) **APO 쓰기 디바운스(120ms) + Preamp 실시간 재계산**(수동 편집 시 클리핑 방지).
- [x] (선구현) **AI 양방향 루프**: `SendPromptAsync`가 현재 EQ(수동 편집 포함)를 컨텍스트로 전달. **되돌리기/리셋**(Undo 스택+베이스) 배선.
### M8 — 설정 화면 & Claude API 키 관리 (0.5~1일) · MVP 필수
> 별도 메뉴 화면(WPF-UI NavigationView: Home/EQ ↔ Settings).
> AI(M4)의 전제이므로 실제 착수는 M1~M4와 **병행 권장**. 상세: ARCHITECTURE §9.
- [ ] 설정 화면: 섹션 = [AI · API 키] / [테마] / [APO] / [데이터베이스].
- [x] (선구현) **API 키 등록/삭제/교체 + DPAPI 암호화**(3사) + **연결 테스트**(AI 관리).
- [ ] 모델 선택(기본 Sonnet / 옵션 Opus). 키 미등록 시 프롬프트 독 비활성 + 안내.
### M9 — EQ 프리셋 공유(내보내기/가져오기) (1일)
> 사용자가 만든 EQ를 다른 사용자와 공유. 파일 규격: **ARCHITECTURE §8 (`.tweq`)**.
- [ ] **내보내기**: 현재 EQ + 대상 IEM/헤드폰 메타 + **AI 대화 히스토리(간략)**`.tweq`(JSON)로 저장.
- [ ] **가져오기**: 파싱·검증 → **정보 패널(대상 기기 / 히스토리 / 작성자 노트) 표시** → EQ 적용.
- [ ] 로컬 DB 동일 기기와 매칭(있으면 연결, 없으면 메타만으로 standalone 적용).
- [ ] 입력값 검증/클램프(Fc/Gain/Q), 히스토리 크기 상한, 텍스트는 표시 전용(코드 실행 없음).
- [ ] (참고) 공유 파일엔 **측정 데이터가 아니라 기기 이름/메타만** 담기므로 라이선스 문제 없음.
### M10 — 멀티 AI 프로바이더 (확장, +1~2일) · MVP 이후
> 기본은 **Claude 단일**. 향후 OpenAI(ChatGPT)/Gemini를 사용자가 선택하도록 확장.
> EqDelta JSON 스키마가 provider 중립적이라 어댑터만 추가하면 됨.
- [x] (선구현) `IAiEqProvider` 추상화 + `AiProviderFactory`(AppSettings 기반).
- [x] (선구현) 어댑터: **Claude(tool use) / OpenAI(function) / Gemini(json) / Ollama(json, 로컬)**.
- [ ] 설정 화면(M8)에 **provider 선택 + provider별 API 키** 저장(DPAPI).
- [ ] provider별 구조화 출력 신뢰도/프롬프트 미세조정 검증.
### M11 — Peace 벤치마킹 기능 (확장)
> 모델/렌더러/서비스는 **선구현됨**. 남은 건 UI·배선.
- [x] (선구현) **크로스피드 / 좌우 프리앰프·밸런스 / 베이스부스트** 모델(`EffectsConfig`) + APO 렌더 + `.tweq` 저장.
- [x] (선구현) 이펙트 **조절 UI**(`EffectsWindow`: 크로스피드/베이스부스트/좌우 트림, 라이브 적용) + **AI 자연어 제어 선구현**(effects 스키마·파서·적용: 크로스피드/밸런스/베이스).
**크로스피드 렌더는 플레이스홀더**`ApoRenderer` 메모대로 저역통과+딜레이 정식 구현 필요.
- [x] (선구현) **명령 창**(`CommandWindow`) — APO 설치 시 config 폴더에 `custom_apo.txt` 저장(config.txt Include 안내).
- [x] (선구현) **핫키**: Ctrl+Alt+B=바이패스, Ctrl+Alt+[ / ]=프리셋 이전/다음. [ ] 사용자 바인딩 UI.
- [x] (선구현) **프리셋 라이브러리**(`PresetLibrary` + `PresetLibraryWindow` UI: 저장/목록/불러오기/삭제). [ ] 핫키 전환.
### M12 — 앱/장치 자동 전환 (확장)
- [x] (선구현) `ForegroundAppWatcher` + `SwitchRule`/`SwitchRuleEvaluator`(순수).
- [x] (선구현) **`ProfileSwitcher`(watcher→evaluator→프리셋 적용) + `SwitchRulesStore` + `SwitchRulesWindow`(규칙 관리 UI)** + 설정 진입 + `AutoSwitchEnabled`.
- [x] (선구현) **장치 변경 감지**(`DefaultDeviceWatcher`) → 앱+장치 모두 규칙 매칭. [ ] (dev) 런타임 규칙 리로드, (AI 결합) 자연어 규칙 생성.
### M13 — 이펙트 확장 (향후)
- [ ] **가상 서라운드 / 리버브** 렌더링(`EffectsConfig`에 자리만 있음). '정확도' 컨셉과 분리된 '이펙트' 영역으로.
> 스피커 확장(스피커 모드/룸 보정)은 **범위에서 제외**한다(측정 기반이 정석인데 그 트랙은 진행 안 함).
### M14 — 시스템 볼륨 / 출력장치 제어 (선구현)
- [x] (선구현) `SystemVolumeService`(NAudio Core Audio): 출력장치 목록 + 장치별 **볼륨/뮤트** +
**Windows 볼륨 변경 → 앱 동기화**(`OnVolumeNotification`, 양방향).
- [x] (선구현) `VolumePanel` UI(그래프 옆): 장치 선택 + 세로 볼륨 슬라이더 + 뮤트 + % 표시.
- [~] `DefaultDeviceSwitcher`(IPolicyConfig): ⚠️ **미검증 COM vtable이 오디오 손상 유발 → 호출 제거함. 재도입 금지.**
- [x] (dev) NAudio 볼륨 확인. **하드웨어/디지털(APO) 하이브리드 볼륨** 구현(라인아웃 DAC 대응). [ ] 라인아웃 DAC 볼륨 UX 추후 재검토(PROGRESS.md).
### M15 — 로컬 AI(오프라인) + AI 관리 (선구현)
- [x] (선구현) **AI 관리 창**(`AiManagerWindow`): 활성 제공자/모델 선택(클라우드+로컬) + 로컬 런타임
자동설치 + 모델 다운로드 진행률 + **저장공간 경고(개당 2~8GB, 다수/대형 모델 시 수십~수백 GB)**.
- [x] (선구현) `WingetInstaller`(winget silent) — **Ollama 전용**(무인 자동화 확실). `OllamaService`(감지/목록/`/api/pull`). `DiskInfo`.
- [x] (선구현) 설정→'AI 관리' 진입 + `AppSettings.AiProvider/AiModel` 저장.
- [x] (선구현) **클라우드 계정 모델 동적 조회**(`CloudModelLister`): 저장된 키로 Claude/OpenAI/Gemini의
list-models API 호출 → 계정별 사용 가능 모델 드롭다운. 실패/키없음 시 기본 목록 + 직접 입력.
- [ ] (dev) **`OllamaProvider`(IAiEqProvider) 어댑터** — 선택 로컬 모델로 EQ 생성(+GBNF/JSON 스키마 제약).
- [ ] (dev) 프롬프트창이 `AppSettings`의 제공자/모델을 사용하도록 배선(M4/M10 연동).
- [ ] (dev) Ollama 사일런트 폴백(`OllamaSetup.exe /VERYSILENT`, winget 부재 시).
- [ ] **추후 테스트 후보**(자동화·헤드리스 무인 운용 검증되면 UI에 추가): **LM Studio, GPT4All, Jan, LocalAI, llamafile**.
※ 초보자 친화 목표상, 검증 전엔 노출하지 않는다. (코드 메모: `LocalRuntime.cs`)
## 공수/토큰 추정
- **시간(파트타임):** MVP(M0~M6 + M8 설정/키 필수) ~**6~8.5일**.
- **+ M9 공유(1일)** + **M7 인터랙티브 편집(+1.5~2.5일)** + **M10 멀티 프로바이더(+1~2일)**
+ **M11~M13(Peace 기능·자동전환·이펙트/스피커): 코어 선구현, UI/배선 +2~4일** → 전체 ~**11~18일**.
- **개발 토큰(Claude 페어프로그래밍):** MVP+M8 ~**0.7M~1.5M** + M9 ~**0.15M~0.3M** + M7 ~**0.2M~0.4M** + M10 ~**0.15M~0.3M**.
- **런타임 토큰:** EQ 요청당 **2~5k**(무시 가능).
## 미결정/결정 필요
- [ ] 저권한 최종 방식: `%APPDATA%` 절대경로 Include vs config폴더+ACL (M0 스파이크로 확정).
- [ ] 차트 라이브러리 최종: LiveCharts2(예쁨) vs ScottPlot(가벼움). 기본=LiveCharts2.
- [ ] 음성 입력(🎤) 포함 시점: MVP 이후 확장(Whisper/Windows STT).
- [ ] 다중 출력 장치별 프로파일: MVP 이후.
- [ ] 인터랙티브 편집(M7) 구현 방식: 커스텀 Canvas 컨트롤 vs LiveCharts2 오버레이(착수 시 확정).
- [ ] 강조색 프리셋 목록 확정(기본=틸/시안) + '윈도우 강조색 추종' 옵션 여부.
- [ ] `.tweq` 확장자/포맷 버전 정책(향후 호환) 확정.
- [ ] M10(멀티 프로바이더)은 MVP 이후 확장으로 확정 — AI 호출부는 M4부터 `IAiEqProvider`로 추상화.
- [ ] 제품명 **확정: Dansori EQ**(표시) / 코드 식별자 **DansoriEQ**.
## 리스크
| 리스크 | 완화 |
|---|---|
| APO Include 절대경로 미지원 | config폴더+ACL 방식 폴백(둘 다 저권한 만족) |
| AutoEQ 소스 라이선스 변동 | manifest에 소스별 license/distributable 기록, restricted 격리 |
| 민감 IEM에서 EQ 후 클리핑 | Preamp 자동 안전값(음수) 강제 |
| API 키 노출 | DPAPI로 로컬 암호화 저장, 로그 미출력 |
| LiveCharts2 노드 편집 폴리시 부족(M7) | 커스텀 Canvas 컨트롤/오버레이로 구현 |
| 라이트 테마에서 그래프 색 어색 | 그래프 색을 테마·강조색 리소스에 바인딩 |
| 그래프 드래그 시 APO 파일 쓰기 폭주 | 쓰로틀/디바운스, 드래그 종료 시 적용 |
| 신뢰 불가한 공유(.tweq) 가져오기 | 스키마 검증·값 클램프·크기 상한, 텍스트 표시 전용 |
| 공유 파일 버전 불일치 | format/version 필드로 하위호환 처리, 미지원 시 안내 |
| API 키 평문 노출 | DPAPI 암호화, 로그·공유파일에 키 미포함 |
## 참고 소스
- AutoEQ: github.com/jaakkopasanen/AutoEq (results = APO ParametricEQ.txt)
- squig.link(향후 추가 소스 후보), oratory1990(측정)
- Equalizer APO 문서: sourceforge.net/projects/equalizerapo (config 문법/Include)
- WPF-UI: github.com/lepoco/wpfui · LiveCharts2: livecharts.dev
+289
View File
@@ -0,0 +1,289 @@
# DansoriEQ Live2D Character HANDOFF
작성일: 2026-07-04
작업 루트: `D:\Work_AI\Dansori`
앱 프로젝트: `D:\Work_AI\Dansori\DansoriEQ`
캐릭터/빌드 문서 루트: `D:\Work_AI\Dansori\Characters_Build_Docs`
이 문서는 세션이 바뀌어도 Live2D/캐릭터 통합 작업을 바로 이어가기 위한 인수인계 문서다. 더 상세한 변경 로그는 `docs/LIVE2D_CHARACTER_INTEGRATION_PLAN.md`에 누적되어 있다.
## 1. 현재 목표
DansoriEQ는 Equalizer APO와 AI 프롬프트를 이용한 Auto AI EQ WPF 앱이다. 최종 목표는 앱 오른쪽 영역에 단순 PNG가 아니라 Live2D에 가까운 동적 캐릭터를 탑재하는 것이다.
현재는 실제 Cubism `.model3.json`이 아니라 WebView2 기반 HTML/CSS/JS 호스트에서 PNG 파츠를 겹쳐 움직이는 하이브리드 퍼펫 방식으로 구현 중이다. 이 방식은 빠르게 WPF 안에서 구도, 캐릭터성, 파츠 움직임을 검증하기 위한 중간 단계다.
## 2. 현재 적용 상태
현재 앱은 신 버전 이소리 시트를 기준으로 만든 `LeeSoriV2` 퍼펫을 사용한다.
신 버전 기준 원본:
- `D:\Work_AI\Dansori\Characters_Build_Docs\LeeSori_Profile\03_Assets\Reference\sori_sheet.png`
앱에 연결된 퍼펫:
- `D:\Work_AI\Dansori\DansoriEQ\src\DansoriEQ.App\Assets\Characters\Puppets\LeeSoriV2\rig.json`
- `D:\Work_AI\Dansori\DansoriEQ\src\DansoriEQ.App\Assets\Characters\Puppets\LeeSoriV2\Images\`
현재 `characters.json`은 이소리를 `LeeSoriV2`로 가리킨다.
- `D:\Work_AI\Dansori\DansoriEQ\src\DansoriEQ.App\Assets\Live2DHost\characters.json`
- LeeSori rig: `../Characters/Puppets/LeeSoriV2/rig.json`
- LeeSori imageBase: `../Characters/Puppets/LeeSoriV2/Images/`
현재 프레이밍은 사용자 확인으로 “비율과 위치가 정확”하다고 승인됨.
- 파일: `D:\Work_AI\Dansori\DansoriEQ\src\DansoriEQ.App\Assets\Live2DHost\style.css`
- 값:
- `right: 6.5%`
- `bottom: -65%`
- `width: 87%`
- 의도: 무릎 위와 왼손 끝 중간쯤부터 머리 위 끝까지 보이는 knee-up 프레이밍.
## 3. 현재 LeeSoriV2 Rig 상태
현재 `rig.json`에서 로드되는 bone은 다음만 남아 있다.
- `base`
- `chest`
- `upperarm_r`
- `hand_r`
- `head`
제거된 animated bone:
- `legs`
- `upperarm_l`
- `hand_l`
제거 이유:
- `legs`: 바지 양쪽 녹색 라인이 base 이미지와 animated legs 레이어에서 중복 표시되어 한 줄/두 줄로 보이는 현상이 있었다.
- `upperarm_l`, `hand_l`: 왼손은 주머니에 들어간 정적 포즈라 따로 움직이면 어색했다. 현재는 base 이미지에만 남겨 정적으로 보이게 했다.
주의:
- `Images` 폴더 안에는 이전에 생성된 `leesori_v2_legs.png`, `leesori_v2_arm_l.png`, `leesori_v2_hand_l.png` 파일이 남아 있을 수 있다.
- 하지만 `rig.json`에서 참조하지 않으면 WebView는 해당 이미지를 생성/표시하지 않는다.
- 다음 작업자는 파일 존재만 보고 활성 파츠라고 판단하지 말고 반드시 `rig.json` 기준으로 확인해야 한다.
## 4. 최근 사용자 피드백
최신 사용자 피드백:
- “비율과 위치는 정확합니다.”
- “바지라인 외곽의 녹색이 한줄/두줄 되는건 여전히 동일하게 남아있고, 자세히 보면 왼손도 약간 어색합니다.”
이에 대해 마지막으로 수행한 조치:
- accepted 프레이밍은 유지했다.
- `legs`, `upperarm_l`, `hand_l` animated bone을 제거했다.
- 움직임은 `chest`, `upperarm_r`, `hand_r`, `head` 중심으로 제한했다.
- 빌드 출력 rig에서도 제거가 반영되었음을 확인했다.
다음 세션 첫 작업은 사용자가 실행 확인 후 녹색 라인 문제가 실제로 사라졌는지 듣는 것이다. 만약 여전히 보이면, 원인은 rig 중복이 아니라 원본 이미지 자체의 바지 녹색 라인/보라색 가장자리 또는 chest/right-arm 파츠 마스크가 하체 라인 일부를 포함하는 문제일 가능성이 높다.
## 5. 검증된 빌드 상태
마지막 검증 결과:
- `dotnet build .\DansoriEQ.sln`: 성공, 경고 0, 오류 0
- `dotnet test .\DansoriEQ.sln --no-build`: 성공, 15/15 통과
- 빌드 출력 CSS에 accepted 프레이밍 값 반영 확인
- 빌드 출력 `LeeSoriV2/rig.json`에서 `legs`, `upperarm_l`, `hand_l`이 더 이상 참조되지 않음
실행 파일:
- `D:\Work_AI\Dansori\DansoriEQ\src\DansoriEQ.App\bin\Debug\net8.0-windows\DansoriEQ.App.exe`
## 6. 주요 구현 파일
WPF 통합:
- `D:\Work_AI\Dansori\DansoriEQ\src\DansoriEQ.App\MainWindow.xaml`
- `D:\Work_AI\Dansori\DansoriEQ\src\DansoriEQ.App\MainWindow.xaml.cs`
- `D:\Work_AI\Dansori\DansoriEQ\src\DansoriEQ.App\Controls\Live2DCharacterView.xaml`
- `D:\Work_AI\Dansori\DansoriEQ\src\DansoriEQ.App\Controls\Live2DCharacterView.xaml.cs`
WebView 호스트:
- `D:\Work_AI\Dansori\DansoriEQ\src\DansoriEQ.App\Assets\Live2DHost\index.html`
- `D:\Work_AI\Dansori\DansoriEQ\src\DansoriEQ.App\Assets\Live2DHost\style.css`
- `D:\Work_AI\Dansori\DansoriEQ\src\DansoriEQ.App\Assets\Live2DHost\characterHost.js`
- `D:\Work_AI\Dansori\DansoriEQ\src\DansoriEQ.App\Assets\Live2DHost\characters.json`
캐릭터 퍼펫:
- `D:\Work_AI\Dansori\DansoriEQ\src\DansoriEQ.App\Assets\Characters\Puppets\LeeSoriV2\rig.json`
- `D:\Work_AI\Dansori\DansoriEQ\src\DansoriEQ.App\Assets\Characters\Puppets\LeeSoriV2\Images\`
- `D:\Work_AI\Dansori\DansoriEQ\src\DansoriEQ.App\Assets\Characters\Live2DPreview\leesori.png`
작업 스크립트:
- `D:\Work_AI\Dansori\Characters_Build_Docs\tools\build_leesori_v2_puppet.py`
- `D:\Work_AI\Dansori\Characters_Build_Docs\tools\update_leesori_v2_framing.py`
- `D:\Work_AI\Dansori\Characters_Build_Docs\tools\fix_leesori_v2_outline_and_left_hand.py`
QA 이미지:
- `D:\Work_AI\Dansori\DansoriEQ\src\DansoriEQ.App\Assets\Characters\Puppets\LeeSoriV2\qa_source_black.png`
- `D:\Work_AI\Dansori\DansoriEQ\src\DansoriEQ.App\Assets\Characters\Puppets\LeeSoriV2\qa_view_390x600_knee_upper.png`
- `D:\Work_AI\Dansori\DansoriEQ\src\DansoriEQ.App\Assets\Characters\Puppets\LeeSoriV2\qa_view_390x600_v3_clean_outline.png`
## 7. 앱 동작 관련 이미 완료된 변경
- WebView2 Live2D placeholder host를 WPF 앱 우측 캐릭터 영역에 통합했다.
- `Live2DCharacterView`는 virtual host mapping을 사용해 로컬 assets를 로드한다.
- `characterHost.js``characters.json`을 읽고 `rig.json`의 bones를 DOM 이미지 레이어로 생성한다.
- CSS keyframes로 idle/thinking/success/error 상태 애니메이션을 적용한다.
- 캐릭터 상태는 `MainWindow.xaml.cs`에서 AI 작업 흐름에 맞춰 `idle`, `thinking`, `success`, `error`로 전환된다.
- 앱 시작 시 EQ는 비활성 상태로 시작되도록 변경했다.
- `ActiveToggle IsChecked="False"`
- `_bypassed = true`
## 8. 이전 시도와 폐기/보존 상태
기존 퍼펫 폴더:
- `LeeSori`: 초기 Canvas/FK 참고용
- `LeeSoriUpper`: 구 버전 상반신 기반. 비율은 좋았으나 손목/하체가 원본에서 잘림.
- `LeeSoriExtended`: AI로 구 버전 전신 확장. 클리핑은 해결했으나 신 버전 이소리가 아니어서 현재 사용하지 않음.
- `LeeSoriV2`: 현재 적용 중. 신 버전 sheet 기반.
중요 판단:
- 신 버전 이소리는 AI 재생성보다 `sori_sheet.png`에서 직접 정면 전신 포즈를 크롭해 쓰는 방식이 캐릭터 일관성이 가장 좋았다.
- 사용자가 승인한 비율/위치는 `LeeSoriV2 + knee-up CSS`다.
## 9. 남은 작업 우선순위
1. 사용자 실행 확인 받기
- 현재 빌드 실행 후 바지 녹색 라인 한 줄/두 줄 문제가 사라졌는지 확인해야 한다.
- 왼손이 더 자연스러워졌는지 확인해야 한다.
- 비율/위치는 이미 승인됐으므로 임의로 건드리지 말 것.
2. 녹색 외곽선 문제가 남아 있을 경우
가능 원인:
- 원본 `sori_sheet.png`의 바지 라인 주변에 이미 보라/녹색 가장자리 픽셀이 존재한다.
- `chest` 또는 `upperarm_r` 파츠 마스크가 바지 라인까지 일부 포함한다.
- base 이미지 자체 가장자리 알파 정리가 부족하다.
권장 조치:
- 먼저 `rig.json`에서 `chest`, `upperarm_r`, `hand_r`, `head`를 하나씩 임시 제거해 원인 파츠를 분리 확인한다.
- 원인 파츠가 있으면 해당 파츠 마스크를 더 좁힌다.
- 그래도 남으면 `leesori_v2_base.png`에서 바지 외곽 라인의 색상/알파를 직접 정리한다.
- 최후 수단으로 하체 라인 영역은 아예 정적 base만 쓰고 상체 레이어도 허리 위까지만 제한한다.
3. 애니메이션 품질 개선
현재는 단순 CSS transform 기반이다. 다음 개선은 다음 순서가 좋다.
- idle: 머리와 오른손만 아주 미세하게 움직이기
- thinking: 머리 기울임 + 오른손/상체 약간 움직임
- success: 과한 점프보다 고개/어깨/오른손 반응
- error: 흔들림은 작게, 얼굴/상체 위주
주의:
- 왼손과 하체는 현재 정적 유지가 자연스럽다.
- 상체 scaleY가 너무 크면 바지/허리 라인에서 이중선이 다시 생길 수 있다.
4. Haruka/Isabel/Noeul 생성
최초 목표에는 `LeeSori_Live2D`를 참고해 `Haruka_Live2D`, `Isabel_Live2D`, `Noeul_Live2D` 생성이 포함되어 있다. 아직 본격 진행하지 않았다.
권장 프로세스:
- 먼저 각 캐릭터의 authoritative sheet/reference가 있는지 확인한다.
- 없으면 ChatGPT/imagegen으로 sheet부터 만든다.
- LeeSoriV2처럼 sheet의 정면 포즈를 직접 크롭해 identity drift를 줄인다.
- 각 캐릭터별 `Puppets/<Name>V1/rig.json``Images/`를 만든다.
- `characters.json`에 puppet 정보를 추가한다.
- selector에서 캐릭터 전환 시 rig가 정상 로드되는지 확인한다.
5. 진짜 Live2D Cubism 전환
현재 방식은 “Live2D-like HTML puppet”이다. 최종 목표가 실제 Live2D라면 다음이 필요하다.
- Cubism Editor 또는 대체 rigging pipeline 결정
- PSD 수준 파츠 분리 필요
- `.model3.json`, `.moc3`, texture atlas, physics 설정 필요
- WPF에서 Cubism SDK를 직접 붙일지, WebView에서 Cubism Web SDK를 로드할지 결정
현실적인 다음 단계:
- 지금은 하이브리드 퍼펫으로 캐릭터 룩/위치/상태 애니메이션을 먼저 확정한다.
- 이후 승인된 아트와 파츠 정의를 Cubism용 PSD/파츠 명세로 정리한다.
## 10. 재개 시 권장 첫 명령
현재 상태 확인:
```powershell
Get-Content -LiteralPath 'D:\Work_AI\Dansori\DansoriEQ\src\DansoriEQ.App\Assets\Characters\Puppets\LeeSoriV2\rig.json'
Select-String -LiteralPath 'D:\Work_AI\Dansori\DansoriEQ\src\DansoriEQ.App\Assets\Live2DHost\style.css' -Pattern 'right: 6.5|bottom: -65|width: 87'
```
빌드/테스트:
```powershell
cd D:\Work_AI\Dansori\DansoriEQ
dotnet build .\DansoriEQ.sln
dotnet test .\DansoriEQ.sln --no-build
```
실행 파일:
```powershell
D:\Work_AI\Dansori\DansoriEQ\src\DansoriEQ.App\bin\Debug\net8.0-windows\DansoriEQ.App.exe
```
## 11. 작업 시 주의사항
- 사용자가 승인한 `LeeSoriV2` 프레이밍은 바꾸지 말 것. 바꿔야 한다면 반드시 이유와 QA 이미지를 먼저 제시한다.
- `LeeSoriExtended`로 되돌리지 말 것. 구 버전 이소리다.
- `sori_sheet.png`가 신 버전 authoritative source다.
- 이미지 생성 AI를 쓸 때는 identity drift가 쉽게 생기므로 원본 sheet 직접 크롭/마스크 편집을 우선한다.
- 앱 Assets 변경 후 반드시 `dotnet build`를 해서 `bin\Debug\net8.0-windows\Assets` 출력까지 갱신해야 한다.
- 사용자는 FHD 모니터 기준에서 앱을 확인하므로 창 크기와 캐릭터 영역 변경은 신중히 해야 한다.
## 12. 2026-07-04 추가 조치: V3 파일명과 WebView 캐시 차단
세션 한도가 남아 추가로 진행한 내용:
- 활성 LeeSoriV2 파츠 파일명을 `leesori_v2_v3_*`로 변경했다.
- `rig.json`은 이제 `leesori_v2_v3_base.png`, `leesori_v2_v3_chest.png`, `leesori_v2_v3_arm_r.png`, `leesori_v2_v3_hand_r.png`, `leesori_v2_v3_head.png`만 참조한다.
- `characterHost.js`에서 puppet 이미지 URL에 `?v=`를 붙여 WebView2 이미지 캐시가 이전 파츠를 보여주는 상황을 막았다.
- 승인된 프레이밍 값은 유지했다: `right: 6.5%`, `bottom: -65%`, `width: 87%`.
- 검증: `node --check` 통과, `dotnet build` 성공, `dotnet test` 15/15 통과.
다음 세션 첫 확인:
- 사용자가 새 빌드를 실행한 뒤 바지 녹색 라인의 한 줄/두 줄 반복이 사라졌는지 확인한다.
- 여전히 남으면 캐시/rig 문제가 아니라 원본 이미지의 색상 가장자리 또는 현재 움직이는 `chest`/`upperarm_r`/`hand_r` 마스크 경계 문제로 보고, 해당 파츠를 하나씩 임시 제거해 원인을 분리한다.
## 13. 2026-07-04 추가 조치: 호흡 애니메이션 축소
- 바지/허리 경계의 미세한 이중선 가능성을 줄이기 위해 `chestBreath``chestThinking`에서 `scaleY`를 제거했다.
- 상체 호흡은 `translateY(-1px)`만 사용한다.
- 오른팔 idle 회전량도 `-0.6deg` / `0.4deg`로 줄였다.
- 승인된 프레이밍 값은 그대로 유지했다.
- 검증: `dotnet build` 성공, `dotnet test` 15/15 통과.
## 14. 2026-07-04 추가 조치: LeeSoriV2 허리 자연화
- 사용자 요청으로 과도하게 잘록한 허리 실루엣만 자연스럽게 수정했다.
- 이전 소스는 `LeeSoriV2/leesori_v2_source_pre_waist_fix.png`로 보존했다.
- AI 편집 후보는 전체 교체하지 않고 복부/허리밴드 주변 패치 소스로만 사용했다. 얼굴, 머리, 손, 전체 포즈는 원본을 유지했다.
- 수정된 기준 소스: `LeeSoriV2/leesori_v2_source.png`.
- 재생성된 활성 파츠: `leesori_v2_v3_*`.
- QA: `qa_source_waist_patch_black.png`, `qa_view_390x600_v3_clean_outline.png`.
- 검증: `dotnet build` 성공, `dotnet test` 15/15 통과.
+126
View File
@@ -0,0 +1,126 @@
# IMAGE-GEN RIGGING · 악세서리 / 소품 (오버레이)
> **역할**: 캐릭터+복장 외의 모든 것. **부착점 앵커로 얹는 진짜 오버레이 레이어** — 어느 바디/헤어 조합에나 합성.
> 조립/앵커/색상 규칙: `IMAGE_GEN_RIGGING_GUIDE.md`.
## ▶ 사용 안내 (당신용)
- **📋 코드블록만** 붙여넣기. **한 블록 = 소품 1개.** 캐릭터 없이 물체만, 투명 배경, 그림자 없음, 텍스트/로고 없음.
- 각 소품의 **부착점**을 아래에 표기(합성 기준). 필요하면 각도를 바꿔 재요청.
- 네온 색은 코드 틴트 가능(가이드 §3). 기본은 Dansori 팔레트(민트 `#38E0C4` → 시안 `#4CC2FF`).
### 파일명
```
착용류 : acc_catears · acc_clubband · acc_headphones · acc_bracelet · acc_necklace · acc_sneakers · acc_heels
소품류 : acc_turntable · acc_lp_disc · acc_piano_keys · acc_mic
```
---
---
## §1. 착용 악세서리
### 1-1. 고양이귀 머리띠 — 부착점: 머리(정수리) · 저장: `acc_catears.png`
📋 붙여넣기 ↓
```
Draw ONLY a cute cat-ear headband: glossy black band with two cat ears, mint/teal (#38E0C4) neon inner-ear
accent, front view, isolated single object, no head, no character. Thin clean anime linework. Output a PNG with
a FULLY TRANSPARENT background (alpha) — no white, no shadow. Object only, no text. Avoid: text, watermark,
white background.
```
### 1-2. 클럽 형광 머리띠 — 부착점: 머리(정수리) · 저장: `acc_clubband.png`
📋 붙여넣기 ↓
```
Draw ONLY a slim club-style glowing headband with a bright neon light strip (mint-to-cyan #38E0C4 → #4CC2FF),
sleek modern rave look, front view, isolated single object, no head, no character. Thin clean anime linework.
Output a PNG with a FULLY TRANSPARENT background (alpha) — no white, no shadow. Object only, no text. Avoid:
text, watermark, white background.
```
### 1-3. 헤드폰 — 부착점: 머리(귀/정수리) · 저장: `acc_headphones.png`
📋 붙여넣기 ↓
```
Draw ONLY a pair of on-ear headphones in 이소리's style: silver/white housing, soft white ear cushions, thin
mint (#38E0C4) cable accent, sleek modern look. Front view (symmetric, as worn), isolated single object, no
head, no character. Thin clean anime linework. Output a PNG with a FULLY TRANSPARENT background (alpha) — no
white, no shadow. Object only, no text, no logo. Avoid: text, watermark, white background.
```
### 1-4. 클럽 팔찌 — 부착점: 손목 · 저장: `acc_bracelet.png`
📋 붙여넣기 ↓
```
Draw ONLY a club wrist bracelet with a glowing mint-to-cyan (#38E0C4 → #4CC2FF) neon strip, sleek sporty look,
slight 3-4 angle, isolated single object, no hand, no character. Thin clean anime linework. Output a PNG with a
FULLY TRANSPARENT background (alpha) — no white, no shadow. Object only, no text. Avoid: text, watermark, white
background.
```
### 1-5. 목걸이 — 부착점: 목선 · 저장: `acc_necklace.png`
📋 붙여넣기 ↓
```
Draw ONLY a delicate necklace: black choker with a small teal gem pendant (이소리's signature), front view as
worn, isolated single object, no neck, no character. Thin clean anime linework. Output a PNG with a FULLY
TRANSPARENT background (alpha) — no white, no shadow. Object only, no text. Avoid: text, watermark, white
background.
```
### 1-6. 운동화 — 부착점: 양 발 · 저장: `acc_sneakers.png`
📋 붙여넣기 ↓
```
Draw ONLY a pair of modern sneakers, white with mint (#38E0C4) accents, both shoes in a standing front-facing
position (as worn, feet apart), isolated single object pair, no legs, no character. Thin clean anime linework.
Output a PNG with a FULLY TRANSPARENT background (alpha) — no white, no shadow. Object only, no text. Avoid:
text, watermark, white background.
```
### 1-7. 구두 — 부착점: 양 발 · 저장: `acc_heels.png`
📋 붙여넣기 ↓
```
Draw ONLY a pair of elegant heels, black with a subtle teal accent, both shoes in a standing front-facing
position (as worn, feet apart), isolated single object pair, no legs, no character. Thin clean anime linework.
Output a PNG with a FULLY TRANSPARENT background (alpha) — no white, no shadow. Object only, no text. Avoid:
text, watermark, white background.
```
> ※ 신발 교체는 **서있는 idle 포즈(발 각도 고정)** 에서 가장 안정적으로 합성된다.
---
---
## §2. 액션 소품 (제스처는 손동작만 그려져 있으니 여기 소품을 얹어 완성)
### 2-1. 턴테이블 — DJ 손 아래 · 저장: `acc_turntable.png`
📋 붙여넣기 ↓
```
Draw ONLY a single DJ turntable deck, slight top-down 3-4 angle: dark platter with a vinyl record and a tonearm,
minimal sleek design with subtle mint/cyan neon trim, isolated single object, no hands, no character. Thin clean
anime linework. Output a PNG with a FULLY TRANSPARENT background (alpha) — no white, no shadow. Object only, no
text, no logo. Avoid: text, watermark, white background, cluttered extra gear.
```
### 2-2. LP 레코드판 — 단독 · 저장: `acc_lp_disc.png`
📋 붙여넣기 ↓
```
Draw ONLY a single vinyl LP record disc, top view (perfect circle), glossy black with a mint-to-cyan
(#38E0C4 → #4CC2FF) neon-tinted center label, subtle groove rings, isolated object, no hands, no character. Thin
clean anime linework. Output a PNG with a FULLY TRANSPARENT background (alpha) — no white, no shadow. Object
only, no text, no logo. Avoid: text, watermark, white background.
```
### 2-3. 피아노 건반 — 피아노 손 아래 · 저장: `acc_piano_keys.png`
📋 붙여넣기 ↓
```
Draw ONLY the front portion of a piano keyboard (a row of white and black keys), gentle player's 3-4 angle,
sleek minimal design with a subtle mint/cyan neon edge glow, isolated object, no hands, no character, no piano
body. Thin clean anime linework. Output a PNG with a FULLY TRANSPARENT background (alpha) — no white, no shadow.
Object only, no text, no logo. Avoid: text, watermark, white background.
```
### 2-4. 마이크 — 손에 쥠 · 저장: `acc_mic.png`
📋 붙여넣기 ↓
```
Draw ONLY a handheld microphone, sleek silver/white body with a mint-to-cyan (#38E0C4 → #4CC2FF) neon accent
ring, slight 3-4 angle, isolated single object, no hand, no character. Thin clean anime linework. Output a PNG
with a FULLY TRANSPARENT background (alpha) — no white, no shadow. Object only, no text, no logo. Avoid: text,
watermark, white background.
```
+244
View File
@@ -0,0 +1,244 @@
# IMAGE-GEN RIGGING · 바디 · 클럽룩 긴 원피스
> **역할**: 이소리 **헤드리스 바디**(목 앵커) 파츠 + 제스처 바디컷. 머리는 `IMAGE_GEN_HAIR.md`에서 합성.
> 복장 = **클럽룩 긴 원피스**(우아한 미디/플로어 길이 흰 클럽 드레스, 시크한 클럽 룩북 무드, 은은한 민트 네온 포인트).
> 조립/앵커 규칙: `IMAGE_GEN_RIGGING_GUIDE.md`. 항상 **`sori_sheet.png` 첨부**.
## ★ 규칙
- **모든 바디는 머리 없이(headless)** — 목에서 잘라 **겹침 여백**을 두고 그린다(머리는 별도 합성).
- 몸통↔팔은 **어깨 겹침 여백**, 몸통↔다리는 **허리/골반 겹침 여백**.
- 표정·헤어는 이 파일에 없음(머리 라이브러리 담당). 여기 포즈는 **몸/팔/손 배치**만.
- 액션 소품(LP·건반·마이크)은 그리지 않음 → 손동작만, 소품은 `IMAGE_GEN_ACCESSORIES.md`에서 합성.
- 투명(alpha)·흰배경 금지·그림자 금지·림라이트 금지·텍스트/로고 없음·고해상 손.
## ▶ 사용 안내 (당신용)
- **📋 코드블록만** 붙여넣기. 위→아래 순서(원하는 지점까지). **필수: §1 파츠 → §2 idle_upper** 부터.
- **헤드리스가 안 나오면**: 머리 포함으로 받아 목 위를 잘라내면 됨(머리는 어차피 따로 합성). 프롬프트의 "no head"는 유지.
- 저장 접두어: `sori_body_dressL_…`.
---
---
## §1. 헤드리스 리그 파츠
📋 붙여넣기 ↓ — **A-포즈 베이스(헤드리스) · 저장: `sori_body_dressL_apose.png`**
```
Using the attached reference sheet, draw the SAME woman 이소리's HEADLESS body in a long white club dress (elegant
midi/floor length), chic club-lookbook mood, subtle mint neon accents, GLAMOROUS adult hourglass figure
(tasteful, not revealing), in a full-body NEUTRAL A-POSE: standing straight, front view, arms slightly away from
torso, palms open forward, legs together, symmetrical. NO head — cut at the neck with a small overlap margin
(head composited separately). Thin clean anime semi-real linework matching the sheet, flat even lighting. FULLY
TRANSPARENT background PNG (alpha) — no white, no shadow, no rim light. Body only, no head, no text, high-detail
hands. Avoid: text, watermark, white background, extra fingers, deformed hands, chibi, drawing a head/face.
```
📋 붙여넣기 ↓ — **몸통 파츠 · 저장: `sori_body_dressL_torso.png`**
```
Using the attached reference sheet, output ONLY the TORSO of 이소리 in a long white club dress (elegant midi/floor
length), chic club-lookbook mood, subtle mint neon accents, glamorous hourglass upper body, NO head and NO arms, front view, cleanly isolated with
a small overlap margin at the neck and both shoulders for rigging. Thin clean anime linework matching the sheet.
FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Torso only, no text. Avoid: text, watermark,
white background, deformed anatomy.
```
📋 붙여넣기 ↓ — **오른팔 파츠 · 저장: `sori_body_dressL_arm_r.png`**
```
Using the attached reference sheet, output ONLY 이소리's RIGHT arm+hand (bare),
relaxed slightly bent, palm open, cleanly isolated with a small overlap margin at the shoulder for rigging. Thin
clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Arm only, no text. Avoid:
text, watermark, white background, extra fingers, deformed hands.
```
📋 붙여넣기 ↓ — **왼팔 파츠 · 저장: `sori_body_dressL_arm_l.png`**
```
Using the attached reference sheet, output ONLY 이소리's LEFT arm+hand (bare),
relaxed slightly bent, palm open, cleanly isolated with a small overlap margin at the shoulder for rigging. Thin
clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Arm only, no text. Avoid:
text, watermark, white background, extra fingers, deformed hands.
```
📋 붙여넣기 ↓ — **다리 파츠 · 저장: `sori_body_dressL_legs.png`**
```
Using the attached reference sheet, output ONLY 이소리's LEGS with the long dress skirt covering the legs,
standing together, plain bare feet (shoes composited separately), cleanly isolated with a small overlap margin
at the waist/hips for rigging. Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no
shadow. Legs only, no text. Avoid: text, watermark, white background, deformed anatomy.
```
---
## §2. 제스처 바디컷 (헤드리스)
> 각 블록 공통: 이소리 클럽룩 긴 원피스, 글래머러스 하워글래스, **머리 없이(목 겹침 여백)**, 투명 배경, 손 고해상, 소품 없음.
> 끄덕·갸웃·호흡·눈감기·입벙긋은 이미지 아님 → 리그(머리 회전) + 표정 프레임으로 처리(가이드 참조).
📋 붙여넣기 ↓ — **전신 idle · 저장: `sori_body_dressL_idle_full.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS full body in a long white club dress (elegant midi/floor
length), chic club-lookbook mood, subtle mint neon accents, glamorous hourglass
figure, relaxed friendly standing idle, one hand near her hip, the long dress skirt covering the legs, plain bare feet. NO head (cut at the neck with a
small overlap margin). Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow,
no rim light. Body only, no head, no text, high-detail hands. Avoid: text, watermark, white background, extra
fingers, deformed hands, drawing a head/face.
```
📋 붙여넣기 ↓ — **상반신 idle · 저장: `sori_body_dressL_idle_upper.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body (waist-up) in a long white club dress (elegant
midi/floor length), chic club-lookbook mood, subtle mint neon accents, glamorous
hourglass, relaxed friendly posture, one hand near chest. NO head (cut at the neck with a small overlap margin).
Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow, no rim light. Body
only, no head, no text, high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed
hands, drawing a head/face.
```
📋 붙여넣기 ↓ — **팔 흔들기(웨이브) · 저장: `sori_body_dressL_wave.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a long white club dress (elegant midi/floor
length), chic club-lookbook mood, subtle mint neon accents, one arm raised beside
where the head would be, open palm in a friendly WAVE, other arm relaxed. NO head (neck cut, overlap margin).
Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no
text, high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head/face.
```
📋 붙여넣기 ↓ — **손만 흔들기 · 저장: `sori_body_dressL_handwave.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a long white club dress (elegant midi/floor
length), chic club-lookbook mood, subtle mint neon accents, one hand raised to
about shoulder height with an open palm mid-wave (small friendly hand wave, elbow low), other arm relaxed. NO
head (neck cut, overlap margin). Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white,
no shadow. Body only, no head, no text, high-detail hands. Avoid: text, watermark, white background, extra
fingers, deformed hands, head/face.
```
📋 붙여넣기 ↓ — **듣는 중 · 저장: `sori_body_dressL_listen.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a long white club dress (elegant midi/floor
length), chic club-lookbook mood, subtle mint neon accents, one hand raised to
where her ear/headphone would be (as if listening intently), other arm relaxed. NO head (neck cut, overlap
margin). Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no
head, no text, high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **손끝 제시(present) · 저장: `sori_body_dressL_present.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a long white club dress (elegant midi/floor
length), chic club-lookbook mood, subtle mint neon accents, one open palm raised
and forward as if presenting sound (hand EMPTY, effects added later), other arm relaxed. NO head (neck cut,
overlap margin). Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body
only, no head, no text, high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed
hands, head.
```
📋 붙여넣기 ↓ — **디제잉(DJ, 소품 없음) · 저장: `sori_body_dressL_dj.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a long white club dress (elegant midi/floor
length), chic club-lookbook mood, subtle mint neon accents in a DJ pose WITHOUT
equipment: ONE hand reaching down flat as if scratching an invisible turntable (empty hand), the OTHER hand
raised to where the ear/headphone would be. NO head (neck cut, overlap margin), NO turntable/record/gear. Thin
clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no
text, high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head, props.
```
📋 붙여넣기 ↓ — **피아노(소품 없음) · 저장: `sori_body_dressL_piano.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a long white club dress (elegant midi/floor
length), chic club-lookbook mood, subtle mint neon accents PLAYING PIANO WITHOUT a
piano: both hands in front at waist height, fingers curved as if pressing invisible keys. NO head (neck cut,
overlap margin), NO piano/keyboard. Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no
white, no shadow. Body only, no head, no text, high-detail hands. Avoid: text, watermark, white background, extra
fingers, deformed hands, head, instrument.
```
📋 붙여넣기 ↓ — **허공 조작(control) · 저장: `sori_body_dressL_control.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a long white club dress (elegant midi/floor
length), chic club-lookbook mood, subtle mint neon accents, both hands pinching/
adjusting invisible mid-air controls (as if operating a holographic EQ, empty hands, panel added later). NO head
(neck cut, overlap margin). Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no
shadow. Body only, no head, no text, high-detail hands. Avoid: text, watermark, white background, extra fingers,
deformed hands, head.
```
📋 붙여넣기 ↓ — **엄지척(thumbs-up) · 저장: `sori_body_dressL_thumbsup.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a long white club dress (elegant midi/floor
length), chic club-lookbook mood, subtle mint neon accents, one hand giving a
clear THUMBS-UP toward the viewer, other arm relaxed. NO head (neck cut, overlap margin). Thin clean anime
linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text,
high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **손하트(finger heart) · 저장: `sori_body_dressL_heart.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a long white club dress (elegant midi/floor
length), chic club-lookbook mood, subtle mint neon accents making a small Korean
finger-heart with one hand near her chest, other arm relaxed. NO head (neck cut, overlap margin). Thin clean
anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text,
high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **박수(clap) · 저장: `sori_body_dressL_clap.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a long white club dress (elegant midi/floor
length), chic club-lookbook mood, subtle mint neon accents clapping — both hands
together in front of the chest mid-clap. NO head (neck cut, overlap margin). Thin clean anime linework. FULLY
TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail hands. Avoid:
text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **브이(peace) · 저장: `sori_body_dressL_peace.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a long white club dress (elegant midi/floor
length), chic club-lookbook mood, subtle mint neon accents making a V / peace sign
with one hand near where the cheek would be, other arm relaxed. NO head (neck cut, overlap margin). Thin clean
anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text,
high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **팔짱(arms crossed) · 저장: `sori_body_dressL_armscross.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a long white club dress (elegant midi/floor
length), chic club-lookbook mood, subtle mint neon accents with arms crossed
confidently over the chest. NO head (neck cut, overlap margin). Thin clean anime linework. FULLY TRANSPARENT
background PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail hands. Avoid: text,
watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **으쓱(shrug) · 저장: `sori_body_dressL_shrug.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a long white club dress (elegant midi/floor
length), chic club-lookbook mood, subtle mint neon accents shrugging — both hands
open at sides near shoulder height, palms up, elbows bent. NO head (neck cut, overlap margin). Thin clean anime
linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text,
high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **가리키기(point) · 저장: `sori_body_dressL_point.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a long white club dress (elegant midi/floor
length), chic club-lookbook mood, subtle mint neon accents pointing forward/upward
with one index finger (presenting), other arm relaxed. NO head (neck cut, overlap margin). Thin clean anime
linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text,
high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **환호(cheer, 성공) · 저장: `sori_body_dressL_cheer.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a long white club dress (elegant midi/floor
length), chic club-lookbook mood, subtle mint neon accents cheering — both fists
raised up in celebration. NO head (neck cut, overlap margin). Thin clean anime linework. FULLY TRANSPARENT
background PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail hands. Avoid: text,
watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **기쁨(joy, 만세) · 저장: `sori_body_dressL_joy.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS full body in a long white club dress (elegant midi/floor
length), chic club-lookbook mood, subtle mint neon accents in a joyful celebration,
both arms up and open, light on her toes. NO head (neck cut, overlap margin). Thin clean anime linework. FULLY
TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail hands. Avoid:
text, watermark, white background, extra fingers, deformed hands, head.
```
> (선택) 추가 후보: 인사(bow)·생각(턱 괴기, headless라 손만)·양손 하트·전화받기 등. 같은 형식으로 확장.
+244
View File
@@ -0,0 +1,244 @@
# IMAGE-GEN RIGGING · 바디 · 클럽룩 짧은 원피스
> **역할**: 이소리 **헤드리스 바디**(목 앵커) 파츠 + 제스처 바디컷. 머리는 `IMAGE_GEN_HAIR.md`에서 합성.
> 복장 = **클럽룩 짧은 원피스**(흰 손수건단 짧은 클럽 드레스 + 시크한 클럽 룩북 무드 + 은은한 민트 네온 포인트).
> 조립/앵커 규칙: `IMAGE_GEN_RIGGING_GUIDE.md`. 항상 **`sori_sheet.png` 첨부**.
## ★ 규칙
- **모든 바디는 머리 없이(headless)** — 목에서 잘라 **겹침 여백**을 두고 그린다(머리는 별도 합성).
- 몸통↔팔은 **어깨 겹침 여백**, 몸통↔다리는 **허리/골반 겹침 여백**.
- 표정·헤어는 이 파일에 없음(머리 라이브러리 담당). 여기 포즈는 **몸/팔/손 배치**만.
- 액션 소품(LP·건반·마이크)은 그리지 않음 → 손동작만, 소품은 `IMAGE_GEN_ACCESSORIES.md`에서 합성.
- 투명(alpha)·흰배경 금지·그림자 금지·림라이트 금지·텍스트/로고 없음·고해상 손.
## ▶ 사용 안내 (당신용)
- **📋 코드블록만** 붙여넣기. 위→아래 순서(원하는 지점까지). **필수: §1 파츠 → §2 idle_upper** 부터.
- **헤드리스가 안 나오면**: 머리 포함으로 받아 목 위를 잘라내면 됨(머리는 어차피 따로 합성). 프롬프트의 "no head"는 유지.
- 저장 접두어: `sori_body_dressS_…`.
---
---
## §1. 헤드리스 리그 파츠
📋 붙여넣기 ↓ — **A-포즈 베이스(헤드리스) · 저장: `sori_body_dressS_apose.png`**
```
Using the attached reference sheet, draw the SAME woman 이소리's HEADLESS body in a short white handkerchief-hem
club dress (asymmetric pointed skirt hem), chic club-lookbook mood, subtle mint neon accents, GLAMOROUS adult
hourglass figure (tasteful, not revealing), in a full-body NEUTRAL A-POSE: standing straight, front view, arms
slightly away from torso, palms open forward, legs together, symmetrical. NO head — cut at the neck with a small
overlap margin (head composited separately). Thin clean anime semi-real linework matching the sheet, flat even
lighting. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow, no rim light. Body only, no head, no
text, high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, chibi, drawing
a head/face.
```
📋 붙여넣기 ↓ — **몸통 파츠 · 저장: `sori_body_dressS_torso.png`**
```
Using the attached reference sheet, output ONLY the TORSO of 이소리 in a short white handkerchief-hem club dress
(asymmetric pointed skirt hem), glamorous hourglass upper body, NO head and NO arms, front view, cleanly isolated
with a small overlap margin at the neck and both shoulders for rigging. Thin clean anime linework matching the
sheet. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Torso only, no text. Avoid: text,
watermark, white background, deformed anatomy.
```
📋 붙여넣기 ↓ — **오른팔 파츠 · 저장: `sori_body_dressS_arm_r.png`**
```
Using the attached reference sheet, output ONLY 이소리's RIGHT arm+hand (bare, short dress strap/sleeve), relaxed
slightly bent, palm open, cleanly isolated with a small overlap margin at the shoulder for rigging. Thin clean
anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Arm only, no text. Avoid: text,
watermark, white background, extra fingers, deformed hands.
```
📋 붙여넣기 ↓ — **왼팔 파츠 · 저장: `sori_body_dressS_arm_l.png`**
```
Using the attached reference sheet, output ONLY 이소리's LEFT arm+hand (bare), relaxed slightly bent, palm open,
cleanly isolated with a small overlap margin at the shoulder for rigging. Thin clean anime linework. FULLY
TRANSPARENT background PNG (alpha) — no white, no shadow. Arm only, no text. Avoid: text, watermark, white
background, extra fingers, deformed hands.
```
📋 붙여넣기 ↓ — **다리 파츠 · 저장: `sori_body_dressS_legs.png`**
```
Using the attached reference sheet, output ONLY 이소리's LEGS with bare legs and the short dress hem above the
knee, standing together, plain bare feet (shoes composited separately), cleanly isolated with a small overlap
margin at the waist/hips for rigging. Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no
white, no shadow. Legs only, no text. Avoid: text, watermark, white background, deformed anatomy.
```
---
## §2. 제스처 바디컷 (헤드리스)
> 각 블록 공통: 이소리 클럽룩 짧은 원피스, 글래머러스 하워글래스, **머리 없이(목 겹침 여백)**, 투명 배경, 손 고해상, 소품 없음.
> 끄덕·갸웃·호흡·눈감기·입벙긋은 이미지 아님 → 리그(머리 회전) + 표정 프레임으로 처리(가이드 참조).
📋 붙여넣기 ↓ — **전신 idle · 저장: `sori_body_dressS_idle_full.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS full body in a short white handkerchief-hem club dress
(asymmetric pointed skirt hem), chic club-lookbook mood, subtle mint neon accents, bare legs with the short dress
hem above the knee, glamorous hourglass figure, relaxed friendly standing idle, one hand near her hip, plain bare
feet. NO head (cut at the neck with a small overlap margin). Thin clean anime linework. FULLY TRANSPARENT
background PNG (alpha) — no white, no shadow, no rim light. Body only, no head, no text, high-detail hands. Avoid:
text, watermark, white background, extra fingers, deformed hands, drawing a head/face.
```
📋 붙여넣기 ↓ — **상반신 idle · 저장: `sori_body_dressS_idle_upper.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body (waist-up) in a short white handkerchief-hem
club dress (asymmetric pointed skirt hem), chic club-lookbook mood, subtle mint neon accents, glamorous hourglass,
relaxed friendly posture, one hand near chest. NO head (cut at the neck with a small overlap margin). Thin clean
anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow, no rim light. Body only, no head,
no text, high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, drawing a
head/face.
```
📋 붙여넣기 ↓ — **팔 흔들기(웨이브) · 저장: `sori_body_dressS_wave.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a short white handkerchief-hem club dress
(asymmetric pointed skirt hem), chic club-lookbook mood, subtle mint neon accents, one arm raised beside where
the head would be, open palm in a friendly WAVE, other arm relaxed. NO head (neck cut, overlap margin). Thin clean
anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text,
high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head/face.
```
📋 붙여넣기 ↓ — **손만 흔들기 · 저장: `sori_body_dressS_handwave.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a short white handkerchief-hem club dress
(asymmetric pointed skirt hem), chic club-lookbook mood, subtle mint neon accents, one hand raised to about
shoulder height with an open palm mid-wave (small friendly hand wave, elbow low), other arm relaxed. NO head (neck
cut, overlap margin). Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow.
Body only, no head, no text, high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed
hands, head/face.
```
📋 붙여넣기 ↓ — **듣는 중 · 저장: `sori_body_dressS_listen.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a short white handkerchief-hem club dress
(asymmetric pointed skirt hem), chic club-lookbook mood, subtle mint neon accents, one hand raised to where her
ear/headphone would be (as if listening intently), other arm relaxed. NO head (neck cut, overlap margin). Thin
clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text,
high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **손끝 제시(present) · 저장: `sori_body_dressS_present.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a short white handkerchief-hem club dress
(asymmetric pointed skirt hem), chic club-lookbook mood, subtle mint neon accents, one open palm raised and
forward as if presenting sound (hand EMPTY, effects added later), other arm relaxed. NO head (neck cut, overlap
margin). Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no
head, no text, high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **디제잉(DJ, 소품 없음) · 저장: `sori_body_dressS_dj.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a short white handkerchief-hem club dress
(asymmetric pointed skirt hem), chic club-lookbook mood, subtle mint neon accents, in a DJ pose WITHOUT equipment:
ONE hand reaching down flat as if scratching an invisible turntable (empty hand), the OTHER hand raised to where
the ear/headphone would be. NO head (neck cut, overlap margin), NO turntable/record/gear. Thin clean anime
linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail
hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head, props.
```
📋 붙여넣기 ↓ — **피아노(소품 없음) · 저장: `sori_body_dressS_piano.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a short white handkerchief-hem club dress
(asymmetric pointed skirt hem), chic club-lookbook mood, subtle mint neon accents, PLAYING PIANO WITHOUT a piano:
both hands in front at waist height, fingers curved as if pressing invisible keys. NO head (neck cut, overlap
margin), NO piano/keyboard. Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no
shadow. Body only, no head, no text, high-detail hands. Avoid: text, watermark, white background, extra fingers,
deformed hands, head, instrument.
```
📋 붙여넣기 ↓ — **허공 조작(control) · 저장: `sori_body_dressS_control.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a short white handkerchief-hem club dress
(asymmetric pointed skirt hem), chic club-lookbook mood, subtle mint neon accents, both hands pinching/adjusting
invisible mid-air controls (as if operating a holographic EQ, empty hands, panel added later). NO head (neck cut,
overlap margin). Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body
only, no head, no text, high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed
hands, head.
```
📋 붙여넣기 ↓ — **엄지척(thumbs-up) · 저장: `sori_body_dressS_thumbsup.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a short white handkerchief-hem club dress
(asymmetric pointed skirt hem), chic club-lookbook mood, subtle mint neon accents, one hand giving a clear
THUMBS-UP toward the viewer, other arm relaxed. NO head (neck cut, overlap margin). Thin clean anime linework.
FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail hands.
Avoid: text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **손하트(finger heart) · 저장: `sori_body_dressS_heart.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a short white handkerchief-hem club dress
(asymmetric pointed skirt hem), chic club-lookbook mood, subtle mint neon accents, making a small Korean
finger-heart with one hand near her chest, other arm relaxed. NO head (neck cut, overlap margin). Thin clean anime
linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail
hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **박수(clap) · 저장: `sori_body_dressS_clap.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a short white handkerchief-hem club dress
(asymmetric pointed skirt hem), chic club-lookbook mood, subtle mint neon accents, clapping — both hands together
in front of the chest mid-clap. NO head (neck cut, overlap margin). Thin clean anime linework. FULLY TRANSPARENT
background PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail hands. Avoid: text,
watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **브이(peace) · 저장: `sori_body_dressS_peace.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a short white handkerchief-hem club dress
(asymmetric pointed skirt hem), chic club-lookbook mood, subtle mint neon accents, making a V / peace sign with
one hand near where the cheek would be, other arm relaxed. NO head (neck cut, overlap margin). Thin clean anime
linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail
hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **팔짱(arms crossed) · 저장: `sori_body_dressS_armscross.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a short white handkerchief-hem club dress
(asymmetric pointed skirt hem), chic club-lookbook mood, subtle mint neon accents, with arms crossed confidently
over the chest. NO head (neck cut, overlap margin). Thin clean anime linework. FULLY TRANSPARENT background PNG
(alpha) — no white, no shadow. Body only, no head, no text, high-detail hands. Avoid: text, watermark, white
background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **으쓱(shrug) · 저장: `sori_body_dressS_shrug.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a short white handkerchief-hem club dress
(asymmetric pointed skirt hem), chic club-lookbook mood, subtle mint neon accents, shrugging — both hands open at
sides near shoulder height, palms up, elbows bent. NO head (neck cut, overlap margin). Thin clean anime linework.
FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail hands.
Avoid: text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **가리키기(point) · 저장: `sori_body_dressS_point.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a short white handkerchief-hem club dress
(asymmetric pointed skirt hem), chic club-lookbook mood, subtle mint neon accents, pointing forward/upward with
one index finger (presenting), other arm relaxed. NO head (neck cut, overlap margin). Thin clean anime linework.
FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail hands.
Avoid: text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **환호(cheer, 성공) · 저장: `sori_body_dressS_cheer.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a short white handkerchief-hem club dress
(asymmetric pointed skirt hem), chic club-lookbook mood, subtle mint neon accents, cheering — both fists raised up
in celebration. NO head (neck cut, overlap margin). Thin clean anime linework. FULLY TRANSPARENT background PNG
(alpha) — no white, no shadow. Body only, no head, no text, high-detail hands. Avoid: text, watermark, white
background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **기쁨(joy, 만세) · 저장: `sori_body_dressS_joy.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS full body in a short white handkerchief-hem club dress
(asymmetric pointed skirt hem), chic club-lookbook mood, subtle mint neon accents, in a joyful celebration, both
arms up and open, light on her toes. NO head (neck cut, overlap margin). Thin clean anime linework. FULLY
TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail hands. Avoid:
text, watermark, white background, extra fingers, deformed hands, head.
```
> (선택) 추가 후보: 인사(bow)·생각(턱 괴기, headless라 손만)·양손 하트·전화받기 등. 같은 형식으로 확장.
+244
View File
@@ -0,0 +1,244 @@
# IMAGE-GEN RIGGING · 바디 · 청바지
> **역할**: 이소리 **헤드리스 바디**(목 앵커) 파츠 + 제스처 바디컷. 머리는 `IMAGE_GEN_HAIR.md`에서 합성.
> 복장 = **청바지**(스키니 블루 데님 진 + 흰 크롭 티셔츠, 캐주얼시크, 은은한 민트 네온 포인트).
> 조립/앵커 규칙: `IMAGE_GEN_RIGGING_GUIDE.md`. 항상 **`sori_sheet.png` 첨부**.
## ★ 규칙
- **모든 바디는 머리 없이(headless)** — 목에서 잘라 **겹침 여백**을 두고 그린다(머리는 별도 합성).
- 몸통↔팔은 **어깨 겹침 여백**, 몸통↔다리는 **허리/골반 겹침 여백**.
- 표정·헤어는 이 파일에 없음(머리 라이브러리 담당). 여기 포즈는 **몸/팔/손 배치**만.
- 액션 소품(LP·건반·마이크)은 그리지 않음 → 손동작만, 소품은 `IMAGE_GEN_ACCESSORIES.md`에서 합성.
- 투명(alpha)·흰배경 금지·그림자 금지·림라이트 금지·텍스트/로고 없음·고해상 손.
## ▶ 사용 안내 (당신용)
- **📋 코드블록만** 붙여넣기. 위→아래 순서(원하는 지점까지). **필수: §1 파츠 → §2 idle_upper** 부터.
- **헤드리스가 안 나오면**: 머리 포함으로 받아 목 위를 잘라내면 됨(머리는 어차피 따로 합성). 프롬프트의 "no head"는 유지.
- 저장 접두어: `sori_body_jeans_…`.
---
---
## §1. 헤드리스 리그 파츠
📋 붙여넣기 ↓ — **A-포즈 베이스(헤드리스) · 저장: `sori_body_jeans_apose.png`**
```
Using the attached reference sheet, draw the SAME woman 이소리's HEADLESS body in skinny blue denim jeans + a
white cropped T-shirt, casual-chic look, subtle mint neon accents, GLAMOROUS adult hourglass figure
(tasteful, not revealing), in a full-body NEUTRAL A-POSE: standing straight, front view, arms slightly away from
torso, palms open forward, legs together, symmetrical. NO head — cut at the neck with a small overlap margin
(head composited separately). Thin clean anime semi-real linework matching the sheet, flat even lighting. FULLY
TRANSPARENT background PNG (alpha) — no white, no shadow, no rim light. Body only, no head, no text, high-detail
hands. Avoid: text, watermark, white background, extra fingers, deformed hands, chibi, drawing a head/face.
```
📋 붙여넣기 ↓ — **몸통 파츠 · 저장: `sori_body_jeans_torso.png`**
```
Using the attached reference sheet, output ONLY the TORSO of 이소리 in skinny blue denim jeans + a white cropped
T-shirt, casual-chic look, subtle mint neon accents, glamorous hourglass upper body, NO head and NO arms, front view, cleanly isolated with
a small overlap margin at the neck and both shoulders for rigging. Thin clean anime linework matching the sheet.
FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Torso only, no text. Avoid: text, watermark,
white background, deformed anatomy.
```
📋 붙여넣기 ↓ — **오른팔 파츠 · 저장: `sori_body_jeans_arm_r.png`**
```
Using the attached reference sheet, output ONLY 이소리's RIGHT arm+hand with the short white T-shirt sleeve,
relaxed slightly bent, palm open, cleanly isolated with a small overlap margin at the shoulder for rigging. Thin
clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Arm only, no text. Avoid:
text, watermark, white background, extra fingers, deformed hands.
```
📋 붙여넣기 ↓ — **왼팔 파츠 · 저장: `sori_body_jeans_arm_l.png`**
```
Using the attached reference sheet, output ONLY 이소리's LEFT arm+hand with the short white T-shirt sleeve,
relaxed slightly bent, palm open, cleanly isolated with a small overlap margin at the shoulder for rigging. Thin
clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Arm only, no text. Avoid:
text, watermark, white background, extra fingers, deformed hands.
```
📋 붙여넣기 ↓ — **다리 파츠 · 저장: `sori_body_jeans_legs.png`**
```
Using the attached reference sheet, output ONLY 이소리's LEGS in skinny blue denim jeans,
standing together, plain bare feet (shoes composited separately), cleanly isolated with a small overlap margin
at the waist/hips for rigging. Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no
shadow. Legs only, no text. Avoid: text, watermark, white background, deformed anatomy.
```
---
## §2. 제스처 바디컷 (헤드리스)
> 각 블록 공통: 이소리 청바지, 글래머러스 하워글래스, **머리 없이(목 겹침 여백)**, 투명 배경, 손 고해상, 소품 없음.
> 끄덕·갸웃·호흡·눈감기·입벙긋은 이미지 아님 → 리그(머리 회전) + 표정 프레임으로 처리(가이드 참조).
📋 붙여넣기 ↓ — **전신 idle · 저장: `sori_body_jeans_idle_full.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS full body in skinny blue denim jeans + a white cropped
T-shirt, casual-chic look, subtle mint neon accents, glamorous hourglass
figure, relaxed friendly standing idle, one hand near her hip, plain bare feet. NO head (cut at the neck with a
small overlap margin). Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow,
no rim light. Body only, no head, no text, high-detail hands. Avoid: text, watermark, white background, extra
fingers, deformed hands, drawing a head/face.
```
📋 붙여넣기 ↓ — **상반신 idle · 저장: `sori_body_jeans_idle_upper.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body (waist-up) in skinny blue denim jeans + a
white cropped T-shirt, casual-chic look, subtle mint neon accents, glamorous
hourglass, relaxed friendly posture, one hand near chest. NO head (cut at the neck with a small overlap margin).
Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow, no rim light. Body
only, no head, no text, high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed
hands, drawing a head/face.
```
📋 붙여넣기 ↓ — **팔 흔들기(웨이브) · 저장: `sori_body_jeans_wave.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in skinny blue denim jeans + a white cropped
T-shirt, casual-chic look, subtle mint neon accents, one arm raised beside
where the head would be, open palm in a friendly WAVE, other arm relaxed. NO head (neck cut, overlap margin).
Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no
text, high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head/face.
```
📋 붙여넣기 ↓ — **손만 흔들기 · 저장: `sori_body_jeans_handwave.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in skinny blue denim jeans + a white cropped
T-shirt, casual-chic look, subtle mint neon accents, one hand raised to
about shoulder height with an open palm mid-wave (small friendly hand wave, elbow low), other arm relaxed. NO
head (neck cut, overlap margin). Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white,
no shadow. Body only, no head, no text, high-detail hands. Avoid: text, watermark, white background, extra
fingers, deformed hands, head/face.
```
📋 붙여넣기 ↓ — **듣는 중 · 저장: `sori_body_jeans_listen.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in skinny blue denim jeans + a white cropped
T-shirt, casual-chic look, subtle mint neon accents, one hand raised to
where her ear/headphone would be (as if listening intently), other arm relaxed. NO head (neck cut, overlap
margin). Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no
head, no text, high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **손끝 제시(present) · 저장: `sori_body_jeans_present.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in skinny blue denim jeans + a white cropped
T-shirt, casual-chic look, subtle mint neon accents, one open palm raised
and forward as if presenting sound (hand EMPTY, effects added later), other arm relaxed. NO head (neck cut,
overlap margin). Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body
only, no head, no text, high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed
hands, head.
```
📋 붙여넣기 ↓ — **디제잉(DJ, 소품 없음) · 저장: `sori_body_jeans_dj.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in skinny blue denim jeans + a white cropped
T-shirt, casual-chic look, subtle mint neon accents in a DJ pose WITHOUT
equipment: ONE hand reaching down flat as if scratching an invisible turntable (empty hand), the OTHER hand
raised to where the ear/headphone would be. NO head (neck cut, overlap margin), NO turntable/record/gear. Thin
clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no
text, high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head, props.
```
📋 붙여넣기 ↓ — **피아노(소품 없음) · 저장: `sori_body_jeans_piano.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in skinny blue denim jeans + a white cropped
T-shirt, casual-chic look, subtle mint neon accents PLAYING PIANO WITHOUT a
piano: both hands in front at waist height, fingers curved as if pressing invisible keys. NO head (neck cut,
overlap margin), NO piano/keyboard. Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no
white, no shadow. Body only, no head, no text, high-detail hands. Avoid: text, watermark, white background, extra
fingers, deformed hands, head, instrument.
```
📋 붙여넣기 ↓ — **허공 조작(control) · 저장: `sori_body_jeans_control.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in skinny blue denim jeans + a white cropped
T-shirt, casual-chic look, subtle mint neon accents, both hands pinching/
adjusting invisible mid-air controls (as if operating a holographic EQ, empty hands, panel added later). NO head
(neck cut, overlap margin). Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no
shadow. Body only, no head, no text, high-detail hands. Avoid: text, watermark, white background, extra fingers,
deformed hands, head.
```
📋 붙여넣기 ↓ — **엄지척(thumbs-up) · 저장: `sori_body_jeans_thumbsup.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in skinny blue denim jeans + a white cropped
T-shirt, casual-chic look, subtle mint neon accents, one hand giving a
clear THUMBS-UP toward the viewer, other arm relaxed. NO head (neck cut, overlap margin). Thin clean anime
linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text,
high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **손하트(finger heart) · 저장: `sori_body_jeans_heart.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in skinny blue denim jeans + a white cropped
T-shirt, casual-chic look, subtle mint neon accents making a small Korean
finger-heart with one hand near her chest, other arm relaxed. NO head (neck cut, overlap margin). Thin clean
anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text,
high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **박수(clap) · 저장: `sori_body_jeans_clap.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in skinny blue denim jeans + a white cropped
T-shirt, casual-chic look, subtle mint neon accents clapping — both hands
together in front of the chest mid-clap. NO head (neck cut, overlap margin). Thin clean anime linework. FULLY
TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail hands. Avoid:
text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **브이(peace) · 저장: `sori_body_jeans_peace.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in skinny blue denim jeans + a white cropped
T-shirt, casual-chic look, subtle mint neon accents making a V / peace sign
with one hand near where the cheek would be, other arm relaxed. NO head (neck cut, overlap margin). Thin clean
anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text,
high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **팔짱(arms crossed) · 저장: `sori_body_jeans_armscross.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in skinny blue denim jeans + a white cropped
T-shirt, casual-chic look, subtle mint neon accents with arms crossed
confidently over the chest. NO head (neck cut, overlap margin). Thin clean anime linework. FULLY TRANSPARENT
background PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail hands. Avoid: text,
watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **으쓱(shrug) · 저장: `sori_body_jeans_shrug.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in skinny blue denim jeans + a white cropped
T-shirt, casual-chic look, subtle mint neon accents shrugging — both hands
open at sides near shoulder height, palms up, elbows bent. NO head (neck cut, overlap margin). Thin clean anime
linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text,
high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **가리키기(point) · 저장: `sori_body_jeans_point.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in skinny blue denim jeans + a white cropped
T-shirt, casual-chic look, subtle mint neon accents pointing forward/upward
with one index finger (presenting), other arm relaxed. NO head (neck cut, overlap margin). Thin clean anime
linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text,
high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **환호(cheer, 성공) · 저장: `sori_body_jeans_cheer.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in skinny blue denim jeans + a white cropped
T-shirt, casual-chic look, subtle mint neon accents cheering — both fists
raised up in celebration. NO head (neck cut, overlap margin). Thin clean anime linework. FULLY TRANSPARENT
background PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail hands. Avoid: text,
watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **기쁨(joy, 만세) · 저장: `sori_body_jeans_joy.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS full body in skinny blue denim jeans + a white cropped
T-shirt, casual-chic look, subtle mint neon accents in a joyful celebration,
both arms up and open, light on her toes. NO head (neck cut, overlap margin). Thin clean anime linework. FULLY
TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail hands. Avoid:
text, watermark, white background, extra fingers, deformed hands, head.
```
> (선택) 추가 후보: 인사(bow)·생각(턱 괴기, headless라 손만)·양손 하트·전화받기 등. 같은 형식으로 확장.
+226
View File
@@ -0,0 +1,226 @@
# IMAGE-GEN RIGGING · 바디 · 트랙슈트 (기준본)
> **역할**: 이소리 **헤드리스 바디**(목 앵커) 파츠 + 제스처 바디컷. 머리는 `IMAGE_GEN_HAIR.md`에서 합성.
> 복장 = **트랙슈트**(흰 크롭 후디 + 민트/블랙 트랙 재킷 + 민트 사이드라인 블랙 트랙팬츠).
> 조립/앵커 규칙: `IMAGE_GEN_RIGGING_GUIDE.md`. 항상 **`sori_sheet.png` 첨부**.
## ★ 규칙
- **모든 바디는 머리 없이(headless)** — 목에서 잘라 **겹침 여백**을 두고 그린다(머리는 별도 합성).
- 몸통↔팔은 **어깨 겹침 여백**, 몸통↔다리는 **허리/골반 겹침 여백**.
- 표정·헤어는 이 파일에 없음(머리 라이브러리 담당). 여기 포즈는 **몸/팔/손 배치**만.
- 액션 소품(LP·건반·마이크)은 그리지 않음 → 손동작만, 소품은 `IMAGE_GEN_ACCESSORIES.md`에서 합성.
- 투명(alpha)·흰배경 금지·그림자 금지·림라이트 금지·텍스트/로고 없음·고해상 손.
## ▶ 사용 안내 (당신용)
- **📋 코드블록만** 붙여넣기. 위→아래 순서(원하는 지점까지). **필수: §1 파츠 → §2 idle_upper** 부터.
- **헤드리스가 안 나오면**: 머리 포함으로 받아 목 위를 잘라내면 됨(머리는 어차피 따로 합성). 프롬프트의 "no head"는 유지.
- 저장 접두어: `sori_body_track_…`.
---
---
## §1. 헤드리스 리그 파츠
📋 붙여넣기 ↓ — **A-포즈 베이스(헤드리스) · 저장: `sori_body_track_apose.png`**
```
Using the attached reference sheet, draw the SAME woman 이소리's HEADLESS body in her track outfit (white cropped
hoodie + mint/black track jacket + black track pants with mint side stripe), GLAMOROUS adult hourglass figure
(tasteful, not revealing), in a full-body NEUTRAL A-POSE: standing straight, front view, arms slightly away from
torso, palms open forward, legs together, symmetrical. NO head — cut at the neck with a small overlap margin
(head composited separately). Thin clean anime semi-real linework matching the sheet, flat even lighting. FULLY
TRANSPARENT background PNG (alpha) — no white, no shadow, no rim light. Body only, no head, no text, high-detail
hands. Avoid: text, watermark, white background, extra fingers, deformed hands, chibi, drawing a head/face.
```
📋 붙여넣기 ↓ — **몸통 파츠 · 저장: `sori_body_track_torso.png`**
```
Using the attached reference sheet, output ONLY the TORSO of 이소리 in her track outfit (white cropped hoodie +
mint/black track jacket), glamorous hourglass upper body, NO head and NO arms, front view, cleanly isolated with
a small overlap margin at the neck and both shoulders for rigging. Thin clean anime linework matching the sheet.
FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Torso only, no text. Avoid: text, watermark,
white background, deformed anatomy.
```
📋 붙여넣기 ↓ — **오른팔 파츠 · 저장: `sori_body_track_arm_r.png`**
```
Using the attached reference sheet, output ONLY 이소리's RIGHT arm+hand with the mint/black track-jacket sleeve,
relaxed slightly bent, palm open, cleanly isolated with a small overlap margin at the shoulder for rigging. Thin
clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Arm only, no text. Avoid:
text, watermark, white background, extra fingers, deformed hands.
```
📋 붙여넣기 ↓ — **왼팔 파츠 · 저장: `sori_body_track_arm_l.png`**
```
Using the attached reference sheet, output ONLY 이소리's LEFT arm+hand with the mint/black track-jacket sleeve,
relaxed slightly bent, palm open, cleanly isolated with a small overlap margin at the shoulder for rigging. Thin
clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Arm only, no text. Avoid:
text, watermark, white background, extra fingers, deformed hands.
```
📋 붙여넣기 ↓ — **다리 파츠 · 저장: `sori_body_track_legs.png`**
```
Using the attached reference sheet, output ONLY 이소리's LEGS in black track pants with a mint side stripe,
standing together, plain bare feet (shoes composited separately), cleanly isolated with a small overlap margin
at the waist/hips for rigging. Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no
shadow. Legs only, no text. Avoid: text, watermark, white background, deformed anatomy.
```
---
## §2. 제스처 바디컷 (헤드리스)
> 각 블록 공통: 이소리 트랙슈트, 글래머러스 하워글래스, **머리 없이(목 겹침 여백)**, 투명 배경, 손 고해상, 소품 없음.
> 끄덕·갸웃·호흡·눈감기·입벙긋은 이미지 아님 → 리그(머리 회전) + 표정 프레임으로 처리(가이드 참조).
📋 붙여넣기 ↓ — **전신 idle · 저장: `sori_body_track_idle_full.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS full body in her track outfit, glamorous hourglass
figure, relaxed friendly standing idle, one hand near her hip, plain bare feet. NO head (cut at the neck with a
small overlap margin). Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow,
no rim light. Body only, no head, no text, high-detail hands. Avoid: text, watermark, white background, extra
fingers, deformed hands, drawing a head/face.
```
📋 붙여넣기 ↓ — **상반신 idle · 저장: `sori_body_track_idle_upper.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body (waist-up) in her track outfit, glamorous
hourglass, relaxed friendly posture, one hand near chest. NO head (cut at the neck with a small overlap margin).
Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow, no rim light. Body
only, no head, no text, high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed
hands, drawing a head/face.
```
📋 붙여넣기 ↓ — **팔 흔들기(웨이브) · 저장: `sori_body_track_wave.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in her track outfit, one arm raised beside
where the head would be, open palm in a friendly WAVE, other arm relaxed. NO head (neck cut, overlap margin).
Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no
text, high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head/face.
```
📋 붙여넣기 ↓ — **손만 흔들기 · 저장: `sori_body_track_handwave.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in her track outfit, one hand raised to
about shoulder height with an open palm mid-wave (small friendly hand wave, elbow low), other arm relaxed. NO
head (neck cut, overlap margin). Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white,
no shadow. Body only, no head, no text, high-detail hands. Avoid: text, watermark, white background, extra
fingers, deformed hands, head/face.
```
📋 붙여넣기 ↓ — **듣는 중 · 저장: `sori_body_track_listen.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in her track outfit, one hand raised to
where her ear/headphone would be (as if listening intently), other arm relaxed. NO head (neck cut, overlap
margin). Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no
head, no text, high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **손끝 제시(present) · 저장: `sori_body_track_present.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in her track outfit, one open palm raised
and forward as if presenting sound (hand EMPTY, effects added later), other arm relaxed. NO head (neck cut,
overlap margin). Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body
only, no head, no text, high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed
hands, head.
```
📋 붙여넣기 ↓ — **디제잉(DJ, 소품 없음) · 저장: `sori_body_track_dj.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in her track outfit in a DJ pose WITHOUT
equipment: ONE hand reaching down flat as if scratching an invisible turntable (empty hand), the OTHER hand
raised to where the ear/headphone would be. NO head (neck cut, overlap margin), NO turntable/record/gear. Thin
clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no
text, high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head, props.
```
📋 붙여넣기 ↓ — **피아노(소품 없음) · 저장: `sori_body_track_piano.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in her track outfit PLAYING PIANO WITHOUT a
piano: both hands in front at waist height, fingers curved as if pressing invisible keys. NO head (neck cut,
overlap margin), NO piano/keyboard. Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no
white, no shadow. Body only, no head, no text, high-detail hands. Avoid: text, watermark, white background, extra
fingers, deformed hands, head, instrument.
```
📋 붙여넣기 ↓ — **허공 조작(control) · 저장: `sori_body_track_control.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in her track outfit, both hands pinching/
adjusting invisible mid-air controls (as if operating a holographic EQ, empty hands, panel added later). NO head
(neck cut, overlap margin). Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no
shadow. Body only, no head, no text, high-detail hands. Avoid: text, watermark, white background, extra fingers,
deformed hands, head.
```
📋 붙여넣기 ↓ — **엄지척(thumbs-up) · 저장: `sori_body_track_thumbsup.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in her track outfit, one hand giving a
clear THUMBS-UP toward the viewer, other arm relaxed. NO head (neck cut, overlap margin). Thin clean anime
linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text,
high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **손하트(finger heart) · 저장: `sori_body_track_heart.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in her track outfit making a small Korean
finger-heart with one hand near her chest, other arm relaxed. NO head (neck cut, overlap margin). Thin clean
anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text,
high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **박수(clap) · 저장: `sori_body_track_clap.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in her track outfit clapping — both hands
together in front of the chest mid-clap. NO head (neck cut, overlap margin). Thin clean anime linework. FULLY
TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail hands. Avoid:
text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **브이(peace) · 저장: `sori_body_track_peace.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in her track outfit making a V / peace sign
with one hand near where the cheek would be, other arm relaxed. NO head (neck cut, overlap margin). Thin clean
anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text,
high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **팔짱(arms crossed) · 저장: `sori_body_track_armscross.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in her track outfit with arms crossed
confidently over the chest. NO head (neck cut, overlap margin). Thin clean anime linework. FULLY TRANSPARENT
background PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail hands. Avoid: text,
watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **으쓱(shrug) · 저장: `sori_body_track_shrug.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in her track outfit shrugging — both hands
open at sides near shoulder height, palms up, elbows bent. NO head (neck cut, overlap margin). Thin clean anime
linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text,
high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **가리키기(point) · 저장: `sori_body_track_point.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in her track outfit pointing forward/upward
with one index finger (presenting), other arm relaxed. NO head (neck cut, overlap margin). Thin clean anime
linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text,
high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **환호(cheer, 성공) · 저장: `sori_body_track_cheer.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in her track outfit cheering — both fists
raised up in celebration. NO head (neck cut, overlap margin). Thin clean anime linework. FULLY TRANSPARENT
background PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail hands. Avoid: text,
watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **기쁨(joy, 만세) · 저장: `sori_body_track_joy.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS full body in her track outfit in a joyful celebration,
both arms up and open, light on her toes. NO head (neck cut, overlap margin). Thin clean anime linework. FULLY
TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail hands. Avoid:
text, watermark, white background, extra fingers, deformed hands, head.
```
> (선택) 추가 후보: 인사(bow)·생각(턱 괴기, headless라 손만)·양손 하트·전화받기 등. 같은 형식으로 확장.
+241
View File
@@ -0,0 +1,241 @@
# IMAGE-GEN RIGGING · 바디 · 티셔츠(캐주얼)
> **역할**: 이소리 **헤드리스 바디**(목 앵커) 파츠 + 제스처 바디컷. 머리는 `IMAGE_GEN_HAIR.md`에서 합성.
> 복장 = **티셔츠(캐주얼)**(편안한 캐주얼 흰 티셔츠 + 심플 블랙 반바지, 은은한 민트 네온 포인트).
> 조립/앵커 규칙: `IMAGE_GEN_RIGGING_GUIDE.md`. 항상 **`sori_sheet.png` 첨부**.
## ★ 규칙
- **모든 바디는 머리 없이(headless)** — 목에서 잘라 **겹침 여백**을 두고 그린다(머리는 별도 합성).
- 몸통↔팔은 **어깨 겹침 여백**, 몸통↔다리는 **허리/골반 겹침 여백**.
- 표정·헤어는 이 파일에 없음(머리 라이브러리 담당). 여기 포즈는 **몸/팔/손 배치**만.
- 액션 소품(LP·건반·마이크)은 그리지 않음 → 손동작만, 소품은 `IMAGE_GEN_ACCESSORIES.md`에서 합성.
- 투명(alpha)·흰배경 금지·그림자 금지·림라이트 금지·텍스트/로고 없음·고해상 손.
## ▶ 사용 안내 (당신용)
- **📋 코드블록만** 붙여넣기. 위→아래 순서(원하는 지점까지). **필수: §1 파츠 → §2 idle_upper** 부터.
- **헤드리스가 안 나오면**: 머리 포함으로 받아 목 위를 잘라내면 됨(머리는 어차피 따로 합성). 프롬프트의 "no head"는 유지.
- 저장 접두어: `sori_body_tee_…`.
---
---
## §1. 헤드리스 리그 파츠
📋 붙여넣기 ↓ — **A-포즈 베이스(헤드리스) · 저장: `sori_body_tee_apose.png`**
```
Using the attached reference sheet, draw the SAME woman 이소리's HEADLESS body in a relaxed casual white T-shirt
with simple black shorts, everyday casual look, subtle mint neon accents, GLAMOROUS adult hourglass figure
(tasteful, not revealing), in a full-body NEUTRAL A-POSE: standing straight, front view, arms slightly away from
torso, palms open forward, legs together, symmetrical. NO head — cut at the neck with a small overlap margin
(head composited separately). Thin clean anime semi-real linework matching the sheet, flat even lighting. FULLY
TRANSPARENT background PNG (alpha) — no white, no shadow, no rim light. Body only, no head, no text, high-detail
hands. Avoid: text, watermark, white background, extra fingers, deformed hands, chibi, drawing a head/face.
```
📋 붙여넣기 ↓ — **몸통 파츠 · 저장: `sori_body_tee_torso.png`**
```
Using the attached reference sheet, output ONLY the TORSO of 이소리 in a relaxed casual white T-shirt, everyday
casual look, subtle mint neon accents, glamorous hourglass upper body, NO head and NO arms, front view, cleanly
isolated with a small overlap margin at the neck and both shoulders for rigging. Thin clean anime linework
matching the sheet. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Torso only, no text. Avoid:
text, watermark, white background, deformed anatomy.
```
📋 붙여넣기 ↓ — **오른팔 파츠 · 저장: `sori_body_tee_arm_r.png`**
```
Using the attached reference sheet, output ONLY 이소리's RIGHT arm+hand with a short white T-shirt sleeve (arm
bare below the short sleeve), relaxed slightly bent, palm open, cleanly isolated with a small overlap margin at
the shoulder for rigging. Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no
shadow. Arm only, no text. Avoid: text, watermark, white background, extra fingers, deformed hands.
```
📋 붙여넣기 ↓ — **왼팔 파츠 · 저장: `sori_body_tee_arm_l.png`**
```
Using the attached reference sheet, output ONLY 이소리's LEFT arm+hand with a short white T-shirt sleeve (arm
bare below the short sleeve), relaxed slightly bent, palm open, cleanly isolated with a small overlap margin at
the shoulder for rigging. Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no
shadow. Arm only, no text. Avoid: text, watermark, white background, extra fingers, deformed hands.
```
📋 붙여넣기 ↓ — **다리 파츠 · 저장: `sori_body_tee_legs.png`**
```
Using the attached reference sheet, output ONLY 이소리's bare legs with simple black shorts,
standing together, plain bare feet (shoes composited separately), cleanly isolated with a small overlap margin
at the waist/hips for rigging. Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no
shadow. Legs only, no text. Avoid: text, watermark, white background, deformed anatomy.
```
---
## §2. 제스처 바디컷 (헤드리스)
> 각 블록 공통: 이소리 티셔츠(캐주얼), 글래머러스 하워글래스, **머리 없이(목 겹침 여백)**, 투명 배경, 손 고해상, 소품 없음.
> 끄덕·갸웃·호흡·눈감기·입벙긋은 이미지 아님 → 리그(머리 회전) + 표정 프레임으로 처리(가이드 참조).
📋 붙여넣기 ↓ — **전신 idle · 저장: `sori_body_tee_idle_full.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS full body in a relaxed casual white T-shirt with simple
black shorts, everyday casual look, subtle mint neon accents, glamorous hourglass figure, relaxed friendly
standing idle, one hand near her hip, bare legs with simple black shorts, plain bare feet. NO head (cut at the
neck with a small overlap margin). Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white,
no shadow, no rim light. Body only, no head, no text, high-detail hands. Avoid: text, watermark, white background,
extra fingers, deformed hands, drawing a head/face.
```
📋 붙여넣기 ↓ — **상반신 idle · 저장: `sori_body_tee_idle_upper.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body (waist-up) in a relaxed casual white T-shirt
with simple black shorts, everyday casual look, subtle mint neon accents, glamorous hourglass, relaxed friendly
posture, one hand near chest. NO head (cut at the neck with a small overlap margin). Thin clean anime linework.
FULLY TRANSPARENT background PNG (alpha) — no white, no shadow, no rim light. Body only, no head, no text,
high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, drawing a head/face.
```
📋 붙여넣기 ↓ — **팔 흔들기(웨이브) · 저장: `sori_body_tee_wave.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a relaxed casual white T-shirt with
simple black shorts, everyday casual look, subtle mint neon accents, one arm raised beside where the head would
be, open palm in a friendly WAVE, other arm relaxed. NO head (neck cut, overlap margin). Thin clean anime
linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail
hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head/face.
```
📋 붙여넣기 ↓ — **손만 흔들기 · 저장: `sori_body_tee_handwave.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a relaxed casual white T-shirt with
simple black shorts, everyday casual look, subtle mint neon accents, one hand raised to about shoulder height
with an open palm mid-wave (small friendly hand wave, elbow low), other arm relaxed. NO head (neck cut, overlap
margin). Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no
head, no text, high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands,
head/face.
```
📋 붙여넣기 ↓ — **듣는 중 · 저장: `sori_body_tee_listen.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a relaxed casual white T-shirt with
simple black shorts, everyday casual look, subtle mint neon accents, one hand raised to where her ear/headphone
would be (as if listening intently), other arm relaxed. NO head (neck cut, overlap margin). Thin clean anime
linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail
hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **손끝 제시(present) · 저장: `sori_body_tee_present.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a relaxed casual white T-shirt with
simple black shorts, everyday casual look, subtle mint neon accents, one open palm raised and forward as if
presenting sound (hand EMPTY, effects added later), other arm relaxed. NO head (neck cut, overlap margin). Thin
clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text,
high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **디제잉(DJ, 소품 없음) · 저장: `sori_body_tee_dj.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a relaxed casual white T-shirt with
simple black shorts, everyday casual look, subtle mint neon accents, in a DJ pose WITHOUT equipment: ONE hand
reaching down flat as if scratching an invisible turntable (empty hand), the OTHER hand raised to where the
ear/headphone would be. NO head (neck cut, overlap margin), NO turntable/record/gear. Thin clean anime linework.
FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail hands.
Avoid: text, watermark, white background, extra fingers, deformed hands, head, props.
```
📋 붙여넣기 ↓ — **피아노(소품 없음) · 저장: `sori_body_tee_piano.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a relaxed casual white T-shirt with
simple black shorts, everyday casual look, subtle mint neon accents, PLAYING PIANO WITHOUT a piano: both hands
in front at waist height, fingers curved as if pressing invisible keys. NO head (neck cut, overlap margin), NO
piano/keyboard. Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body
only, no head, no text, high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed
hands, head, instrument.
```
📋 붙여넣기 ↓ — **허공 조작(control) · 저장: `sori_body_tee_control.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a relaxed casual white T-shirt with
simple black shorts, everyday casual look, subtle mint neon accents, both hands pinching/adjusting invisible
mid-air controls (as if operating a holographic EQ, empty hands, panel added later). NO head (neck cut, overlap
margin). Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no
head, no text, high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **엄지척(thumbs-up) · 저장: `sori_body_tee_thumbsup.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a relaxed casual white T-shirt with
simple black shorts, everyday casual look, subtle mint neon accents, one hand giving a clear THUMBS-UP toward the
viewer, other arm relaxed. NO head (neck cut, overlap margin). Thin clean anime linework. FULLY TRANSPARENT
background PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail hands. Avoid: text,
watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **손하트(finger heart) · 저장: `sori_body_tee_heart.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a relaxed casual white T-shirt with
simple black shorts, everyday casual look, subtle mint neon accents, making a small Korean finger-heart with one
hand near her chest, other arm relaxed. NO head (neck cut, overlap margin). Thin clean anime linework. FULLY
TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail hands. Avoid:
text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **박수(clap) · 저장: `sori_body_tee_clap.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a relaxed casual white T-shirt with
simple black shorts, everyday casual look, subtle mint neon accents, clapping — both hands together in front of
the chest mid-clap. NO head (neck cut, overlap margin). Thin clean anime linework. FULLY TRANSPARENT background
PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail hands. Avoid: text, watermark, white
background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **브이(peace) · 저장: `sori_body_tee_peace.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a relaxed casual white T-shirt with
simple black shorts, everyday casual look, subtle mint neon accents, making a V / peace sign with one hand near
where the cheek would be, other arm relaxed. NO head (neck cut, overlap margin). Thin clean anime linework. FULLY
TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail hands. Avoid:
text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **팔짱(arms crossed) · 저장: `sori_body_tee_armscross.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a relaxed casual white T-shirt with
simple black shorts, everyday casual look, subtle mint neon accents, with arms crossed confidently over the
chest. NO head (neck cut, overlap margin). Thin clean anime linework. FULLY TRANSPARENT background PNG (alpha) —
no white, no shadow. Body only, no head, no text, high-detail hands. Avoid: text, watermark, white background,
extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **으쓱(shrug) · 저장: `sori_body_tee_shrug.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a relaxed casual white T-shirt with
simple black shorts, everyday casual look, subtle mint neon accents, shrugging — both hands open at sides near
shoulder height, palms up, elbows bent. NO head (neck cut, overlap margin). Thin clean anime linework. FULLY
TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail hands. Avoid:
text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **가리키기(point) · 저장: `sori_body_tee_point.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a relaxed casual white T-shirt with
simple black shorts, everyday casual look, subtle mint neon accents, pointing forward/upward with one index
finger (presenting), other arm relaxed. NO head (neck cut, overlap margin). Thin clean anime linework. FULLY
TRANSPARENT background PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail hands. Avoid:
text, watermark, white background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **환호(cheer, 성공) · 저장: `sori_body_tee_cheer.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS upper body in a relaxed casual white T-shirt with
simple black shorts, everyday casual look, subtle mint neon accents, cheering — both fists raised up in
celebration. NO head (neck cut, overlap margin). Thin clean anime linework. FULLY TRANSPARENT background PNG
(alpha) — no white, no shadow. Body only, no head, no text, high-detail hands. Avoid: text, watermark, white
background, extra fingers, deformed hands, head.
```
📋 붙여넣기 ↓ — **기쁨(joy, 만세) · 저장: `sori_body_tee_joy.png`**
```
Using the attached reference sheet, draw 이소리's HEADLESS full body in a relaxed casual white T-shirt with simple
black shorts, everyday casual look, subtle mint neon accents, in a joyful celebration, both arms up and open,
light on her toes. NO head (neck cut, overlap margin). Thin clean anime linework. FULLY TRANSPARENT background
PNG (alpha) — no white, no shadow. Body only, no head, no text, high-detail hands. Avoid: text, watermark, white
background, extra fingers, deformed hands, head.
```
> (선택) 추가 후보: 인사(bow)·생각(턱 괴기, headless라 손만)·양손 하트·전화받기 등. 같은 형식으로 확장.
+111
View File
@@ -0,0 +1,111 @@
# IMAGE-GEN RIGGING · 헤어 라이브러리 (머리 + 표정)
> **역할**: 어느 바디에나 **목(neck) 앵커로 합성**되는 머리 라이브러리. 머리 = 얼굴 + 헤어(모양).
> **헤드폰 없음**(헤드폰·머리띠는 악세서리로 얹음). **색상은 이미지로 만들지 않고 코드 틴트**로 처리.
> 조립/색상 규칙: `IMAGE_GEN_RIGGING_GUIDE.md`. 항상 **`sori_sheet.png` 첨부**.
## ★ 규칙
- 머리 모양 4종: **short(단발)·long(긴 생머리)·waveS(짧은 웨이브)·waveL(긴 웨이브).**
- 각 모양마다 **① 머리(기본 neutral) · ② 표정 프레임 세트 · ③ hairmask(머리카락만 알파)** 를 만든다.
- 표정 프레임은 **머리와 완전히 같은 위치·크기·각도**, 눈/입/눈썹만 변경(프레임 교체용).
- **민트/틸 기본색**으로만 생성 — 밝음/어두움/파랑/노랑/붉은/은색은 **코드에서 hairmask로 틴트**.
- 투명 배경(alpha)·흰배경 금지·헤어 림라이트 금지·헤드폰/텍스트/로고 없음·목 아래 겹침 여백.
## ▶ 사용 안내 (당신용)
- **📋 코드블록만** 붙여넣기. **먼저 `short`부터** 만들어 파이프라인을 검증하고 나머지 모양으로 확장.
- 표정 SET은 도구 프레임 제한 시 목록을 나눠 요청. 표정은 많을수록 좋음.
- 아래는 `short` 기준 전체 블록. **다른 모양은 프롬프트의 헤어 묘사만 바꿔** 동일하게 반복(저장 접두어 `sori_head_<shape>_…`).
- short → `mint/teal chin-length bob, volume bang`
- long → `long straight mint/teal hair past the shoulders`
- waveS → `short wavy mint/teal hair (soft curls, chin-to-neck length)`
- waveL → `long wavy mint/teal hair (soft curls, past the shoulders)`
---
---
## §S-1. 머리 (기본 neutral) · 저장: `sori_head_short.png` · 첨부: `sori_sheet.png`
📋 붙여넣기 ↓
```
Using the attached reference sheet, output ONLY the HEAD of the SAME woman 이소리 (East-Asian face, brown eyes,
gentle confident smile), with mint/teal chin-length BOB hair with a volume bang. NO headphones, NO hair
accessory. Front view, head level, cleanly isolated at the neck with a small overlap margin below the chin for
rigging. Thin clean anime semi-real linework matching the sheet. Output a PNG with a FULLY TRANSPARENT
background (alpha) — no white, no shadow, no rim light / glowing outline on hair. Head only, no headphones, no
text, no logo. Avoid: text, watermark, thick outlines, white background, deformed face.
```
## §S-2. 표정 프레임 (SET A · 핵심 6) · 저장: `sori_head_short_neutral/_blink/_talk/_talk_wide/_smile/_positive.png` · 첨부: `sori_sheet.png` + `sori_head_short.png`
📋 붙여넣기 ↓
```
Using the attached head reference, create expression frames of the SAME head (이소리, mint bob, no headphones).
Produce 6 SEPARATE images with the head in the EXACT SAME position, size, crop and angle as the attached head —
change ONLY eyes, mouth and eyebrows:
(1) neutral: eyes open, mouth closed, gentle confident smile;
(2) blink: eyes closed, mouth closed;
(3) talk: eyes open, mouth slightly open mid-speech;
(4) talk_wide: eyes open, mouth wide open (emphatic speech);
(5) smile: eyes happy, warm open smile;
(6) positive: bright excited eager look, raised cheeks (nod / yes feeling).
Keep the EXACT same face identity and framing. Thin clean anime linework. Output PNGs with a FULLY TRANSPARENT
background (alpha) — no white, no rim light on hair, no headphones. Head only, no text. Avoid: text, watermark,
inconsistent framing, white background, deformed face.
```
## §S-3. 표정 프레임 (SET B · 리액션 6) · 저장: `sori_head_short_negative/_confused/_wink/_surprised/_laugh/_thinking.png` · 첨부: `sori_head_short.png`
📋 붙여넣기 ↓
```
Using the attached head reference, create MORE expression frames of the SAME head, EXACT SAME position/size/
crop/angle — change ONLY eyes, mouth, eyebrows:
(1) negative: downturned brows/mouth, gentle "no" feeling;
(2) confused: one eyebrow up, small uncertain mouth, puzzled "?" look;
(3) wink: one eye winking, playful smile;
(4) surprised: wide eyes, small open "oh!" mouth;
(5) laugh: eyes closed happy arcs, big laughing smile;
(6) thinking: eyes glancing up, lips pursed "hmm".
Keep the EXACT same face and framing. Thin clean anime linework. Output PNGs with a FULLY TRANSPARENT background
(alpha) — no white, no rim light, no headphones. Head only, no text. Avoid: text, watermark, inconsistent
framing, white background, deformed face.
```
## §S-4. 표정 프레임 (SET C · 브랜딩 이모트 8) · 저장: `sori_head_short_cool/_love/_shy/_sad/_pout/_sleepy/_proud/_playful.png` · 첨부: `sori_head_short.png`
📋 붙여넣기 ↓
```
Using the attached head reference, create BRANDING EMOTE expression frames of the SAME head, EXACT SAME
position/size/crop/angle — change ONLY eyes, mouth, eyebrows (small comic accents like blush or sparkle only
where noted, no props):
(1) cool: half-lidded confident look, tiny smirk;
(2) love: heart-shaped sparkling eyes, soft happy smile;
(3) shy: light cheek blush, bashful small smile, eyes glancing away;
(4) sad: teary downturned eyes, small frown;
(5) pout: puffed cheeks, sulky pout;
(6) sleepy: droopy half-closed eyes, small yawn;
(7) proud: chin up, satisfied confident smile, closed happy eyes;
(8) playful: one eye wink + playful tongue out.
Keep the EXACT same face and framing. Thin clean anime linework. Output PNGs with a FULLY TRANSPARENT background
(alpha) — no white, no rim light, no headphones. Head only, no text. Avoid: text, watermark, inconsistent
framing, white background, deformed face.
```
▶ (선택) 더 추가 후보: determined(결의)·angry(발끈)·curious(호기심)·sing(노래)·starstruck(반짝)·crying_comic(폭풍눈물).
## §S-5. 헤어 마스크 (색상 코드용) · 저장: `sori_hairmask_short.png` · 첨부: `sori_head_short.png`
📋 붙여넣기 ↓
```
Using the attached head, output a MATTE/MASK image the EXACT same size and position as the head, showing ONLY
the HAIR region filled solid white on full transparency — everything else (face, skin, neck, background) fully
transparent. This is an alpha mask of the hair only, for recoloring in code. No shading, no gradient, just a
clean solid-white hair silhouette. Output a PNG with a FULLY TRANSPARENT background (alpha). No text.
```
---
---
## §L / §WS / §WL. 다른 머리 모양 (long · waveS · waveL)
▶ 위 §S-1 ~ §S-5 블록을 **그대로 반복**하되:
1. 프롬프트의 헤어 묘사 문구만 아래로 교체
- **long** : `long straight mint/teal hair past the shoulders`
- **waveS**: `short wavy mint/teal hair, soft curls, chin-to-neck length`
- **waveL**: `long wavy mint/teal hair, soft curls, past the shoulders`
2. 저장 접두어를 `sori_head_long_…` / `sori_head_waveS_…` / `sori_head_waveL_…` (마스크는 `sori_hairmask_<shape>.png`)로.
3. 첨부는 해당 모양의 §-1 머리(예: `sori_head_long.png`)를 §-2~§-5에 첨부.
> **색상**: 위 4모양 × (밝음·약간어두움·파랑·노랑·붉은·은색)은 **이미지로 만들지 않는다.** hairmask로 **코드에서 틴트**.
+181
View File
@@ -0,0 +1,181 @@
# IMAGE-GEN REQUESTS — 재생성 요청문 (투명 배경 강제)
> 마스코트 **이소리(민트 여) · 이단(시안 남)** 에셋을 **투명 배경 PNG로 재생성**하기 위한 복붙 요청문.
> 각 코드블록은 **그대로 복사해 AI에 붙여넣으면 되는 완성 프롬프트**다(일관성·화풍·투명·글래머러스·금지어 포함).
> 설정: `BRAND_CHARACTERS.md` · 프로필/베리에이션 팔레트: `CHARACTER_PROFILES.md` · 베리에이션 요청: `IMAGE_GEN_VARIATIONS.md`.
---
## ▶ 사용 안내 (당신용 — 이 섹션만 지침)
- **가장 중요 — 투명 배경**: 각 프롬프트가 "fully TRANSPARENT background PNG"를 요구한다.
- ChatGPT/gpt-image: **PNG·투명 배경 옵션을 켜고** 요청. 흰 배경으로 나오면 **"redo with a transparent (alpha) background, no white"** 로 재생성.
- 그래도 흰색이면: 순수 흰 배경으로 받아 후처리(rembg)로 키아웃 — 단 **1순위는 네이티브 투명**.
- **한 코드블록 = 이미지 1장.** 통째 복사, 문구 수정/추가 없음.
- **첨부**: 소제목의 `첨부: __` 이미지를 함께 올린다(시트가 있으면 동일 인물 유지에 필수).
- **순서**: §1 시트 → §2 파츠 → §3 아바타 → §4 이소리 포즈 → §5 이단 포즈 → §6 듀오.
- 결과는 `Characters/` 루트에 저장 → 분류는 대신 해줌. 소제목의 `저장:`은 파일명 힌트.
- **이소리 변경점**: 이번 재생성부터 **글래머러스한 성인 실루엣(풍성한 가슴·아워글래스 상체, 품위 있게)**.
---
## §1. 캐릭터 시트 (일관성 기준 — 먼저)
### 1-1. 이소리 시트 — **저장: `sori_sheet.png`**
```
Character reference sheet of one Asian young adult woman (mid-to-late 20s), modern anime semi-real style,
thin clean linework, ~7-head adult proportions. GLAMOROUS confident figure with a fuller bust and an elegant
hourglass upper body (tasteful adult casual-chic, NOT revealing). Mint/teal green bob hair, brown eyes,
East-Asian face, bright confident smile. Outfit: white cropped hoodie, mint-and-black track jacket, black
track pants with mint side stripe, black choker with a teal gem, silver on-ear headphones. Include front /
3-4 / side full-body turnaround plus 6 face expressions (neutral, smile, laugh, focused, wink, surprised).
Flat even lighting. Output a PNG with a FULLY TRANSPARENT background (alpha) — no white, no backdrop, no
ground shadow. Character only, no text, no logo. Avoid: text, watermark, white/opaque background, chibi,
child, deformed hands.
```
### 1-2. 이단 시트 — **저장: `dan_sheet.png`**
```
Character reference sheet of one Asian young adult man (late 20s/early 30s), modern anime semi-real style,
thin clean linework, ~7-head adult proportions, fit athletic build. Short dark textured hair with a cyan/blue
streak, confident grin. Outfit: navy-black hoodie + bomber with blue zippers, white tee, black pants, black
smartwatch, blue/cyan over-ear headphones around neck. Include front / 3-4 / side full-body turnaround plus 6
face expressions (neutral, smile, laugh, focused, wink, surprised). Flat even lighting. Output a PNG with a
FULLY TRANSPARENT background (alpha) — no white, no backdrop, no ground shadow. Character only, no text, no
logo. Avoid: text, watermark, white/opaque background, chibi, child, deformed hands.
```
---
## §2. 리깅 파츠 (컷아웃) · *첨부: 해당 시트*
```
Using the attached reference sheet, draw the SAME character in a full-body NEUTRAL RIGGING POSE: relaxed
A-pose, arms slightly away from torso, limbs clearly separated, palms open, symmetrical, front view, flat
lighting. Keep the EXACT same face/hair/outfit (이소리 keeps her glamorous hourglass upper body). Thin clean
anime linework matching the sheet. Output a PNG with a FULLY TRANSPARENT background (alpha) — no white, no
shadow. Character only, no text. Avoid: text, watermark, white background, deformed hands, chibi.
```
개별 파츠(머리 / 오른팔 / 왼팔 / 몸통 — 각각 1장):
```
Using the attached reference sheet, output ONLY the [HEAD with hair and headphones / RIGHT arm+hand with
sleeve / LEFT arm+hand / TORSO top only, no arms, no head] of the SAME character, cleanly isolated with a
small overlap margin at the joints. Keep the EXACT same face/hair/outfit and the soft anime style of the
sheet. Output a PNG with a FULLY TRANSPARENT background (alpha) — no white. No text, no logo. Avoid: text,
watermark, thick outlines, white background, deformed hands.
```
---
## §3. 아바타 4프레임 (눈 깜빡임·립싱크)
> 4장을 **완전히 같은 위치·크기·크롭**으로.
### 3-1. 이소리 — **저장: `sori_avatar_a~d.png` · 첨부: `sori_sheet.png`**
```
Using the attached reference sheet, create a circular head-and-shoulders avatar of the same woman (이소리,
mint bob, teal-gem choker, glamorous). Produce 4 SEPARATE images with the head in the EXACT SAME position,
size and crop, changing ONLY the eyes/mouth: (a) eyes open + mouth closed, gentle smile; (b) eyes closed
(blink); (c) mouth open (talking); (d) wink. Keep the EXACT same face. Thin clean anime style matching the
sheet. Output a PNG with a FULLY TRANSPARENT background (alpha) — no white. Head only, no text, no logo.
Avoid: text, watermark, inconsistent framing, white background, deformed face.
```
### 3-2. 이단 — **저장: `dan_avatar_a~d.png` · 첨부: `dan_sheet.png`**
```
Using the attached reference sheet, create a circular head-and-shoulders avatar of the same man (이단, dark
hair with cyan streak, blue headphones around neck). Produce 4 SEPARATE images with the head in the EXACT
SAME position, size and crop, changing ONLY the eyes/mouth: (a) eyes open + mouth closed, confident smile;
(b) eyes closed (blink); (c) mouth open (talking); (d) confident wink. Keep the EXACT same face. Thin clean
anime style matching the sheet. Output a PNG with a FULLY TRANSPARENT background (alpha) — no white. Head
only, no text. Avoid: text, watermark, inconsistent framing, white background, deformed face.
```
---
## §4. 이소리 — 장면 포즈 · *첨부: `sori_sheet.png`*
> 공통: 이소리는 **글래머러스한 아워글래스 상체** 유지. 아래 각 블록의 `[POSE]`만 다름.
### 4-1. idle — **저장: `sori_idle.png`**
```
Using the attached reference sheet, draw the same woman (이소리), identical glamorous face/figure/hair/outfit.
Waist-up, relaxed friendly smile, one hand near chest. Thin clean anime style matching the sheet. Output a
PNG with a FULLY TRANSPARENT background (alpha) — no white, no shadow. Character only, no text, high detail
hands. Avoid: text, watermark, white background, extra fingers, deformed hands, chibi.
```
### 4-2. present (손끝 음파) — **저장: `sori_present.png`**
```
Using the attached reference sheet, draw the same woman (이소리), identical glamorous face/figure/hair/outfit.
3/4 view, one open palm raised as if presenting sound — hand EMPTY (soundwaves added later). Gentle smile.
Thin clean anime style. Output a PNG with a FULLY TRANSPARENT background (alpha) — no white. Character only,
no text, high detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands.
```
### 4-3. happy — **저장: `sori_happy.png`**
```
Using the attached reference sheet, draw the same woman (이소리), identical glamorous face/figure/hair/outfit.
Both hands up in a cheerful celebration, big happy smile. Thin clean anime style. Output a PNG with a FULLY
TRANSPARENT background (alpha) — no white. Character only, no text, high detail hands. Avoid: text, watermark,
white background, extra fingers, deformed hands.
```
### 4-4. listen — **저장: `sori_listen.png`**
```
Using the attached reference sheet, draw the same woman (이소리), identical glamorous face/figure/hair/outfit.
One hand touching her headphone, eyes softly closed, focused listening. Thin clean anime style. Output a PNG
with a FULLY TRANSPARENT background (alpha) — no white. Character only, no text. Avoid: text, watermark,
white background, deformed hands.
```
### 4-5. headphones_off — **저장: `sori_headphones_off.png`**
```
Using the attached reference sheet, draw the same woman (이소리), identical glamorous face/figure/hair/outfit,
SAME body position/scale/crop as the idle pose. Sliding the headphones down onto the neck, relaxed neutral
expression. Thin clean anime style. Output a PNG with a FULLY TRANSPARENT background (alpha) — no white.
Character only, no text. Avoid: text, watermark, white background, deformed hands.
```
---
## §5. 이단 — 장면 포즈 · *첨부: `dan_sheet.png`*
### 5-1. idle — **저장: `dan_idle.png`**
```
Using the attached reference sheet, draw the same man (이단), identical face/hair/outfit. Waist-up, confident
grin, arms relaxed. Thin clean anime style matching the sheet. Output a PNG with a FULLY TRANSPARENT
background (alpha) — no white, no shadow. Character only, no text, high detail hands. Avoid: text, watermark,
white background, extra fingers, deformed hands.
```
### 5-2. tune — **저장: `dan_tune.png`**
```
Using the attached reference sheet, draw the same man (이단), identical face/hair/outfit. 3/4 view, one hand
pinching/adjusting an INVISIBLE control in mid-air (panel added later), focused confident look. Thin clean
anime style. Output a PNG with a FULLY TRANSPARENT background (alpha) — no white. Character only, no text,
high detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands.
```
### 5-3. thumbsup — **저장: `dan_thumbsup.png`**
```
Using the attached reference sheet, draw the same man (이단), identical face/hair/outfit. Thumbs-up, big
friendly smile. Thin clean anime style. Output a PNG with a FULLY TRANSPARENT background (alpha) — no white.
Character only, no text, high detail hands. Avoid: text, watermark, white background, extra fingers, deformed
hands.
```
### 5-4. headphones_off — **저장: `dan_headphones_off.png`**
```
Using the attached reference sheet, draw the same man (이단), identical face/hair/outfit, SAME body
position/scale/crop as the idle pose. Taking the over-ear headphones off, relaxed expression. Thin clean anime
style. Output a PNG with a FULLY TRANSPARENT background (alpha) — no white. Character only, no text. Avoid:
text, watermark, white background, deformed hands.
```
---
## §6. 듀오 — **저장: `duo_backtoback.png` · 첨부: `sori_sheet.png` + `dan_sheet.png`**
```
Using BOTH attached reference sheets, draw the same two characters — 이소리 (mint bob, glamorous hourglass
upper body, identical face/outfit) and 이단 (cyan-streak dark hair, identical face/outfit) — standing
back-to-back, full body. She gestures with an open empty palm; he adjusts an invisible control; confident
partner chemistry. Keep the EXACT same faces. Thin clean anime style matching the sheets. Output a PNG with a
FULLY TRANSPARENT background (alpha) — no white, no shadow. Characters only, no text, no logo. Avoid: text,
watermark, white background, extra fingers, deformed hands, chibi.
```
---
## 참고 — 투명 배경이 정말 안 나올 때
- 프롬프트에 "transparent PNG"를 명시해도 일부 툴은 흰색을 준다. 이때는 **순수 단색(흰/녹색) 배경 + 그림자 없음**으로 받아
`tools/make_transparent.py`(색상키) 또는 rembg로 키아웃. **네이티브 투명이 1순위**, 후처리는 폴백.
- 이소리 헤어의 밝은 테두리(림라이트)를 없애려면 프롬프트에 "no rim light, no glowing outline on hair" 추가.
+110
View File
@@ -0,0 +1,110 @@
# IMAGE-GEN RIGGING · 악세서리 / 소품 (공용)
> **원칙**: 캐릭터 + 의상 외의 **모든 물체는 여기서 별도 제작**해 어떤 이소리 버전에든 **합성**한다(캐릭터에 그리지 않음).
> 제스처 포즈(디제잉·피아노 등)는 손동작만 그려져 있으니, 여기 소품을 얹어 완성한다.
> 스타일/색은 Dansori 팔레트(민트 `#38E0C4` → 시안 `#4CC2FF`, 은색/화이트, 딥네이비)에 맞춘다.
## ▶ 사용 안내 (당신용 — 붙여넣지 말 것)
- **📋 코드블록만** AI에 붙여넣는다. **한 블록 = 소품 1개.**
- **캐릭터 없이 물체만**, 투명 배경(alpha), 그림자 없음, 텍스트/로고 없음.
- 합성 방향(정면 or 약간 3-4 각도)을 손동작 포즈에 맞춰 뽑는다. 필요하면 각도를 바꿔 재요청.
- `저장:` = 파일명 힌트. 첨부 불필요(색 참고가 필요하면 `sori_sheet.png`를 곁들여도 됨).
### 파일명 규칙
```
acc_headphones_sori · acc_turntable · acc_lp_disc · acc_piano_keys · acc_mic · acc_catears · acc_wristband_neon
(원한다면 acc_soundwave 는 벡터 FX(Lottie)로 별도 처리 — 이미지 아님)
```
---
---
## §A. 착탈형 헤드폰 (이소리용) · 저장: `acc_headphones_sori.png`
▶ 캐릭터가 벗거나 손에 든 장면, 또는 고양이귀와 교체할 때 얹는 용도.
📋 붙여넣기 ↓
```
Draw ONLY a pair of on-ear headphones in 이소리's style: silver/white housing, soft white ear cushions, a thin
mint (#38E0C4) cable accent, sleek modern look. 3-4 front angle, isolated single object. Thin clean anime
linework. Output a PNG with a FULLY TRANSPARENT background (alpha) — no white, no shadow. Object only, no
character, no text, no logo. Avoid: text, watermark, white background.
```
---
## §B. 턴테이블 (DJ용) · 저장: `acc_turntable.png`
▶ `sori_dj.png`의 아래로 뻗은 손 밑에 합성.
📋 붙여넣기 ↓
```
Draw ONLY a single DJ turntable deck seen from a slight top-down 3-4 angle: a dark platter with a vinyl record
on it, a tonearm, minimal sleek modern design with subtle mint/cyan (#38E0C4 → #4CC2FF) neon trim. Isolated
single object, no hands, no character. Thin clean anime linework. Output a PNG with a FULLY TRANSPARENT
background (alpha) — no white, no shadow. Object only, no text, no logo. Avoid: text, watermark, white
background, cluttered extra gear.
```
---
## §C. LP 레코드판 (단독) · 저장: `acc_lp_disc.png`
▶ 손 밑에 얹거나 회전 FX로 쓸 단독 디스크.
📋 붙여넣기 ↓
```
Draw ONLY a single vinyl LP record disc, top view (perfect circle), glossy black with a mint-to-cyan
(#38E0C4 → #4CC2FF) neon-tinted center label, subtle groove rings. Isolated object, no hands, no character.
Thin clean anime linework. Output a PNG with a FULLY TRANSPARENT background (alpha) — no white, no shadow.
Object only, no text, no logo. Avoid: text, watermark, white background.
```
---
## §D. 피아노 건반 (연주용) · 저장: `acc_piano_keys.png`
▶ `sori_piano.png`의 손 아래에 합성.
📋 붙여넣기 ↓
```
Draw ONLY the front portion of a piano keyboard (a row of white and black keys) seen from a gentle player's
3-4 angle, sleek modern minimal design with a subtle mint/cyan neon edge glow. Isolated object, no hands, no
character, no piano body. Thin clean anime linework. Output a PNG with a FULLY TRANSPARENT background (alpha) —
no white, no shadow. Object only, no text, no logo. Avoid: text, watermark, white background.
```
---
## §E. 마이크 (호스트/토크용) · 저장: `acc_mic.png`
▶ 말하기/방송 연출에 손에 쥐어줄 소품.
📋 붙여넣기 ↓
```
Draw ONLY a handheld microphone, modern sleek design with a silver/white body and a mint-to-cyan
(#38E0C4 → #4CC2FF) neon accent ring, slight 3-4 angle, isolated single object, no hand, no character. Thin
clean anime linework. Output a PNG with a FULLY TRANSPARENT background (alpha) — no white, no shadow. Object
only, no text, no logo. Avoid: text, watermark, white background.
```
---
## §F. 고양이귀 머리띠 · 저장: `acc_catears.png`
▶ 헤드폰 대신 머리에 얹는 데코(머리 파츠 위 합성).
📋 붙여넣기 ↓
```
Draw ONLY a cute cat-ear headband: glossy black band with two cat ears, mint/teal (#38E0C4) neon inner-ear
accent to match the Dansori palette, front view, isolated single object, no head, no character. Thin clean anime
linework. Output a PNG with a FULLY TRANSPARENT background (alpha) — no white, no shadow. Object only, no text.
Avoid: text, watermark, white background.
```
---
## §G. 손목 네온 밴드 · 저장: `acc_wristband_neon.png`
▶ 손목에 얹는 데코(제스처 손 위 합성).
📋 붙여넣기 ↓
```
Draw ONLY a slim wrist band / bracelet with a glowing mint-to-cyan (#38E0C4 → #4CC2FF) neon strip, sleek modern
sporty look, slight 3-4 angle, isolated single object, no hand, no character. Thin clean anime linework. Output
a PNG with a FULLY TRANSPARENT background (alpha) — no white, no shadow. Object only, no text. Avoid: text,
watermark, white background.
```
+84
View File
@@ -0,0 +1,84 @@
# IMAGE-GEN RIGGING · 조립형(페이퍼돌) 가이드 — 이소리
> **목표**: "바디(제스처) + 복장 + 헤어 + 악세서리"를 골라 **인형 옷갈아입히기식으로 조립**해 무한에 가까운 변형을 만든다.
> 이 문서는 **전체 구조·조립 규칙·네이밍·색상 처리**의 총괄 가이드다. 실제 생성 프롬프트는 아래 하위 문서에 있다.
> 캐릭터 외형 기준: `BRAND_CHARACTERS.md`. (구버전 요청서는 `*.old`로 보관됨.)
---
## 1. 왜 "하이브리드" 조립인가 (필독)
이미지 생성 AI는 **매 장을 독립적으로 그려서 서로 정합(위치·비율·크롭)이 맞지 않는다.**
→ 따라서 **정합이 필요한 것은 함께 굽고, 국소 부착·색상만 런타임 레이어**로 조립한다.
| 레이어 | 처리 방식 | 근거 |
|---|---|---|
| **바디 + 복장** | **함께 생성**(복장이 몸에 발라진 헤드리스 바디). 복장별 1세트 | 몸-옷 정합이 깨지면 안 됨 |
| **헤어 + 표정** | **머리 라이브러리로 함께 생성**(머리+표정 프레임). 머리는 **목(neck) 앵커**로 어느 바디에나 합성 | 얼굴-머리 정합 필요, 목은 국소 앵커라 합성 OK |
| **악세서리** | **진짜 오버레이** — 부착점에 얹기 | 작고 국소 부착이라 정합 문제 적음 ✅ |
| **색상(헤어 염색·네온)** | **코드에서 틴트(hue-shift)** — 이미지 생성 안 함 | 6색×N모양 이미지 폭발을 제거 |
**핵심 조립식**: `헤드리스 바디(복장)` + `머리(헤어모양)` + `표정 프레임` + `악세서리들` + `코드 색상` → 완성 캐릭터.
동작(끄덕·갸웃·호흡·손흔듦 등)은 **리그(코드 트랜스폼) + 표정 프레임**으로, 이미지 없이 표현한다.
---
## 2. 조립 앵커(정합점) 규칙
모든 파츠/오버레이는 **정해진 앵커**에서 겹치도록 그린다(약간의 겹침 여백 포함).
- **목(neck)**: 헤드리스 바디 ↔ 머리. (모든 바디는 **머리 없이**, 목에서 잘라 그린다.)
- **어깨(shoulder)**: 몸통 ↔ 팔.
- **귀/정수리(head)**: 머리 ↔ 헤드폰·머리띠(고양이귀·클럽밴드).
- **목선(neckline)**: 머리/몸통 ↔ 목걸이.
- **손목(wrist)**: 팔 ↔ 팔찌.
- **발(feet)**: 다리 ↔ 신발(운동화·구두). *신발 교체는 서있는 idle 포즈에서 가장 안정적(발 각도 고정).*
## 3. 색상 = 코드 처리 (이미지 아님)
- 헤어 6톤: **밝은톤 · 약간 어두운톤 · 파랑 · 노랑 · 붉은계열 · 은색** → **런타임 hue/색조 변환**으로 생성.
- 이를 위해 헤어 문서에서 각 머리마다 **`hairmask`(머리카락만 알파)**를 함께 요청 → 코드가 머리카락 영역만 틴트.
- 네온 악세서리(클럽밴드·팔찌 등)도 같은 방식으로 색 변형 가능.
- **즉, 헤어는 "모양"만 이미지로 만들고 "색"은 만들지 않는다.**
---
## 4. 문서 지도 (하위 요청서)
- **바디(복장별)** — 헤드리스 바디 파츠 + 제스처 바디컷:
`IMAGE_GEN_BODY_TRACK.md`(트랙슈트·기준본) · `_DRESS_SHORT` · `_DRESS_LONG` · `_JEANS` · `_TSHIRT`
- **헤어** — 머리+표정 라이브러리(모양 4종) + hairmask: `IMAGE_GEN_HAIR.md`
- **악세서리** — 오버레이 7종: `IMAGE_GEN_ACCESSORIES.md`
- 각 문서는 **위 → 아래 순서대로** 붙여넣기(원하는 지점까지만 해도 됨). **📋 코드블록만** AI에 붙여넣는다.
- 모든 바디/머리 생성 시 **`Characters/00_sheets/sori_sheet.png` 첨부**(동일 인물 유지).
---
## 5. 네이밍 규칙 (전체)
```
바디(복장별) sori_body_<outfit>_<part|pose>
outfit = track · dressS · dressL · jeans · tee
part = apose · torso · arm_r · arm_l · legs (헤드리스 리그 파츠)
pose = idle_full · idle_upper · wave · handwave · listen · present · dj · piano ·
control · thumbsup · heart · clap · peace · armscross · bow · shrug ·
think · point · cheer · success · joy (헤드리스 제스처 바디컷)
헤어 sori_head_<shape> (민트 기본색 머리, 헤드폰 없음, 목 앵커)
sori_head_<shape>_<expr> (같은 크롭, 표정만 다름)
sori_hairmask_<shape> (머리카락만 알파 — 코드 색상용)
shape = short · long · waveS · waveL
expr = neutral · blink · talk · talk_wide · smile · laugh · positive · negative ·
confused · wink · surprised · thinking · cool · love · shy · sad · pout ·
sleepy · determined · playful · angry · proud · curious · sing …
악세서리 acc_catears · acc_clubband · acc_headphones · acc_bracelet · acc_necklace ·
acc_sneakers · acc_heels
색상(코드) tone_light · tone_dark · blue · yellow · red · silver (이미지 아님)
```
---
## 6. 우선순위 (권장 생성 순서)
1. **헤어 기본 1모양**(short) 머리 + 핵심 표정(neutral/blink/talk) → 파이프라인 검증.
2. **바디 트랙슈트** 리그 파츠(§1) + idle_upper → 배경 리그 교체.
3. 제스처 바디컷(wave·listen·success·joy·dj·piano …) 순차.
4. 나머지 헤어 모양·복장·악세서리 → 조립 폭 확장.
5. 색상 6톤은 **코드**로(이미지 생성 불필요).
> ⚠️ 이미지 수가 많아지는 방식이다(조립 다양성의 대가). 우선순위 상위부터, 필요한 만큼만 생성해도 앱은 동작한다.
+190
View File
@@ -0,0 +1,190 @@
# IMAGE-GEN RIGGING · 이소리 · 기본 세트 (BASE)
> 이소리 **기본 룩(민트 단발 + 트랙 재킷 세트)** 의 리깅 자산 요청서.
> **위 → 아래 순서대로** 코드블록을 붙여넣으면 된다(원하는 지점까지만 해도 됨).
> 베리에이션은 별도 파일: `..._SORI_DRESS_BOB.md` · `..._SORI_DRESS_LONG.md` · `..._SORI_JEANS.md`.
> 소품(헤드폰·LP·건반·마이크 등)은 **`IMAGE_GEN_RIGGING_ACCESSORIES.md`** 에서 따로 제작해 합성한다.
> 외형 기준: `BRAND_CHARACTERS.md`. 항상 **`Characters/00_sheets/sori_sheet.png` 첨부**.
---
## ★ 원칙
1. **모든 이소리 베리에이션은 이 기본 세트와 동일한 구성**(파츠 분해·표정 종류·제스처)을 가진다. 변하는 건 의상/헤어뿐.
2. 파츠는 **관절 겹침 여백**을 두고 분리(회전 시 이음새가 안 벌어지게).
3. 표정 프레임은 **머리 파츠와 동일한 위치·크기·각도**로, 눈/입/눈썹만 변경(프레임 교체용).
4. **투명 배경(alpha) · 흰배경 금지 · 헤어 림라이트 금지 · 텍스트/로고 금지.**
5. **캐릭터 + 의상 외의 모든 물체(헤드폰 포함 착탈형·LP·턴테이블·건반·마이크 등)는 이 문서에서 그리지 않고 악세서리로 분리** →
제스처는 **소품 없이 손동작만**(빈 손 위치)으로 그려 나중에 합성.
*단, 캐릭터가 늘 착용한 은색 온이어 헤드폰은 시그니처이므로 파츠/포즈에 그대로 그린다(별도 착탈용 헤드폰은 악세서리에 따로 있음).*
## ▶ 사용 안내 (당신용 — 붙여넣지 말 것)
- **📋 코드블록만** AI에 붙여넣는다. 한글 설명은 사람용.
- **`저장:`** = 결과 파일명 힌트, **`첨부:`** = 함께 올릴 레퍼런스.
- **SET** 표기 블록 = 여러 프레임을 한 번에. 도구가 프레임 수를 제한하면 목록을 나눠 2번에 요청.
- 표정은 많을수록 좋음(브랜딩용). 아래 목록 외에 더 뽑아도 됨 — 같은 크롭 규칙만 지키면 프레임 교체로 재사용 가능.
### 파일명 규칙 (기본 세트)
```
파츠 : sori_rig_apose · sori_part_head · sori_part_torso · sori_part_arm_r · sori_part_arm_l
표정 : sori_face_<name> (name = neutral, blink, talk, talk_wide, smile, laugh, positive, negative,
confused, wink, surprised, thinking, cool, love, shy, sad, pout, sleepy,
playful, determined …)
제스처 : sori_wave · sori_dj · sori_piano (소품은 합성)
```
---
---
## §1. 기본 리깅 파츠 · 첨부: `sori_sheet.png`
📋 붙여넣기 ↓ — **① A-포즈 리깅 베이스 · 저장: `sori_rig_apose.png`**
```
Using the attached reference sheet, draw the SAME woman 이소리 (mint/teal bob hair, brown eyes, East-Asian
face, bright confident look, GLAMOROUS adult hourglass upper body — tasteful, not revealing; white cropped
hoodie + mint/black track jacket + black track pants with mint side stripe, black choker with teal gem,
silver/white on-ear headphones) in a full-body NEUTRAL RIGGING A-POSE: standing straight, front view, arms
slightly away from the torso, elbows soft, palms open facing forward, legs together, symmetrical, head level.
Thin clean anime semi-real linework matching the sheet, flat even lighting. Output a PNG with a FULLY
TRANSPARENT background (alpha) — no white, no backdrop, no ground shadow, no rim light / glowing outline on
hair. Character only, no text, no logo. Avoid: text, watermark, white/opaque background, chibi, child, extra
fingers, deformed hands.
```
📋 붙여넣기 ↓ — **② 머리 파츠 · 저장: `sori_part_head.png`**
```
Using the attached reference sheet, output ONLY the HEAD of the SAME woman 이소리 (mint/teal bob hair, brown
eyes, East-Asian face, gentle confident smile, silver/white on-ear headphones), including hair and headphones,
front view, head level, cleanly isolated at the neck with a small overlap margin below the chin for rigging.
Thin clean anime linework matching the sheet. Output a PNG with a FULLY TRANSPARENT background (alpha) — no
white, no shadow, no rim light / glowing outline on hair. Head only, no text, no logo. Avoid: text, watermark,
thick outlines, white background, deformed face.
```
📋 붙여넣기 ↓ — **③ 몸통 파츠 · 저장: `sori_part_torso.png`**
```
Using the attached reference sheet, output ONLY the TORSO of the SAME woman 이소리 (glamorous hourglass upper
body, white cropped hoodie + mint/black track jacket, black track pants with mint side stripe), NO head and NO
arms, front view, cleanly isolated with a small overlap margin at the neck and both shoulders for rigging. Thin
clean anime linework matching the sheet. Output a PNG with a FULLY TRANSPARENT background (alpha) — no white, no
shadow. Torso only, no text, no logo. Avoid: text, watermark, white background, deformed anatomy.
```
📋 붙여넣기 ↓ — **④ 오른팔 파츠 · 저장: `sori_part_arm_r.png`**
```
Using the attached reference sheet, output ONLY the character's RIGHT arm+hand (with jacket sleeve) of the SAME
woman 이소리, relaxed and slightly bent, palm open, cleanly isolated with a small overlap margin at the shoulder
for rigging. Thin clean anime linework matching the sheet. Output a PNG with a FULLY TRANSPARENT background
(alpha) — no white, no shadow. Arm only, no text. Avoid: text, watermark, white background, extra fingers,
deformed hands.
```
📋 붙여넣기 ↓ — **⑤ 왼팔 파츠 · 저장: `sori_part_arm_l.png`**
```
Using the attached reference sheet, output ONLY the character's LEFT arm+hand (with jacket sleeve) of the SAME
woman 이소리, relaxed and slightly bent, palm open, cleanly isolated with a small overlap margin at the shoulder
for rigging. Thin clean anime linework matching the sheet. Output a PNG with a FULLY TRANSPARENT background
(alpha) — no white, no shadow. Arm only, no text. Avoid: text, watermark, white background, extra fingers,
deformed hands.
```
---
## §2. 표정 프레임 (SET) · 첨부: `sori_sheet.png` + `sori_part_head.png`
▶ 지침: **머리 파츠와 완전히 같은 위치·크기·각도**로 눈/입/눈썹만 바꾼다. 3개 SET로 나눠 요청(도구 프레임 제한 대응). 더 만들면 좋음.
- 애니메이션 필수: neutral·blink·talk (·talk_wide) — 반드시 정합 일치.
- 신호용: positive(끄덕/긍정)·negative(저음/부정)·confused(갸웃/오류).
📋 붙여넣기 ↓ — **표정 SET A (핵심 6) · 저장: `sori_face_neutral/_blink/_talk/_talk_wide/_smile/_positive.png`**
```
Using the attached head reference, create expression frames of the SAME woman 이소리's head (mint bob, brown
eyes, silver/white on-ear headphones). Produce 6 SEPARATE images with the head in the EXACT SAME position, size,
crop and angle as the attached head — change ONLY eyes, mouth and eyebrows:
(1) neutral: eyes open, mouth closed, gentle confident smile;
(2) blink: eyes closed, mouth closed;
(3) talk: eyes open, mouth slightly open mid-speech;
(4) talk_wide: eyes open, mouth wide open (emphatic speech);
(5) smile: eyes happy, warm open smile;
(6) positive: bright excited eager look, raised cheeks (nod / yes feeling).
Keep the EXACT same face identity and framing across all frames. Thin clean anime linework matching the sheet.
Output PNGs with a FULLY TRANSPARENT background (alpha) — no white, no rim light on hair. Head only, no text.
Avoid: text, watermark, inconsistent framing, white background, deformed face.
```
📋 붙여넣기 ↓ — **표정 SET B (신호·리액션 6) · 저장: `sori_face_negative/_confused/_wink/_surprised/_laugh/_thinking.png`**
```
Using the attached head reference, create MORE expression frames of the SAME woman 이소리's head, EXACT SAME
position/size/crop/angle as the attached head — change ONLY eyes, mouth and eyebrows:
(1) negative: slightly downturned brows and mouth, gentle "no" head-shake feeling;
(2) confused: one eyebrow raised, small uncertain mouth, puzzled tilted "?" look;
(3) wink: one eye winking, playful smile;
(4) surprised: wide eyes, small open "oh!" mouth, raised brows;
(5) laugh: eyes closed happy arcs, big open laughing smile;
(6) thinking: eyes glancing up, one brow up, lips pursed "hmm".
Keep the EXACT same face identity and framing. Thin clean anime linework matching the sheet. Output PNGs with a
FULLY TRANSPARENT background (alpha) — no white, no rim light on hair. Head only, no text. Avoid: text,
watermark, inconsistent framing, white background, deformed face.
```
📋 붙여넣기 ↓ — **표정 SET C (브랜딩 이모트 6) · 저장: `sori_face_cool/_love/_shy/_sad/_pout/_sleepy.png`**
```
Using the attached head reference, create BRANDING EMOTE expression frames of the SAME woman 이소리's head, EXACT
SAME position/size/crop/angle as the attached head — change ONLY eyes, mouth and eyebrows (add small comic
accents like blush or sparkle only where noted, no extra props):
(1) cool: half-lidded confident look, tiny smirk;
(2) love: heart-shaped sparkling eyes, soft happy smile (comic heart eyes);
(3) shy: slight blush on cheeks, bashful small smile, eyes glancing away;
(4) sad: teary downturned eyes, small frown;
(5) pout: puffed cheeks, sulky pout, brows slightly furrowed;
(6) sleepy: droopy half-closed eyes, small yawn.
Keep the EXACT same face identity and framing. Thin clean anime linework matching the sheet. Output PNGs with a
FULLY TRANSPARENT background (alpha) — no white, no rim light on hair. Head only, no text. Avoid: text,
watermark, inconsistent framing, white background, deformed face.
```
▶ (선택) 더 확장할 이모트 후보: determined(결의), starstruck(반짝 감탄), playful_tongue(메롱), relieved(안도),
proud(뿌듯), crying_comic(폭풍눈물), angry(발끈). 필요 시 위 SET 형식(같은 크롭) 그대로 추가.
---
## §3. 제스처 포즈 (소품 없이 손동작만) · 첨부: `sori_sheet.png`
▶ 지침: LP·턴테이블·건반 등 **소품은 그리지 않는다**(악세서리로 합성). 손은 소품을 쓰는 위치로만. 헤드폰은 착용 상태 유지.
- 끄덕/저음/갸웃/호흡/간단한 손흔듦은 §1 파츠 + §2 표정을 **코드 애니**로 구현(이미지 불필요).
📋 붙여넣기 ↓ — **① 손 흔들기(웨이브) · 저장: `sori_wave.png`**
```
Using the attached reference sheet, draw the SAME woman 이소리 (identical glamorous face/hair/figure/outfit,
silver/white on-ear headphones), waist-up, one hand raised beside her head in a friendly WAVE, open palm,
bright cheerful smile, other hand relaxed. Thin clean anime linework matching the sheet. Output a PNG with a
FULLY TRANSPARENT background (alpha) — no white, no shadow, no rim light on hair. Character only, no text,
high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, chibi.
```
📋 붙여넣기 ↓ — **② 디제잉(DJ) — 소품 없음 · 저장: `sori_dj.png`**
```
Using the attached reference sheet, draw the SAME woman 이소리 (identical glamorous face/hair/figure/outfit) in
a classic DJ pose but WITHOUT any equipment: ONE hand reaching down and flat as if scratching an invisible
turntable disc (empty hand, disc will be composited later), the OTHER hand pressing one ear cup of her
silver/white on-ear headphones to her ear, cool focused confident expression, leaning slightly into the beat.
NO turntable, NO record, NO gear drawn — only the character and her hand positions. Thin clean anime linework
matching the sheet. Output a PNG with a FULLY TRANSPARENT background (alpha) — no white, no shadow, no rim light
on hair. Character only, no text, high-detail hands. Avoid: text, watermark, white background, extra fingers,
deformed hands, any equipment or props.
```
📋 붙여넣기 ↓ — **③ 피아노 연주 — 소품 없음 · 저장: `sori_piano.png`**
```
Using the attached reference sheet, draw the SAME woman 이소리 (identical glamorous face/hair/figure/outfit)
in a PIANO-PLAYING pose but WITHOUT any piano: both hands held in front of her at waist height, fingers curved
and spread as if pressing invisible piano keys (keyboard will be composited later), gentle absorbed expression
as if enjoying the music, upper body view. NO piano, NO keyboard drawn — only the character and her hand
positions. Thin clean anime linework matching the sheet. Output a PNG with a FULLY TRANSPARENT background
(alpha) — no white, no shadow, no rim light on hair. Character only, no text, high-detail hands. Avoid: text,
watermark, white background, extra fingers, deformed hands, any instrument or props.
```
---
## §4. 소품/악세서리
→ **`IMAGE_GEN_RIGGING_ACCESSORIES.md`** 참조(헤드폰·LP/턴테이블·건반·마이크·고양이귀·손목밴드 등, 캐릭터와 무관하게 1회 제작해 모든 버전에 합성).
@@ -0,0 +1,208 @@
# IMAGE-GEN RIGGING · 이소리 · 원피스(단발) 베리에이션
> 이소리 **원피스 룩(민트 단발 + 화이트 손수건 헴 드레스)** 의 리깅 자산 요청서.
> **기본 세트(`..._SORI_BASE.md`)의 리깅 구조를 그대로 상속**한다(파츠 분해·표정 종류·제스처 동일). 변하는 건 의상뿐.
> **위 → 아래 순서대로** 코드블록을 붙여넣으면 된다(원하는 지점까지만 해도 됨). 먼저 **§0 베리에이션 시트**부터 만든다.
> 소품(헤드폰·LP·건반·마이크 등)은 **`IMAGE_GEN_RIGGING_ACCESSORIES.md`** 에서 따로 제작해 합성한다.
> 외형 기준: `BRAND_CHARACTERS.md`. 이 베리에이션은 **`Characters/00_sheets/sori_dress_sheet.png` 첨부**(§0에서 생성).
---
## ★ 원칙
1. **모든 이소리 베리에이션은 기본 세트와 동일한 구성**(파츠 분해·표정 종류·제스처)을 가진다. 변하는 건 의상/헤어뿐.
2. 파츠는 **관절 겹침 여백**을 두고 분리(회전 시 이음새가 안 벌어지게).
3. 표정 프레임은 **머리 파츠와 동일한 위치·크기·각도**로, 눈/입/눈썹만 변경(프레임 교체용).
4. **투명 배경(alpha) · 흰배경 금지 · 헤어 림라이트 금지 · 텍스트/로고 금지.**
5. **캐릭터 + 의상 외의 모든 물체(헤드폰 포함 착탈형·LP·턴테이블·건반·마이크 등)는 이 문서에서 그리지 않고 악세서리로 분리** →
제스처는 **소품 없이 손동작만**(빈 손 위치)으로 그려 나중에 합성.
*단, 캐릭터가 늘 착용한 은색 온이어 헤드폰은 시그니처이므로 파츠/포즈에 그대로 그린다(별도 착탈용 헤드폰은 악세서리에 따로 있음).*
## ▶ 사용 안내 (당신용 — 붙여넣지 말 것)
- **📋 코드블록만** AI에 붙여넣는다. 한글 설명은 사람용.
- **`저장:`** = 결과 파일명 힌트, **`첨부:`** = 함께 올릴 레퍼런스.
- **SET** 표기 블록 = 여러 프레임을 한 번에. 도구가 프레임 수를 제한하면 목록을 나눠 2번에 요청.
- 표정은 많을수록 좋음(브랜딩용). 아래 목록 외에 더 뽑아도 됨 — 같은 크롭 규칙만 지키면 프레임 교체로 재사용 가능.
### 파일명 규칙 (원피스 세트)
```
시트 : sori_dress_sheet
파츠 : sori_dress_rig_apose · sori_dress_part_head · sori_dress_part_torso · sori_dress_part_arm_r · sori_dress_part_arm_l
표정 : sori_dress_face_<name> (name = neutral, blink, talk, talk_wide, smile, laugh, positive, negative,
confused, wink, surprised, thinking, cool, love, shy, sad, pout, sleepy,
playful, determined …)
제스처 : sori_dress_wave · sori_dress_dj · sori_dress_piano (소품은 합성)
```
---
---
## §0. 베리에이션 시트 (먼저) · 첨부: `sori_sheet.png`
▶ 지침: 기본 시트(`sori_sheet.png`)를 첨부해 **얼굴 정체성·헤어·체형은 그대로 유지**하고 **의상만** 원피스로 교체한 새 레퍼런스 시트를 만든다. 이후 §1~§3은 이 시트(`sori_dress_sheet.png`)를 첨부한다.
📋 붙여넣기 ↓ — **① 원피스 베리에이션 레퍼런스 시트 · 저장: `sori_dress_sheet.png`**
```
Using the attached reference sheet, keep the EXACT SAME woman 이소리 — same face identity, mint/teal bob hair,
brown eyes, East-Asian face, bright confident look, GLAMOROUS adult hourglass upper body (tasteful, not
revealing) — and change ONLY the outfit to a short white handkerchief-hem dress (asymmetric pointed skirt hem),
chic club-lookbook mood, subtle mint neon accents, silver/white on-ear headphones. Produce a CHARACTER
REFERENCE SHEET: full-body turnaround (front / three-quarter / side) plus 6 face expressions (neutral, smile,
laugh, focused, wink, surprised). Thin clean anime semi-real linework, flat even lighting. Output a PNG with a
FULLY TRANSPARENT background (alpha) — no white, no shadow, no rim light / glowing outline on hair. Character
only, no text, no logo. Avoid: text, watermark, white/opaque background, chibi, child, deformed hands.
```
---
## §1. 기본 리깅 파츠 · 첨부: `sori_dress_sheet.png`
📋 붙여넣기 ↓ — **① A-포즈 리깅 베이스 · 저장: `sori_dress_rig_apose.png`**
```
Using the attached reference sheet, draw the SAME woman 이소리 (mint/teal bob hair, brown eyes, East-Asian
face, bright confident look, GLAMOROUS adult hourglass upper body — tasteful, not revealing; a short white
handkerchief-hem dress (asymmetric pointed skirt hem), chic club-lookbook mood, subtle mint neon accents,
silver/white on-ear headphones) in a full-body NEUTRAL RIGGING A-POSE: standing straight, front view, arms
slightly away from the torso, elbows soft, palms open facing forward, legs together, symmetrical, head level.
Thin clean anime semi-real linework matching the sheet, flat even lighting. Output a PNG with a FULLY
TRANSPARENT background (alpha) — no white, no backdrop, no ground shadow, no rim light / glowing outline on
hair. Character only, no text, no logo. Avoid: text, watermark, white/opaque background, chibi, child, extra
fingers, deformed hands.
```
📋 붙여넣기 ↓ — **② 머리 파츠 · 저장: `sori_dress_part_head.png`**
```
Using the attached reference sheet, output ONLY the HEAD of the SAME woman 이소리 (mint/teal bob hair, brown
eyes, East-Asian face, gentle confident smile, silver/white on-ear headphones), including hair and headphones,
front view, head level, cleanly isolated at the neck with a small overlap margin below the chin for rigging.
Thin clean anime linework matching the sheet. Output a PNG with a FULLY TRANSPARENT background (alpha) — no
white, no shadow, no rim light / glowing outline on hair. Head only, no text, no logo. Avoid: text, watermark,
thick outlines, white background, deformed face.
```
📋 붙여넣기 ↓ — **③ 몸통 파츠 · 저장: `sori_dress_part_torso.png`**
```
Using the attached reference sheet, output ONLY the TORSO of the SAME woman 이소리 (glamorous hourglass upper
body, a short white handkerchief-hem dress (asymmetric pointed skirt hem), chic club-lookbook mood, subtle mint
neon accents), NO head and NO arms, front view, cleanly isolated with a small overlap margin at the neck and both
shoulders for rigging. Thin clean anime linework matching the sheet. Output a PNG with a FULLY TRANSPARENT
background (alpha) — no white, no shadow. Torso only, no text, no logo. Avoid: text, watermark, white background,
deformed anatomy.
```
📋 붙여넣기 ↓ — **④ 오른팔 파츠 · 저장: `sori_dress_part_arm_r.png`**
```
Using the attached reference sheet, output ONLY the character's RIGHT arm+hand of the SAME woman 이소리, relaxed
and slightly bent, palm open, cleanly isolated with a small overlap margin at the shoulder for rigging. Thin
clean anime linework matching the sheet. Output a PNG with a FULLY TRANSPARENT background (alpha) — no white, no
shadow. Arm only, no text. Avoid: text, watermark, white background, extra fingers, deformed hands.
```
📋 붙여넣기 ↓ — **⑤ 왼팔 파츠 · 저장: `sori_dress_part_arm_l.png`**
```
Using the attached reference sheet, output ONLY the character's LEFT arm+hand of the SAME woman 이소리, relaxed
and slightly bent, palm open, cleanly isolated with a small overlap margin at the shoulder for rigging. Thin
clean anime linework matching the sheet. Output a PNG with a FULLY TRANSPARENT background (alpha) — no white, no
shadow. Arm only, no text. Avoid: text, watermark, white background, extra fingers, deformed hands.
```
---
## §2. 표정 프레임 (SET) · 첨부: `sori_dress_sheet.png` + `sori_dress_part_head.png`
▶ 지침: **머리 파츠와 완전히 같은 위치·크기·각도**로 눈/입/눈썹만 바꾼다. 3개 SET로 나눠 요청(도구 프레임 제한 대응). 더 만들면 좋음.
- 애니메이션 필수: neutral·blink·talk (·talk_wide) — 반드시 정합 일치.
- 신호용: positive(끄덕/긍정)·negative(저음/부정)·confused(갸웃/오류).
📋 붙여넣기 ↓ — **표정 SET A (핵심 6) · 저장: `sori_dress_face_neutral/_blink/_talk/_talk_wide/_smile/_positive.png`**
```
Using the attached head reference, create expression frames of the SAME woman 이소리's head (mint bob, brown
eyes, silver/white on-ear headphones). Produce 6 SEPARATE images with the head in the EXACT SAME position, size,
crop and angle as the attached head — change ONLY eyes, mouth and eyebrows:
(1) neutral: eyes open, mouth closed, gentle confident smile;
(2) blink: eyes closed, mouth closed;
(3) talk: eyes open, mouth slightly open mid-speech;
(4) talk_wide: eyes open, mouth wide open (emphatic speech);
(5) smile: eyes happy, warm open smile;
(6) positive: bright excited eager look, raised cheeks (nod / yes feeling).
Keep the EXACT same face identity and framing across all frames. Thin clean anime linework matching the sheet.
Output PNGs with a FULLY TRANSPARENT background (alpha) — no white, no rim light on hair. Head only, no text.
Avoid: text, watermark, inconsistent framing, white background, deformed face.
```
📋 붙여넣기 ↓ — **표정 SET B (신호·리액션 6) · 저장: `sori_dress_face_negative/_confused/_wink/_surprised/_laugh/_thinking.png`**
```
Using the attached head reference, create MORE expression frames of the SAME woman 이소리's head, EXACT SAME
position/size/crop/angle as the attached head — change ONLY eyes, mouth and eyebrows:
(1) negative: slightly downturned brows and mouth, gentle "no" head-shake feeling;
(2) confused: one eyebrow raised, small uncertain mouth, puzzled tilted "?" look;
(3) wink: one eye winking, playful smile;
(4) surprised: wide eyes, small open "oh!" mouth, raised brows;
(5) laugh: eyes closed happy arcs, big open laughing smile;
(6) thinking: eyes glancing up, one brow up, lips pursed "hmm".
Keep the EXACT same face identity and framing. Thin clean anime linework matching the sheet. Output PNGs with a
FULLY TRANSPARENT background (alpha) — no white, no rim light on hair. Head only, no text. Avoid: text,
watermark, inconsistent framing, white background, deformed face.
```
📋 붙여넣기 ↓ — **표정 SET C (브랜딩 이모트 6) · 저장: `sori_dress_face_cool/_love/_shy/_sad/_pout/_sleepy.png`**
```
Using the attached head reference, create BRANDING EMOTE expression frames of the SAME woman 이소리's head, EXACT
SAME position/size/crop/angle as the attached head — change ONLY eyes, mouth and eyebrows (add small comic
accents like blush or sparkle only where noted, no extra props):
(1) cool: half-lidded confident look, tiny smirk;
(2) love: heart-shaped sparkling eyes, soft happy smile (comic heart eyes);
(3) shy: slight blush on cheeks, bashful small smile, eyes glancing away;
(4) sad: teary downturned eyes, small frown;
(5) pout: puffed cheeks, sulky pout, brows slightly furrowed;
(6) sleepy: droopy half-closed eyes, small yawn.
Keep the EXACT same face identity and framing. Thin clean anime linework matching the sheet. Output PNGs with a
FULLY TRANSPARENT background (alpha) — no white, no rim light on hair. Head only, no text. Avoid: text,
watermark, inconsistent framing, white background, deformed face.
```
▶ (선택) 더 확장할 이모트 후보: determined(결의), starstruck(반짝 감탄), playful_tongue(메롱), relieved(안도),
proud(뿌듯), crying_comic(폭풍눈물), angry(발끈). 필요 시 위 SET 형식(같은 크롭) 그대로 추가.
---
## §3. 제스처 포즈 (소품 없이 손동작만) · 첨부: `sori_dress_sheet.png`
▶ 지침: LP·턴테이블·건반 등 **소품은 그리지 않는다**(악세서리로 합성). 손은 소품을 쓰는 위치로만. 헤드폰은 착용 상태 유지.
- 끄덕/저음/갸웃/호흡/간단한 손흔듦은 §1 파츠 + §2 표정을 **코드 애니**로 구현(이미지 불필요).
📋 붙여넣기 ↓ — **① 손 흔들기(웨이브) · 저장: `sori_dress_wave.png`**
```
Using the attached reference sheet, draw the SAME woman 이소리 (identical glamorous face/hair/figure/outfit,
silver/white on-ear headphones), waist-up, one hand raised beside her head in a friendly WAVE, open palm,
bright cheerful smile, other hand relaxed. Thin clean anime linework matching the sheet. Output a PNG with a
FULLY TRANSPARENT background (alpha) — no white, no shadow, no rim light on hair. Character only, no text,
high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, chibi.
```
📋 붙여넣기 ↓ — **② 디제잉(DJ) — 소품 없음 · 저장: `sori_dress_dj.png`**
```
Using the attached reference sheet, draw the SAME woman 이소리 (identical glamorous face/hair/figure/outfit) in
a classic DJ pose but WITHOUT any equipment: ONE hand reaching down and flat as if scratching an invisible
turntable disc (empty hand, disc will be composited later), the OTHER hand pressing one ear cup of her
silver/white on-ear headphones to her ear, cool focused confident expression, leaning slightly into the beat.
NO turntable, NO record, NO gear drawn — only the character and her hand positions. Thin clean anime linework
matching the sheet. Output a PNG with a FULLY TRANSPARENT background (alpha) — no white, no shadow, no rim light
on hair. Character only, no text, high-detail hands. Avoid: text, watermark, white background, extra fingers,
deformed hands, any equipment or props.
```
📋 붙여넣기 ↓ — **③ 피아노 연주 — 소품 없음 · 저장: `sori_dress_piano.png`**
```
Using the attached reference sheet, draw the SAME woman 이소리 (identical glamorous face/hair/figure/outfit)
in a PIANO-PLAYING pose but WITHOUT any piano: both hands held in front of her at waist height, fingers curved
and spread as if pressing invisible piano keys (keyboard will be composited later), gentle absorbed expression
as if enjoying the music, upper body view. NO piano, NO keyboard drawn — only the character and her hand
positions. Thin clean anime linework matching the sheet. Output a PNG with a FULLY TRANSPARENT background
(alpha) — no white, no shadow, no rim light on hair. Character only, no text, high-detail hands. Avoid: text,
watermark, white background, extra fingers, deformed hands, any instrument or props.
```
---
## §4. 소품/악세서리
→ **`IMAGE_GEN_RIGGING_ACCESSORIES.md`** 참조(헤드폰·LP/턴테이블·건반·마이크·고양이귀·손목밴드 등, 캐릭터와 무관하게 1회 제작해 모든 버전에 합성).
@@ -0,0 +1,211 @@
# IMAGE-GEN RIGGING · 이소리 · 원피스(긴 생머리) 베리에이션
> 이소리 **원피스 룩(긴 생머리 + 화이트 핸드커치프 헴 드레스)** 의 리깅 자산 요청서.
> 이 파일은 **기본 세트(BASE)의 리깅 구조를 그대로 상속**한다(파츠 분해·표정 종류·제스처 동일). 변하는 건 **헤어(긴 생머리)와 의상(원피스)뿐**.
> **위 → 아래 순서대로** 코드블록을 붙여넣으면 된다(원하는 지점까지만 해도 됨). **§0 베리에이션 시트를 가장 먼저** 만든다.
> 소품(헤드폰·LP·건반·마이크 등)은 **`IMAGE_GEN_RIGGING_ACCESSORIES.md`** 에서 따로 제작해 합성한다.
> 외형 기준: `BRAND_CHARACTERS.md`. §0에서 만든 **`Characters/00_sheets/sori_dressL_sheet.png` 첨부**.
---
## ★ 원칙
1. **모든 이소리 베리에이션은 기본 세트와 동일한 구성**(파츠 분해·표정 종류·제스처)을 가진다. 변하는 건 의상/헤어뿐.
2. 파츠는 **관절 겹침 여백**을 두고 분리(회전 시 이음새가 안 벌어지게).
3. 표정 프레임은 **머리 파츠와 동일한 위치·크기·각도**로, 눈/입/눈썹만 변경(프레임 교체용).
4. **투명 배경(alpha) · 흰배경 금지 · 헤어 림라이트 금지 · 텍스트/로고 금지.**
5. **캐릭터 + 의상 외의 모든 물체(헤드폰 포함 착탈형·LP·턴테이블·건반·마이크 등)는 이 문서에서 그리지 않고 악세서리로 분리** →
제스처는 **소품 없이 손동작만**(빈 손 위치)으로 그려 나중에 합성.
*단, 캐릭터가 늘 착용한 은색 온이어 헤드폰은 시그니처이므로 파츠/포즈에 그대로 그린다(별도 착탈용 헤드폰은 악세서리에 따로 있음).*
## ▶ 사용 안내 (당신용 — 붙여넣지 말 것)
- **📋 코드블록만** AI에 붙여넣는다. 한글 설명은 사람용.
- **`저장:`** = 결과 파일명 힌트, **`첨부:`** = 함께 올릴 레퍼런스.
- **SET** 표기 블록 = 여러 프레임을 한 번에. 도구가 프레임 수를 제한하면 목록을 나눠 2번에 요청.
- 표정은 많을수록 좋음(브랜딩용). 아래 목록 외에 더 뽑아도 됨 — 같은 크롭 규칙만 지키면 프레임 교체로 재사용 가능.
### 파일명 규칙 (원피스 긴 생머리 베리에이션)
```
시트 : sori_dressL_sheet
파츠 : sori_dressL_rig_apose · sori_dressL_part_head · sori_dressL_part_torso · sori_dressL_part_arm_r · sori_dressL_part_arm_l
표정 : sori_dressL_face_<name> (name = neutral, blink, talk, talk_wide, smile, laugh, positive, negative,
confused, wink, surprised, thinking, cool, love, shy, sad, pout, sleepy,
playful, determined …)
제스처 : sori_dressL_wave · sori_dressL_dj · sori_dressL_piano (소품은 합성)
```
---
---
## §0. 베리에이션 시트 (먼저) · 첨부: `sori_sheet.png`
▶ 지침: 기본 시트(`sori_sheet.png`)를 레퍼런스로 올려 **동일 인물 이소리**를 유지한 채 **헤어를 긴 생머리로, 의상을 원피스로만** 바꾼 새 캐릭터 시트를 먼저 만든다. 이후 모든 §1~§3 요청은 여기서 나온 `sori_dressL_sheet.png` 를 첨부한다.
📋 붙여넣기 ↓ — **베리에이션 레퍼런스 시트 · 저장: `sori_dressL_sheet.png`**
```
Using the attached reference sheet, draw the SAME woman 이소리 — keep the EXACT same face identity, the same
mint/teal hair COLOR, brown eyes, East-Asian face, bright confident look, and the same GLAMOROUS adult
hourglass upper body (tasteful, not revealing) — but CHANGE the hair to long straight mint/teal hair past the
shoulders, AND CHANGE the outfit to a short white handkerchief-hem dress (asymmetric pointed skirt hem), chic
club-lookbook mood, subtle mint neon accents, silver/white on-ear headphones. Produce a CHARACTER REFERENCE
SHEET: full-body turnaround (front / three-quarter / side) plus 6 face expressions (neutral, smile, laugh,
focused, wink, surprised). Thin clean anime semi-real linework, flat even lighting. Output a PNG with a FULLY
TRANSPARENT background (alpha) — no white, no backdrop, no ground shadow, no rim light / glowing outline on
hair. Character only, no text, no logo. Avoid: text, watermark, white/opaque background, chibi, child, extra
fingers, deformed hands.
```
---
## §1. 기본 리깅 파츠 · 첨부: `sori_dressL_sheet.png`
📋 붙여넣기 ↓ — **① A-포즈 리깅 베이스 · 저장: `sori_dressL_rig_apose.png`**
```
Using the attached reference sheet, draw the SAME woman 이소리 (long straight mint/teal hair past the shoulders,
brown eyes, East-Asian face, bright confident look, GLAMOROUS adult hourglass upper body — tasteful, not
revealing; a short white handkerchief-hem dress (asymmetric pointed skirt hem), chic club-lookbook mood, subtle
mint neon accents, silver/white on-ear headphones) in a full-body NEUTRAL RIGGING A-POSE: standing straight,
front view, arms slightly away from the torso, elbows soft, palms open facing forward, legs together,
symmetrical, head level. Thin clean anime semi-real linework matching the sheet, flat even lighting. Output a
PNG with a FULLY TRANSPARENT background (alpha) — no white, no backdrop, no ground shadow, no rim light /
glowing outline on hair. Character only, no text, no logo. Avoid: text, watermark, white/opaque background,
chibi, child, extra fingers, deformed hands.
```
📋 붙여넣기 ↓ — **② 머리 파츠 · 저장: `sori_dressL_part_head.png`**
```
Using the attached reference sheet, output ONLY the HEAD of the SAME woman 이소리 (long straight mint/teal hair
past the shoulders, brown eyes, East-Asian face, gentle confident smile, silver/white on-ear headphones),
including hair and headphones, front view, head level, cleanly isolated at the neck with a small overlap margin
below the chin for rigging. Thin clean anime linework matching the sheet. Output a PNG with a FULLY TRANSPARENT
background (alpha) — no white, no shadow, no rim light / glowing outline on hair. Head only, no text, no logo.
Avoid: text, watermark, thick outlines, white background, deformed face.
```
📋 붙여넣기 ↓ — **③ 몸통 파츠 · 저장: `sori_dressL_part_torso.png`**
```
Using the attached reference sheet, output ONLY the TORSO of the SAME woman 이소리 (glamorous hourglass upper
body, a short white handkerchief-hem dress (asymmetric pointed skirt hem), chic club-lookbook mood, subtle mint
neon accents), NO head and NO arms, front view, cleanly isolated with a small overlap margin at the neck and
both shoulders for rigging. Thin clean anime linework matching the sheet. Output a PNG with a FULLY TRANSPARENT
background (alpha) — no white, no shadow. Torso only, no text, no logo. Avoid: text, watermark, white
background, deformed anatomy.
```
📋 붙여넣기 ↓ — **④ 오른팔 파츠 · 저장: `sori_dressL_part_arm_r.png`**
```
Using the attached reference sheet, output ONLY the character's RIGHT arm+hand of the SAME woman 이소리, relaxed
and slightly bent, palm open, cleanly isolated with a small overlap margin at the shoulder for rigging. Thin
clean anime linework matching the sheet. Output a PNG with a FULLY TRANSPARENT background (alpha) — no white, no
shadow. Arm only, no text. Avoid: text, watermark, white background, extra fingers, deformed hands.
```
📋 붙여넣기 ↓ — **⑤ 왼팔 파츠 · 저장: `sori_dressL_part_arm_l.png`**
```
Using the attached reference sheet, output ONLY the character's LEFT arm+hand of the SAME woman 이소리, relaxed
and slightly bent, palm open, cleanly isolated with a small overlap margin at the shoulder for rigging. Thin
clean anime linework matching the sheet. Output a PNG with a FULLY TRANSPARENT background (alpha) — no white, no
shadow. Arm only, no text. Avoid: text, watermark, white background, extra fingers, deformed hands.
```
---
## §2. 표정 프레임 (SET) · 첨부: `sori_dressL_sheet.png` + `sori_dressL_part_head.png`
▶ 지침: **머리 파츠와 완전히 같은 위치·크기·각도**로 눈/입/눈썹만 바꾼다. 3개 SET로 나눠 요청(도구 프레임 제한 대응). 더 만들면 좋음.
- 애니메이션 필수: neutral·blink·talk (·talk_wide) — 반드시 정합 일치.
- 신호용: positive(끄덕/긍정)·negative(저음/부정)·confused(갸웃/오류).
📋 붙여넣기 ↓ — **표정 SET A (핵심 6) · 저장: `sori_dressL_face_neutral/_blink/_talk/_talk_wide/_smile/_positive.png`**
```
Using the attached head reference, create expression frames of the SAME woman 이소리's head (long straight
mint/teal hair past the shoulders, brown eyes, silver/white on-ear headphones). Produce 6 SEPARATE images with
the head in the EXACT SAME position, size, crop and angle as the attached head — change ONLY eyes, mouth and
eyebrows:
(1) neutral: eyes open, mouth closed, gentle confident smile;
(2) blink: eyes closed, mouth closed;
(3) talk: eyes open, mouth slightly open mid-speech;
(4) talk_wide: eyes open, mouth wide open (emphatic speech);
(5) smile: eyes happy, warm open smile;
(6) positive: bright excited eager look, raised cheeks (nod / yes feeling).
Keep the EXACT same face identity and framing across all frames. Thin clean anime linework matching the sheet.
Output PNGs with a FULLY TRANSPARENT background (alpha) — no white, no rim light on hair. Head only, no text.
Avoid: text, watermark, inconsistent framing, white background, deformed face.
```
📋 붙여넣기 ↓ — **표정 SET B (신호·리액션 6) · 저장: `sori_dressL_face_negative/_confused/_wink/_surprised/_laugh/_thinking.png`**
```
Using the attached head reference, create MORE expression frames of the SAME woman 이소리's head, EXACT SAME
position/size/crop/angle as the attached head — change ONLY eyes, mouth and eyebrows:
(1) negative: slightly downturned brows and mouth, gentle "no" head-shake feeling;
(2) confused: one eyebrow raised, small uncertain mouth, puzzled tilted "?" look;
(3) wink: one eye winking, playful smile;
(4) surprised: wide eyes, small open "oh!" mouth, raised brows;
(5) laugh: eyes closed happy arcs, big open laughing smile;
(6) thinking: eyes glancing up, one brow up, lips pursed "hmm".
Keep the EXACT same face identity and framing. Thin clean anime linework matching the sheet. Output PNGs with a
FULLY TRANSPARENT background (alpha) — no white, no rim light on hair. Head only, no text. Avoid: text,
watermark, inconsistent framing, white background, deformed face.
```
📋 붙여넣기 ↓ — **표정 SET C (브랜딩 이모트 6) · 저장: `sori_dressL_face_cool/_love/_shy/_sad/_pout/_sleepy.png`**
```
Using the attached head reference, create BRANDING EMOTE expression frames of the SAME woman 이소리's head, EXACT
SAME position/size/crop/angle as the attached head — change ONLY eyes, mouth and eyebrows (add small comic
accents like blush or sparkle only where noted, no extra props):
(1) cool: half-lidded confident look, tiny smirk;
(2) love: heart-shaped sparkling eyes, soft happy smile (comic heart eyes);
(3) shy: slight blush on cheeks, bashful small smile, eyes glancing away;
(4) sad: teary downturned eyes, small frown;
(5) pout: puffed cheeks, sulky pout, brows slightly furrowed;
(6) sleepy: droopy half-closed eyes, small yawn.
Keep the EXACT same face identity and framing. Thin clean anime linework matching the sheet. Output PNGs with a
FULLY TRANSPARENT background (alpha) — no white, no rim light on hair. Head only, no text. Avoid: text,
watermark, inconsistent framing, white background, deformed face.
```
▶ (선택) 더 확장할 이모트 후보: determined(결의), starstruck(반짝 감탄), playful_tongue(메롱), relieved(안도),
proud(뿌듯), crying_comic(폭풍눈물), angry(발끈). 필요 시 위 SET 형식(같은 크롭) 그대로 추가.
---
## §3. 제스처 포즈 (소품 없이 손동작만) · 첨부: `sori_dressL_sheet.png`
▶ 지침: LP·턴테이블·건반 등 **소품은 그리지 않는다**(악세서리로 합성). 손은 소품을 쓰는 위치로만. 헤드폰은 착용 상태 유지.
- 끄덕/저음/갸웃/호흡/간단한 손흔듦은 §1 파츠 + §2 표정을 **코드 애니**로 구현(이미지 불필요).
📋 붙여넣기 ↓ — **① 손 흔들기(웨이브) · 저장: `sori_dressL_wave.png`**
```
Using the attached reference sheet, draw the SAME woman 이소리 (identical glamorous face/hair/figure/outfit,
silver/white on-ear headphones), waist-up, one hand raised beside her head in a friendly WAVE, open palm,
bright cheerful smile, other hand relaxed. Thin clean anime linework matching the sheet. Output a PNG with a
FULLY TRANSPARENT background (alpha) — no white, no shadow, no rim light on hair. Character only, no text,
high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, chibi.
```
📋 붙여넣기 ↓ — **② 디제잉(DJ) — 소품 없음 · 저장: `sori_dressL_dj.png`**
```
Using the attached reference sheet, draw the SAME woman 이소리 (identical glamorous face/hair/figure/outfit) in
a classic DJ pose but WITHOUT any equipment: ONE hand reaching down and flat as if scratching an invisible
turntable disc (empty hand, disc will be composited later), the OTHER hand pressing one ear cup of her
silver/white on-ear headphones to her ear, cool focused confident expression, leaning slightly into the beat.
NO turntable, NO record, NO gear drawn — only the character and her hand positions. Thin clean anime linework
matching the sheet. Output a PNG with a FULLY TRANSPARENT background (alpha) — no white, no shadow, no rim light
on hair. Character only, no text, high-detail hands. Avoid: text, watermark, white background, extra fingers,
deformed hands, any equipment or props.
```
📋 붙여넣기 ↓ — **③ 피아노 연주 — 소품 없음 · 저장: `sori_dressL_piano.png`**
```
Using the attached reference sheet, draw the SAME woman 이소리 (identical glamorous face/hair/figure/outfit)
in a PIANO-PLAYING pose but WITHOUT any piano: both hands held in front of her at waist height, fingers curved
and spread as if pressing invisible piano keys (keyboard will be composited later), gentle absorbed expression
as if enjoying the music, upper body view. NO piano, NO keyboard drawn — only the character and her hand
positions. Thin clean anime linework matching the sheet. Output a PNG with a FULLY TRANSPARENT background
(alpha) — no white, no shadow, no rim light on hair. Character only, no text, high-detail hands. Avoid: text,
watermark, white background, extra fingers, deformed hands, any instrument or props.
```
---
## §4. 소품/악세서리
→ **`IMAGE_GEN_RIGGING_ACCESSORIES.md`** 참조(헤드폰·LP/턴테이블·건반·마이크·고양이귀·손목밴드 등, 캐릭터와 무관하게 1회 제작해 모든 버전에 합성).
+209
View File
@@ -0,0 +1,209 @@
# IMAGE-GEN RIGGING · 이소리 · 청바지 베리에이션
> 이소리 **청바지 룩(스키니 데님 + 화이트 크롭 티)** 의 리깅 자산 요청서.
> 이 문서는 **기본 세트(BASE)의 리깅 구조를 그대로 상속**한다(파츠 분해·표정 종류·제스처 동일). 변하는 건 의상뿐.
> **위 → 아래 순서대로** 코드블록을 붙여넣으면 된다(원하는 지점까지만 해도 됨).
> 다른 베리에이션은 별도 파일: `..._SORI_DRESS_BOB.md` · `..._SORI_DRESS_LONG.md` · `..._SORI_BASE.md`.
> 소품(헤드폰·LP·건반·마이크 등)은 **`IMAGE_GEN_RIGGING_ACCESSORIES.md`** 에서 따로 제작해 합성한다.
> 외형 기준: `BRAND_CHARACTERS.md`. 이 베리에이션은 **먼저 §0에서 `sori_jeans_sheet.png` 를 만든 뒤, 그 시트를 첨부**한다.
---
## ★ 원칙
1. **모든 이소리 베리에이션은 이 기본 세트와 동일한 구성**(파츠 분해·표정 종류·제스처)을 가진다. 변하는 건 의상/헤어뿐.
2. 파츠는 **관절 겹침 여백**을 두고 분리(회전 시 이음새가 안 벌어지게).
3. 표정 프레임은 **머리 파츠와 동일한 위치·크기·각도**로, 눈/입/눈썹만 변경(프레임 교체용).
4. **투명 배경(alpha) · 흰배경 금지 · 헤어 림라이트 금지 · 텍스트/로고 금지.**
5. **캐릭터 + 의상 외의 모든 물체(헤드폰 포함 착탈형·LP·턴테이블·건반·마이크 등)는 이 문서에서 그리지 않고 악세서리로 분리** →
제스처는 **소품 없이 손동작만**(빈 손 위치)으로 그려 나중에 합성.
*단, 캐릭터가 늘 착용한 은색 온이어 헤드폰은 시그니처이므로 파츠/포즈에 그대로 그린다(별도 착탈용 헤드폰은 악세서리에 따로 있음).*
## ▶ 사용 안내 (당신용 — 붙여넣지 말 것)
- **📋 코드블록만** AI에 붙여넣는다. 한글 설명은 사람용.
- **`저장:`** = 결과 파일명 힌트, **`첨부:`** = 함께 올릴 레퍼런스.
- **SET** 표기 블록 = 여러 프레임을 한 번에. 도구가 프레임 수를 제한하면 목록을 나눠 2번에 요청.
- 표정은 많을수록 좋음(브랜딩용). 아래 목록 외에 더 뽑아도 됨 — 같은 크롭 규칙만 지키면 프레임 교체로 재사용 가능.
### 파일명 규칙 (청바지 베리에이션)
```
시트 : sori_jeans_sheet
파츠 : sori_jeans_rig_apose · sori_jeans_part_head · sori_jeans_part_torso · sori_jeans_part_arm_r · sori_jeans_part_arm_l
표정 : sori_jeans_face_<name> (name = neutral, blink, talk, talk_wide, smile, laugh, positive, negative,
confused, wink, surprised, thinking, cool, love, shy, sad, pout, sleepy,
playful, determined …)
제스처 : sori_jeans_wave · sori_jeans_dj · sori_jeans_piano (소품은 합성)
```
---
---
## §0. 베리에이션 시트 (먼저) · 첨부: `sori_sheet.png`
▶ 지침: 기본 시트(`sori_sheet.png`)를 첨부해 **동일 인물 이소리**를 유지하되 **의상만 청바지 룩으로** 교체한 새 레퍼런스 시트를 만든다. 이후 모든 §1~§3 블록은 여기서 만든 `sori_jeans_sheet.png` 를 첨부한다.
📋 붙여넣기 ↓ — **베리에이션 레퍼런스 시트 · 저장: `sori_jeans_sheet.png`**
```
Using the attached reference sheet, keep the EXACT SAME woman 이소리 — same face identity, mint/teal BOB hair,
brown eyes, East-Asian face, bright confident look, GLAMOROUS adult hourglass upper body (tasteful, not
revealing) — and change ONLY the outfit to skinny blue denim jeans + a white cropped T-shirt, casual-chic look,
subtle mint neon accents, silver/white on-ear headphones. Produce a CHARACTER REFERENCE SHEET: full-body
turnaround (front / three-quarter / side) plus 6 face expressions (neutral, smile, laugh, focused, wink,
surprised). Thin clean anime semi-real linework matching the sheet, flat even lighting. Output a PNG with a
FULLY TRANSPARENT background (alpha) — no white, no shadow, no rim light / glowing outline on hair. Character
only, no text, no logo. Avoid: text, watermark, white/opaque background, chibi, child, deformed hands.
```
---
## §1. 기본 리깅 파츠 · 첨부: `sori_jeans_sheet.png`
📋 붙여넣기 ↓ — **① A-포즈 리깅 베이스 · 저장: `sori_jeans_rig_apose.png`**
```
Using the attached reference sheet, draw the SAME woman 이소리 (mint/teal bob hair, brown eyes, East-Asian
face, bright confident look, GLAMOROUS adult hourglass upper body — tasteful, not revealing; skinny blue denim
jeans + a white cropped T-shirt, casual-chic look, subtle mint neon accents, silver/white on-ear headphones) in
a full-body NEUTRAL RIGGING A-POSE: standing straight, front view, arms slightly away from the torso, elbows
soft, palms open facing forward, legs together, symmetrical, head level. Thin clean anime semi-real linework
matching the sheet, flat even lighting. Output a PNG with a FULLY TRANSPARENT background (alpha) — no white, no
backdrop, no ground shadow, no rim light / glowing outline on hair. Character only, no text, no logo. Avoid:
text, watermark, white/opaque background, chibi, child, extra fingers, deformed hands.
```
📋 붙여넣기 ↓ — **② 머리 파츠 · 저장: `sori_jeans_part_head.png`**
```
Using the attached reference sheet, output ONLY the HEAD of the SAME woman 이소리 (mint/teal bob hair, brown
eyes, East-Asian face, gentle confident smile, silver/white on-ear headphones), including hair and headphones,
front view, head level, cleanly isolated at the neck with a small overlap margin below the chin for rigging.
Thin clean anime linework matching the sheet. Output a PNG with a FULLY TRANSPARENT background (alpha) — no
white, no shadow, no rim light / glowing outline on hair. Head only, no text, no logo. Avoid: text, watermark,
thick outlines, white background, deformed face.
```
📋 붙여넣기 ↓ — **③ 몸통 파츠 · 저장: `sori_jeans_part_torso.png`**
```
Using the attached reference sheet, output ONLY the TORSO of the SAME woman 이소리 (glamorous hourglass upper
body, skinny blue denim jeans + a white cropped T-shirt, casual-chic look, subtle mint neon accents), NO head
and NO arms, front view, cleanly isolated with a small overlap margin at the neck and both shoulders for
rigging. Thin clean anime linework matching the sheet. Output a PNG with a FULLY TRANSPARENT background (alpha)
— no white, no shadow. Torso only, no text, no logo. Avoid: text, watermark, white background, deformed anatomy.
```
📋 붙여넣기 ↓ — **④ 오른팔 파츠 · 저장: `sori_jeans_part_arm_r.png`**
```
Using the attached reference sheet, output ONLY the character's RIGHT arm+hand (with white T-shirt sleeve) of
the SAME woman 이소리, relaxed and slightly bent, palm open, cleanly isolated with a small overlap margin at the
shoulder for rigging. Thin clean anime linework matching the sheet. Output a PNG with a FULLY TRANSPARENT
background (alpha) — no white, no shadow. Arm only, no text. Avoid: text, watermark, white background, extra
fingers, deformed hands.
```
📋 붙여넣기 ↓ — **⑤ 왼팔 파츠 · 저장: `sori_jeans_part_arm_l.png`**
```
Using the attached reference sheet, output ONLY the character's LEFT arm+hand (with white T-shirt sleeve) of the
SAME woman 이소리, relaxed and slightly bent, palm open, cleanly isolated with a small overlap margin at the
shoulder for rigging. Thin clean anime linework matching the sheet. Output a PNG with a FULLY TRANSPARENT
background (alpha) — no white, no shadow. Arm only, no text. Avoid: text, watermark, white background, extra
fingers, deformed hands.
```
---
## §2. 표정 프레임 (SET) · 첨부: `sori_jeans_sheet.png` + `sori_jeans_part_head.png`
▶ 지침: **머리 파츠와 완전히 같은 위치·크기·각도**로 눈/입/눈썹만 바꾼다. 3개 SET로 나눠 요청(도구 프레임 제한 대응). 더 만들면 좋음.
- 애니메이션 필수: neutral·blink·talk (·talk_wide) — 반드시 정합 일치.
- 신호용: positive(끄덕/긍정)·negative(저음/부정)·confused(갸웃/오류).
📋 붙여넣기 ↓ — **표정 SET A (핵심 6) · 저장: `sori_jeans_face_neutral/_blink/_talk/_talk_wide/_smile/_positive.png`**
```
Using the attached head reference, create expression frames of the SAME woman 이소리's head (mint bob, brown
eyes, silver/white on-ear headphones). Produce 6 SEPARATE images with the head in the EXACT SAME position, size,
crop and angle as the attached head — change ONLY eyes, mouth and eyebrows:
(1) neutral: eyes open, mouth closed, gentle confident smile;
(2) blink: eyes closed, mouth closed;
(3) talk: eyes open, mouth slightly open mid-speech;
(4) talk_wide: eyes open, mouth wide open (emphatic speech);
(5) smile: eyes happy, warm open smile;
(6) positive: bright excited eager look, raised cheeks (nod / yes feeling).
Keep the EXACT same face identity and framing across all frames. Thin clean anime linework matching the sheet.
Output PNGs with a FULLY TRANSPARENT background (alpha) — no white, no rim light on hair. Head only, no text.
Avoid: text, watermark, inconsistent framing, white background, deformed face.
```
📋 붙여넣기 ↓ — **표정 SET B (신호·리액션 6) · 저장: `sori_jeans_face_negative/_confused/_wink/_surprised/_laugh/_thinking.png`**
```
Using the attached head reference, create MORE expression frames of the SAME woman 이소리's head, EXACT SAME
position/size/crop/angle as the attached head — change ONLY eyes, mouth and eyebrows:
(1) negative: slightly downturned brows and mouth, gentle "no" head-shake feeling;
(2) confused: one eyebrow raised, small uncertain mouth, puzzled tilted "?" look;
(3) wink: one eye winking, playful smile;
(4) surprised: wide eyes, small open "oh!" mouth, raised brows;
(5) laugh: eyes closed happy arcs, big open laughing smile;
(6) thinking: eyes glancing up, one brow up, lips pursed "hmm".
Keep the EXACT same face identity and framing. Thin clean anime linework matching the sheet. Output PNGs with a
FULLY TRANSPARENT background (alpha) — no white, no rim light on hair. Head only, no text. Avoid: text,
watermark, inconsistent framing, white background, deformed face.
```
📋 붙여넣기 ↓ — **표정 SET C (브랜딩 이모트 6) · 저장: `sori_jeans_face_cool/_love/_shy/_sad/_pout/_sleepy.png`**
```
Using the attached head reference, create BRANDING EMOTE expression frames of the SAME woman 이소리's head, EXACT
SAME position/size/crop/angle as the attached head — change ONLY eyes, mouth and eyebrows (add small comic
accents like blush or sparkle only where noted, no extra props):
(1) cool: half-lidded confident look, tiny smirk;
(2) love: heart-shaped sparkling eyes, soft happy smile (comic heart eyes);
(3) shy: slight blush on cheeks, bashful small smile, eyes glancing away;
(4) sad: teary downturned eyes, small frown;
(5) pout: puffed cheeks, sulky pout, brows slightly furrowed;
(6) sleepy: droopy half-closed eyes, small yawn.
Keep the EXACT same face identity and framing. Thin clean anime linework matching the sheet. Output PNGs with a
FULLY TRANSPARENT background (alpha) — no white, no rim light on hair. Head only, no text. Avoid: text,
watermark, inconsistent framing, white background, deformed face.
```
▶ (선택) 더 확장할 이모트 후보: determined(결의), starstruck(반짝 감탄), playful_tongue(메롱), relieved(안도),
proud(뿌듯), crying_comic(폭풍눈물), angry(발끈). 필요 시 위 SET 형식(같은 크롭) 그대로 추가.
---
## §3. 제스처 포즈 (소품 없이 손동작만) · 첨부: `sori_jeans_sheet.png`
▶ 지침: LP·턴테이블·건반 등 **소품은 그리지 않는다**(악세서리로 합성). 손은 소품을 쓰는 위치로만. 헤드폰은 착용 상태 유지.
- 끄덕/저음/갸웃/호흡/간단한 손흔듦은 §1 파츠 + §2 표정을 **코드 애니**로 구현(이미지 불필요).
📋 붙여넣기 ↓ — **① 손 흔들기(웨이브) · 저장: `sori_jeans_wave.png`**
```
Using the attached reference sheet, draw the SAME woman 이소리 (identical glamorous face/hair/figure/outfit,
silver/white on-ear headphones), waist-up, one hand raised beside her head in a friendly WAVE, open palm,
bright cheerful smile, other hand relaxed. Thin clean anime linework matching the sheet. Output a PNG with a
FULLY TRANSPARENT background (alpha) — no white, no shadow, no rim light on hair. Character only, no text,
high-detail hands. Avoid: text, watermark, white background, extra fingers, deformed hands, chibi.
```
📋 붙여넣기 ↓ — **② 디제잉(DJ) — 소품 없음 · 저장: `sori_jeans_dj.png`**
```
Using the attached reference sheet, draw the SAME woman 이소리 (identical glamorous face/hair/figure/outfit) in
a classic DJ pose but WITHOUT any equipment: ONE hand reaching down and flat as if scratching an invisible
turntable disc (empty hand, disc will be composited later), the OTHER hand pressing one ear cup of her
silver/white on-ear headphones to her ear, cool focused confident expression, leaning slightly into the beat.
NO turntable, NO record, NO gear drawn — only the character and her hand positions. Thin clean anime linework
matching the sheet. Output a PNG with a FULLY TRANSPARENT background (alpha) — no white, no shadow, no rim light
on hair. Character only, no text, high-detail hands. Avoid: text, watermark, white background, extra fingers,
deformed hands, any equipment or props.
```
📋 붙여넣기 ↓ — **③ 피아노 연주 — 소품 없음 · 저장: `sori_jeans_piano.png`**
```
Using the attached reference sheet, draw the SAME woman 이소리 (identical glamorous face/hair/figure/outfit)
in a PIANO-PLAYING pose but WITHOUT any piano: both hands held in front of her at waist height, fingers curved
and spread as if pressing invisible piano keys (keyboard will be composited later), gentle absorbed expression
as if enjoying the music, upper body view. NO piano, NO keyboard drawn — only the character and her hand
positions. Thin clean anime linework matching the sheet. Output a PNG with a FULLY TRANSPARENT background
(alpha) — no white, no shadow, no rim light on hair. Character only, no text, high-detail hands. Avoid: text,
watermark, white background, extra fingers, deformed hands, any instrument or props.
```
---
## §4. 소품/악세서리
→ **`IMAGE_GEN_RIGGING_ACCESSORIES.md`** 참조(헤드폰·LP/턴테이블·건반·마이크·고양이귀·손목밴드 등, 캐릭터와 무관하게 1회 제작해 모든 버전에 합성).
+167
View File
@@ -0,0 +1,167 @@
# IMAGE-GEN VARIATIONS — 헤어 · 의상 베리에이션 요청문 (세트별)
> 마스코트 **이소리 · 이단**의 헤어 컬러/스타일·의상 베리에이션을 **세트 종류별**로 요청하기 위한 복붙 요청문.
> 팔레트·스타일 정의: `CHARACTER_PROFILES.md §1-6 / §2-6`. 기본 재생성: `IMAGE_GEN_REQUESTS.md`.
> **원칙**: 얼굴·나이·체형·정체성은 고정, **바뀌는 건 표시된 속성(헤어/의상)뿐.** 투명 배경 PNG.
---
## ▶ 사용 안내 (당신용 — 이 섹션만 지침)
- 각 세트는 **베이스 프롬프트 1개 + 변형표**로 구성. 프롬프트의 **`<<...>>`** 부분만 표의 값으로 바꿔 **각 변형을 1장씩** 요청한다.
- 매 요청에 **해당 캐릭터 시트(`sori_sheet.png`/`dan_sheet.png`)를 첨부**한다(동일 인물 유지).
- 출력은 **투명 배경 PNG(알파)**. 흰 배경으로 나오면 "transparent alpha, no white"로 재생성.
- 저장: `Characters/<char>/variations/` 권장. 파일명 예: `sori_hair_lavender.png`, `sori_outfit_street.png`.
- 용도: 스티커·시즌 이벤트·마케팅·테마 스킨(브랜드 핵심 접점은 시그니처 고정).
---
# 이소리 (Lee Sori)
## SET A — 이소리 헤어 **컬러** (스타일=기본 단발밥, 상반신)
**베이스 프롬프트** · *첨부: `sori_sheet.png`*
```
Using the attached reference sheet, draw the SAME woman (이소리) — identical glamorous face, hourglass upper
body and signature outfit — waist-up, gentle smile. Change ONLY the HAIR COLOR to <<COLOR>>, keeping the same
bob hairstyle. Keep the EXACT same face; thin clean anime style matching the sheet. Output a PNG with a FULLY
TRANSPARENT background (alpha) — no white, no shadow, no rim light on hair. Character only, no text.
Avoid: text, watermark, white background, deformed face/hands, chibi.
```
**변형표** (`<<COLOR>>` 자리)
| 저장명 | `<<COLOR>>` |
|---|---|
| `sori_hair_mint`(기본) | mint/teal green (#38E0C4) |
| `sori_hair_aqua` | aqua cyan (#4CD9E8) |
| `sori_hair_lavender` | lavender purple (#B79CFF) |
| `sori_hair_coral` | coral pink (#FF8FB1) |
| `sori_hair_sunset` | sunset orange (#FFB454) |
| `sori_hair_rosegold` | rose gold (#F5C2A0) |
| `sori_hair_navy` | deep navy blue (#3A5BD9) |
| `sori_hair_snowmint` | snow white fading to mint gradient |
| `sori_hair_black` | natural black/brown |
## SET B — 이소리 헤어 **스타일** (컬러=기본 민트, 상반신)
**베이스 프롬프트** · *첨부: `sori_sheet.png`*
```
Using the attached reference sheet, draw the SAME woman (이소리) — identical glamorous face, hourglass upper
body and signature outfit — waist-up, gentle smile. Keep mint/teal hair color but change ONLY the HAIRSTYLE
to <<STYLE>>. Keep the EXACT same face; thin clean anime style matching the sheet. Output a PNG with a FULLY
TRANSPARENT background (alpha) — no white, no rim light on hair. Character only, no text.
Avoid: text, watermark, white background, deformed face/hands, chibi.
```
**변형표** (`<<STYLE>>` 자리)
| 저장명 | `<<STYLE>>` |
|---|---|
| `sori_style_bob`(기본) | a voluminous chin-length bob |
| `sori_style_ponytail` | a high ponytail with loose strands |
| `sori_style_halfup` | a half-up half-down style |
| `sori_style_long` | long straight hair below the shoulders |
| `sori_style_wavy` | medium wavy hair |
| `sori_style_braid` | a side braid |
| `sori_style_pixie` | a short chic pixie cut |
| `sori_style_bun` | an updo bun that fits with headphones |
## SET C — 이소리 **의상**
**베이스 프롬프트** · *첨부: `sori_sheet.png`*
```
Using the attached reference sheet, draw the SAME woman (이소리) — identical glamorous face, hourglass upper
body, mint bob hair — full body, confident friendly pose. Change ONLY the OUTFIT to <<OUTFIT>> (tasteful
adult casual-chic, not revealing). Keep the EXACT same face; thin clean anime style matching the sheet.
Output a PNG with a FULLY TRANSPARENT background (alpha) — no white, no shadow. Character only, no text.
Avoid: text, watermark, white background, deformed face/hands, chibi.
```
**변형표** (`<<OUTFIT>>` 자리)
| 저장명 | `<<OUTFIT>>` |
|---|---|
| `sori_outfit_signature`(기본) | white cropped hoodie + mint-and-black track jacket + black track pants |
| `sori_outfit_street` | an oversized hoodie, a cap and sneakers, minimal streetwear |
| `sori_outfit_studio` | a simple tee with full over-ear headphones and denim |
| `sori_outfit_cozy` | a cozy knit sweater with a blanket, holding a mug |
| `sori_outfit_summer` | a light short-sleeve summer outfit in bright tones |
| `sori_outfit_winter` | a padded winter coat and muffler with mint accents |
| `sori_outfit_party` | a sleek party jacket with holographic mint accents |
---
# 이단 (Lee Dan)
## SET D — 이단 헤어 **컬러** (스타일=기본 텍스처 크롭, 상반신)
**베이스 프롬프트** · *첨부: `dan_sheet.png`*
```
Using the attached reference sheet, draw the SAME man (이단) — identical face, fit build and signature outfit
— waist-up, confident grin. Change ONLY the HAIR COLOR to <<COLOR>>, keeping the same short textured crop.
Keep the EXACT same face; thin clean anime style matching the sheet. Output a PNG with a FULLY TRANSPARENT
background (alpha) — no white, no shadow. Character only, no text.
Avoid: text, watermark, white background, deformed face/hands, chibi.
```
**변형표** (`<<COLOR>>` 자리)
| 저장명 | `<<COLOR>>` |
|---|---|
| `dan_hair_cyanstreak`(기본) | dark black with a cyan/blue streak (#4CC2FF) |
| `dan_hair_bluetint` | blue-tinted dark hair (#1E3A5F) |
| `dan_hair_ash` | ash silver (#C9CED6) |
| `dan_hair_navy` | deep navy (#2B3A67) |
| `dan_hair_black` | natural black |
| `dan_hair_cyanfull` | full cyan (#4CC2FF) |
## SET E — 이단 헤어 **스타일** (컬러=기본, 상반신)
**베이스 프롬프트** · *첨부: `dan_sheet.png`*
```
Using the attached reference sheet, draw the SAME man (이단) — identical face, fit build and signature outfit
— waist-up, confident grin. Keep dark hair with a cyan streak but change ONLY the HAIRSTYLE to <<STYLE>>.
Keep the EXACT same face; thin clean anime style matching the sheet. Output a PNG with a FULLY TRANSPARENT
background (alpha) — no white. Character only, no text.
Avoid: text, watermark, white background, deformed face/hands, chibi.
```
**변형표** (`<<STYLE>>` 자리)
| 저장명 | `<<STYLE>>` |
|---|---|
| `dan_style_crop`(기본) | a short textured crop |
| `dan_style_slickback` | a slicked-back style |
| `dan_style_undercut` | a sharp modern undercut |
| `dan_style_wavy` | relaxed medium wavy hair |
| `dan_style_beanie` | wearing a beanie |
| `dan_style_buzz` | a short buzz cut with the cyan streak |
## SET F — 이단 **의상**
**베이스 프롬프트** · *첨부: `dan_sheet.png`*
```
Using the attached reference sheet, draw the SAME man (이단) — identical face, fit build, dark cyan-streak
hair — full body, confident pose. Change ONLY the OUTFIT to <<OUTFIT>>. Keep the EXACT same face; thin clean
anime style matching the sheet. Output a PNG with a FULLY TRANSPARENT background (alpha) — no white, no
shadow. Character only, no text.
Avoid: text, watermark, white background, deformed face/hands, chibi.
```
**변형표** (`<<OUTFIT>>` 자리)
| 저장명 | `<<OUTFIT>>` |
|---|---|
| `dan_outfit_signature`(기본) | navy-black hoodie+bomber with blue zippers, white tee, black pants |
| `dan_outfit_street` | a bomber jacket, cap and sneakers, streetwear |
| `dan_outfit_studio` | a rolled-up shirt/hoodie with full over-ear headphones |
| `dan_outfit_tech` | a minimal zip-up with the smartwatch emphasized |
| `dan_outfit_winter` | a padded winter hoodie with cyan accents |
| `dan_outfit_formal` | a smart-casual blazer over a tee |
---
# SET G — 시즌 / 이벤트 (듀오) · *첨부: 두 시트*
**베이스 프롬프트**
```
Using BOTH attached reference sheets, draw the same two characters — 이소리 (mint bob, glamorous hourglass
upper body) and 이단 (cyan-streak dark hair) — together in a <<THEME>> themed look, cheerful partner
chemistry, full body. Keep the EXACT same faces; thin clean anime style matching the sheets. Output a PNG
with a FULLY TRANSPARENT background (alpha) — no white, no shadow. Characters only, no text, no logo.
Avoid: text, watermark, white background, deformed hands, chibi.
```
**변형표** (`<<THEME>>` 자리)
| 저장명 | `<<THEME>>` |
|---|---|
| `duo_theme_summer` | summer / beach casual |
| `duo_theme_winter` | winter / cozy holiday |
| `duo_theme_newyear` | new-year celebration |
| `duo_theme_launch` | product-launch party with mint+cyan confetti |
---
## 메모
- 컬러 HEX·무드·용도 상세: `CHARACTER_PROFILES.md`. 강조색 테마 연동 아이디어(앱 강조색=헤어색)도 거기에.
- 헤어 밝은 테두리(림라이트)가 싫으면 프롬프트에 `no rim light, no glowing hair outline` 추가.
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

File diff suppressed because it is too large Load Diff
+124
View File
@@ -0,0 +1,124 @@
# PREBUILT — 토의 세션에서 미리 생성한 코드
> 목적: **토큰 부하가 큰 작업을 개발 세션 밖에서 선(先)생성**해 두어, 개발 세션은
> "컴파일·검증·연결"만 하도록 함. 아래 파일들은 **미검증(컴파일 안 해봄)** 상태다.
> 반드시 dev 세션에서 `dotnet build` 후 오류를 잡을 것.
## 생성된 파일과 상태
| 파일 | 대응 | 신뢰도 | 비고 |
|---|---|---|---|
| `src/DansoriEQ.Core/Eq/FilterType.cs` | M3 | 높음 | 순수 로직 |
| `src/DansoriEQ.Core/Eq/Filter.cs` | M3/M5 | 높음 | **RBJ Cookbook 수학** — 단위테스트 권장 |
| `src/DansoriEQ.Core/Eq/EqState.cs` | M3 | 높음 | |
| `src/DansoriEQ.Core/Eq/FrequencyResponse.cs` | M5 | 높음 | 그래프용 로그축 샘플링 |
| `src/DansoriEQ.Core/Eq/PreampCalculator.cs` | M3/M4 | 높음 | 클리핑 방지 |
| `src/DansoriEQ.Core/Eq/ApoRenderer.cs` | M3 | 높음 | EqState → APO config 텍스트 |
| `src/DansoriEQ.Core/Ai/EqDelta.cs` | M4 | 높음 | AI 구조화 출력 모델 |
| `src/DansoriEQ.Core/Ai/EqPromptBuilder.cs` | M4 | 중간 | **시스템 프롬프트/툴 스키마 — 여기서 튜닝** |
| `src/DansoriEQ.App/Controls/EqGraphControl.cs` | **M7** | 중간 | **최대 토큰 싱크**. WPF API 검증 필요 |
| `src/DansoriEQ.App/MainWindow.xaml`(+cs) | M1/M5 | 중간 | 플레인 WPF 레이아웃(목업 재현) |
| `src/DansoriEQ.App/App.xaml`(+cs), `*.csproj` | M1 | 높음 | 프로젝트 뼈대 |
| `src/DansoriEQ.Core/Profiles/DbInfo.cs` | M2 | 높음 | DB 정보 DTO(+표시 헬퍼) |
| `src/DansoriEQ.Core/Profiles/IProfileDbService.cs` | M2 | 높음 | DB 서비스 계약(GetInfo/UpdateAsync) |
| `src/DansoriEQ.App/Design/DesignProfileDbService.cs` | M2 | 높음 | **디자인 스텁**(샘플 데이터/모의 업데이트) |
| `src/DansoriEQ.App/DbManagerWindow.xaml`(+cs) | M2 | 중간 | **DB 관리 팝업**(현재 상태·출처·업데이트 진행) |
| `src/DansoriEQ.Core/Security/ISecretStore.cs` | M8 | 높음 | 암호화 저장 계약 |
| `src/DansoriEQ.App/Security/DpapiSecretStore.cs` | M8 | 높음 | **DPAPI 암호화**(평문 저장 안 함) · ProtectedData 패키지 |
| `src/DansoriEQ.Core/Ai/ProviderKeys.cs` | M8/M10 | 높음 | claude/openai/gemini 키 상수 |
| `src/DansoriEQ.App/Controls/ApiKeyRow.xaml`(+cs) | M8 | 중간 | 입력 ↔ "이미 입력됨" 상태 전환 |
| `src/DansoriEQ.App/SettingsWindow.xaml`(+cs) | M8 | 중간 | **설정 화면**(3사 API 키 입력) |
| `src/DansoriEQ.Core/Presets/EqPreset.cs` | M9 | 높음 | `.tweq` 모델 |
| `src/DansoriEQ.Core/Presets/PresetSerializer.cs` | M9 | 높음 | 직렬화/검증/EqState 변환 |
| `src/DansoriEQ.App/PresetInfoWindow.xaml`(+cs) | M9 | 중간 | 가져오기 정보 미리보기 + **DB 매칭 상태** |
| `src/DansoriEQ.Core/Profiles/AutoEqParser.cs` | M2 | 높음 | ParametricEQ.txt → EqState 파서 |
| `src/DansoriEQ.Core/Profiles/ProfileRef.cs` | M2 | 높음 | 매칭용 프로파일 참조 |
| `src/DansoriEQ.Core/Ai/ClaudeClient.cs` | M4 | 중간 | **Anthropic Messages API(tool use)** — 키 없으면 미실행 |
| `src/DansoriEQ.Core/Ai/EqDeltaApplier.cs` | M4 | 높음 | AI delta → EqState 적용 |
| `src/DansoriEQ.Core/Apo/IApoWriter.cs` | M3 | 높음 | APO 쓰기 추상화 |
| `src/DansoriEQ.App/Apo/*.cs` | M3 | 중간 | Locator/IncludeWriter(실제)/NullWriter(미리보기)/Factory |
| `src/DansoriEQ.App/AppSettings.cs` | M3 | 높음 | APO 경로 등 설정 저장(settings.json) |
| `src/DansoriEQ.App/Apo/ApoInstaller.cs` | M3/M6 | 중간 | 공식 설치파일 다운로드·실행(무인설치 불가) |
| `src/DansoriEQ.App/ApoSetupWindow.xaml`(+cs) | M3/M6 | 중간 | 시작 시 APO 없으면: **자동설치/경로설정/미리보기** |
| `tests/DansoriEQ.Core.Tests/*` | 품질 | 높음 | **단위테스트**(Filter 수학·AutoEqParser·PresetSerializer·ApoRenderer 이펙트) |
| `src/DansoriEQ.Core/Eq/EffectsConfig.cs` | M11 | 높음 | 크로스피드·밸런스·베이스부스트 |
| `ApoRenderer.cs` (이펙트 오버로드) | M11 | 높음 | EQ+이펙트 렌더 (**크로스피드=플레이스홀더**, 파일 메모) |
| `src/DansoriEQ.App/EffectsWindow.xaml`(+cs) | M11 | 중간 | **이펙트 조절 UI**(라이브) |
| `src/DansoriEQ.Core/Presets/PresetLibrary.cs` | M11 | 높음 | 로컬 프리셋 저장/목록/불러오기 |
| `src/DansoriEQ.App/PresetLibraryWindow.xaml`(+cs) | M11 | 중간 | **프리셋 라이브러리 UI** |
| MainWindow **도움말 드로어** + `ApiKeyRow` 발급 링크 | M6 | 중간 | **온보딩 도움말**(오른쪽 슬라이드) + API 키 발급 공식 링크 |
| `src/DansoriEQ.App/Audio/SystemVolumeService.cs` | M14 | 중간 | NAudio 장치별 볼륨/뮤트 + **Windows 볼륨 동기화** |
| `src/DansoriEQ.App/Audio/DefaultDeviceSwitcher.cs` | M14 | 낮음 | 기본 출력 전환(**undocumented COM**, 검증 필요) |
| `src/DansoriEQ.App/Controls/VolumePanel.xaml`(+cs) | M14 | 중간 | 그래프 옆 볼륨/장치 컨트롤 |
| `src/DansoriEQ.Core/Ai/LocalRuntime.cs` | M15 | 높음 | 로컬 런타임 레지스트리(**Ollama 전용**; 후보는 코드 메모) |
| `src/DansoriEQ.App/Ai/WingetInstaller.cs` | M15 | 중간 | winget 사일런트 설치 |
| `src/DansoriEQ.App/Ai/OllamaService.cs` | M15 | 중간 | Ollama 감지/모델목록/pull 진행률 |
| `src/DansoriEQ.App/Ai/DiskInfo.cs` | M15 | 높음 | 모델 드라이브 여유 공간 |
| `src/DansoriEQ.App/AiManagerWindow.xaml`(+cs) | M15 | 중간 | **AI 관리**(모델 선택·런타임 설치·저장공간 경고) |
| `src/DansoriEQ.App/Ai/CloudModelLister.cs` | M15 | 중간 | 클라우드 **계정 모델 목록** 동적 조회(Claude/OpenAI/Gemini) |
| `.../Ai/IAiEqProvider.cs` + `EqDeltaParser.cs` | M4/M10 | 높음 | provider 추상화 + 공유 JSON 파서 |
| `.../Ai/OpenAiProvider.cs`·`GeminiProvider.cs`·`OllamaProvider.cs` | M10 | 중간 | 클라우드/로컬 어댑터(모두 `IAiEqProvider`) |
| `src/DansoriEQ.App/Ai/AiProviderFactory.cs` | M4 | 높음 | 활성 provider 생성(AppSettings+키) |
| MainWindow **AI 프롬프트 실배선** + 편집 디바운스 | M4/M7 | 중간 | 프롬프트→provider→적용, Preamp 자동 재계산 |
| `src/DansoriEQ.App/Input/HotkeyManager.cs` | M11 | 중간 | 전역 핫키(Win32) |
| `src/DansoriEQ.App/CommandWindow.xaml`(+cs) | M11 | 중간 | 원시 APO 명령 입력 |
| `src/DansoriEQ.Core/Switching/*` | M12 | 높음 | 자동전환 규칙·평가(순수) |
| `src/DansoriEQ.App/Switching/ForegroundAppWatcher.cs` | M12 | 중간 | 포그라운드 앱 감지(Win32) |
| `.../Switching/ProfileSwitcher.cs`·`SwitchRulesStore.cs` | M12 | 중간 | 자동전환 서비스 + 규칙 저장 |
| `src/DansoriEQ.App/SwitchRulesWindow.xaml`(+cs) | M12 | 중간 | 자동전환 규칙 관리 UI |
| MainWindow **바이패스 핫키(Ctrl+Alt+B)** + '활성' 토글 | M11 | 높음 | EQ 켜기/끄기 |
| **프리셋 전환 핫키**(Ctrl+Alt+[ / ]) · **연결 테스트** · **명령창→APO config** | M11/M8 | 중간 | 소소한 배선 |
| `src/DansoriEQ.App/Profiles/SqliteProfileDbService.cs` | M2 | 중간 | **실제 SQLite 저장소**(스키마·검색·로드·업서트·AutoEq import) |
| MainWindow **되돌리기/리셋**(Undo 스택 + 베이스) | M4/M7 | 높음 | 편집 실행취소·초기화 |
| `.../Switching/DefaultDeviceWatcher.cs` | M12 | 중간 | 기본 출력장치 변경 감지(NAudio) → 장치 규칙 |
| 이펙트 **AI 자연어 제어** + 자동전환 **런타임 규칙 리로드** | M11/M12 | 중간 | effects 스키마·파서·적용 |
| `README.md` | M6 | 높음 | 프로젝트 개요·빌드·기능 |
## 지금 시점의 동작 범위
- **컴파일만 하면** Core(순수 C#) + WPF 앱이 떠서, **데모 EQ가 그래프에 그려지고**
노드를 **드래그/휠/더블클릭/우클릭으로 편집**하는 M7 인터랙션이 동작하도록 작성됨.
- **DB 업데이트 버튼** → **DB 관리 팝업**이 뜨고, `DesignProfileDbService` 스텁 데이터로
**현재 상태·출처(배포가능/제한 배지)** 표시 + **모의 업데이트 진행바**가 동작함.
- **⚙ 설정** → 설정 창: Claude/ChatGPT/Gemini **API 키 입력**. 저장 시 **DPAPI 암호화**되어
`secrets.dat`에 저장되고 화면은 **"이미 입력되어 있음"(값 숨김)** 으로 전환. 삭제도 가능.
(provider *선택* 로직은 M10 확장 — 지금은 입력/저장만.)
- **↥ 내보내기 / ↧ 가져오기** → `.tweq`(JSON) 저장/열기. 가져오기 시 **정보 미리보기 창**
(대상 기기·히스토리·노트 + **로컬 DB 자동 매칭 상태**) 후 적용. 매칭 실패 시 **"DB 업데이트" 안내**.
(내보내기의 대상/히스토리는 M2/M4 연결 전까지 데모값)
- **시작 시 APO 탐색**: APO가 없으면 `ApoSetupWindow`가 떠서 **① 자동설치(공식 설치파일 다운로드·실행)
② config 폴더 직접 지정 ③ 미리보기로 계속** 중 선택. 경로 지정 시 `settings.json`에 저장되어
다음부터 실제 쓰기로 동작.
- **APO 미설치 환경**: `NullApoWriter`가 생성된 APO config를
`%LOCALAPPDATA%\DansoriEQ\preview_apo_config.txt`에 써서 **파이프라인을 검증**할 수 있음.
창 제목에 "APO 미설치(미리보기 모드)" 표시.
- **아직 없는 것(연동/배선)**: DB **실제 SQLite/AutoEQ 다운로드**(M2 — 파서는 있음, 스텁 교체),
**AI 프롬프트창 → ClaudeClient → EqDeltaApplier → 적용** 배선 + 키 주입(M4),
**APO 실제 적용 검증**(이 PC 미설치라 미리보기로 대체), ViewModel/바인딩, 테마 전환(M5), 마감(M6).
- **교체 지점**: `IProfileDbService` 실제 구현(SQLite) + 프롬프트창에 `ClaudeClient`(키는 `DpapiSecretStore.Load`) 연결.
## 개발 세션 착수 절차
1. 솔루션 생성:
```
dotnet new sln -n DansoriEQ
dotnet sln add src/DansoriEQ.Core/DansoriEQ.Core.csproj
dotnet sln add src/DansoriEQ.App/DansoriEQ.App.csproj
dotnet sln add tests/DansoriEQ.Core.Tests/DansoriEQ.Core.Tests.csproj
dotnet build
dotnet test # 단위테스트 3종 실행 (Filter 수학·AutoEqParser·PresetSerializer)
```
2. 컴파일 오류 수정(특히 `EqGraphControl.cs`의 WPF 시그니처, XAML 네임스페이스).
3. `App.csproj` 주석의 NuGet 패키지(WPF-UI/LiveCharts2/CommunityToolkit.Mvvm/Microsoft.Data.Sqlite)
버전 핀 후 추가. **그다음** MainWindow 루트를 `ui:FluentWindow`로 승격 + 테마 적용.
4. DEV_PLAN M0(스파이크) → M2(DB) → M3(APO IO) → M4(AI) 순으로 살 붙이기.
## 검증 우선순위(컴파일 후)
1. **`Filter.cs` 단위테스트**: 예) Peaking Fc=1k, +6dB, Q1 → `GainDbAt(1000)` ≈ +6.0.
Low/High shelf도 통과 대역에서 목표 dB 근사 확인.
2. **EqGraphControl** 시각 확인: 데모 EQ 곡선 모양, 노드 드래그시 Fc(x)/Gain(y) 반영, 휠=Q.
3. **ApoRenderer** 출력이 APO 문법과 일치하는지 실제 `config.txt`에 붙여 확인.
## 주의(리스크)
- `EqGraphControl`은 **컴파일 안 해본 WPF 코드**다. `OnMouseDoubleClick` 등 시그니처,
`StreamGeometry`/`DrawingContext` 사용을 dev 세션에서 확인·수정할 것.
- `MainWindow.xaml`은 **플레인 WPF**(WPF-UI 미사용)로 작성해 단독 컴파일 가능. 예쁜 Fluent는
WPF-UI 추가 후 재적용.
- 프롬프트(`EqPromptBuilder`)는 실제 호출로 **EQ 품질을 반복 검증**하며 문구를 다듬을 것.
+117
View File
@@ -0,0 +1,117 @@
# 개발 세션 진행 로그 (PROGRESS)
> 이 문서는 **실제 빌드/실행 개발 세션**에서 진행한 내용을 기록한다.
> 설계·선생성 범위는 `PREBUILT.md`·`DEV_PLAN.md` 참조. 여기는 "미컴파일 선생성 → 실동작"으로
> 전환하며 실제로 검증/수정한 것과 **다음에 할 일**을 담는다.
> 최종 갱신: 2026-07-01
---
## ✅ 이번까지 완료 (실동작 검증됨)
### 빌드 / 실행
- 솔루션 빌드 성공(오류 0). `dotnet build src/DansoriEQ.App` 정상.
- WPF-UI **Fluent 다크테마 + Mica 배경** 적용 확인.
- **주의(빌드 함정)**: 앱 실행 중이면 `bin\Debug\...\DansoriEQ.Core.dll` 복사 단계가 **파일 잠금(MSB3021/3027)**으로 실패한다.
→ 빌드 전 반드시 `DansoriEQ.App` 프로세스를 종료할 것. (컴파일 자체는 통과, 복사만 실패하므로 착각 주의)
### AI (M4/M10)
- **Gemini 무료 API로 자연어 → EQ 적용 동작 확인.** (`aistudio.google.com` 키)
- `GeminiProvider``responseMimeType: application/json`으로 구조화 출력.
- 프롬프트창 → provider → `EqDeltaApplier` → APO 적용 실배선 동작.
- Claude API는 사용자 계정 이슈(크레딧 충전 비활성)로 **보류**, Gemini로 테스트 진행.
- 만족도(EQ 품질) 평가는 사용자가 **추후 별도 진행** 예정.
### 프로파일 DB (M2)
- **AutoEQ SQLite 다운로드/적재 동작.** `UpdateAsync` 청크 다운로드(128KB) + 불확정 진행률(-1) 처리로 "멈춤" 오해 해소.
- 사이드바 **IEM / 헤드폰 2분할** 표시(그리드 2행).
### APO 연동 (M3)
- `ApoConfigInstaller` 신설: `config.txt`**`Include: ai_eq.txt`** 자동 추가(직접 쓰기 → 실패 시 승격 PowerShell 폴백).
- 최초 연동 안내 모달 **`ApoLinkWindow`**(다크 모던 UI)로 통일.
- 사용자가 **APO Configurator에서 자기 출력장치(DAC)**를 선택해야 실제 적용됨을 확인(가이드 완료).
- 실제 EQ 적용 동작 확인(활성 체크/바이패스 배선 포함).
### 창/헤더 UI
- **타이틀바(`ui:TitleBar`)** 추가 → 창 이동 가능.
- 헤더 버튼(설정/이펙트/되돌리기/리셋/⋯/활성)이 **기기 이름을 가리던 문제** → 헤더 Grid 2열 분리로 해결.
- `ACTIVE FILTERS` 박스 잘림 → ScrollViewer 패딩을 내부 StackPanel 마진으로 이동해 해결.
- 창 크기 확대(1400×860).
### EQ 밴드 편집 팝업 (M7 핵심) — 신규
- 필터 칩 **더블클릭 → 자체 그래픽 편집 팝업**(외부 APO 실행 아님). PowerAmp/Peace 지향.
- **전체 필터 타입 18종** 지원 (드롭다운):
Peak / Low Pass / High Pass / Band Pass / Low Shelf / High Shelf / Notch / All Pass /
Low·High Shelf(Slope dB) / Low·High Pass Butterworth(짝수차) /
Low·High Pass Linkwitz-Riley(짝수차) / Low·High Shelf(Q as Slope) /
Low·High Shelf(Corner Freq, Q as Slope).
- `FilterType` 열거형 + 메타(`UsesGain`/`ThirdParam`/`DisplayName`/`ShortLabel`/APO 토큰) 확장.
- `Filter.cs`: RBJ 바이쿼드 + **Butterworth/LR 폐형식** + 슬로프 셸프 수학 구현.
- `ApoRenderer`: 타입별 정확한 APO 라인 + **Butterworth/LR은 2차 섹션 캐스케이드**로 전개.
- **컨텍스트 UI**: 타입에 따라 게인 숨김/표시, 3번째 컨트롤이 **Q / 기울기 / 차수**로 자동 전환.
- **Peace식 정밀 수치 입력**: 주파수·게인·Q/기울기/차수 각각 **입력창 직접 타이핑**(Enter/포커스이동 반영) + 슬라이더 + 그래프 3방향 동기화.
- **축 라벨(Hz/dB)을 그래프 컨트롤 내부에 로그/선형 실제 위치로 렌더** → 격자·라벨 정렬(이전 균등간격 라벨 오정렬 해소).
- **크래시 수정**: 생성자에서 `InitializeComponent()` 전에 `_editState` 미할당 상태로 이벤트가 발생해 NRE로 앱이 종료되던 문제 → 상태를 먼저 할당하도록 순서 수정. `App`**전역 예외 핸들러** 추가(이제 예외 시 종료 대신 오류창).
### 볼륨 / 출력장치 (M14)
- **하드웨어/디지털 하이브리드 볼륨** 구현.
- 장치 선택 시 하드웨어 볼륨 지원 여부 **자동 프로브**.
- 지원 → NAudio 엔드포인트 볼륨. 미지원(라인아웃 DAC) → **APO Preamp 디지털 감쇠**로 자동 전환(`SoftVolumeChanged``ApoRenderer.Render(volumeDb)`).
- `ModeLabel`에 "하드웨어 볼륨 / 디지털 볼륨(APO)" 표시.
- **위험 요소 제거**: `DefaultDeviceSwitcher`(IPolicyConfig, 미검증 COM vtable) 호출 제거 — 오디오 손상 원인이었음. **재도입 금지.**
- 사용자 환경: **DAC 2대**. ① 라인아웃(헤드폰앰프 연결, 고정 레벨 → 하드웨어 볼륨 없음) ② 올인원(하드웨어 볼륨 O). 상세는 저장 메모 참조.
---
## 마스코트 UI (경로 A — WPF 네이티브) ✅ 진행 중
> 캐릭터(이소리·이단) 에셋을 앱에 결합. 방침=경로 A(WPF Storyboard/도형) → 필요한 곳만 경로 B(Lottie). `Characters/`.
- **AI 아바타**(`MascotAvatar`): 눈 깜빡임·말하기(프레임 교체)·부유. AI 응답 대기 중 말하기.
- **음파 링**(`SoundwaveRings`) + **EQ 막대 생각중**(`EqBarsFx`): AI 처리 중 연출.
- **성공 토스트**(`MascotToast`): 이단 thumbs-up 팝인, 명령창 위 중앙.
- **로딩**: `EqBarsFx`를 DB 업데이트 진행에 재사용.
- **온보딩**: 도움말 드로어에 이소리·이단 듀오.
- **스플래시**(`SplashWindow`): 시작 시 듀오 브랜드, 자동 페이드.
- **팝업 네온 테두리**: `App.xaml``NeonPopup` 스타일 + Grid창은 오버레이 프레임 → 다크 배경에서 팝업 분리감.
- **이미지 투명화**: `tools/make_transparent.py`(색상키, 폐기) → **rembg(U²-Net) 재처리**가 최선. 원본 `Characters/_opaque_backup/`.
- ⚠️ **이소리 헤어의 얇은 밝은 테두리(림라이트)는 원본 아트 특성** → 후처리 한계. **완전 제거는 투명 네이티브로 재생성 필요**(향후).
- **DB 창 모던화**: `DbManagerWindow` → FluentWindow+TitleBar. 업데이트는 **upsert(name,source)로 중복 없음**(단 매번 전체 재다운로드 — 캐시 최적화는 선택).
## ⚠️ 알려진 이슈 / 보류
- **라인아웃 DAC 볼륨**: 하드웨어가 소프트웨어 볼륨을 원천 미지원(Windows 믹서도 무반응 확인). 디지털(APO) 폴백은
**해당 DAC에 APO가 설정돼 있어야** 동작. 사용자 요청으로 **추후 재검토**.
- **크로스피드 렌더는 여전히 플레이스홀더**(`ApoRenderer` 메모: 저역통과+딜레이 정식 구현 필요).
- All Pass 필터는 진폭 평탄(위상만) → 그래프에서 평탄선이 **정상**.
- Corner-Freq 셸프 변형은 미리보기에서 중심주파수를 코너로 **근사**.
---
## ▶ 다음에 할 일
### 1) 그래프 도트(노드) 위치 정상화 ← ✅ **완료(사용자 모니터링 중, 2026-07-02)**
**해결**: 노드를 **합성 곡선(보이는 실선) 위**에 배치(`ShapeDbAt(Fc)`). 드래그는 좌우=Fc(전 타입),
상하=게인(게인 있는 타입만, 상대/델타 방식). 게인 없는 타입은 상하 드래그로 게인 안 생김.
메인 그래프 + 편집 팝업 **동일 규칙** 적용. `EqGraphControl.cs`(OnRender/HitNode/OnMouseMove).
> 아래는 당시 원인 분석(참고용, 히스토리).
**현상**: 그래프의 필터 노드(동그라미)가 곡선과 어긋난 위치에 그려지는 경우가 있음.
**원인 분석**(코드 기준):
- `EqGraphControl`은 모든 노드를 **`(HzToX(Fc), DbToY(GainDb))`** 위치에 균일하게 그린다.
- **Peaking**: Fc에서 곡선 정점 ≈ GainDb → 노드가 곡선 위에 얹힘(정상).
- **셸프(LS/HS 등)**: Fc에서 곡선값은 대략 **GainDb/2**(중간점)인데 노드는 GainDb에 → 곡선보다 위에 뜸.
- **게인 없는 타입**(LP/HP/BP/Notch/AP/Butterworth/LR): `GainDb=0` → 노드가 0 dB 라인에 있는데
실제 곡선은 컷오프에서 내려감 → 노드가 곡선에서 떨어짐.
- 편집 팝업의 **메인 실선 곡선은 전체 필터 합성**이라, 개별 노드가 합성 곡선 위에 없을 수 있음.
**해결 방향(택1, 다음 세션에서 확정)**:
- (A) 노드 Y를 **해당 필터의 자기 응답값 at Fc**(개별 곡선 높이)로 배치 → 항상 자기 곡선 위.
- (B) 노드 Y를 **합성 곡선값 at Fc**로 배치 → 메인 실선 위에 얹힘(Peace 유사).
- 드래그 시맨틱 정리: 게인 있는 타입은 상하=Gain, 게인 없는 타입은 **상하 드래그 비활성 또는 Q/차수 매핑** 고려.
- 메인 화면 그래프와 편집 팝업 그래프 **동일 규칙** 적용.
**관련 파일**: `src/DansoriEQ.App/Controls/EqGraphControl.cs` (OnRender 노드 그리기 / HitNode / OnMouseMove).
### 2) 이후(우선순위 낮음)
- 라인아웃 DAC 볼륨 UX 재정리(APO 폴백 안내 강화).
- LiveCharts2 vs 커스텀 캔버스 최종(M5). 현재 커스텀 캔버스 유지 중.
- AI EQ 품질 만족도 평가(사용자) 반영.
+68
View File
@@ -0,0 +1,68 @@
# SCENARIO — 제품 요구사항 (권위 있는 원본)
## 1. 목적
자연어로 헤드폰/IEM의 음색을 조정하는 Windows 앱. 사용자가 "보컬 가까이, 저음 단단히" 같은
문장을 입력하면, AI가 파라메트릭 EQ를 만들어 **Equalizer APO**에 즉시 반영한다.
Luxsin X8의 AI EQ 경험을 소프트웨어로 재현하되, **어떤 DAC/앰프와도 무관하게** 동작한다.
## 2. 범위
### In scope
- 헤드폰/IEM 프로파일 로컬 DB (AutoEQ 기반) + 앱 내 업데이트
- 프로파일 선택 → 베이스 파라메트릭 EQ 로드
- 자연어 프롬프트 → Claude API → EQ delta(구조화 JSON) → 적용
- EQ 그래프 시각화(현재 EQ + 타깃)
- APO config 렌더링/쓰기 + 라이브 적용
- 되돌리기/히스토리/베이스 리셋, 활성/바이패스 토글
### Out of scope
- **DAC/앰프 EQ 프로파일**(평탄하므로 대상 아님; 색채는 EQ로 표현 불가)
- 측정 마이크 기반 실측 보정(현 단계 미채택; 향후 확장 여지만 남김)
- 모바일/웹/멀티플랫폼 (Windows 네이티브 전용)
## 3. 핵심 제약 (사용자 확정)
1. **미적으로 아름다운 모던 GUI** — WPF 모던 UI 감성. 단순/텍스트 UI 금지. 웹앱 금지.
2. **EQ 그래프 시각화 포함** — 보기 좋은 그래픽.
3. **저권한** — 사용자 개입 최소. (최초 1회 설정만 승격, 이후 무승격 — ARCHITECTURE 참조)
4. **프로파일 목록 IEM/헤드폰 분리 표시.**
5. **라이선스 분리 관리** — 배포 불가 데이터는 **별도 폴더**, **배포 시 제외 옵션**.
그러나 **UI에는 구분 없이 병합 표시**.
6. **AutoEQ 베이스 + 귀로 AI 미세조정** (측정 없음).
7. **Anthropic API 키는 사용자 제공**(설정에서 입력/저장).
## 4. 사용자 워크플로 (해피 패스)
1. 앱 실행 → (최초 1회) APO 연동 설정 마법사 = 1회 UAC 승격.
2. 사이드바에서 이어폰/헤드폰 검색·선택(IEM/헤드폰 그룹 구분).
3. 해당 AutoEQ 베이스 EQ가 그래프와 필터 목록에 로드됨(자동 적용).
4. 하단 프롬프트에 "보컬 더 가깝게, 저음 단단하게" 입력 → 전송.
5. AI가 EQ를 갱신하고 **무엇을·왜 바꿨는지 설명**을 표시 → APO에 즉시 적용.
6. 귀로 듣고 "치찰음 조금 줄여" 등 반복 → 만족 시 종료(설정 유지).
7. 필요 시 "베이스로 리셋" 또는 "되돌리기".
## 4.5 핵심 사용자 여정 (End-to-End) — 정식
1. **프로파일 업데이트** — DB 관리 팝업에서 AutoEQ 최신 프로파일을 받는다.
2. **프로파일 선택** — 내 이어폰/헤드폰(IEM·헤드폰 분리 목록)을 골라 베이스 EQ를 로드한다.
3. **AI로 APO PEQ 조절** — 자연어("보컬 가까이, 저음 단단히")로 AI가 EQ를 생성/수정하고
Equalizer APO에 즉시 적용한다. (그래프에서 손으로도 미세조정)
4. **나만의 EQ 완성** — 귀로 듣고 반복 조정해 개인화된 EQ를 확정한다.
5. **EQ 공유** — 완성한 EQ를 `.tweq`로 내보낸다(대상 기기 + AI 대화 히스토리 포함).
6. **다른 사용자가 받아 듣기/수정** — 우리 프로그램으로 `.tweq`를 가져오면
**정보 미리보기(대상 기기·히스토리·노트)** 후 적용한다. 가져올 때 **대상 기기 프로파일을
로컬 DB와 자동 매칭**하고, 없으면 **DB 업데이트로 내려받도록 안내**한다. 받은 EQ는
**그래프 편집 + AI 프롬프트로 재수정**하고 **다시 공유**할 수 있다(완전한 왕복 루프).
원칙:
- 공유 EQ는 **기기 종속적**이다(같은 기기에서 가장 정확). 그래서 `.tweq`에 대상 기기명을 담아
미리보기에서 보여준다.
- `.tweq`**측정 데이터가 아니라 기기 이름/메타만** 담겨 라이선스 문제 없이 배포된다.
- **DAC/앰프는 EQ 대상이 아니다**(평탄). 유효 변수는 트랜스듀서 + 귀 + 취향.
## 5. 계절/사용 컨텍스트 (참고)
- 여름 IEM 위주 / 겨울 헤드폰 위주, 서로 오감. → 프로파일 전환이 잦음(사이드바 UX 중요).
- IEM은 착용/팁에 따라 응답이 변하므로 **귀 튜닝 루프**가 특히 유효.
## 6. 성공 기준
- 알려진 헤드폰/IEM 선택 시 즉시 합리적 베이스 EQ 적용.
- 자연어 1~2회로 원하는 방향(보컬/저음/치찰음 등) 도달.
- APO 반영이 ~1초 내 체감.
- 최초 설정 후에는 UAC 프롬프트가 다시 뜨지 않음.
- UI가 "예쁘다"는 인상(다크 Fluent, 그래프 포함).
+63
View File
@@ -0,0 +1,63 @@
# TYPOGRAPHY — 타이포그래피 규칙
> ⚠️ **가독성 최우선(readability first).** 이 앱은 오디오 튜닝 도구로, 사용자가 값을 읽고
> 자연어를 입력하며 오래 들여다봅니다. **작고 흐린 글자로 인한 피로를 피하는 것이 규칙의 목적**입니다.
> 애매하면 **더 크게, 더 또렷하게**를 택한다.
## 핵심 규칙 (절대 원칙)
1. **최소 12px** — 어떤 텍스트도 12px 미만 금지. (라벨·힌트·배지·축 포함)
2. **최대 24px** — 최상위 제목만 24px. 그 이상 키우지 않는다.
3. **저대비 회색 텍스트(dim/mute)는 12px 이상**을 유지하고, **중요한 정보는 14px 이상**을 권장.
4. 정보 위계는 **크기 + 굵기 + 색**으로 표현한다(크기만으로 과하게 벌리지 않기).
## 타입 스케일 (12 → 24)
| 역할(Role) | px | Weight | 사용처 |
|---|---|---|---|
| **Caption** (최소) | **12** | 400/600 | 라벨, 힌트, 배지, 그래프 축, 보조 캡션 |
| Body S | 13 | 400/600 | 칩, 버튼, 보조 본문 |
| Body | 14 | 400 | 기본 본문, 리스트 항목, 설명문 |
| Body L | 15 | 600 | 값 강조, 입력 텍스트, 프로파일명(목록) |
| Subtitle | 16 | 600 | 카드 강조, 대상 기기명 |
| Section | 18 | 700 | 섹션/창 소제목, 헤더 타이틀 |
| Heading | 21 | 700 | 다이얼로그 제목 |
| **Title** (최대) | **24** | 700 | 페이지/최상위 제목 |
- 반(半)단계(13.5·14.5 등)는 목업(HTML) 미세조정용일 뿐, **WPF에서는 위 정수 스케일로 스냅**한다.
## 색·대비 (다크 테마 기준)
- 본문 기본: `#F2F3F5` (text)
- 보조: `#A8ABB4` (dim) — **12px 이상에서만** 사용
- 약한 보조: `#767A83` (mute) — 캡션/각주 한정, **작은 크기에서 남용 금지**
- 강조/링크: `#4CC2FF` (accent)
- 라이트 테마(M5) 도입 시에도 **동일 대비 비율**을 유지한다.
## 간격·굵기 가이드
- 줄간격(line-height) 본문 1.4~1.6.
- 굵기: 제목 700, 강조 값 600, 본문 400. **얇은(300) 폰트 금지**(가독성).
- 폰트 패밀리: `Segoe UI Variable, Segoe UI`.
## WPF 구현 지침 (M1/M5에서 적용)
- **창 기본 FontSize = 14** 로 두고, 역할별 스타일 키를 리소스로 정의해 **인라인 FontSize 사용을 지양**한다.
- 예시 `ResourceDictionary`:
```xml
<sys:Double x:Key="Font.Caption">12</sys:Double>
<sys:Double x:Key="Font.BodyS">13</sys:Double>
<sys:Double x:Key="Font.Body">14</sys:Double>
<sys:Double x:Key="Font.BodyL">15</sys:Double>
<sys:Double x:Key="Font.Subtitle">16</sys:Double>
<sys:Double x:Key="Font.Section">18</sys:Double>
<sys:Double x:Key="Font.Heading">21</sys:Double>
<sys:Double x:Key="Font.Title">24</sys:Double>
<Style x:Key="Caption" TargetType="TextBlock">
<Setter Property="FontSize" Value="{StaticResource Font.Caption}"/>
<Setter Property="Foreground" Value="{DynamicResource TextMuteBrush}"/>
</Style>
<!-- Body / Section / Title 등 동일 패턴 -->
```
- 기존 프리빌트 XAML의 인라인 `FontSize`는 **M5(테마) 단계에서 위 스타일 키로 치환**한다.
- 접근성: 사용자 OS 글꼴 배율(125%/150%)에서도 레이아웃이 깨지지 않도록 **고정 폭보다 Auto/*, 최소 높이 지정**을 선호.
## 목업과의 관계
- `mockups/gallery.html`은 이 스케일(최소 12·최대 24)로 조정되어 있다. 시각 기준은 갤러리를 참고하되,
**수치 기준(정수 스케일)은 이 문서가 원본(source of truth)**이다.
+186
View File
@@ -0,0 +1,186 @@
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8"/>
<title>Dansori — 캐릭터 컨셉 샘플</title>
<style>
:root{ --bg:#141418; --card:#1e1e24; --stroke:#3a3a42; --text:#f2f3f5; --dim:#a8abb4;
--cyan:#4cc2ff; --mint:#38e0c4; font-family:"Segoe UI Variable","Segoe UI",system-ui,sans-serif; }
body{margin:0;background:var(--bg);color:var(--text);padding:32px}
h1{font-size:24px;margin:0 0 4px} .sub{color:var(--dim);margin:0 0 26px;font-size:14px}
h2{font-size:15px;color:var(--mint);margin:30px 0 12px}
.row{display:flex;gap:22px;flex-wrap:wrap;align-items:flex-start}
.card{background:var(--card);border:1px solid var(--stroke);border-radius:16px;padding:18px;width:280px}
.card .nm{font-weight:700;font-size:17px;margin-top:6px}
.card .rl{color:var(--dim);font-size:13px;margin-top:2px}
.chip{display:inline-block;background:#26262b;border:1px solid var(--stroke);border-radius:20px;padding:4px 10px;font-size:12px;color:var(--dim);margin:6px 6px 0 0}
.avwrap{display:flex;gap:16px;align-items:center;flex-wrap:wrap}
pre{background:#0f0f13;border:1px solid var(--stroke);border-radius:12px;padding:14px;color:#cdd3da;
font-family:Consolas,monospace;font-size:12.5px;white-space:pre-wrap;line-height:1.55}
.note{color:var(--dim);font-size:13px;line-height:1.6}
</style>
</head>
<body>
<h1>Dansori — 캐릭터 컨셉 샘플</h1>
<p class="sub">손으로 그린 SVG 컨셉(발랄·친근 치비 마스코트). 이름은 미정 · 임시로 여=민트 / 남=시안.</p>
<div class="row">
<!-- ================= FEMALE (mint) ================= -->
<div class="card">
<svg viewBox="0 0 240 300" width="100%">
<!-- floating notes -->
<g fill="var(--mint)" opacity="0.9" font-size="22" font-weight="700">
<text x="24" y="70"></text><text x="196" y="52"></text>
</g>
<!-- soundwave ribbon -->
<path d="M30 150 q10 -18 20 0 t20 0" stroke="var(--mint)" stroke-width="4" fill="none" stroke-linecap="round" opacity=".7"/>
<!-- torso -->
<path d="M74 300 L74 214 Q74 182 120 182 Q166 182 166 214 L166 300 Z" fill="#EAF9F5" stroke="#14141a" stroke-width="3"/>
<!-- EQ bars on shirt -->
<g fill="var(--mint)"><rect x="104" y="228" width="7" height="34" rx="3"/><rect x="116" y="220" width="7" height="42" rx="3"/><rect x="128" y="234" width="7" height="28" rx="3"/></g>
<!-- neck -->
<rect x="106" y="158" width="28" height="26" rx="12" fill="#FFD9BC" stroke="#14141a" stroke-width="3"/>
<!-- back hair -->
<ellipse cx="120" cy="104" rx="80" ry="78" fill="var(--mint)"/>
<path d="M44 120 Q40 175 66 200 L80 176 Q60 150 62 118 Z" fill="var(--mint)"/>
<path d="M196 120 Q200 175 174 200 L160 176 Q180 150 178 118 Z" fill="var(--mint)"/>
<!-- face -->
<circle cx="120" cy="104" r="60" fill="#FFE3C8" stroke="#14141a" stroke-width="3"/>
<!-- bangs -->
<path d="M62 96 Q66 48 120 46 Q174 48 178 96 Q150 72 132 78 Q120 66 108 78 Q90 72 62 96 Z" fill="var(--mint)" stroke="#14141a" stroke-width="3"/>
<!-- headband -->
<path d="M64 78 Q120 30 176 78" stroke="#1FB89E" stroke-width="9" fill="none" stroke-linecap="round"/>
<!-- cat ears -->
<path d="M60 64 L44 26 L84 44 Z" fill="var(--mint)" stroke="#14141a" stroke-width="3" stroke-linejoin="round"/>
<path d="M180 64 L196 26 L156 44 Z" fill="var(--mint)" stroke="#14141a" stroke-width="3" stroke-linejoin="round"/>
<path d="M62 58 L54 40 L74 48 Z" fill="#FF9DB0"/><path d="M178 58 L186 40 L166 48 Z" fill="#FF9DB0"/>
<!-- earcups -->
<ellipse cx="58" cy="110" rx="14" ry="20" fill="#1FB89E" stroke="#14141a" stroke-width="3"/>
<ellipse cx="182" cy="110" rx="14" ry="20" fill="#1FB89E" stroke="#14141a" stroke-width="3"/>
<!-- eyes -->
<g><ellipse cx="99" cy="112" rx="11" ry="14" fill="#20242e"/><circle cx="103" cy="107" r="4" fill="#fff"/></g>
<g><ellipse cx="141" cy="112" rx="11" ry="14" fill="#20242e"/><circle cx="145" cy="107" r="4" fill="#fff"/></g>
<!-- blush -->
<ellipse cx="84" cy="130" rx="9" ry="5" fill="#FF9DB0" opacity=".75"/>
<ellipse cx="156" cy="130" rx="9" ry="5" fill="#FF9DB0" opacity=".75"/>
<!-- smile -->
<path d="M108 130 Q120 143 132 130" stroke="#14141a" stroke-width="3" fill="none" stroke-linecap="round"/>
</svg>
<div class="nm">여자 캐릭터 · 소리형 (임시)</div>
<div class="rl">AI 어시스턴트 · 발랄·수다·호기심</div>
<div><span class="chip">민트·틸</span><span class="chip">고양이귀 헤드폰</span><span class="chip">음파·음표</span></div>
</div>
<!-- ================= MALE (cyan) ================= -->
<div class="card">
<svg viewBox="0 0 240 300" width="100%">
<!-- torso hoodie -->
<path d="M72 300 L72 212 Q72 180 120 180 Q168 180 168 212 L168 300 Z" fill="#2A2F3A" stroke="#14141a" stroke-width="3"/>
<!-- hoodie strings + fader knobs -->
<line x1="112" y1="196" x2="112" y2="238" stroke="var(--cyan)" stroke-width="4" stroke-linecap="round"/>
<line x1="128" y1="196" x2="128" y2="238" stroke="var(--cyan)" stroke-width="4" stroke-linecap="round"/>
<circle cx="112" cy="224" r="6" fill="#fff" stroke="var(--cyan)" stroke-width="3"/>
<circle cx="128" cy="212" r="6" fill="#fff" stroke="var(--cyan)" stroke-width="3"/>
<!-- neck -->
<rect x="106" y="156" width="28" height="26" rx="12" fill="#FFD3B0" stroke="#14141a" stroke-width="3"/>
<!-- neckband headphones -->
<path d="M80 176 Q120 206 160 176" stroke="var(--cyan)" stroke-width="9" fill="none" stroke-linecap="round"/>
<ellipse cx="80" cy="176" rx="9" ry="12" fill="#2E9BD6" stroke="#14141a" stroke-width="3"/>
<ellipse cx="160" cy="176" rx="9" ry="12" fill="#2E9BD6" stroke="#14141a" stroke-width="3"/>
<!-- face -->
<circle cx="120" cy="100" r="58" fill="#FFD8BB" stroke="#14141a" stroke-width="3"/>
<!-- hair short messy dark + cyan streak -->
<path d="M64 96 Q60 46 120 44 Q180 46 176 96 Q168 74 150 72 Q156 58 138 60 Q140 46 122 52 Q108 44 104 60 Q92 56 92 72 Q74 72 64 96 Z" fill="#33343c" stroke="#14141a" stroke-width="3"/>
<path d="M104 60 Q120 50 138 60 Q128 62 122 58 Q112 64 104 60 Z" fill="var(--cyan)"/>
<!-- eyes big + friendly -->
<g><ellipse cx="100" cy="106" rx="10" ry="13" fill="#20242e"/><circle cx="104" cy="101" r="3.6" fill="#fff"/></g>
<g><ellipse cx="140" cy="106" rx="10" ry="13" fill="#20242e"/><circle cx="144" cy="101" r="3.6" fill="#fff"/></g>
<!-- big grin -->
<path d="M100 126 Q120 150 140 126 Q120 136 100 126 Z" fill="#fff" stroke="#14141a" stroke-width="3" stroke-linejoin="round"/>
<!-- blush -->
<ellipse cx="86" cy="124" rx="8" ry="4.5" fill="#FF9DB0" opacity=".6"/>
<ellipse cx="154" cy="124" rx="8" ry="4.5" fill="#FF9DB0" opacity=".6"/>
</svg>
<div class="nm">남자 캐릭터 · 단이형 (임시)</div>
<div class="rl">정밀 튜너 · 든든·유쾌한 큰웃음</div>
<div><span class="chip">시안·블루</span><span class="chip">넥밴드 헤드폰</span><span class="chip">페이더/노브</span></div>
</div>
<!-- ================= DUO ================= -->
<div class="card" style="width:280px">
<svg viewBox="0 0 260 220" width="100%">
<!-- shared cable -->
<path d="M92 150 Q130 190 168 150" stroke="#5a5f6b" stroke-width="4" fill="none"/>
<!-- mini female -->
<g transform="translate(20,20) scale(0.62)">
<circle cx="120" cy="104" r="60" fill="#FFE3C8" stroke="#14141a" stroke-width="4"/>
<path d="M62 96 Q66 48 120 46 Q174 48 178 96 Q150 72 132 78 Q120 66 108 78 Q90 72 62 96 Z" fill="#38e0c4" stroke="#14141a" stroke-width="4"/>
<path d="M60 64 L44 26 L84 44 Z" fill="#38e0c4" stroke="#14141a" stroke-width="4" stroke-linejoin="round"/>
<ellipse cx="182" cy="110" rx="14" ry="20" fill="#1FB89E" stroke="#14141a" stroke-width="4"/>
<ellipse cx="99" cy="112" rx="11" ry="14" fill="#20242e"/><ellipse cx="141" cy="112" rx="11" ry="14" fill="#20242e"/>
<path d="M108 130 Q120 143 132 130" stroke="#14141a" stroke-width="4" fill="none" stroke-linecap="round"/>
<ellipse cx="84" cy="130" rx="9" ry="5" fill="#FF9DB0" opacity=".75"/><ellipse cx="156" cy="130" rx="9" ry="5" fill="#FF9DB0" opacity=".75"/>
</g>
<!-- mini male -->
<g transform="translate(120,20) scale(0.62)">
<circle cx="120" cy="104" r="58" fill="#FFD8BB" stroke="#14141a" stroke-width="4"/>
<path d="M64 96 Q60 46 120 44 Q180 46 176 96 Q168 74 150 72 Q140 58 122 60 Q108 52 104 66 Q80 66 64 96 Z" fill="#33343c" stroke="#14141a" stroke-width="4"/>
<path d="M104 66 Q120 54 138 64 Q122 62 104 66 Z" fill="#4cc2ff"/>
<ellipse cx="80" cy="110" rx="13" ry="18" fill="#2E9BD6" stroke="#14141a" stroke-width="4"/>
<ellipse cx="100" cy="106" rx="10" ry="13" fill="#20242e"/><ellipse cx="140" cy="106" rx="10" ry="13" fill="#20242e"/>
<path d="M100 126 Q120 150 140 126 Q120 136 100 126 Z" fill="#fff" stroke="#14141a" stroke-width="4" stroke-linejoin="round"/>
</g>
<text x="130" y="205" text-anchor="middle" fill="#4cc2ff" font-size="16" font-weight="700">함께 = Dansori</text>
</svg>
<div class="nm">듀오 · "헤드폰 한 짝씩"</div>
<div class="rl">둘이 모여 브랜드 완성</div>
</div>
</div>
<h2>앱용 원형 아바타 (AI 응답창 등)</h2>
<div class="avwrap">
<svg viewBox="0 0 120 120" width="84" height="84">
<defs><clipPath id="c1"><circle cx="60" cy="60" r="58"/></clipPath></defs>
<circle cx="60" cy="60" r="58" fill="#20242e"/>
<g clip-path="url(#c1)" transform="translate(-8,6) scale(0.62)">
<circle cx="120" cy="104" r="60" fill="#FFE3C8"/>
<path d="M62 96 Q66 48 120 46 Q174 48 178 96 Q150 72 132 78 Q120 66 108 78 Q90 72 62 96 Z" fill="#38e0c4"/>
<path d="M60 64 L44 26 L84 44 Z" fill="#38e0c4"/><path d="M180 64 L196 26 L156 44 Z" fill="#38e0c4"/>
<ellipse cx="99" cy="112" rx="11" ry="14" fill="#20242e"/><ellipse cx="141" cy="112" rx="11" ry="14" fill="#20242e"/>
<path d="M108 130 Q120 143 132 130" stroke="#14141a" stroke-width="4" fill="none" stroke-linecap="round"/>
</g>
<circle cx="60" cy="60" r="58" fill="none" stroke="#38e0c4" stroke-width="3"/>
</svg>
<svg viewBox="0 0 120 120" width="84" height="84">
<defs><clipPath id="c2"><circle cx="60" cy="60" r="58"/></clipPath></defs>
<circle cx="60" cy="60" r="58" fill="#20242e"/>
<g clip-path="url(#c2)" transform="translate(-8,10) scale(0.62)">
<circle cx="120" cy="100" r="58" fill="#FFD8BB"/>
<path d="M64 96 Q60 46 120 44 Q180 46 176 96 Q168 74 150 72 Q140 58 122 60 Q108 52 104 66 Q80 66 64 96 Z" fill="#33343c"/>
<path d="M104 66 Q120 54 138 64 Q122 62 104 66 Z" fill="#4cc2ff"/>
<ellipse cx="100" cy="106" rx="10" ry="13" fill="#20242e"/><ellipse cx="140" cy="106" rx="10" ry="13" fill="#20242e"/>
<path d="M100 126 Q120 150 140 126 Q120 136 100 126 Z" fill="#fff"/>
</g>
<circle cx="60" cy="60" r="58" fill="none" stroke="#4cc2ff" stroke-width="3"/>
</svg>
<span class="note">← 이 원형 버전을 그대로 AI 응답창 아바타/알림 아이콘에 쓸 수 있어요.</span>
</div>
<h2>이미지 생성 AI용 프롬프트 (Midjourney/DALL·E 등에 붙여넣기)</h2>
<p class="note">SVG는 컨셉 스케치입니다. 아래 프롬프트로 고퀄 일러스트를 뽑아 보세요.</p>
<pre>[여자 · Sori]
cute chibi mascot girl for an audio app, 2.5 heads tall, big sparkly eyes, cheerful friendly smile, soft blush,
mint-teal bob hair with soundwave-shaped ends, wearing cat-ear headphones (mint), small music notes floating around,
white top with tiny equalizer bars, flat vector sticker style, bold clean outlines, mint (#38E0C4) accent,
dark navy background, kawaii, energetic pose — mascot design, front view</pre>
<pre>[남자 · Dan]
cute chibi mascot boy for an audio app, 2.5 heads tall, big friendly eyes, wide happy grin, slightly messy dark hair
with a cyan streak, cyan neckband headphones around neck, hoodie with mixer fader/knob details, thumbs up,
flat vector sticker style, bold clean outlines, cyan (#4CC2FF) accent, dark navy background, kawaii, cheerful —
mascot design, front view</pre>
<pre>[듀오]
two cute chibi audio mascots, a mint-haired cheerful girl with cat-ear headphones and a cyan-haired grinning boy with
neckband headphones, sharing one pair of headphones (a cable between them), happy, flat vector sticker style,
bold outlines, mint + cyan on dark navy, brand mascots for a music EQ app "Dansori", front view, friendly & bright</pre>
</body>
</html>
+290
View File
@@ -0,0 +1,290 @@
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>Dansori EQ — GUI 목업 갤러리</title>
<!-- Visual mockups of all pre-built screens (WPF can't render here). Open in a browser. -->
<style>
:root{
--bg:#141418; --mica1:#232733; --mica2:#1a1c22; --win:#1b1b1f;
--card:#26262b; --card2:#2d2d33; --stroke:#3a3a42;
--text:#f2f3f5; --dim:#a8abb4; --mute:#767a83;
--accent:#4cc2ff; --accent2:#38e0c4; --good:#4fd08a; --warn:#ffb454;
font-family:"Segoe UI Variable","Segoe UI",system-ui,sans-serif;
}
*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--text);padding:32px}
h1{font-size:24px;margin:0 0 4px}
.sub{color:var(--mute);margin:0 0 28px;font-size:15px}
h2{font-size:16px;color:var(--accent2);margin:34px 0 12px;letter-spacing:.3px}
.win{background:linear-gradient(180deg,var(--mica1),var(--mica2));border:1px solid var(--stroke);
border-radius:14px;box-shadow:0 20px 50px rgba(0,0,0,.5);overflow:hidden;margin-bottom:8px}
.tbar{height:38px;display:flex;align-items:center;gap:9px;padding:0 14px;border-bottom:1px solid var(--stroke);background:rgba(255,255,255,.015)}
.logo{width:18px;height:18px;border-radius:5px;background:conic-gradient(from 200deg,var(--accent),var(--accent2),var(--accent));box-shadow:0 0 12px rgba(76,194,255,.5)}
.tbar .t{font-size:14px;font-weight:600}
.tbar .t .s{color:var(--mute);font-weight:400}
.wbtns{margin-left:auto;color:var(--mute);font-size:14px;letter-spacing:6px}
.grid{display:grid;grid-template-columns:repeat(2,minmax(360px,1fr));gap:22px;align-items:start}
.btn{display:inline-flex;align-items:center;height:30px;padding:0 11px;border-radius:8px;background:var(--card);
border:1px solid var(--stroke);color:var(--dim);font-size:14px;font-weight:600;white-space:nowrap}
.btn.acc{background:linear-gradient(180deg,#57c7ff,#2f9fe0);color:#04222f;border:0}
.btn.help{background:#243b4a;color:#4cc2ff;border:0}
.btn.ghost{background:transparent;border:0;color:var(--mute)}
.chip{display:inline-block;background:var(--card2);border:1px solid var(--stroke);border-radius:9px;padding:6px 10px;font-size:13.5px;color:var(--dim);margin:0 6px 6px 0}
.badge{font-size:13px;font-weight:700;padding:2px 8px;border-radius:20px}
.badge.iem{background:rgba(56,224,196,.14);color:var(--accent2)}
.badge.src{background:var(--card);color:var(--mute)}
.card{background:var(--card);border:1px solid var(--stroke);border-radius:11px;padding:14px}
.lbl{color:var(--mute);font-size:13px}
.val{font-weight:600;font-size:15px}
.cap{color:var(--dim);font-weight:700;font-size:14px;letter-spacing:.3px}
.field{height:34px;border-radius:8px;border:1px solid var(--stroke);background:var(--card);display:flex;align-items:center;padding:0 12px;color:var(--mute);font-size:14.5px}
input,select{all:unset}
.row{display:flex;align-items:center;gap:8px}
/* svg */
svg .g{stroke:#33333b;stroke-width:1}
svg .ax{fill:var(--mute);font-size:12px}
/* volume */
.vslider{width:8px;height:150px;border-radius:8px;background:var(--card2);position:relative;margin:0 auto}
.vfill{position:absolute;bottom:0;left:0;right:0;height:62%;border-radius:8px;background:linear-gradient(180deg,var(--accent),var(--accent2))}
.vknob{position:absolute;left:50%;transform:translate(-50%,-50%);top:38%;width:16px;height:16px;border-radius:50%;background:#fff;box-shadow:0 1px 4px rgba(0,0,0,.5)}
.note{color:var(--mute);font-size:13px;line-height:1.5}
.flex{display:flex;gap:16px}
</style>
</head>
<body>
<h1>Dansori EQ — GUI 목업 갤러리</h1>
<p class="sub">지금까지 선구현한 화면들의 시각 목업입니다. 실제 앱은 .NET 8 + WPF + WPF-UI(Fluent)로 이 룩을 네이티브 렌더링합니다.</p>
<!-- ===================== MAIN WINDOW ===================== -->
<h2>1. 메인 창 (그래프 · 볼륨 · AI 입력)</h2>
<div class="win">
<div class="tbar"><div class="logo"></div><div class="t">Dansori EQ <span class="s">· AI EQ for Equalizer APO</span></div><div class="wbtns">— ▢ ✕</div></div>
<div style="display:flex;min-height:520px">
<!-- sidebar -->
<div style="width:250px;border-right:1px solid var(--stroke);background:rgba(0,0,0,.12);display:flex;flex-direction:column">
<div style="padding:12px"><div class="field">🔎 이어폰 · 헤드폰 검색…</div></div>
<div style="flex:1;padding:0 10px;overflow:auto">
<div style="color:var(--mute);font-size:13px;font-weight:700;padding:10px 8px 4px">🎧 IN-EAR MONITORS</div>
<div style="background:rgba(76,194,255,.14);box-shadow:inset 0 0 0 1px rgba(76,194,255,.35);border-radius:9px;padding:8px 10px;font-size:14.5px;font-weight:600">Truthear × Crinacle Zero<div style="color:var(--mute);font-size:13px;font-weight:400">Truthear · IEM</div></div>
<div style="padding:8px 10px;font-size:14.5px;color:var(--dim)">Moondrop Blessing 2</div>
<div style="padding:8px 10px;font-size:14.5px;color:var(--dim)">7Hz Timeless</div>
<div style="color:var(--mute);font-size:13px;font-weight:700;padding:10px 8px 4px">🎧 HEADPHONES</div>
<div style="padding:8px 10px;font-size:14.5px;color:var(--dim)">Sennheiser HD 600</div>
<div style="padding:8px 10px;font-size:14.5px;color:var(--dim)">HIFIMAN Sundara</div>
</div>
<div style="border-top:1px solid var(--stroke);padding:12px">
<div class="btn" style="width:100%;justify-content:center">⟳ 프로파일 DB 업데이트</div>
<div style="color:var(--mute);font-size:13px;text-align:center;margin-top:8px">4,213 profiles · 2026-06-28</div>
</div>
</div>
<!-- main -->
<div style="flex:1;display:flex;flex-direction:column">
<div style="padding:14px 18px 4px">
<div class="row" style="flex-wrap:wrap">
<b style="font-size:19px">Truthear × Crinacle Zero</b>
<span class="badge iem">IEM</span><span class="badge src">AutoEQ · Harman IE 2019</span>
</div>
<div class="row" style="flex-wrap:wrap;margin-top:8px">
<span class="btn help">❓ 도움말</span><span class="btn">⚙ 설정</span><span class="btn">⌨ 명령</span>
<span class="btn">🎚 이펙트</span><span class="btn">📚 프리셋</span><span class="btn">↥ 내보내기</span>
<span class="btn">↧ 가져오기</span><span class="btn">↶ 되돌리기</span><span class="btn">⟲ 리셋</span>
<span class="btn ghost">활성 ●</span>
</div>
</div>
<div style="flex:1;padding:12px 18px 0">
<!-- graph + volume -->
<div class="card" style="margin-bottom:14px">
<div class="row" style="margin-bottom:8px"><span class="cap">EQUALIZATION CURVE</span>
<span style="margin-left:auto;background:rgba(255,180,84,.12);color:var(--warn);font-weight:700;font-size:13px;padding:2px 9px;border-radius:20px">Preamp 6.0 dB</span></div>
<div class="flex">
<svg viewBox="0 0 720 240" style="flex:1;height:210px">
<line class="g" x1="30" y1="50" x2="700" y2="50"/><line class="g" x1="30" y1="120" x2="700" y2="120" stroke="#44454e"/><line class="g" x1="30" y1="190" x2="700" y2="190"/>
<text class="ax" x="4" y="54">+12</text><text class="ax" x="10" y="124">0</text><text class="ax" x="4" y="194">12</text>
<defs><linearGradient id="f" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="rgba(76,194,255,.35)"/><stop offset="1" stop-color="rgba(76,194,255,0)"/></linearGradient>
<linearGradient id="s" x1="0" x2="1"><stop offset="0" stop-color="#38e0c4"/><stop offset="1" stop-color="#4cc2ff"/></linearGradient></defs>
<path d="M30 96 C110 92 160 130 250 138 S360 140 400 120 S500 92 540 104 S640 142 700 128 L700 210 L30 210 Z" fill="url(#f)"/>
<path d="M30 96 C110 92 160 130 250 138 S360 140 400 120 S500 92 540 104 S640 142 700 128" fill="none" stroke="url(#s)" stroke-width="2.5"/>
<circle cx="80" cy="94" r="5" fill="#04222f" stroke="#38e0c4" stroke-width="2.4"/><circle cx="250" cy="138" r="5" fill="#04222f" stroke="#4cc2ff" stroke-width="2.4"/><circle cx="500" cy="96" r="5" fill="#04222f" stroke="#4cc2ff" stroke-width="2.4"/>
</svg>
<!-- volume panel -->
<div style="width:130px">
<div class="lbl" style="font-weight:700;margin-bottom:6px">출력 · 볼륨</div>
<div class="field" style="height:30px;justify-content:space-between">스피커 (Realtek) ▾</div>
<div style="height:160px;display:flex;align-items:center;justify-content:center;margin-top:8px"><div class="vslider"><div class="vfill"></div><div class="vknob"></div></div></div>
<div style="text-align:center;font-weight:600;margin:6px 0">62%</div>
<div class="btn" style="width:100%;justify-content:center">🔇 음소거</div>
</div>
</div>
</div>
<!-- filters -->
<div class="card">
<div class="row" style="margin-bottom:8px"><span class="cap">ACTIVE FILTERS · 6 / 40 bands</span>
<span class="btn" style="height:26px;margin-left:auto"> 밴드 추가</span><span class="btn" style="height:26px;margin-left:6px">전체 지우기</span></div>
<span class="chip">LSC 90Hz · Q0.7 <b style="color:var(--good)">+4.0</b></span>
<span class="chip">PK 180Hz · Q1.0 <b style="color:var(--warn)">2.5</b></span>
<span class="chip">PK 3.0kHz · Q1.2 <b style="color:var(--good)">+3.0</b></span>
<span class="chip">PK 6.5kHz · Q3.0 <b style="color:var(--warn)">2.0</b></span>
<span class="chip">HSC 10kHz · Q0.7 <b style="color:var(--warn)">1.5</b></span>
</div>
</div>
<!-- AI dock -->
<div style="border-top:1px solid var(--stroke);padding:12px 18px;background:rgba(0,0,0,.14)">
<div style="background:var(--card);border:1px solid var(--stroke);border-radius:11px;padding:10px 13px;margin-bottom:10px;font-size:14px;color:var(--dim);max-width:640px">
보컬을 앞으로 3kHz +3dB, 저음 단단하게 180Hz 2.5dB, 무게 45Hz +2dB. 클리핑 방지 Preamp 6.0dB. <b style="color:var(--text)">적용됨 ✓</b></div>
<div class="row"><div class="field" style="flex:1;height:44px">예: 보컬을 더 가깝게, 저음은 단단하게 · 치찰음 줄여줘</div><div class="btn acc" style="width:44px;height:44px;justify-content:center;font-size:18px"></div></div>
</div>
</div>
</div>
</div>
<!-- ===================== SECONDARY WINDOWS ===================== -->
<h2>2. 부가 창들</h2>
<div class="grid">
<!-- Help drawer -->
<div class="win">
<div class="tbar"><div class="t">❓ 도움말 (오른쪽에서 슬라이드)</div></div>
<div style="padding:18px">
<b style="font-size:17px">도움말</b>
<p class="note" style="margin:8px 0 14px">처음 오셨나요? 아래 3단계면 나만의 소리를 만들 수 있어요.</p>
<div class="card" style="margin-bottom:8px"><b style="color:var(--accent)">① 기기 고르기</b><p class="note" style="margin:6px 0 0">왼쪽 목록에서 이어폰/헤드폰 선택. 없으면 'DB 업데이트'.</p></div>
<div class="card" style="margin-bottom:8px"><b style="color:var(--accent)">② 말로 소리 만들기</b><p class="note" style="margin:6px 0 0">"보컬을 더 가깝게", "저음은 단단하게" 처럼 입력.</p></div>
<div class="card" style="margin-bottom:12px"><b style="color:var(--accent)">③ 그래프로 다듬기</b><p class="note" style="margin:6px 0 0">드래그=주파수/음량 · 휠=Q · 더블클릭=추가 · 우클릭=삭제</p></div>
<b style="font-size:14px">AI API 키 발급</b>
<div class="btn" style="width:100%;justify-content:flex-start;margin-top:6px;color:var(--accent)">🔗 Claude (Anthropic) 키 발급</div>
<div class="btn" style="width:100%;justify-content:flex-start;margin-top:6px;color:var(--accent)">🔗 ChatGPT (OpenAI) 키 발급</div>
<div class="btn" style="width:100%;justify-content:flex-start;margin-top:6px;color:var(--accent)">🔗 Gemini (Google) 키 발급</div>
</div>
</div>
<!-- Settings -->
<div class="win">
<div class="tbar"><div class="t">⚙ 설정</div></div>
<div style="padding:18px">
<div class="card">
<div class="cap" style="margin-bottom:6px">AI · API 키</div>
<p class="note" style="margin:0 0 10px">키는 DPAPI로 암호화 저장(평문 X). 저장 후 '이미 입력됨'으로 표시.</p>
<div class="card2" style="background:var(--card2);border-radius:9px;padding:10px;margin-bottom:8px;display:flex;align-items:center">
<div style="width:150px"><div class="val">Claude API</div><div style="color:var(--accent);font-size:13px">🔗 키 발급 방법</div></div>
<div style="flex:1;color:var(--good);font-size:14px">🔒 이미 입력되어 있음 (••••••••)</div><span class="btn">삭제</span></div>
<div style="background:var(--card2);border-radius:9px;padding:10px;margin-bottom:8px;display:flex;align-items:center">
<div style="width:150px"><div class="val">ChatGPT (OpenAI)</div><div style="color:var(--accent);font-size:13px">🔗 키 발급 방법</div></div>
<div class="field" style="flex:1;height:32px">API 키 붙여넣기…</div><span class="btn acc" style="margin-left:8px">저장</span></div>
<div style="background:var(--card2);border-radius:9px;padding:10px;display:flex;align-items:center">
<div style="width:150px"><div class="val">Gemini</div><div style="color:var(--accent);font-size:13px">🔗 키 발급 방법</div></div>
<div class="field" style="flex:1;height:32px">API 키 붙여넣기…</div><span class="btn acc" style="margin-left:8px">저장</span></div>
<div class="row" style="margin-top:10px"><span class="lbl" style="width:150px">Claude 모델</span><div class="field" style="width:200px;height:32px">Claude Sonnet (기본) ▾</div></div>
</div>
<div class="card" style="margin-top:10px"><div class="cap">테마</div><p class="note" style="margin:6px 0 0">Dark / Light / System + 강조색 (M5)</p></div>
</div>
</div>
<!-- DB Manager -->
<div class="win">
<div class="tbar"><div class="t">프로파일 데이터베이스</div></div>
<div style="padding:18px">
<div class="card" style="margin-bottom:12px">
<div class="cap" style="margin-bottom:10px">현재 상태</div>
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:10px">
<div><div class="lbl">전체</div><div class="val" style="font-size:21px">4,213</div></div>
<div><div class="lbl">이어폰(IEM)</div><div class="val">2,140</div></div>
<div><div class="lbl">헤드폰</div><div class="val">2,073</div></div>
<div><div class="lbl">최근 업데이트</div><div class="val">2026-06-28</div></div>
<div><div class="lbl">DB 크기</div><div class="val">7.0 MB</div></div>
<div><div class="lbl">스키마</div><div class="val">v1</div></div>
</div>
</div>
<div class="card">
<div class="cap" style="margin-bottom:10px">데이터 출처 (Sources)</div>
<div style="background:var(--card2);border-radius:9px;padding:10px;margin-bottom:8px;display:flex;align-items:center"><div style="flex:1"><b style="font-size:15px">AutoEQ</b><div style="color:var(--mute);font-size:13px">MIT / mixed · 3,600개</div></div><span class="badge src" style="margin-right:8px">배포 가능</span><span style="color:var(--dim);font-size:13px">업데이트 있음</span></div>
<div style="background:var(--card2);border-radius:9px;padding:10px;display:flex;align-items:center"><div style="flex:1"><b style="font-size:15px">oratory1990</b><div style="color:var(--mute);font-size:13px">restricted · 480개</div></div><span class="badge src" style="margin-right:8px">배포 제한</span><span style="color:var(--dim);font-size:13px">최신</span></div>
</div>
<div class="row" style="margin-top:12px"><div style="flex:1;height:8px;border-radius:8px;background:var(--card2);position:relative"><div style="position:absolute;left:0;top:0;bottom:0;width:40%;border-radius:8px;background:var(--accent)"></div></div><span class="lbl">파싱 중…</span></div>
<div class="row" style="justify-content:flex-end;margin-top:12px"><span class="btn acc">지금 업데이트</span><span class="btn" style="margin-left:8px">닫기</span></div>
</div>
</div>
<!-- Effects -->
<div class="win">
<div class="tbar"><div class="t">🎚 이펙트</div></div>
<div style="padding:18px">
<div class="card">
<div class="row"><span class="lbl" style="flex:1">크로스피드</span><b>30 %</b></div>
<div style="height:6px;border-radius:8px;background:var(--card2);margin:6px 0 14px;position:relative"><div style="position:absolute;left:0;top:0;bottom:0;width:30%;border-radius:8px;background:var(--accent)"></div></div>
<div class="row"><span class="lbl" style="flex:1">베이스 부스트</span><b>+3.0 dB</b></div>
<div style="height:6px;border-radius:8px;background:var(--card2);margin:6px 0 14px;position:relative"><div style="position:absolute;left:0;top:0;bottom:0;width:25%;border-radius:8px;background:var(--accent)"></div></div>
<div class="row"><span class="lbl" style="flex:1">왼쪽 트림</span><b>0.0 dB</b></div>
<div style="height:6px;border-radius:8px;background:var(--card2);margin:6px 0 14px;position:relative"><div style="position:absolute;left:0;top:0;bottom:0;width:100%;border-radius:8px;background:var(--accent)"></div></div>
<div class="row"><span class="lbl" style="flex:1">오른쪽 트림</span><b>1.5 dB</b></div>
<div style="height:6px;border-radius:8px;background:var(--card2);margin:6px 0 0;position:relative"><div style="position:absolute;left:0;top:0;bottom:0;width:88%;border-radius:8px;background:var(--accent)"></div></div>
</div>
<p class="note" style="margin:10px 0 0">※ 크로스피드는 현재 플레이스홀더입니다(정식 구현 예정).</p>
</div>
</div>
<!-- Preset Library -->
<div class="win">
<div class="tbar"><div class="t">📚 프리셋 라이브러리</div></div>
<div style="padding:18px">
<div class="row" style="margin-bottom:12px"><div class="field" style="flex:1">프리셋 이름…</div><span class="btn acc" style="margin-left:8px">현재 상태 저장</span></div>
<div class="card" style="padding:8px">
<div style="padding:9px 10px;background:rgba(76,194,255,.12);border-radius:8px;font-size:15px">밤에 듣기 (보컬 강조)</div>
<div style="padding:9px 10px;color:var(--dim);font-size:15px">게이밍 (발소리)</div>
<div style="padding:9px 10px;color:var(--dim);font-size:15px">저음 강조</div>
<div style="padding:9px 10px;color:var(--dim);font-size:15px">레퍼런스 (플랫)</div>
</div>
<div class="row" style="justify-content:flex-end;margin-top:12px"><span class="btn">불러오기</span><span class="btn" style="margin-left:8px">삭제</span><span class="btn" style="margin-left:8px">닫기</span></div>
</div>
</div>
<!-- Import preview -->
<div class="win">
<div class="tbar"><div class="t">EQ 프리셋 가져오기</div></div>
<div style="padding:18px">
<b style="font-size:17px">이 EQ를 적용할까요?</b>
<div class="card" style="margin:12px 0">
<div class="lbl">대상 기기</div><div class="val" style="font-size:17px;margin:2px 0 6px">Moondrop Blessing 2 (iem)</div>
<div style="color:var(--dim);font-size:14px">Moondrop · AutoEQ · Harman IE 2019</div>
<div style="color:var(--dim);font-size:14px;margin-top:4px">7 bands · Preamp 6.5 dB</div>
</div>
<div class="card" style="margin-bottom:12px"><span style="color:var(--warn);font-size:14px">⚠ 이 기기 프로파일이 로컬 DB에 없습니다.</span> <span class="btn" style="margin-left:6px">DB 업데이트</span></div>
<div class="card"><div class="cap" style="margin-bottom:8px">제작 히스토리 (AI 대화)</div>
<div style="background:var(--card2);border-radius:8px;padding:8px;margin-bottom:6px"><div style="color:var(--mute);font-size:13px;font-weight:700">USER</div><div style="color:var(--dim);font-size:14px">보컬 가까이, 저음 단단히</div></div>
<div style="background:var(--card2);border-radius:8px;padding:8px"><div style="color:var(--mute);font-size:13px;font-weight:700">AI</div><div style="color:var(--dim);font-size:14px">3kHz +3dB, 180Hz 2.5dB…</div></div>
</div>
<div class="row" style="justify-content:flex-end;margin-top:12px"><span class="btn acc">적용</span><span class="btn" style="margin-left:8px">취소</span></div>
</div>
</div>
<!-- APO setup -->
<div class="win">
<div class="tbar"><div class="t">Equalizer APO 설정 (시작 시)</div></div>
<div style="padding:18px">
<b style="font-size:17px">Equalizer APO가 감지되지 않았습니다</b>
<p class="note" style="margin:8px 0 14px">이 앱은 APO로 EQ를 적용합니다. 설치하거나 config 폴더 경로를 지정하세요.</p>
<div class="card">
<div class="btn acc" style="width:100%;justify-content:flex-start;margin-bottom:8px">⬇ APO 자동 설치 (공식 설치파일 다운로드·실행)</div>
<div class="btn" style="width:100%;justify-content:flex-start;margin-bottom:8px">📁 APO config 폴더 직접 지정</div>
<div class="btn ghost" style="width:100%;justify-content:flex-start">나중에 (미리보기 모드로 계속)</div>
</div>
<div style="height:8px;border-radius:8px;background:var(--card2);margin:14px 0 6px"></div>
<p class="note" style="margin:0">APO 설치는 장치 선택과 재부팅이 필요합니다.</p>
</div>
</div>
<!-- Command window -->
<div class="win">
<div class="tbar"><div class="t">⌨ APO 명령 입력 (고급)</div></div>
<div style="padding:18px">
<b style="font-size:16px">Equalizer APO 명령 직접 입력</b>
<p class="note" style="margin:6px 0 12px">예: 'Preamp: -3 dB', 'Filter: ON PK Fc 1000 Hz Gain 2 dB Q 1'</p>
<div style="background:var(--card);border:1px solid var(--stroke);border-radius:8px;padding:12px;font-family:Consolas,monospace;font-size:14.5px;color:var(--dim);min-height:120px;line-height:1.7">
Preamp: -3 dB<br>Filter: ON PK Fc 2500 Hz Gain 2 dB Q 1.2<br>Copy: L=R R=L</div>
<div class="row" style="justify-content:flex-end;margin-top:12px"><span class="btn acc">적용</span><span class="btn" style="margin-left:8px">닫기</span></div>
</div>
</div>
</div>
</body>
</html>
+329
View File
@@ -0,0 +1,329 @@
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Dansori EQ — GUI Mockup</title>
<!--
VISUAL TARGET MOCKUP (not the real app).
Represents the intended look of the native app: .NET 8 + WPF + WPF-UI (Fluent) + LiveCharts2.
Open in a browser to preview the aesthetic. Dark Fluent, Mica-like background, accent cyan.
-->
<style>
:root{
--bg:#1b1b1f;
--mica-1:#232733;
--mica-2:#1a1c22;
--card:#26262b;
--card-2:#2d2d33;
--stroke:#3a3a42;
--text:#f2f3f5;
--text-dim:#a8abb4;
--text-mute:#767a83;
--accent:#4cc2ff;
--accent-2:#38e0c4;
--accent-soft:rgba(76,194,255,.14);
--good:#4fd08a;
--warn:#ffb454;
--radius:12px;
--radius-lg:16px;
font-family:"Segoe UI Variable","Segoe UI",system-ui,sans-serif;
}
*{box-sizing:border-box;}
html,body{margin:0;height:100%;}
body{
background:
radial-gradient(1200px 500px at 12% -8%, #2b3550 0%, transparent 55%),
radial-gradient(900px 500px at 100% 0%, #22403c 0%, transparent 50%),
var(--bg);
color:var(--text);
display:flex;align-items:center;justify-content:center;
height:100vh;overflow:hidden;
}
.window{
width:1180px;height:720px;
background:linear-gradient(180deg,var(--mica-1),var(--mica-2));
border:1px solid var(--stroke);
border-radius:var(--radius-lg);
box-shadow:0 30px 80px rgba(0,0,0,.55);
display:flex;flex-direction:column;overflow:hidden;
}
/* ---- title bar ---- */
.titlebar{
height:44px;display:flex;align-items:center;gap:10px;
padding:0 16px;border-bottom:1px solid var(--stroke);
-webkit-app-region:drag;background:rgba(255,255,255,.015);
}
.logo{width:22px;height:22px;border-radius:6px;
background:conic-gradient(from 200deg,var(--accent),var(--accent-2),var(--accent));
box-shadow:0 0 14px rgba(76,194,255,.5);}
.title{font-size:13px;font-weight:600;letter-spacing:.2px;}
.title .sub{color:var(--text-mute);font-weight:400;margin-left:8px;}
.winbtns{margin-left:auto;display:flex;gap:14px;color:var(--text-mute);}
.winbtns span{font-size:13px;}
/* ---- body ---- */
.body{flex:1;display:flex;min-height:0;}
/* ---- sidebar ---- */
.sidebar{
width:288px;border-right:1px solid var(--stroke);
display:flex;flex-direction:column;background:rgba(0,0,0,.12);
}
.search{padding:14px 14px 8px;}
.search input{
width:100%;height:38px;border-radius:9px;border:1px solid var(--stroke);
background:var(--card);color:var(--text);padding:0 12px 0 34px;font-size:13px;
background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' stroke='%23888' stroke-width='2' viewBox='0 0 24 24'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M21 21l-4.3-4.3'/%3E%3C/svg%3E");
background-repeat:no-repeat;background-position:11px center;outline:none;
}
.search input:focus{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft);}
.list{flex:1;overflow:auto;padding:4px 8px 8px;}
.grouphdr{
display:flex;align-items:center;gap:8px;
padding:12px 10px 6px;font-size:11px;font-weight:700;letter-spacing:.8px;
color:var(--text-mute);text-transform:uppercase;
}
.grouphdr .count{margin-left:auto;font-weight:600;color:var(--text-mute);
background:var(--card);padding:1px 8px;border-radius:20px;font-size:10px;letter-spacing:0;}
.item{
display:flex;align-items:center;gap:11px;padding:9px 10px;border-radius:9px;
cursor:pointer;margin:2px 0;
}
.item:hover{background:var(--card);}
.item.active{background:var(--accent-soft);box-shadow:inset 0 0 0 1px rgba(76,194,255,.35);}
.item .ic{width:30px;height:30px;border-radius:8px;background:var(--card-2);
display:flex;align-items:center;justify-content:center;flex-shrink:0;color:var(--text-dim);}
.item.active .ic{color:var(--accent);}
.item .nm{font-size:13px;font-weight:600;line-height:1.15;}
.item .br{font-size:11px;color:var(--text-mute);}
.sidefoot{border-top:1px solid var(--stroke);padding:12px;display:flex;flex-direction:column;gap:8px;}
.btn{
height:38px;border-radius:9px;border:1px solid var(--stroke);background:var(--card);
color:var(--text);font-size:13px;font-weight:600;display:flex;align-items:center;
justify-content:center;gap:8px;cursor:pointer;
}
.btn:hover{background:var(--card-2);}
.btn.accent{background:linear-gradient(180deg,#57c7ff,#2f9fe0);border-color:transparent;color:#04222f;}
.dbmeta{font-size:11px;color:var(--text-mute);text-align:center;}
/* ---- main ---- */
.main{flex:1;display:flex;flex-direction:column;min-width:0;}
.mainhdr{display:flex;align-items:center;gap:14px;padding:18px 22px 6px;}
.mainhdr h1{font-size:20px;margin:0;font-weight:700;letter-spacing:.2px;}
.badge{font-size:11px;font-weight:700;padding:3px 9px;border-radius:20px;letter-spacing:.4px;}
.badge.iem{background:rgba(56,224,196,.14);color:var(--accent-2);}
.badge.src{background:var(--card);color:var(--text-mute);font-weight:600;}
.hdr-actions{margin-left:auto;display:flex;gap:8px;align-items:center;}
.chipbtn{height:32px;padding:0 12px;border-radius:8px;border:1px solid var(--stroke);
background:var(--card);color:var(--text-dim);font-size:12px;font-weight:600;cursor:pointer;
display:flex;align-items:center;gap:6px;}
.chipbtn:hover{background:var(--card-2);color:var(--text);}
.toggle{display:flex;align-items:center;gap:8px;font-size:12px;color:var(--text-dim);}
.sw{width:38px;height:22px;border-radius:20px;background:linear-gradient(90deg,#3aa0d8,#38e0c4);
position:relative;}
.sw::after{content:"";position:absolute;right:3px;top:3px;width:16px;height:16px;border-radius:50%;background:#fff;}
/* graph card */
.content{flex:1;overflow:auto;padding:12px 22px 0;}
.card{background:var(--card);border:1px solid var(--stroke);border-radius:var(--radius);padding:16px 18px;margin-bottom:16px;}
.card .caption{display:flex;align-items:center;gap:10px;margin-bottom:10px;}
.card .caption .t{font-size:13px;font-weight:700;color:var(--text-dim);letter-spacing:.3px;}
.preamp{margin-left:auto;font-size:12px;font-weight:700;color:var(--warn);
background:rgba(255,180,84,.12);padding:3px 10px;border-radius:20px;}
.legend{display:flex;gap:16px;font-size:11px;color:var(--text-mute);}
.legend i{display:inline-block;width:14px;height:0;border-top:2px solid;vertical-align:middle;margin-right:5px;}
.graphwrap{position:relative;}
svg .grid{stroke:#33333b;stroke-width:1;}
svg .axis{fill:var(--text-mute);font-size:10px;}
/* filter chips */
.filters{display:flex;flex-wrap:wrap;gap:8px;}
.fchip{display:flex;align-items:center;gap:8px;padding:7px 11px;border-radius:9px;
background:var(--card-2);border:1px solid var(--stroke);font-size:12px;}
.fchip .type{font-weight:700;color:var(--accent);font-size:10px;letter-spacing:.5px;}
.fchip .val{color:var(--text-dim);}
.fchip .g.pos{color:var(--good);font-weight:600;}
.fchip .g.neg{color:var(--warn);font-weight:600;}
/* AI dock */
.aidock{border-top:1px solid var(--stroke);padding:14px 22px 18px;background:rgba(0,0,0,.14);}
.airesp{display:flex;gap:11px;margin-bottom:12px;}
.airesp .av{width:28px;height:28px;border-radius:8px;flex-shrink:0;
background:conic-gradient(from 200deg,var(--accent),var(--accent-2));box-shadow:0 0 12px rgba(76,194,255,.45);}
.airesp .bubble{background:var(--card);border:1px solid var(--stroke);border-radius:12px;
padding:11px 14px;font-size:12.5px;line-height:1.5;color:var(--text-dim);max-width:820px;}
.airesp .bubble b{color:var(--text);font-weight:600;}
.promptbar{display:flex;gap:10px;align-items:center;}
.promptbar .field{flex:1;height:46px;border-radius:12px;border:1px solid var(--stroke);
background:var(--card);display:flex;align-items:center;padding:0 8px 0 16px;}
.promptbar .field:focus-within{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft);}
.promptbar input{flex:1;border:none;background:none;color:var(--text);font-size:14px;outline:none;}
.promptbar input::placeholder{color:var(--text-mute);}
.mic{width:32px;height:32px;border-radius:8px;background:var(--card-2);display:flex;align-items:center;justify-content:center;color:var(--text-mute);}
.send{width:46px;height:46px;border-radius:12px;border:none;cursor:pointer;
background:linear-gradient(180deg,#57c7ff,#2f9fe0);color:#04222f;display:flex;align-items:center;justify-content:center;}
.hint{font-size:11px;color:var(--text-mute);margin-top:8px;}
::-webkit-scrollbar{width:10px;}::-webkit-scrollbar-thumb{background:#3a3a42;border-radius:8px;border:3px solid transparent;background-clip:content-box;}
</style>
</head>
<body>
<div class="window">
<!-- title bar -->
<div class="titlebar">
<div class="logo"></div>
<div class="title">Dansori EQ <span class="sub">· AI EQ for Equalizer APO</span></div>
<div class="winbtns"><span></span><span></span><span></span></div>
</div>
<div class="body">
<!-- sidebar -->
<aside class="sidebar">
<div class="search"><input placeholder="이어폰 · 헤드폰 검색…" value="" /></div>
<div class="list">
<div class="grouphdr">🎧 In-Ear Monitors <span class="count">2,140</span></div>
<div class="item active">
<div class="ic">🎵</div>
<div><div class="nm">Truthear × Crinacle Zero</div><div class="br">Truthear · IEM</div></div>
</div>
<div class="item">
<div class="ic">🎵</div>
<div><div class="nm">Moondrop Blessing 2</div><div class="br">Moondrop · IEM</div></div>
</div>
<div class="item">
<div class="ic">🎵</div>
<div><div class="nm">7Hz Timeless</div><div class="br">7Hz · IEM</div></div>
</div>
<div class="item">
<div class="ic">🎵</div>
<div><div class="nm">Etymotic ER2XR</div><div class="br">Etymotic · IEM</div></div>
</div>
<div class="grouphdr">🎧 Headphones <span class="count">2,073</span></div>
<div class="item">
<div class="ic">🎧</div>
<div><div class="nm">Sennheiser HD 600</div><div class="br">Sennheiser · Over-ear</div></div>
</div>
<div class="item">
<div class="ic">🎧</div>
<div><div class="nm">HIFIMAN Sundara</div><div class="br">HIFIMAN · Over-ear</div></div>
</div>
<div class="item">
<div class="ic">🎧</div>
<div><div class="nm">Focal Clear</div><div class="br">Focal · Over-ear</div></div>
</div>
</div>
<div class="sidefoot">
<button class="btn"><span></span> 프로파일 DB 업데이트</button>
<div class="dbmeta">4,213 profiles · 최신: 2026-06-28</div>
</div>
</aside>
<!-- main -->
<section class="main">
<div class="mainhdr">
<h1>Truthear × Crinacle Zero</h1>
<span class="badge iem">IEM</span>
<span class="badge src">AutoEQ · Harman IE 2019</span>
<div class="hdr-actions">
<button class="chipbtn">↶ 되돌리기</button>
<button class="chipbtn">⟲ 베이스로 리셋</button>
<div class="toggle">활성 <div class="sw"></div></div>
</div>
</div>
<div class="content">
<!-- EQ GRAPH -->
<div class="card">
<div class="caption">
<span class="t">EQUALIZATION CURVE</span>
<div class="legend">
<span><i style="border-color:#5a5f6b;border-top-style:dashed"></i>타깃</span>
<span><i style="border-color:var(--accent)"></i>현재 EQ</span>
</div>
<span class="preamp">Preamp 6.0 dB</span>
</div>
<div class="graphwrap">
<svg viewBox="0 0 900 300" width="100%" height="300">
<defs>
<linearGradient id="fill" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="rgba(76,194,255,.35)"/>
<stop offset="100%" stop-color="rgba(76,194,255,0)"/>
</linearGradient>
<linearGradient id="stroke" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#38e0c4"/>
<stop offset="100%" stop-color="#4cc2ff"/>
</linearGradient>
</defs>
<!-- horizontal grid (dB) -->
<line class="grid" x1="40" y1="60" x2="880" y2="60"/>
<line class="grid" x1="40" y1="110" x2="880" y2="110"/>
<line class="grid" x1="40" y1="150" x2="880" y2="150" stroke="#44454e"/>
<line class="grid" x1="40" y1="190" x2="880" y2="190"/>
<line class="grid" x1="40" y1="240" x2="880" y2="240"/>
<text class="axis" x="8" y="64">+12</text>
<text class="axis" x="12" y="154">0</text>
<text class="axis" x="8" y="244">12</text>
<!-- vertical grid (freq) -->
<line class="grid" x1="130" y1="40" x2="130" y2="260"/>
<line class="grid" x1="300" y1="40" x2="300" y2="260"/>
<line class="grid" x1="470" y1="40" x2="470" y2="260"/>
<line class="grid" x1="640" y1="40" x2="640" y2="260"/>
<line class="grid" x1="810" y1="40" x2="810" y2="260"/>
<text class="axis" x="118" y="278">50</text>
<text class="axis" x="285" y="278">200</text>
<text class="axis" x="452" y="278">1k</text>
<text class="axis" x="625" y="278">5k</text>
<text class="axis" x="792" y="278">20k</text>
<!-- target (dashed) -->
<path d="M40 150 C160 148 240 156 320 158 S470 152 560 150 S720 148 880 150"
fill="none" stroke="#5a5f6b" stroke-width="1.6" stroke-dasharray="5 5"/>
<!-- current EQ area -->
<path d="M40 120 C120 116 190 150 300 170 S430 172 470 150 S560 118 620 130
S740 176 800 164 S860 158 880 156 L880 260 L40 260 Z"
fill="url(#fill)"/>
<!-- current EQ line -->
<path d="M40 120 C120 116 190 150 300 170 S430 172 470 150 S560 118 620 130
S740 176 800 164 S860 158 880 156"
fill="none" stroke="url(#stroke)" stroke-width="3" stroke-linecap="round"/>
<!-- filter nodes -->
<circle cx="95" cy="118" r="5" fill="#04222f" stroke="#38e0c4" stroke-width="2.5"/>
<circle cx="300" cy="170" r="5" fill="#04222f" stroke="#4cc2ff" stroke-width="2.5"/>
<circle cx="560" cy="122" r="5" fill="#04222f" stroke="#4cc2ff" stroke-width="2.5"/>
<circle cx="770" cy="172" r="5" fill="#04222f" stroke="#4cc2ff" stroke-width="2.5"/>
</svg>
</div>
</div>
<!-- FILTER CHIPS -->
<div class="card">
<div class="caption"><span class="t">ACTIVE FILTERS · 6 bands</span></div>
<div class="filters">
<div class="fchip"><span class="type">LSC</span><span class="val">90 Hz · Q0.7</span><span class="g pos">+4.0 dB</span></div>
<div class="fchip"><span class="type">PK</span><span class="val">180 Hz · Q1.0</span><span class="g neg">2.5 dB</span></div>
<div class="fchip"><span class="type">PK</span><span class="val">3.0 kHz · Q1.2</span><span class="g pos">+3.0 dB</span></div>
<div class="fchip"><span class="type">PK</span><span class="val">6.5 kHz · Q3.0</span><span class="g neg">2.0 dB</span></div>
<div class="fchip"><span class="type">HSC</span><span class="val">10 kHz · Q0.7</span><span class="g neg">1.5 dB</span></div>
<div class="fchip"><span class="type">PK</span><span class="val">45 Hz · Q0.9</span><span class="g pos">+2.0 dB</span></div>
</div>
</div>
</div>
<!-- AI DOCK -->
<div class="aidock">
<div class="airesp">
<div class="av"></div>
<div class="bubble">
보컬을 앞으로 당기기 위해 <b>3 kHz를 +3 dB(Q1.2)</b> 올리고, 저음을 단단하게 하려고
<b>180 Hz를 2.5 dB</b>로 뭉침을 줄이면서 <b>45 Hz +2 dB</b>로 무게는 유지했습니다.
클리핑 방지를 위해 <b>Preamp를 6.0 dB</b>로 설정했습니다. 적용됨 ✓
</div>
</div>
<div class="promptbar">
<div class="field">
<input placeholder="예: 보컬을 더 가깝게, 저음은 단단하게 · 치찰음 줄여줘" />
<div class="mic">🎤</div>
</div>
<button class="send"></button>
</div>
<div class="hint">Enter로 전송 · 변경은 Equalizer APO에 즉시 적용됩니다 · 모델: Claude Sonnet</div>
</div>
</section>
</div>
</div>
</body>
</html>
+24
View File
@@ -0,0 +1,24 @@
// PRE-GENERATED (design session). Builds the active IAiEqProvider from AppSettings + stored key.
using DansoriEQ.Core.Ai;
using DansoriEQ.Core.Security;
namespace DansoriEQ.App.Ai;
public static class AiProviderFactory
{
/// <summary>Returns the configured provider, or null if a cloud key is missing.</summary>
public static IAiEqProvider? Create(ISecretStore store)
{
var s = AppSettings.Load();
var provider = s.AiProvider ?? "claude";
var model = s.AiModel;
return provider switch
{
"openai" => store.Load(ProviderKeys.OpenAi) is { Length: > 0 } ok ? new OpenAiProvider(ok, model) : null,
"gemini" => store.Load(ProviderKeys.Gemini) is { Length: > 0 } gk ? new GeminiProvider(gk, model) : null,
"ollama" => new OllamaProvider(model ?? "phi3.5"),
_ => store.Load(ProviderKeys.Claude) is { Length: > 0 } ck ? new ClaudeClient(ck, model) : null
};
}
}
+95
View File
@@ -0,0 +1,95 @@
// PRE-GENERATED (design session). Fetches the models available to the user's ACCOUNT
// from each cloud provider's list-models API, using the stored API key. Untested here.
// Returns [] on failure (caller falls back to a static list).
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
namespace DansoriEQ.App.Ai;
public static class CloudModelLister
{
private static readonly HttpClient Http = new() { Timeout = TimeSpan.FromSeconds(20) };
public static Task<List<string>> ListAsync(string provider, string apiKey) => provider switch
{
"openai" => OpenAiAsync(apiKey),
"gemini" => GeminiAsync(apiKey),
_ => ClaudeAsync(apiKey)
};
private static async Task<List<string>> ClaudeAsync(string key)
{
var result = new List<string>();
try
{
using var req = new HttpRequestMessage(HttpMethod.Get, "https://api.anthropic.com/v1/models?limit=100");
req.Headers.Add("x-api-key", key);
req.Headers.Add("anthropic-version", "2023-06-01");
using var resp = await Http.SendAsync(req);
if (!resp.IsSuccessStatusCode) return result;
using var doc = JsonDocument.Parse(await resp.Content.ReadAsStringAsync());
if (doc.RootElement.TryGetProperty("data", out var arr))
foreach (var m in arr.EnumerateArray())
if (m.TryGetProperty("id", out var id)) result.Add(id.GetString() ?? "");
}
catch { }
return result;
}
private static async Task<List<string>> OpenAiAsync(string key)
{
var result = new List<string>();
try
{
using var req = new HttpRequestMessage(HttpMethod.Get, "https://api.openai.com/v1/models");
req.Headers.Add("Authorization", "Bearer " + key);
using var resp = await Http.SendAsync(req);
if (!resp.IsSuccessStatusCode) return result;
using var doc = JsonDocument.Parse(await resp.Content.ReadAsStringAsync());
if (doc.RootElement.TryGetProperty("data", out var arr))
foreach (var m in arr.EnumerateArray())
if (m.TryGetProperty("id", out var idEl))
{
var id = idEl.GetString() ?? "";
// chat-capable families only (skip embeddings/tts/whisper/image…)
if (id.StartsWith("gpt") || id.StartsWith("o1") || id.StartsWith("o3") ||
id.StartsWith("o4") || id.StartsWith("chatgpt"))
result.Add(id);
}
result.Sort();
}
catch { }
return result;
}
private static async Task<List<string>> GeminiAsync(string key)
{
var result = new List<string>();
try
{
var url = "https://generativelanguage.googleapis.com/v1beta/models?key=" + Uri.EscapeDataString(key);
using var resp = await Http.GetAsync(url);
if (!resp.IsSuccessStatusCode) return result;
using var doc = JsonDocument.Parse(await resp.Content.ReadAsStringAsync());
if (doc.RootElement.TryGetProperty("models", out var arr))
foreach (var m in arr.EnumerateArray())
{
var supportsGen = false;
if (m.TryGetProperty("supportedGenerationMethods", out var methods))
foreach (var meth in methods.EnumerateArray())
if (meth.GetString() == "generateContent") { supportsGen = true; break; }
if (supportsGen && m.TryGetProperty("name", out var nameEl))
{
var name = nameEl.GetString() ?? "";
if (name.StartsWith("models/")) name = name.Substring("models/".Length);
result.Add(name);
}
}
}
catch { }
return result;
}
}
+21
View File
@@ -0,0 +1,21 @@
// PRE-GENERATED (design session). Free space on the drive where local models are stored.
using System;
using System.IO;
namespace DansoriEQ.App.Ai;
public static class DiskInfo
{
/// <summary>Free space (GB) on the drive that holds Ollama models (~%USERPROFILE%\.ollama).</summary>
public static (double freeGb, string drive) ModelDriveFree()
{
var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".ollama");
var root = Path.GetPathRoot(path) ?? "C:\\";
try
{
var di = new DriveInfo(root);
return (di.AvailableFreeSpace / 1024.0 / 1024.0 / 1024.0, root);
}
catch { return (0, root); }
}
}
+68
View File
@@ -0,0 +1,68 @@
// PRE-GENERATED (design session). Talks to a local Ollama server (localhost:11434).
// Detect / list models / pull with progress. Untested here.
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
namespace DansoriEQ.App.Ai;
public sealed class OllamaService
{
private const string Base = "http://localhost:11434";
private readonly HttpClient _http = new() { Timeout = TimeSpan.FromMinutes(60) };
public async Task<bool> IsRunningAsync()
{
try { var r = await _http.GetAsync($"{Base}/api/tags"); return r.IsSuccessStatusCode; }
catch { return false; }
}
public async Task<List<string>> ListModelsAsync()
{
var models = new List<string>();
try
{
var json = await _http.GetStringAsync($"{Base}/api/tags");
using var doc = JsonDocument.Parse(json);
if (doc.RootElement.TryGetProperty("models", out var arr))
foreach (var m in arr.EnumerateArray())
if (m.TryGetProperty("name", out var n)) models.Add(n.GetString() ?? "");
}
catch { }
return models;
}
public async Task PullModelAsync(string model, IProgress<double>? progress, CancellationToken ct = default)
{
var body = JsonSerializer.Serialize(new { name = model, stream = true });
using var req = new HttpRequestMessage(HttpMethod.Post, $"{Base}/api/pull")
{ Content = new StringContent(body, Encoding.UTF8, "application/json") };
using var resp = await _http.SendAsync(req, HttpCompletionOption.ResponseHeadersRead, ct);
resp.EnsureSuccessStatusCode();
using var stream = await resp.Content.ReadAsStreamAsync(ct);
using var reader = new StreamReader(stream);
string? line;
while ((line = await reader.ReadLineAsync()) != null)
{
if (string.IsNullOrWhiteSpace(line)) continue;
try
{
using var doc = JsonDocument.Parse(line);
if (doc.RootElement.TryGetProperty("total", out var tot) &&
doc.RootElement.TryGetProperty("completed", out var comp))
{
double t = tot.GetInt64(), c = comp.GetInt64();
if (t > 0) progress?.Report(c / t);
}
}
catch { /* non-progress status line */ }
}
progress?.Report(1.0);
}
}
+37
View File
@@ -0,0 +1,37 @@
// PRE-GENERATED (design session). Silent install of local AI runtimes via winget.
// Untested here. winget must be present (Win10 1809+/Win11 usually have it).
using System.Diagnostics;
using System.Threading.Tasks;
namespace DansoriEQ.App.Ai;
public static class WingetInstaller
{
public static bool IsAvailable()
{
try
{
var psi = new ProcessStartInfo("winget", "--version")
{ UseShellExecute = false, CreateNoWindow = true, RedirectStandardOutput = true };
using var p = Process.Start(psi);
if (p == null) return false;
p.WaitForExit(4000);
return p.ExitCode == 0;
}
catch { return false; }
}
public static async Task<bool> InstallAsync(string wingetId)
{
var args = $"install --id {wingetId} -e --silent --accept-package-agreements --accept-source-agreements";
var psi = new ProcessStartInfo("winget", args) { UseShellExecute = true }; // may prompt UAC
try
{
using var p = Process.Start(psi);
if (p == null) return false;
await p.WaitForExitAsync();
return p.ExitCode == 0;
}
catch { return false; }
}
}
+126
View File
@@ -0,0 +1,126 @@
<!-- PRE-GENERATED (design session). AI 관리: 활성 모델 선택 + 로컬 런타임 설치 + 모델 다운로드 + 저장공간 경고. -->
<ui:FluentWindow x:Class="DansoriEQ.App.AiManagerWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
Title="AI 관리" Height="680" Width="640"
WindowStartupLocation="CenterOwner"
ExtendsContentIntoTitleBar="True" WindowBackdropType="Mica"
Background="#1B1B1F" Foreground="#F2F3F5"
FontFamily="Segoe UI Variable, Segoe UI" FontSize="14">
<Window.Resources>
<SolidColorBrush x:Key="Card" Color="#26262B"/>
<SolidColorBrush x:Key="Card2" Color="#2D2D33"/>
<SolidColorBrush x:Key="Stroke" Color="#3A3A42"/>
<SolidColorBrush x:Key="Dim" Color="#A8ABB4"/>
<SolidColorBrush x:Key="Mute" Color="#767A83"/>
<SolidColorBrush x:Key="Accent" Color="#4CC2FF"/>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ui:TitleBar Grid.Row="0" Title="AI 관리" Foreground="#F2F3F5" Padding="14,6"/>
<Border Grid.Row="1" Style="{StaticResource NeonPopup}">
<DockPanel Margin="20">
<TextBlock DockPanel.Dock="Top" Text="AI 관리" FontSize="21" FontWeight="Bold" Margin="0,0,0,14"/>
<Button DockPanel.Dock="Bottom" Content="닫기" Click="Close_Click" HorizontalAlignment="Right"
Height="36" Padding="18,0" Margin="0,14,0,0"
Background="{StaticResource Card}" Foreground="{StaticResource Dim}" BorderBrush="{StaticResource Stroke}"/>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel>
<!-- 1. 활성 AI -->
<Border Background="{StaticResource Card}" BorderBrush="{StaticResource Stroke}" BorderThickness="1" CornerRadius="12" Padding="16" Margin="0,0,0,14">
<StackPanel>
<TextBlock Text="활성 AI 선택" FontWeight="Bold" Foreground="{StaticResource Dim}" Margin="0,0,0,10"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/><ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/><ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="제공자" VerticalAlignment="Center" Foreground="{StaticResource Dim}" Margin="0,0,8,0"/>
<ComboBox x:Name="ProviderCombo" Grid.Column="1" SelectionChanged="Provider_Changed" Background="#2D2D33" Foreground="#F2F3F5" Margin="0,0,12,0">
<ComboBoxItem>Claude (클라우드)</ComboBoxItem>
<ComboBoxItem>ChatGPT · OpenAI (클라우드)</ComboBoxItem>
<ComboBoxItem>Gemini (클라우드)</ComboBoxItem>
<ComboBoxItem>Ollama (로컬)</ComboBoxItem>
</ComboBox>
<TextBlock Text="모델" Grid.Column="2" VerticalAlignment="Center" Foreground="{StaticResource Dim}" Margin="0,0,8,0"/>
<ComboBox x:Name="ModelCombo" Grid.Column="3" IsEditable="True" SelectionChanged="Model_Changed" Background="#2D2D33" Foreground="#F2F3F5"/>
</Grid>
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
<Button Content="🔄 계정 모델 불러오기" Click="RefreshModels_Click" Height="30" Padding="12,0"
Background="{StaticResource Card2}" Foreground="{StaticResource Dim}" BorderBrush="{StaticResource Stroke}"/>
<Button Content="🔌 연결 테스트" Click="TestConnection_Click" Height="30" Padding="12,0" Margin="8,0,0,0"
Background="{StaticResource Card2}" Foreground="{StaticResource Dim}" BorderBrush="{StaticResource Stroke}"/>
<TextBlock x:Name="ModelStatus" VerticalAlignment="Center" Foreground="{StaticResource Mute}" FontSize="12" Margin="10,0,0,0"/>
</StackPanel>
<TextBlock Foreground="{StaticResource Mute}" FontSize="12" Margin="0,8,0,0" TextWrapping="Wrap"
Text="클라우드는 API 키가 있으면 '계정에서 사용 가능한 모델'을 불러오고, 없으면 기본 목록을 씁니다. 직접 입력도 가능하며, 로컬(Ollama)은 다운로드된 모델만 표시됩니다."/>
</StackPanel>
</Border>
<!-- 2. 로컬 런타임 설치 -->
<Border Background="{StaticResource Card}" BorderBrush="{StaticResource Stroke}" BorderThickness="1" CornerRadius="12" Padding="16" Margin="0,0,0,14">
<StackPanel>
<TextBlock Text="로컬 AI 런타임 (자동 설치)" FontWeight="Bold" Foreground="{StaticResource Dim}" Margin="0,0,0,4"/>
<TextBlock x:Name="WingetNote" Foreground="{StaticResource Mute}" FontSize="12" Margin="0,0,0,10"
Text="winget으로 자동 설치합니다."/>
<Grid Margin="0,0,0,8">
<Grid.ColumnDefinitions><ColumnDefinition Width="*"/><ColumnDefinition Width="Auto"/><ColumnDefinition Width="Auto"/></Grid.ColumnDefinitions>
<StackPanel Grid.Column="0"><TextBlock Text="Ollama" FontWeight="SemiBold"/><TextBlock Text="OpenAI 호환 · per-user(무권한·무재부팅)" Foreground="{StaticResource Mute}" FontSize="12"/></StackPanel>
<TextBlock x:Name="OllamaStatus" Grid.Column="1" VerticalAlignment="Center" Foreground="{StaticResource Dim}" FontSize="12" Margin="0,0,10,0" Text="확인 중…"/>
<Button Grid.Column="2" Content="설치" Tag="Ollama.Ollama" Click="Install_Click" Height="30" Padding="16,0" Background="{StaticResource Accent}" Foreground="#04222F" FontWeight="Bold" BorderThickness="0"/>
</Grid>
<TextBlock Foreground="{StaticResource Mute}" FontSize="12" Margin="0,8,0,0" TextWrapping="Wrap"
Text="※ 현재 무인 자동설치가 확실한 로컬 런타임은 Ollama뿐입니다. LM Studio·GPT4All 등은 검증 후 추가 예정."/>
</StackPanel>
</Border>
<!-- 3. Ollama 모델 다운로드 -->
<Border Background="{StaticResource Card}" BorderBrush="{StaticResource Stroke}" BorderThickness="1" CornerRadius="12" Padding="16" Margin="0,0,0,14">
<StackPanel>
<TextBlock Text="로컬 모델 (Ollama)" FontWeight="Bold" Foreground="{StaticResource Dim}" Margin="0,0,0,10"/>
<Grid>
<Grid.ColumnDefinitions><ColumnDefinition Width="*"/><ColumnDefinition Width="Auto"/></Grid.ColumnDefinitions>
<ComboBox x:Name="OllamaModelCombo" Grid.Column="0" IsEditable="True" Background="#2D2D33" Foreground="#F2F3F5">
<ComboBoxItem>phi3.5</ComboBoxItem>
<ComboBoxItem>llama3.2</ComboBoxItem>
<ComboBoxItem>qwen2.5:3b</ComboBoxItem>
<ComboBoxItem>gemma2:2b</ComboBoxItem>
</ComboBox>
<Button x:Name="PullBtn" Grid.Column="1" Content="⬇ 다운로드" Click="Pull_Click" Height="32" Padding="14,0" Margin="8,0,0,0" Background="{StaticResource Accent}" Foreground="#04222F" FontWeight="Bold" BorderThickness="0"/>
</Grid>
<Grid Margin="0,10,0,0">
<Grid.ColumnDefinitions><ColumnDefinition Width="*"/><ColumnDefinition Width="Auto"/></Grid.ColumnDefinitions>
<ProgressBar x:Name="PullProgress" Grid.Column="0" Height="8" Minimum="0" Maximum="100" Background="#2D2D33" Foreground="{StaticResource Accent}" BorderThickness="0"/>
<TextBlock x:Name="PullStatus" Grid.Column="1" VerticalAlignment="Center" Foreground="{StaticResource Mute}" FontSize="12" Margin="10,0,0,0" Text="대기"/>
</Grid>
<TextBlock Text="설치된 모델" Foreground="{StaticResource Mute}" FontSize="12" Margin="0,12,0,4"/>
<ListBox x:Name="InstalledList" Height="80" BorderThickness="0" Background="#2D2D33" Foreground="{StaticResource Dim}"/>
</StackPanel>
</Border>
<!-- 4. 저장공간 경고 -->
<Border Background="#2A2420" BorderBrush="#5a4a30" BorderThickness="1" CornerRadius="12" Padding="16">
<StackPanel>
<TextBlock Text="⚠️ 저장 공간 안내" FontWeight="Bold" Foreground="#FFB454"/>
<TextBlock Foreground="{StaticResource Dim}" FontSize="13" TextWrapping="Wrap" Margin="0,8,0,0"
Text="로컬 AI 모델은 개당 약 2~8GB이며, 여러 모델을 받거나 큰 모델(수십B급)을 쓰면 전체적으로 수십~수백 GB가 필요할 수 있습니다. 넉넉한 여유 공간(최소 20GB 이상, 여러 모델 사용 시 100GB+)을 권장합니다."/>
<TextBlock x:Name="DiskText" Foreground="#FFB454" FontWeight="SemiBold" Margin="0,10,0,0" Text="여유 공간 확인 중…"/>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
</DockPanel>
</Border>
</Grid>
</ui:FluentWindow>
+181
View File
@@ -0,0 +1,181 @@
// PRE-GENERATED (design session). AI 관리 창 code-behind (계정 모델 목록 동적 로드 포함).
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using DansoriEQ.App.Ai;
using DansoriEQ.Core.Ai;
using DansoriEQ.Core.Security;
namespace DansoriEQ.App;
public partial class AiManagerWindow : Wpf.Ui.Controls.FluentWindow
{
private readonly OllamaService _ollama = new();
private readonly ISecretStore _store;
private List<string> _installedOllama = new();
public AiManagerWindow(ISecretStore store)
{
InitializeComponent();
_store = store;
Loaded += OnLoaded;
}
private async void OnLoaded(object sender, RoutedEventArgs e)
{
var (free, drive) = DiskInfo.ModelDriveFree();
DiskText.Text = $"현재 여유 공간: 약 {free:0.0} GB (드라이브 {drive})";
if (!WingetInstaller.IsAvailable())
WingetNote.Text = "⚠ winget이 감지되지 않습니다. 자동 설치가 제한될 수 있어요(수동 설치 필요).";
var s = AppSettings.Load();
ProviderCombo.SelectedIndex = s.AiProvider switch { "openai" => 1, "gemini" => 2, "ollama" => 3, _ => 0 };
await RefreshOllamaAsync();
await RefreshModelsAsync();
}
private static string ProviderId(int index) => index switch { 1 => "openai", 2 => "gemini", 3 => "ollama", _ => "claude" };
private static string ProviderSecretKey(string provider) => provider switch
{
"openai" => ProviderKeys.OpenAi,
"gemini" => ProviderKeys.Gemini,
_ => ProviderKeys.Claude
};
private static string[] StaticModels(string provider) => provider switch
{
"openai" => new[] { "gpt-4o", "gpt-4o-mini" },
"gemini" => new[] { "gemini-2.0-flash", "gemini-2.0-pro" },
_ => new[] { "claude-sonnet-4-6", "claude-opus-4-8" }
};
private async void Provider_Changed(object sender, SelectionChangedEventArgs e) => await RefreshModelsAsync();
private async void RefreshModels_Click(object sender, RoutedEventArgs e) => await RefreshModelsAsync();
private async void TestConnection_Click(object sender, RoutedEventArgs e)
{
var prov = ProviderId(ProviderCombo.SelectedIndex);
ModelStatus.Text = "연결 테스트 중…";
if (prov == "ollama")
{
ModelStatus.Text = await _ollama.IsRunningAsync() ? "✓ Ollama 연결됨" : "✗ Ollama 미실행";
return;
}
var key = _store.Load(ProviderSecretKey(prov));
if (string.IsNullOrEmpty(key)) { ModelStatus.Text = "✗ API 키 없음(설정에서 입력)"; return; }
var models = await CloudModelLister.ListAsync(prov, key);
ModelStatus.Text = models.Count > 0 ? $"✓ 연결 성공 (모델 {models.Count}개)" : "✗ 연결 실패 (키/네트워크 확인)";
}
private void Model_Changed(object sender, SelectionChangedEventArgs e) => SaveSelection();
/// <summary>Populate ModelCombo: local = downloaded models; cloud = account models (via key) with static fallback.</summary>
private async Task RefreshModelsAsync()
{
var prov = ProviderId(ProviderCombo.SelectedIndex);
if (prov == "ollama")
{
ModelCombo.ItemsSource = _installedOllama.Count > 0
? (IEnumerable<string>)_installedOllama.ToArray()
: new[] { "(모델 없음 — 아래에서 다운로드)" };
ModelStatus.Text = _installedOllama.Count > 0 ? $"로컬 모델 {_installedOllama.Count}개" : "다운로드 필요";
RestoreSelection();
SaveSelection();
return;
}
var key = _store.Load(ProviderSecretKey(prov));
if (string.IsNullOrEmpty(key))
{
ModelCombo.ItemsSource = StaticModels(prov);
ModelStatus.Text = "API 키 없음 — 기본 목록(설정에서 키 입력)";
RestoreSelection();
SaveSelection();
return;
}
ModelStatus.Text = "계정 모델 불러오는 중…";
var models = await CloudModelLister.ListAsync(prov, key);
if (models.Count > 0)
{
ModelCombo.ItemsSource = models;
ModelStatus.Text = $"계정 모델 {models.Count}개";
}
else
{
ModelCombo.ItemsSource = StaticModels(prov);
ModelStatus.Text = "불러오기 실패 — 기본 목록(직접 입력도 가능)";
}
RestoreSelection();
SaveSelection();
}
private void RestoreSelection()
{
var saved = AppSettings.Load().AiModel;
if (saved != null && ModelCombo.Items.Contains(saved)) ModelCombo.SelectedItem = saved;
else if (ModelCombo.Items.Count > 0) ModelCombo.SelectedIndex = 0;
}
private void SaveSelection()
{
var s = AppSettings.Load();
s.AiProvider = ProviderId(ProviderCombo.SelectedIndex);
s.AiModel = string.IsNullOrWhiteSpace(ModelCombo.Text) ? ModelCombo.SelectedItem as string : ModelCombo.Text;
s.Save();
}
private async Task RefreshOllamaAsync()
{
if (await _ollama.IsRunningAsync())
{
OllamaStatus.Text = "감지됨 (실행 중)";
_installedOllama = await _ollama.ListModelsAsync();
}
else
{
OllamaStatus.Text = "미설치 / 미실행";
_installedOllama = new();
}
InstalledList.ItemsSource = _installedOllama;
if (ProviderId(ProviderCombo.SelectedIndex) == "ollama") await RefreshModelsAsync();
}
private async void Install_Click(object sender, RoutedEventArgs e)
{
if (sender is not FrameworkElement fe || fe.Tag is not string wingetId) return;
if (!WingetInstaller.IsAvailable())
{
MessageBox.Show(this, "winget이 없어 자동 설치할 수 없습니다. 수동 설치가 필요합니다.", "안내");
return;
}
if (sender is Button b) b.IsEnabled = false;
var ok = await WingetInstaller.InstallAsync(wingetId);
if (sender is Button b2) b2.IsEnabled = true;
MessageBox.Show(this, ok ? "설치가 완료되었습니다." : "설치가 취소되었거나 실패했습니다.", "설치");
await RefreshOllamaAsync();
}
private async void Pull_Click(object sender, RoutedEventArgs e)
{
var model = OllamaModelCombo.Text?.Trim();
if (string.IsNullOrEmpty(model)) return;
if (!await _ollama.IsRunningAsync())
{
MessageBox.Show(this, "Ollama가 실행 중이 아닙니다. 먼저 위에서 Ollama를 설치/실행하세요.", "안내");
return;
}
PullBtn.IsEnabled = false;
var progress = new Progress<double>(p => { PullProgress.Value = p * 100; PullStatus.Text = $"다운로드 {p * 100:0}%"; });
try { await _ollama.PullModelAsync(model, progress); PullStatus.Text = "완료 ✓"; await RefreshOllamaAsync(); }
catch (Exception ex) { PullStatus.Text = "실패: " + ex.Message; }
finally { PullBtn.IsEnabled = true; }
}
private void Close_Click(object sender, RoutedEventArgs e) => Close();
}
@@ -0,0 +1,73 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
namespace DansoriEQ.App.Apo;
public static class ApoConfigInstaller
{
private const string IncludeLine = "Include: ai_eq.txt";
public static bool IsIncluded(string configDir)
{
var path = Path.Combine(configDir, "config.txt");
if (!File.Exists(path)) return false;
return File.ReadAllLines(path)
.Any(l => l.Trim().Equals(IncludeLine, StringComparison.OrdinalIgnoreCase));
}
/// <summary>Tries direct write first; falls back to an elevated PowerShell call.</summary>
public static bool TryAddInclude(string configDir)
{
if (IsIncluded(configDir)) return true;
var configTxt = Path.Combine(configDir, "config.txt");
try
{
File.AppendAllText(configTxt, Environment.NewLine + IncludeLine + Environment.NewLine);
return true;
}
catch (UnauthorizedAccessException)
{
return TryAddIncludeElevated(configTxt);
}
catch
{
return false;
}
}
/// <summary>Ensure an empty ai_eq.txt exists so APO doesn't log a missing-file warning.</summary>
public static void EnsureAiEqFile(string configDir)
{
var target = Path.Combine(configDir, "ai_eq.txt");
if (!File.Exists(target))
File.WriteAllText(target, "# Dansori EQ — managed automatically\n");
}
private static bool TryAddIncludeElevated(string configTxtPath)
{
// Escape single-quotes in path for PowerShell
var escaped = configTxtPath.Replace("'", "''");
var psCmd = $"Add-Content -Encoding UTF8 -Path '{escaped}' -Value \"`r`nInclude: ai_eq.txt`r`n\"";
try
{
var psi = new ProcessStartInfo("powershell.exe",
$"-NonInteractive -WindowStyle Hidden -Command \"{psCmd}\"")
{
Verb = "runas",
UseShellExecute = true,
WindowStyle = ProcessWindowStyle.Hidden
};
using var proc = Process.Start(psi)
?? throw new InvalidOperationException("Process.Start returned null");
proc.WaitForExit(15_000);
return IsIncluded(Path.GetDirectoryName(configTxtPath)!);
}
catch
{
return false;
}
}
}
+25
View File
@@ -0,0 +1,25 @@
// PRE-GENERATED (design session). Writes the live APO include file (ai_eq.txt).
// NOTE: config.txt must Include this file + the file must be user-writable — that is the
// one-time elevated setup (M3/M6). Untested on this machine (no APO installed here).
using System.IO;
using DansoriEQ.Core.Apo;
namespace DansoriEQ.App.Apo;
public sealed class ApoIncludeWriter : IApoWriter
{
private readonly string _includePath;
public ApoIncludeWriter(string configDir)
=> _includePath = Path.Combine(configDir, "ai_eq.txt");
public bool IsLive => true;
public string TargetPath => _includePath;
public string? LastConfig { get; private set; }
public void Apply(string apoConfigText)
{
File.WriteAllText(_includePath, apoConfigText); // APO live-reloads on save
LastConfig = apoConfigText;
}
}
+46
View File
@@ -0,0 +1,46 @@
// PRE-GENERATED (design session). Downloads the official Equalizer APO installer and launches it.
// NOTE: APO install is NOT silent — it needs device selection + a REBOOT. So "auto install"
// = download official installer + launch it; the user completes the wizard and reboots.
// Untested here (needs network + admin). Verify the download URL in the dev session.
using System;
using System.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace DansoriEQ.App.Apo;
public static class ApoInstaller
{
// SourceForge "latest" redirect for Equalizer APO. VERIFY current link in dev session.
public const string DownloadUrl = "https://sourceforge.net/projects/equalizerapo/files/latest/download";
public static async Task<string> DownloadAsync(IProgress<double>? progress = null, CancellationToken ct = default)
{
var target = Path.Combine(Path.GetTempPath(), "EqualizerAPO-setup.exe");
using var http = new HttpClient();
http.DefaultRequestHeaders.Add("User-Agent", "DansoriEQ");
using var resp = await http.GetAsync(DownloadUrl, HttpCompletionOption.ResponseHeadersRead, ct);
resp.EnsureSuccessStatusCode();
var total = resp.Content.Headers.ContentLength ?? -1L;
await using var src = await resp.Content.ReadAsStreamAsync(ct);
await using var dst = File.Create(target);
var buffer = new byte[81920];
long readTotal = 0;
int n;
while ((n = await src.ReadAsync(buffer, ct)) > 0)
{
await dst.WriteAsync(buffer.AsMemory(0, n), ct);
readTotal += n;
if (total > 0) progress?.Report((double)readTotal / total);
}
return target;
}
public static void Launch(string installerPath)
=> Process.Start(new ProcessStartInfo(installerPath) { UseShellExecute = true }); // triggers UAC
}
+26
View File
@@ -0,0 +1,26 @@
// PRE-GENERATED (design session). Locates the Equalizer APO config dir via default paths.
// Dev session may add a registry lookup (HKLM\SOFTWARE\EqualizerAPO) for robustness.
using System;
using System.IO;
namespace DansoriEQ.App.Apo;
public static class ApoLocator
{
public static string? FindConfigDir()
{
foreach (var pf in new[]
{
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86)
})
{
if (string.IsNullOrEmpty(pf)) continue;
var dir = Path.Combine(pf, "EqualizerAPO", "config");
if (Directory.Exists(dir)) return dir;
}
return null;
}
public static bool IsInstalled => FindConfigDir() != null;
}
+23
View File
@@ -0,0 +1,23 @@
// PRE-GENERATED (design session). Picks the live writer if APO is present, else preview mode.
// Resolution order: user-set path (settings) -> default install location -> null (preview).
using System.IO;
using DansoriEQ.Core.Apo;
namespace DansoriEQ.App.Apo;
public static class ApoWriterFactory
{
public static string? ResolveConfigDir()
{
var s = AppSettings.Load();
if (!string.IsNullOrEmpty(s.ApoConfigDir) && Directory.Exists(s.ApoConfigDir))
return s.ApoConfigDir;
return ApoLocator.FindConfigDir();
}
public static IApoWriter Create()
{
var dir = ResolveConfigDir();
return dir != null ? new ApoIncludeWriter(dir) : new NullApoWriter();
}
}
+31
View File
@@ -0,0 +1,31 @@
// PRE-GENERATED (design session). Preview/dry-run writer used when APO is NOT installed.
// Lets the whole EQ chain run offline-of-APO and writes the generated config to a preview
// file so you can verify exactly what WOULD be applied.
using System;
using System.IO;
using DansoriEQ.Core.Apo;
namespace DansoriEQ.App.Apo;
public sealed class NullApoWriter : IApoWriter
{
private readonly string _previewPath;
public NullApoWriter()
{
var dir = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "DansoriEQ");
Directory.CreateDirectory(dir);
_previewPath = Path.Combine(dir, "preview_apo_config.txt");
}
public bool IsLive => false;
public string TargetPath => _previewPath;
public string? LastConfig { get; private set; }
public void Apply(string apoConfigText)
{
LastConfig = apoConfigText;
try { File.WriteAllText(_previewPath, apoConfigText); } catch { /* preview only */ }
}
}
+52
View File
@@ -0,0 +1,52 @@
<ui:FluentWindow x:Class="DansoriEQ.App.ApoLinkWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
Title="APO 연동 설정" Height="300" Width="500"
WindowStartupLocation="CenterScreen" ResizeMode="NoResize"
ExtendsContentIntoTitleBar="True" WindowBackdropType="Mica"
Background="#1B1B1F" Foreground="#F2F3F5"
FontFamily="Segoe UI Variable, Segoe UI">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ui:TitleBar Grid.Row="0" Title="APO 연동 설정" Foreground="#F2F3F5" Padding="14,6"/>
<Border Grid.Row="1" Style="{StaticResource NeonPopup}">
<DockPanel Margin="24">
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal"
HorizontalAlignment="Right" Margin="0,16,0,0">
<Button x:Name="BtnNo" Content="나중에" Width="90" Height="36"
Click="BtnNo_Click" Margin="0,0,10,0"
Background="#26262B" Foreground="#A8ABB4" BorderBrush="#3A3A42"/>
<Button x:Name="BtnYes" Content="예, 연동 설정" Width="130" Height="36"
Click="BtnYes_Click"
Background="#4CC2FF" Foreground="#04222F"
FontWeight="Bold" BorderThickness="0"/>
</StackPanel>
<StackPanel>
<TextBlock Text="Equalizer APO 연동 설정"
FontSize="16" FontWeight="Bold" Margin="0,0,0,16"/>
<Border Background="#26262B" BorderBrush="#3A3A42"
BorderThickness="1" CornerRadius="10" Padding="16,14">
<StackPanel>
<TextBlock TextWrapping="Wrap" Foreground="#A8ABB4" FontSize="13" LineHeight="20"
Text="EQ를 실제 소리에 반영하려면 APO config.txt에 Include 줄을 한 번만 추가해야 합니다."/>
<TextBlock Foreground="#767A83" FontSize="11.5" Margin="0,10,0,0"
Text="※ 관리자 권한(UAC)이 요청됩니다. 이 작업은 최초 1회만 필요하며, 이후 EQ 변경은 권한 없이 자동 적용됩니다."/>
</StackPanel>
</Border>
<TextBlock x:Name="StatusText" Foreground="#767A83" FontSize="11"
Margin="0,14,0,0" TextWrapping="Wrap"/>
</StackPanel>
</DockPanel>
</Border>
</Grid>
</ui:FluentWindow>
+43
View File
@@ -0,0 +1,43 @@
using System.Windows;
using DansoriEQ.App.Apo;
namespace DansoriEQ.App;
public partial class ApoLinkWindow : Wpf.Ui.Controls.FluentWindow
{
private readonly string _configDir;
public ApoLinkWindow(string configDir)
{
InitializeComponent();
_configDir = configDir;
}
private void BtnYes_Click(object sender, RoutedEventArgs e)
{
BtnYes.IsEnabled = false;
BtnNo.IsEnabled = false;
StatusText.Text = "관리자 권한 요청 중…";
bool ok = ApoConfigInstaller.TryAddInclude(_configDir);
if (ok)
{
ApoConfigInstaller.EnsureAiEqFile(_configDir);
StatusText.Text = "✓ 연동 완료. EQ 변경이 즉시 소리에 반영됩니다.";
}
else
{
StatusText.Foreground = System.Windows.Media.Brushes.OrangeRed;
StatusText.Text =
$"자동 설정 실패. 수동으로 아래 파일에 'Include: ai_eq.txt'를 추가해주세요.\n{_configDir}\\config.txt";
}
BtnYes.Content = "닫기";
BtnYes.IsEnabled = true;
BtnYes.Click -= BtnYes_Click;
BtnYes.Click += (_, __) => Close();
BtnNo.Visibility = Visibility.Collapsed;
}
private void BtnNo_Click(object sender, RoutedEventArgs e) => Close();
}
+59
View File
@@ -0,0 +1,59 @@
<!-- PRE-GENERATED (design session). Shown at startup when APO isn't found.
Modern chrome: FluentWindow + ui:TitleBar (Mica), matching DbManagerWindow. -->
<ui:FluentWindow x:Class="DansoriEQ.App.ApoSetupWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
Title="Equalizer APO 설정" Height="430" Width="560"
WindowStartupLocation="CenterScreen" ResizeMode="NoResize"
ExtendsContentIntoTitleBar="True" WindowBackdropType="Mica"
Background="#1B1B1F" Foreground="#F2F3F5"
FontFamily="Segoe UI Variable, Segoe UI">
<Window.Resources>
<SolidColorBrush x:Key="Card" Color="#26262B"/>
<SolidColorBrush x:Key="Stroke" Color="#3A3A42"/>
<SolidColorBrush x:Key="TextDim" Color="#A8ABB4"/>
<SolidColorBrush x:Key="TextMute" Color="#767A83"/>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ui:TitleBar Grid.Row="0" Title="Equalizer APO 설정"
Foreground="#F2F3F5" Padding="14,6">
<ui:TitleBar.Icon>
<ui:SymbolIcon Symbol="Options24"/>
</ui:TitleBar.Icon>
</ui:TitleBar>
<Border Grid.Row="1" Style="{StaticResource NeonPopup}">
<StackPanel Margin="24,8,24,24">
<TextBlock Text="Equalizer APO가 감지되지 않았습니다" FontSize="18" FontWeight="Bold"/>
<TextBlock Foreground="{StaticResource TextDim}" FontSize="13" TextWrapping="Wrap" Margin="0,8,0,18"
Text="이 앱은 Equalizer APO를 통해 EQ를 적용합니다. 아래에서 설치하거나, 이미 설치돼 있다면 config 폴더 경로를 지정하세요. 지금은 미리보기 모드로 계속할 수도 있습니다."/>
<Border Background="{StaticResource Card}" BorderBrush="{StaticResource Stroke}" BorderThickness="1" CornerRadius="12" Padding="16">
<StackPanel>
<Button x:Name="BtnAutoInstall" Content="⬇ APO 자동 설치 (공식 설치 파일 다운로드·실행)" Click="BtnAutoInstall_Click"
Height="40" HorizontalContentAlignment="Left" Padding="12,0" Margin="0,0,0,8"
Background="#4CC2FF" Foreground="#04222F" FontWeight="Bold" BorderThickness="0"/>
<Button x:Name="BtnSetPath" Content="📁 APO config 폴더 직접 지정" Click="BtnSetPath_Click"
Height="40" HorizontalContentAlignment="Left" Padding="12,0" Margin="0,0,0,8"
Background="#2D2D33" Foreground="{StaticResource TextDim}" BorderBrush="{StaticResource Stroke}"/>
<Button x:Name="BtnLater" Content="나중에 (미리보기 모드로 계속)" Click="BtnLater_Click"
Height="36" HorizontalContentAlignment="Left" Padding="12,0"
Background="Transparent" Foreground="{StaticResource TextMute}" BorderThickness="0"/>
</StackPanel>
</Border>
<ProgressBar x:Name="Prog" Height="8" Minimum="0" Maximum="100" Value="0" Margin="0,16,0,6"
Background="#2D2D33" Foreground="#4CC2FF" BorderThickness="0"/>
<TextBlock x:Name="TxtStatus" Foreground="{StaticResource TextMute}" FontSize="12"
Text="APO 설치는 장치 선택과 재부팅이 필요합니다. 재부팅 후 앱을 다시 실행하세요."/>
</StackPanel>
</Border>
</Grid>
</ui:FluentWindow>
+47
View File
@@ -0,0 +1,47 @@
// PRE-GENERATED (design session). Startup APO setup dialog code-behind.
using System;
using System.Windows;
using DansoriEQ.App.Apo;
namespace DansoriEQ.App;
public partial class ApoSetupWindow : Wpf.Ui.Controls.FluentWindow
{
public ApoSetupWindow() => InitializeComponent();
private async void BtnAutoInstall_Click(object sender, RoutedEventArgs e)
{
BtnAutoInstall.IsEnabled = false;
var progress = new Progress<double>(p =>
{
Prog.Value = p * 100;
TxtStatus.Text = $"설치 파일 다운로드 중… {p * 100:0}%";
});
try
{
var path = await ApoInstaller.DownloadAsync(progress);
TxtStatus.Text = "설치 관리자를 실행합니다. 장치 선택 후 재부팅하고, 재부팅 후 앱을 다시 실행하세요.";
ApoInstaller.Launch(path);
}
catch (Exception ex)
{
TxtStatus.Text = "다운로드 실패: " + ex.Message;
BtnAutoInstall.IsEnabled = true;
}
}
private void BtnSetPath_Click(object sender, RoutedEventArgs e)
{
var dlg = new Microsoft.Win32.OpenFolderDialog { Title = "Equalizer APO의 config 폴더를 선택하세요" };
if (dlg.ShowDialog() == true)
{
var s = AppSettings.Load();
s.ApoConfigDir = dlg.FolderName;
s.Save();
TxtStatus.Text = "APO 경로가 설정되었습니다.";
DialogResult = true;
}
}
private void BtnLater_Click(object sender, RoutedEventArgs e) => Close();
}
+27
View File
@@ -0,0 +1,27 @@
<Application x:Class="DansoriEQ.App.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ui:ThemesDictionary Theme="Dark" />
<ui:ControlsDictionary />
</ResourceDictionary.MergedDictionaries>
<!-- Neon popup frame: bright accent border so dialogs separate from the dark background. -->
<Style x:Key="NeonPopup" TargetType="Border">
<Setter Property="Background" Value="#1B1B1F"/>
<Setter Property="BorderBrush" Value="#4CC2FF"/>
<Setter Property="BorderThickness" Value="1.5"/>
<Setter Property="CornerRadius" Value="10"/>
<Setter Property="Margin" Value="6"/>
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect Color="#4CC2FF" BlurRadius="20" ShadowDepth="0" Opacity="0.45"/>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>
+70
View File
@@ -0,0 +1,70 @@
using System.Windows;
using DansoriEQ.App.Apo;
using Wpf.Ui.Appearance;
namespace DansoriEQ.App;
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
// PoC hook (Path B / Lottie). Run "DansoriEQ.App.exe --lottie" to open only the
// Lottie test window, bypassing the normal splash/APO/main flow. Remove after decision.
if (e.Args.Length > 0 && e.Args[0] == "--lottie")
{
ShutdownMode = ShutdownMode.OnMainWindowClose;
var poc = new LottiePocWindow();
MainWindow = poc;
poc.Show();
return;
}
// Keep the app alive while pre-main dialogs (splash / APO setup) open and close;
// otherwise closing the splash with no other window would shut the app down.
ShutdownMode = ShutdownMode.OnExplicitShutdown;
// Surface unhandled UI-thread exceptions instead of silently terminating.
DispatcherUnhandledException += (_, args) =>
{
System.Windows.MessageBox.Show(
args.Exception.ToString(),
"오류가 발생했습니다",
MessageBoxButton.OK, MessageBoxImage.Error);
args.Handled = true; // keep the app alive
};
var s = AppSettings.Load();
var theme = s.Theme switch
{
"light" => ApplicationTheme.Light,
_ => ApplicationTheme.Dark
};
ApplicationThemeManager.Apply(theme);
// Brand splash (이소리·이단) — brief, before the setup flow.
try { new SplashWindow().ShowDialog(); } catch { /* splash is non-essential */ }
var apoDir = ApoWriterFactory.ResolveConfigDir();
if (apoDir is null)
{
new ApoSetupWindow().ShowDialog();
}
else if (!ApoConfigInstaller.IsIncluded(apoDir))
{
new ApoLinkWindow(apoDir).ShowDialog();
}
else
{
ApoConfigInstaller.EnsureAiEqFile(apoDir);
}
var main = new MainWindow();
MainWindow = main;
main.Show();
// Now that the main window exists, tie app lifetime to it.
ShutdownMode = ShutdownMode.OnMainWindowClose;
}
}
+22
View File
@@ -0,0 +1,22 @@
// PRE-GENERATED (design session). Common local paths.
using System;
using System.IO;
namespace DansoriEQ.App;
public static class AppPaths
{
public static string Root
{
get
{
var d = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "DansoriEQ");
Directory.CreateDirectory(d);
return d;
}
}
public static string PresetsDir => Path.Combine(Root, "presets");
public static string DbPath => Path.Combine(Root, "dansorieq.db");
public static string SwitchRulesFile => Path.Combine(Root, "switch_rules.json");
}
+39
View File
@@ -0,0 +1,39 @@
// PRE-GENERATED (design session). Small persisted app settings (APO path override, etc.).
using System;
using System.IO;
using System.Text.Json;
namespace DansoriEQ.App;
public sealed class AppSettings
{
public string? ApoConfigDir { get; set; }
public string? AiProvider { get; set; } // claude | openai | gemini | ollama
public string? AiModel { get; set; }
public bool AutoSwitchEnabled { get; set; }
public string? Theme { get; set; } // "dark" | "light" | "system" (default: dark)
private static string FilePath
{
get
{
var dir = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "DansoriEQ");
Directory.CreateDirectory(dir);
return Path.Combine(dir, "settings.json");
}
}
public static AppSettings Load()
{
try
{
return File.Exists(FilePath)
? JsonSerializer.Deserialize<AppSettings>(File.ReadAllText(FilePath)) ?? new()
: new();
}
catch { return new(); }
}
public void Save() => File.WriteAllText(FilePath, JsonSerializer.Serialize(this));
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 944 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

Some files were not shown because too many files have changed in this diff Show More