Skip to content

[MAT-269] 필기 성능 최적화 + PR #262 리뷰 반영#285

Merged
b0nsu merged 15 commits intorefactor/mat-240-drawing-extractfrom
feat/mat-269-writingFeel-tune
Apr 17, 2026
Merged

[MAT-269] 필기 성능 최적화 + PR #262 리뷰 반영#285
b0nsu merged 15 commits intorefactor/mat-240-drawing-extractfrom
feat/mat-269-writingFeel-tune

Conversation

@b0nsu
Copy link
Copy Markdown
Collaborator

@b0nsu b0nsu commented Apr 17, 2026

Summary

필기 캔버스(pointer-native-drawing)의 성능 최적화 및 PR #262 sterdsterd 리뷰 반영. erase undo path 캐싱, native drawing session, Float64Array stroke 전환을 통해 전반적인 레이턴시 및 메모리 사용량을 개선합니다.

Linear

Changes

PR #262 리뷰 반영

  • 패키지 버전 맞추기 (reanimated ~4.1.6, typescript ~5.9.2, gesture-handler ~2.28.0)
  • podspec author/homepage/source → team-ppointer
  • useImperativeHandle stale ref 수정 (textBoxesRef 도입)
  • useTextBoxManager 인라인 객체 useMemo 감싸기
  • committed paths dispose queueMicrotask 지연 (live path과 동일 패턴)
  • TextBoxData 마이그레이션 (기존 데이터 width/height fallback)

Phase 4-C: Erase Undo Path 캐싱

  • HistoryManager: EraseStrokesEntry에 cachedPathsBefore 필드 + onEntryEvicted 콜백
  • useDrawingDocumentController: beginEraseTransaction/commitEraseTransaction (paths 스냅샷)
  • erase undo 시 O(ΣP) path rebuild → O(S) 배열 복사 (~100ms → ~1ms)

Phase 3: Native Drawing Session

  • NativeDrawingSession.h/cpp: C++ 터치 샘플 축적, 속도 계산, frozen prefix path 빌드
  • NativeDrawingLivePathBridge.h/cpp: thread-safe 정적 브릿지 (UI↔JS thread)
  • StylusInputView.mm: Fabric event 전에 native session으로 터치 인터셉트
  • CatmullRomPathBuilderJSI.mm: getNativeLivePath, setSessionConfig, registerLivePathCallback JSI 함수
  • JS renderer에서 native path 우선 사용 (JS fallback 유지)

Phase 4-A: Float64Array Stroke

  • Stroke.points/samples: Point[] | Float64Array dual type 지원
  • DrawingEngine.finalizeStroke: Float64Array로 stroke 생성 (메모리 60-70% 절감, GC 0)
  • strokeUtils, smoothing, nativePathBuilder 등 전체 소비자 dual type 대응
  • nativePathBuilder: Float64Array 직통 전달 (re-pack 생략)

저장 버그 수정

  • useDrawingState: markAsUnsaved 액션 추가
  • ScrapDetailScreen: onChange → markAsUnsaved 연결 (autosave 활성화)
  • useHandwritingManager: unmount 시 저장 (뒤로가기/탭 전환 대응)
  • lastSavedDataRef 비교로 query refetch 시 중복 로드 방지
  • handwritingEncoder: Float64Array stroke → JSON 변환 지원

Testing

  • 필기 → 지우기 → undo: path 즉시 복원 확인 (Phase 4-C)
  • 필기 → 저장 → 앱 재시작 → 데이터 유지 확인
  • 필기 → 뒤로가기 → 재진입: 데이터 유지 확인
  • 기존 JSON 데이터 정상 로드 (하위 호환)
  • ProblemScreen / ScrapDetailScreen 모두 필기 정상 동작

Risk / Impact

  • 영향 범위: pointer-native-drawing 패키지 전체, ScrapDetailScreen 저장 로직
  • 확인이 필요한 부분: Phase 3 native path 품질 (JS path와 일치 여부), Float64Array freeze 동작
  • Phase 3D (CallInvoker push): New Arch에서 비활성 → 별도 PR
  • Phase 4-D (binary 직렬화): JSON으로 원복 → 검증 후 별도 PR로 재도입

b0nsu and others added 13 commits April 9, 2026 20:04
…ering

- Overhaul WritingFeelConfig: pressure gamma, velocity thinning, tilt, EMA smoothing
- Add isFixedWidthConfig() detection for centerline vs polygon envelope rendering
- Add buildVariableWidthPath with frozen prefix optimization for long strokes
- Add arc-length resampling and velocity recomputation pipeline
- Switch live path scheduling from rAF to queueMicrotask (1-frame latency reduction)
- Convert live path from ref-based to state-based (skia v2 reconciliation requirement)
- Add deferred SkPath dispose to prevent use-after-dispose in Skia Canvas
- Add pencilOnly support in RNGH adapter with SharedValue for worklet access
- Skip velocity computation and tilt calculation in fixed-width mode
- Add eraser cursor visualization and React.memo on SkiaDrawingCanvasSurface

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tingFeel-tune

# Conflicts:
#	packages/pointer-native-drawing/src/DrawingCanvas.tsx
#	packages/pointer-native-drawing/src/index.ts
#	packages/pointer-native-drawing/src/input/nativeStylusAdapter.tsx
#	packages/pointer-native-drawing/src/input/rnghPanAdapter.ts
#	packages/pointer-native-drawing/src/model/writingFeel.ts
#	packages/pointer-native-drawing/src/render/skia/SkiaDrawingCanvasSurface.tsx
#	packages/pointer-native-drawing/src/render/skia/skiaDrawingUtils.ts
#	packages/pointer-native-drawing/src/render/skia/useSkiaDrawingRenderer.ts
#	packages/pointer-native-drawing/src/smoothing.ts
…13b430

ce13b430 merge: native finger input Phase 2 tuning
de8ecc3e fix: tune native finger input from device testing
3b5f7a51 feat: integrate native finger input for iOS (Phase 0+1)

git-subtree-dir: packages/pointer-native-drawing
git-subtree-split: ce13b4305ca54b4e381fe3c249d68073be7a6b23
- 버전 맞추기: reanimated ~4.1.6, gesture-handler ~2.28.0, typescript ~5.9.2
- podspec author/homepage/source를 team-ppointer로 변경
- useImperativeHandle stale ref 수정 (textBoxesRef 도입)
- useTextBoxManager 인라인 객체 useMemo 감싸기
- TextBoxData 마이그레이션: width/height 없는 기존 데이터 fallback
- committed paths dispose를 queueMicrotask로 지연 (live path과 동일 패턴)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
EraseStrokesEntry에 cachedPathsBefore 필드 추가.
erase 시작 시 committedPaths 스냅샷을 history entry에 저장하고,
undo 시 캐시된 paths를 직접 복원하여 O(ΣP) path rebuild 생략.

- HistoryManager: cachedPathsBefore, onEntryEvicted 콜백, push/clear/discard 시 dispose
- rendererTypes: replaceCommittedStrokes에 prebuiltPaths 파라미터, getCommittedPaths
- useDrawingDocumentController: beginEraseTransaction/commitEraseTransaction 래퍼
- useDrawingInteractionController: docController 래퍼 호출로 변경

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
터치 이벤트를 Fabric EventEmitter 전에 native에서 인터셉트하여
path를 미리 빌드. JS는 getNativeLivePath()로 미리 빌드된 path를 사용.

Native C++:
- NativeDrawingSession: 포인트 축적, 속도 계산, frozen prefix path 빌드
- NativeDrawingLivePathBridge: thread-safe 정적 브릿지 (mutex + CallInvoker push)
- StylusInputView: 터치 인터셉트, tilt 변환, config 동기화 (static activeView)

JSI:
- getNativeLivePath(): 최신 native path 복사
- setSessionConfig(): JS config → native session 동기화
- registerLivePathCallback(): CallInvoker push (Phase 3D, New Arch 미활성)

TODO: Phase 3D New Arch CallInvoker 접근 방식 수정 (별도 PR)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Stroke.points/samples가 Point[]|Float64Array 둘 다 지원.
새 stroke는 finalizeStroke에서 Float64Array로 생성 (메모리 60-70% 절감, GC 0).

- drawingTypes: packed stride 상수, pack/unpack 헬퍼, 접근 함수
- DrawingEngine: finalizeStroke에서 packPoints/packSamplesArray 사용
- strokeUtils: deepCopyStrokes, getStrokeBounds, getMaxY Float64Array 지원
- smoothing: buildSmoothPath/buildCenterlinePath union 시그니처 + unpack fallback
- nativePathBuilder: packSamples Float64Array 직통 (re-pack 생략)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
JSON.stringify → binary packing (DataView + ArrayBuffer → base64).
decode 시 자동 감지 (첫 바이트 0x01=binary, 그 외=legacy JSON).
Float64Array stroke 직접 encode/decode (Phase 4-A 연동).

- timestamp 정밀도: stroke별 baseTimestamp(float64) + delta offset(float32)
- 색상 테이블: stroke color 중복 제거
- 하위 호환: 기존 JSON 데이터 + TextBoxData 마이그레이션 유지

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
TanStack Query 백그라운드 refetch 시 setStrokes 재호출 방지.
initialLoadDoneRef로 초기 1회만 데이터 로드.

근본 해결: refactor/mat-313에서 useHandwritingManager 구조 리팩토링 필요.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- unused imports 제거 (useCallback, useRef, DocumentSnapshot, ReadonlyPoint)
- unused destructuring에 _ prefix (historyRef, maxYRef)
- no-explicit-any → HistoryEntry 타입 캐스팅 + eslint-disable 주석
- prettier 자동 포맷팅 적용

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Phase 4-D binary encoder → JSON 원복 (Float64Array→object 변환 후 JSON.stringify)
- binary 데이터 감지 시 빈 캔버스로 fallback (테스트 중 저장된 binary 대응)
- useDrawingState: markAsUnsaved 액션 추가
- ScrapDetailScreen: onChange → markAsUnsaved 연결 → autosave 활성화
- useHandwritingManager: unmount 시 저장 (뒤로가기/탭 전환 대응)
- lastSavedDataRef 비교로 query refetch 시 중복 로드 방지

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@linear
Copy link
Copy Markdown

linear bot commented Apr 17, 2026

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 17, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
pointer-admin Ready Ready Preview, Comment Apr 17, 2026 6:31am

import { colors } from '@/theme/tokens';
import { type StudentRootStackParamList } from '@/navigation/student/types';
import Container from '@/components/common/Container';
import ContentInset from '@/components/common/ContentInset';
@b0nsu b0nsu changed the base branch from main to refactor/mat-240-drawing-extract April 17, 2026 06:08
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
base 브랜치 변경사항 통합. mat-269 최적화 코드 유지.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@b0nsu b0nsu merged commit 3ae55b7 into refactor/mat-240-drawing-extract Apr 17, 2026
2 checks passed
@b0nsu b0nsu deleted the feat/mat-269-writingFeel-tune branch April 18, 2026 01:28
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.

1 participant