v0.2.65
v0.2.65 — 에셋 이미지 표시 배율 (%) + 노드 자동 spacing (겹침 방지) + leerness 1.9.247
horizontal mode
- (
compute2DTreeLayout): - leaf 마다
rowHeight = max(ROW_HEIGHT, customH + ROW_GAP)계산. - 누적
rowTop[k]+ piecewise-linearyFor(rowF)— float rowF 도 정확한 cell 안에 위치. - 한 노드라도 oversize 면 variable mode, 모두 default 면 빠른 경로 (
rowF * ROW_HEIGHT). - column 폭도 depth 별 max(customW) 로 자동 확장 (기본 COLUMN_W=480 미만이면 영향 X).
city mode
- (
compute2DCityLayout): packBlock의 파일 grid 가colW[c] = max(CELL_W, customW)+rowH[r] = max(CELL_H, customH)로 cell 크기 자동 조정.- 누적
colX[c]+rowY[r]으로 각 파일을 정확한 위치에 배치. - 블록 bounds 계산도 effective 크기 기반 (큰 이미지가 block 밖으로 튀어나오지 않음).
vertical / smart / otel mode
- 자체 spacing 은 default 만 사용. 신규
applyOverlapPostPasssafety-net 이 모든 모드에 적용됨. - *
applyOverlapPostPasssafety-net (신규)**: - 모든 레이아웃 산출물에 적용되는 비겹침 post-pass.
compute2DTreeLayoutdispatcher 안에서 city/smart/otel delegated 호출의 결과 + default horizontal/vertical path 의 결과 둘 다 통과. - 동작 조건:
options.getNodeSize가 지정되었고 + 적어도 한 노드가 default (220×36) 보다 큰 경우만. 그렇지 않으면 즉시 return (성능 비용 0). - 알고리즘: spatial-hash bucket (BUCKET=320 world px) → 이웃 9-cell 안의 노드 쌍 AABB 겹침 체크 → 더 작은 overlap 축으로
(overlap/2 + 0.5)px만큼 양쪽 밀어냄 + minGap=8. - 6 iteration 까지 반복, moves=0 이면 조기 종료. 5000+ 노드에서도 O(N) 시간 (bucket 으로 인접 노드만 비교).
- post-pass 후
folderBounds재계산 (자손 노드 새 위치 기준) +bounds재계산. - side effect: positions Map mutate. externalPositions 는 변경 X (외부 노드 영역은 layout 끝쪽이라 겹침 없음).
- *
Graph2D.tsx— getNodeSize 연결**: useViewportAssetStore((s) => s.rev)구독 → asset 변경 시 layout 재계산 trigger.compute2DTreeLayout호출에getNodeSize: (id, isDir) => getEffectiveNodeSize({path: id, isDirectory: isDir})전달.
변경 파일
src/store/viewportAssetStore.ts— SizedAssetFields, measureImageSize, clampScale, setKindScale/setExtensionScale/setEdgeKindScale, getEffectiveNodeSize, resolveNodeImage 반환 타입 변경, resolveEdgePattern 반환 타입 변경, resolveViewportAssetEntry 추가.src/components/Visualizer2D/FileNodeCard.tsx—<img style={{ width, height }}>적용.src/components/Visualizer2D/Graph2D.tsx— EdgePatternOverlay 의 per-edge sticker size + spacing, CustomBackgroundTileOverlay backgroundSize, layout useMemo 의 assetRev 의존성 + getNodeSize callback.src/components/Layout/SettingsModal.tsx—<ScaleInput>컴포넌트 + 3 섹션 row 에 적용 + 업로드 시 measureImageSize 호출.src/utils/layoutAlgorithm.ts—Layout2DOptions.getNodeSize, horizontal variable row/column, citypackBlockper-cell sizes, 신규applyOverlapPostPasssafety-net + dispatcher wiring..harness/HARNESS_VERSION1.9.191 → 1.9.247.package.json0.2.64 → 0.2.65.
검증
npx tsc --noEmitexit=0.npm run build성공 — renderer 6.47s, 번들 3,521.80 kB (post-pass 추가 후).leerness verify✓ (warnings=5, failures=0).
사용 시나리오
- 설정 → 에셋 → "뷰포트 커스텀 이미지" → "파일 노드" 업로드 (예: 200×200 logo).
- 같은 row 의
<ScaleInput>으로 50% 입력 → 노드 표시 100×100. 200% → 400×400. - 뷰포트 자동 relayout — 큰 이미지 노드 행/열 spacing 이 자동으로 늘어나 옆 노드와 안 겹침.
- 확장자별 / 엣지 종류별도 같은 방식.
핸드오프 메모
- WebGL 2D 엔진 (
WebGLGraph2D.tsx) 은getNodeSize적용 보류 — InstancedMesh 의 quad 크기 일괄 변경 필요해 별도 iteration. - 3D 엔진 (
Scene3D.tsx등) 도 noscaled — 텍스처 텐서 / 메시 크기 조정 별도 작업. - vertical / ai-recommended / otel layout 도 callback 받지만 미적용 — 사용자 피드백 따라 우선순위 결정.
- naturalSize 가 없는 (외부 URL or 측정 실패) 이미지는 CSS
transform: scale(n)fallback — 자식 요소 layout 영향 X (transform-origin top-left). - --
📦 GitHub 릴리스 노트: v0.2.65