Skip to content

feat: 반응형 스프라이트와 요소 회전, 편집 저장 안정화 - #167

Merged
lee-sihun merged 128 commits into
mainfrom
feat/sprite-oneshot-pin
Sep 6, 2026
Merged

lee-sihun merged 128 commits into
mainfrom
feat/sprite-oneshot-pin

Conversation

@eun-yeon

@eun-yeon eun-yeon commented Sep 6, 2026

Copy link
Copy Markdown
Member

개요

이미지에 담당 키를 붙여 자세를 바꾸는 스프라이트 요소와 요소 회전을 추가하고, 저장 실패와 종료 사이에 편집이 사라지지 않게 정리

변경 내용

스프라이트

  • 새 요소 종류 spritePositions. 담당 키를 누르는 동안 자세를 바꾸거나 단발로 한 번 재생하고, 자세마다 이미지·이동·회전·배율·전환 시간·모션을 가짐
  • 기준점과 축 배치를 캔버스 핸들과 패널에서 편집. 자세 수치는 그대로 두고 배치만 바꾸므로 기존 자세가 틀어지지 않는다
  • 리사이즈는 비율 고정이 기본이고 상한은 백엔드와 같은 상수를 공유. 그룹 리사이즈에 섞여도 비율과 최소 크기 유지
  • 창 밖으로 넘치는 그림은 오버레이 창을 넓히고 원점을 보정. 왼쪽·위쪽 넘침도 포함
  • 이미지 임포트는 내용 검증과 원자 저장을 거치고 정리 sweep 보호 집합에 등록. 프리셋에는 이미지를 내장하고 절대 경로를 남기지 않음
  • 커스텀 CSS 변수 --sprite-transform, --sprite-transition과 선택자 추가
  • 플러그인 스냅샷에 spritePositions, 이벤트 spritePositions:changed 추가하고 OBS 포워딩 목록에 등록

요소 회전

  • 키·통계·그래프·노브·스프라이트에 rotation 저장. 논리 상자는 축 정렬 그대로 두고 화면만 돌리므로 마퀴·정렬·스냅은 기존 기준 유지
  • 꼭짓점 바깥 영역에서 드래그해 회전, Shift 15° 스냅, 회전 한 번이 히스토리 한 칸
  • 다중 선택과 그룹은 하나의 틀로 같은 중심을 기준으로 회전. 회전한 틀의 리사이즈는 동일 배율. 플러그인이 섞이면 회전과 그룹 리사이즈를 막고 윤곽만 남긴다
  • 노트 트랙과 바깥 카운터가 키를 따라 돌고, 같은 방향으로 기울인 키끼리 시작선을 맞춤. 0°는 기존 수식 그대로
  • 회전 요소의 실제 범위를 창 크기와 클릭 영역에 반영. 클릭 영역은 가로 띠로 근사하고, 복원할 수 없는 CSS 변환은 축 정렬 상자로 후퇴
  • 손상된 rotation은 요소를 지우지 않고 그 필드만 0으로 복구. 이전 버전이 모르는 필드를 무시하던 동작과 맞춤
  • EDITOR_OPS_VERSION 4

편집 저장

  • 영속 쓰기 API를 종료 barrier로 추적하고, 종료 신호를 받으면 프론트 정산을 마친 뒤 종료
  • 예약 커밋을 barrier 안에서 시작해 완료까지 정산. history 잠금이 시작되면 진행 중 드래그·스크럽·핸들을 취소하고 분리 패널 document에도 같은 잠금
  • 저장이 실패하면 미저장 안내와 다시 저장. 노트 설정·이름 변경·배경색·플러그인 설정은 실패해도 입력값을 유지하고 저장값을 복원

수정

  • OBS 윈도우 캡처가 오버레이 대신 메인 창을 잡던 문제. 세 창에 고유 클래스 이름을 붙였으므로 기존 씬은 소스를 다시 골라야 한다
  • 오버레이를 반복해서 켜고 끌 때 위치가 누적 이동하던 문제와 히트 패널 독립 창 정렬
  • 빈 탭 프리셋을 불러오면 기존 요소가 남던 문제, 이전 모드의 키 이벤트가 새 탭에 적용되던 문제
  • 파일 없이 저장된 내장 CSS 표시와 제거

문서

  • 키·에디터·오버레이·프리셋·설정 API 레퍼런스와 CSS 변수 문서 영어·한국어 반영

알려진 동작

  • 이 버전의 프리셋을 구버전에서 열면 스프라이트와 회전 값이 빠진 채 들어온다. 구버전이 모르는 필드를 무시하는 기존 정책이라 오류는 나지 않는다
  • 창 클래스 이름이 바뀌어 OBS 윈도우 캡처 소스는 다시 골라야 한다
  • 스프라이트가 왼쪽·위로 넘치면 OBS 브라우저 소스는 창이 안 커지므로 레이아웃이 밀릴 수 있다
  • 이미지 임포트에 바이트 상한이 없다. 워밍업은 동시 6개·캐시 256으로 제한

검증

  • npm run type-check 통과
  • npm run lint 통과, 기존 경고 1
  • npm run format:check 통과
  • npx vitest run 통과, 4646건
  • cargo check --locked 통과
  • cargo clippy --all-targets 통과
  • cargo fmt --check 통과
  • cargo test 통과, 1170건
  • CI 3플랫폼 통과, run 34017303768 (머지 커밋 2e5d2ea 기준, 회전 커밋 제외)
  • 2.0.2 저장 데이터·프리셋 상호 로드 실험, main 머지 3방향 대조 128파일

머지 전 실기 확인

  • Windows: 회전 커서 표시와 추종, 오버레이 창 고정 상태에서 회전 요소 클릭 통과, 스프라이트 넘침 시 창 보정, 이미지 선택창과 대용량 임포트, 읽기 전용 store에서 미저장 안내, 창 닫기 중 저장, 세션 종료 후 데이터 보존
  • OBS: 기존 씬 재선택, 브라우저 소스의 스프라이트·회전 트랙 표시, 넘침 시 레이아웃
  • 물리 키보드로 스프라이트 트리거와 단발 재생
  • 스프라이트·회전 프리셋 내보내기와 빈 데이터에서 불러오기

파일 경로 없이 CSS 원문만 남아도 현재 CSS 카드에서 확인하고 지울 수 있게 한다. 제거는 원문만 비워 마스터 토글 상태를 유지한다.

저장 중 중복 동작을 막고 실패 시 상태를 보존하며 재시도 안내를 표시한다. 다섯 언어의 안내 문장을 줄바꿈한다.

CSS 패널과 관련 저장·안내 테스트 86건, 타입·린트·포맷 검증을 통과했다. 격리 앱에서 제거·실패·재시작을 실기 검증한 코드를 유지한다.
AppKit에 전달하는 창 이동량을 대칭으로 반올림해 표시 토글을 왕복할 때 좌표가 누적 이동하는 현상을 막는다. macOS에만 적용하고 창 크기 계산과 표시 시점은 유지한다.

여섯 기준점, 양·음수 원점, 소수 이동량의 반복 왕복 회귀를 추가한다. AppState 테스트 101건과 check·clippy·fmt 검증을 통과했다. 격리 앱의 실제 반복 토글에서도 시작 위치로 복귀함을 확인했다.

웹 그림과 네이티브 창 갱신 사이의 순간 흔들림은 별도 미해결 사항이다. 창 영역 유지와 갱신 순서 변경 실험은 포함하지 않는다.
@eun-yeon

eun-yeon commented Sep 6, 2026

Copy link
Copy Markdown
Member Author

#166과의 순서

겹치는 파일은 경로가 같은 것 99개, #166이 옮기는 파일 중 이번에 고친 것 129개. 폴더 이동은 main 최신 위에서 기계적으로 다시 만들 수 있지만, 이 PR의 기능 변경을 쪼개진 파일 위에 다시 얹는 건 수작업이라 이 PR을 먼저 합치고 #166의 폴더 재배치를 그 위에서 다시 생성하는 순서를 제안. #166의 OBS percent escape 수정과 테스트 안정화는 먼저 들어가도 문제 없음. 둘 중 하나가 합쳐지기 전에는 다른 쪽을 main에 넣지 않는 걸로

Draft는 CI Gate가 초록이 되면 Ready로 바꿔도 되고, 실기 확인 뒤 바로 합쳐도 됨

Windows 실기 목록 전체

대상: HEAD 3676115 (origin/main 1412247 + 스프라이트·기준점·회전·편집 저장 수명주기·OBS 창 클래스). CI(windows-2025)는 컴파일·테스트·빌드만 검증하므로 실제 화면·입력·GPU·DPI·파일 시스템 동작은 실기로만 확인할 수 있다. PR #167.

0. 환경과 빌드

항목 내용
OS Windows 11 권장, 가능하면 Windows 10도 1회
화면 주 모니터 DPI 100%, 보조 모니터 150% 이상으로 서로 다른 배율 구성. 설정 > 접근성 > 텍스트 크기 125%도 1회
GPU 실제 GPU 1종 이상. 가능하면 내장 GPU 노트북도 1회
빌드 브랜치를 받아 npm cinpm run tauri:build:fast:win. ASIO SDK(src-tauri/vendor/asio-sdk)가 없으면 npm run tauri:build:fast:win:no-asio. 실행 파일은 src-tauri/target/release-fast/dm-note.exe
서명 브랜치에서는 서명 빌드를 만들 수 없다(Release Windows 워크플로는 기본 브랜치 전용). 서명본 확인은 main 머지 뒤 release=false 수동 실행 산출물로 별도 진행
데이터 앱 데이터는 %APPDATA%\com.dmnote.desktop. 테스트 전 폴더를 통째로 백업하고, 항목 1은 2.0.2가 쓴 실제 데이터로 시작한다
증거 항목마다 스크린샷 또는 짧은 녹화, 관련 store.json 전후 사본, 내보낸 프리셋 파일. Windows 버전·DPI·GPU를 보고서 머리에 적는다

결과는 항목 번호별로 통과/실패/미실행과 증거 파일명을 적는다. 실패는 재현 단계와 기대·실제를 나눠 쓴다.

1. 업그레이드와 기동

  1. 2.0.2로 만들어 둔 앱 데이터(키 4종 요소, 탭 여러 개, 그룹, 플러그인, 커스텀 이미지, 사운드)를 둔 채 새 빌드 실행. 기대: 모든 요소·탭·매핑·이미지·사운드가 그대로 보이고 저장 안내나 복구 알림이 없다. store.jsonrotation: 0과 빈 spritePositions만 추가된다.
  2. 앱 데이터가 없는 상태에서 첫 실행. 기대: 기본 프리셋이 뜨고 오버레이가 열린다.
  3. 앱을 켠 채 로그아웃 또는 재시작. 기대: 재로그인 뒤 마지막 편집이 남아 있다. 종료 신호 정산은 unix 전용이고 Windows 세션 종료 처리 코드는 없으므로 실제 동작 확인이 필요하다.

2. 스프라이트

  1. 툴바 또는 우클릭 메뉴로 스프라이트 추가 후 이미지 선택창. 기대: 선택창이 메인 창 위에 뜨고 앱이 멈추지 않는다. png·jpg·webp·gif·bmp·svg·ico·avif를 각각 하나씩 넣는다. 경로에 공백·한글·긴 경로를 포함한 파일도 1회.
  2. 4096×4096 이상 큰 이미지 1장과 2048×2048 이미지 20장(자세 3개씩). 기대: 임포트와 재시작 워밍업이 멈춤 없이 끝난다. 작업 관리자 메모리 수치를 기록한다(상한이 없어 참고 수치가 필요하다).
  3. 담당 키를 물리 키보드로 지정하고 오버레이에서 확인. 기대: 누르는 동안 자세가 바뀌고 떼면 돌아온다. 단발 모드는 한 번만 재생된다. 멀티 키 매핑 조합 키도 1회.
  4. 기준점 핸들을 캔버스와 패널에서 편집하고 축 배치를 전환. 기대: 그림이 기준점 기준으로 움직이고 오버레이와 캔버스가 같은 결과를 보인다.
  5. 스프라이트를 오버레이 창 왼쪽·위쪽 밖으로 넘치게 배치. 기대: 오버레이 창이 넓어지고 기존 요소 위치가 화면에서 밀리지 않는다. DPI 150% 모니터와 텍스트 크기 125%에서 잘림이 없어야 한다. 이 가로 보정은 이번에 새로 들어갔다.
  6. 비율 고정 리사이즈, 스프라이트가 섞인 그룹 리사이즈, 최소 크기. 기대: 비율이 유지되고 최소 크기 아래로 줄지 않는다.
  7. 복제 고스트, 다른 탭으로 복사·붙여넣기. 기대: 트리거 키가 붙여넣은 탭의 매핑으로 다시 연결된다.
  8. 스프라이트를 삭제하고 앱을 재시작. 기대: 삭제한 이미지는 trash\<세션> 아래로 옮겨지고, 남아 있는 스프라이트 이미지는 지워지지 않는다.

3. 요소 회전

  1. 키·통계·그래프·노브·스프라이트 각각을 선택하고 꼭짓점 바깥 L자 영역에서 드래그. 기대: 곡선 양방향 화살표 커서가 나타나 포인터를 따라오고, Shift로 15° 스냅, Escape로 취소, 놓으면 기본 커서로 돌아오며 커서가 겹쳐 보이지 않는다. Windows에서는 이 SVG 커서를 처음 쓴다. 커서가 안 보이면 십자 커서로 대체되는지 기록한다.
  2. 속성 패널 회전 입력에서 스크럽과 직접 입력(음수·소수·-180·180). 기대: 오버레이가 즉시 따라오고 실행 취소가 한 칸씩 되돌린다.
  3. 여러 요소와 그룹을 함께 선택해 회전. 기대: 하나의 틀로 같은 중심 기준으로 돌고, 회전한 틀의 리사이즈는 같은 배율로 커진다.
  4. 회전한 키의 노트 트랙. 기대: 트랙이 키 각도를 따라가고 그라데이션·글로우·테두리가 깨지지 않는다. 같은 방향으로 기울인 키끼리 시작선이 맞는다. 60Hz와 144Hz 이상 모니터에서 각각 확인.
  5. 회전한 키의 바깥 카운터. 기대: 카운터가 키와 함께 돈다.
  6. 회전 요소가 많은 탭(20개 이상)에서 오버레이 유휴 CPU. 기대: 글로우 애니메이션이 있어도 작업 관리자 CPU가 지속적으로 오르지 않는다. 수치를 기록한다.

4. 오버레이 히트 창

  1. 오버레이 창 고정을 켜고(히트 창 활성) 회전한 키를 다른 앱 위에 둔다. 기대: 회전한 얼굴 안쪽 클릭은 오버레이가 받고, 축 정렬 상자 모서리의 빈 부분 클릭은 뒤의 앱으로 통과한다. DPI 150% 모니터에서 오프셋 없이 같은 결과여야 한다.
  2. 같은 상태에서 요소를 드래그로 옮기고 크기를 바꾼 뒤 클릭 영역이 따라오는지 확인. 애니메이션 중인 요소도 1회.

5. 편집 저장 수명주기

  1. store.json을 읽기 전용으로 바꾼 뒤 요소를 편집. 기대: 미저장 안내가 뜨고 편집값은 화면에 남는다. 읽기 전용을 풀고 다시 저장을 누르면 저장된다.
  2. 이미지 파일을 다른 프로그램이 잡고 있는 상태(예: 이미지 뷰어로 열어 둠)에서 그 이미지를 쓰는 스프라이트를 삭제하고 재시작. 기대: 앱이 멈추거나 죽지 않고, 정리 실패가 로그에만 남는다.
  3. 숫자 입력 스크럽이나 드래그 도중 창의 닫기 버튼을 누른다. 기대: 저장을 마친 뒤 종료되고, 다시 열면 마지막 값이 남아 있다.
  4. 분리한 속성 패널에서 편집 중 실행 취소·다시 실행, 그리고 패널을 연 채 메인 창 닫기. 기대: 패널의 편집도 저장되고 history 잠금이 풀린 뒤 종료된다.
  5. 노트 설정·이름 변경·배경색·플러그인 설정을 읽기 전용 상태에서 저장. 기대: 실패 안내가 뜨고 입력값이 사라지지 않으며, 읽기 전용을 풀면 저장된다.

6. main 통합 회귀

  1. 하단바와 탭 목록에서 탭 드래그 순서 변경, 우클릭 이름 변경·삭제.
  2. 속성 패널을 분리해 DPI가 다른 모니터 사이로 드래그. 기대: 떨림과 커서 어긋남이 없다.
  3. 웹 폰트 편집 시트와 폰트 목록 팝업 열기·닫기.
  4. 키 매핑 변경과 카운터 초기화가 오버레이에 바로 반영.

7. OBS

  1. 기존 2.0.2 씬의 윈도우 캡처 소스를 그대로 둔 채 새 빌드 실행. 기대: 창 클래스가 바뀌어 캡처가 끊기거나 메인 창을 잡을 수 있다. 소스를 다시 고르면 DmNoteOverlayWindow 오버레이만 잡힌다. 이 결과를 릴리스 노트 문구의 근거로 기록한다.
  2. OBS 모드로 브라우저 소스 연결. 기대: 스프라이트 이미지가 표시되고 키 입력에 반응하며, 앱에서 스프라이트를 옮기면 브라우저 소스가 따라온다. bmp·ico·avif 이미지도 표시된다.
  3. 브라우저 소스에서 회전 키와 회전 노트 트랙. 기대: 오버레이 창과 같은 모양이다.
  4. 스프라이트나 회전 요소가 왼쪽·위로 넘칠 때 브라우저 소스. 기대: OBS는 창 크기가 바뀌지 않으므로 전체 레이아웃이 밀릴 수 있다. 밀림 정도를 기록한다.

8. 프리셋

  1. 스프라이트·회전·그룹이 든 탭을 프리셋으로 내보내고 파일을 열어 C:\ 같은 절대 경로가 없는지 확인. 기대: 이미지는 내장되고 절대 경로는 없다.
  2. 앱 데이터를 비운 뒤 그 프리셋을 불러온다. 기대: 이미지·자세·기준점·회전·트리거가 복원된다.
  3. 같은 프리셋을 2.0.2 빌드에서 불러온다. 기대: 오류 없이 스프라이트와 회전만 빠진 채 들어온다. 이 동작은 기존 정책이며 릴리스 노트에 적는다.

9. 개발 게이트 (Windows 셸에서 1회)

  1. npm run type-check, npx vitest run, cd src-tauri && cargo test. 기대: macOS와 같은 수(vitest 4,646, cargo 1,170 근처)로 통과한다. Windows 전용 테스트 4개가 여기서 처음 실행된다.

PR #166의 모듈 경계와 strict 검사를 유지하며 PR #167의 스프라이트, 회전, 종료 전 저장 및 회귀 테스트를 이동 경로에 통합한다.
@lee-sihun
lee-sihun marked this pull request as ready for review September 6, 2026 10:05
@lee-sihun
lee-sihun merged commit c24aa7c into main Sep 6, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants