diff --git a/frontend/src/lib/components/HandwriteCanvas.svelte b/frontend/src/lib/components/HandwriteCanvas.svelte index 7488b6c..5f2e157 100644 --- a/frontend/src/lib/components/HandwriteCanvas.svelte +++ b/frontend/src/lib/components/HandwriteCanvas.svelte @@ -87,6 +87,19 @@ coalesced: 0, lastType: '-', lastPressure: 0, + // pressure 파이프라인 진단 — raw → mapped → final. + // raw = PointerEvent.pressure 원본 + // mapped = getStrokePressure 의 inputP (raw 매핑 또는 속도 fallback) + // final = fixedPressure update 후 perfect-freehand 에 전달되는 값 + rawP: 0, + mappedP: 0, + finalP: 0, + tiltX: 0, tiltY: 0, + ptrW: 0, ptrH: 0, + buttons: 0, + // raw pressure 의 세션 min/max — 사용자가 펜 강약 시도 후 확인. + rawMin: 1, + rawMax: 0, }); // dimension 측정 — button click 시 어느 element 의 dimension 이 변하는지 진단. let dimDbg = $state({ canW: 0, canH: 0, conW: 0, conH: 0 }); @@ -359,31 +372,39 @@ // 1. inputP 결정. let inputP: number; if (Number.isFinite(rawPressure) && rawPressure > 0.1 && rawPressure < 0.99) { - // raw pressure 0.1~0.99 → 0.6~1.0 매핑. floor 보장. inputP = PRESSURE_FLOOR + ((rawPressure - 0.1) / 0.89) * (1 - PRESSURE_FLOOR); } else { const last = target.points[target.points.length - 1]; if (last) { const dist = Math.hypot(x - last[0], y - last[1]); - // 속도 기반 0.6~1.0. inputP = Math.max(PRESSURE_FLOOR, Math.min(1.0, 1.6 - dist / 25)); } else { inputP = FIRST_POINT_PRESSURE; } } // 2. fixed hybrid. + let finalP: number; if (target.fixedPressure === undefined) { target.fixedPressure = inputP; - return inputP; + finalP = inputP; + } else { + const dev = Math.abs(inputP - target.fixedPressure); + if (dev >= FIXED_LARGE) { + target.fixedPressure = inputP; + finalP = inputP; + } else { + const alpha = dev < FIXED_THRESHOLD ? FIXED_ALPHA_NOISE : FIXED_ALPHA_INTENT; + target.fixedPressure = target.fixedPressure + (inputP - target.fixedPressure) * alpha; + finalP = target.fixedPressure; + } } - const dev = Math.abs(inputP - target.fixedPressure); - if (dev >= FIXED_LARGE) { - target.fixedPressure = inputP; - return inputP; + // DBG: raw → mapped → final 3 단계 + raw min/max 추적. + if (DBG) { + const rawMin = Math.min(dbg.rawMin, rawPressure); + const rawMax = Math.max(dbg.rawMax, rawPressure); + dbg = { ...dbg, rawP: rawPressure, mappedP: inputP, finalP, rawMin, rawMax }; } - const alpha = dev < FIXED_THRESHOLD ? FIXED_ALPHA_NOISE : FIXED_ALPHA_INTENT; - target.fixedPressure = target.fixedPressure + (inputP - target.fixedPressure) * alpha; - return target.fixedPressure; + return finalP; } function pushPointWithInterp(target: Stroke, x: number, y: number, p: number) { const last = target.points[target.points.length - 1]; @@ -514,7 +535,19 @@ } function onPointerMove(e: PointerEvent) { - if (DBG) dbg = { ...dbg, move: dbg.move + 1, lastType: e.pointerType, lastPressure: e.pressure }; + if (DBG) { + dbg = { + ...dbg, + move: dbg.move + 1, + lastType: e.pointerType, + lastPressure: e.pressure, + tiltX: e.tiltX ?? 0, + tiltY: e.tiltY ?? 0, + ptrW: e.width ?? 0, + ptrH: e.height ?? 0, + buttons: e.buttons, + }; + } // 지우개 인디케이터 — hover (펜 미접촉) 만으로도 cursor 위치 추적. isDrawing // 가드 *전*이라 mouse hover / Pencil hover 모두 잡힘. @@ -934,15 +967,17 @@
tool:{tool} width:{widthMode}
- btn pen:{btnDbg.pen} er:{btnDbg.eraser} w:{btnDbg.width}
- css:{cssWidth}×{cssHeight}
- canvas:{dimDbg.canW}×{dimDbg.canH}
- container:{dimDbg.conW}×{dimDbg.conH}
- type:{dbg.lastType} p:{dbg.lastPressure.toFixed(2)}
+ type:{dbg.lastType} buttons:{dbg.buttons}
+ PRESSURE PIPELINE
+ raw:{dbg.rawP.toFixed(3)} (min:{dbg.rawMin.toFixed(2)} max:{dbg.rawMax.toFixed(2)})
+ mapped:{dbg.mappedP.toFixed(3)} final:{dbg.finalP.toFixed(3)}
+ tilt:{dbg.tiltX},{dbg.tiltY} ptr:{dbg.ptrW}×{dbg.ptrH}
+ EVENT COUNTERS
down:{dbg.down} move:{dbg.move} up:{dbg.up} cancel:{dbg.cancel}
rejType:{dbg.rejectedByType} rejId:{dbg.rejectedByPointerId} coal:{dbg.coalesced}
drawing:{isDrawing ? 'Y' : 'N'} actId:{activePointerId ?? '-'} infPts:{inflight?.points.length ?? 0}
- strokes:{strokes.length} + strokes:{strokes.length} btn pen:{btnDbg.pen} er:{btnDbg.eraser}
+ css:{cssWidth}×{cssHeight} canvas:{dimDbg.canW}×{dimDbg.canH}
{/if}