← 미리디 아카이브 / 병합 대치 정렬 문제

내용시각화 post-replace-relayout 작업트리 2026-08-26

재배치 알고리즘 파이프라인

내용 대치가 끝난 컴포넌트를 넘침·겹침·유휴 여백이 없도록 다시 배치한다. 연산자가 여섯 개(method 1~6)이고, 축이 다른 것끼리 정해진 순서로 조립된다. 그 순서가 왜 그 순서인지, 각 연산자가 무엇을 고정하고 무엇을 푸는지를 코드에서 정리했다.

miricanvas-iui · src/post-replace-relayout 후보 11개 (단독 6 · 합본 5) 실측 111
§0

30초 요약

  • 푸는 문제대치로 글이 길어져 넘침·겹침이 생겼다. 페이지에는 여백이 남아 있다 — 「공간이 없다」가 아니라 「공간이 잘못 나뉘어 있다」가 문제다.
  • 연산자 6축이 다르다 — 세로(1) · 가로 확장(2) · 가로 축소(3) · 유닛 사이 겹침(4) · 유닛 안 겹침(5) · 폰트 축소(6).
  • 조립 순서3 → 1 → 2 → 5 → 4 → 6. 크기를 먼저 정하고, 겹침을 안에서 밖으로 풀고, 글자 줄이기는 맨 마지막.
  • 정렬 원칙정확히 풀 수 있는 것을 먼저. 예측이 0인 연산자(1·3①·4)가 앞이고, 줄바꿈 예측이 들어가는 것(2·3②)이 뒤다.
  • 성적넘침 면적 4,107,470 → 368,345px²(91%↓), 겹침 게이트 PASS 34 → 97/111. 넘침은 3+1+2에서 끝나고 겹침은 +5+4가 푼다.
  • 대가method 6이 손대는 순간 판정은 SUCCESS가 될 수 없다(폰트 배율 < 1). 그래서 맨 뒤이고, 앞 다섯이 못 푼 것에만 발동한다.

이 문서가 보는 코드

miricanvas-iui 브랜치 feat/post-replace-relayout작업트리(2026-08-26)다. method6.ts 는 아직 커밋되지 않았고 나머지도 대부분 수정 중이라, GitHub 링크 대신 편집기 링크를 건다(§9). 숫자와 코드가 다르면 코드가 맞다.

§1

후보를 파일로 가른다

후보 하나 = 파일 하나다. 서로 접근 방식이 다른 알고리즘을 나란히 놓고 고르려는 것이므로, 한 파일에 분기를 몰아넣지 않는다. 합본도 후보 하나로 친다 — 「따로 쓸 때와 합쳐 쓸 때 중 무엇이 나은가」에 답하려면 둘 다 같은 케이스에 태워 각자 채점해야 한다.

후보는 sheetJson → sheetJson 순수 함수다. 그래서 굽는 단계가 없다 — 케이스 폴더에 rendered.json 하나만 있으면 뷰어가 브라우저에서 직접 불러 전 후보를 화면에 띄우고, 후보 코드를 고치면 HMR로 즉시 반영된다.

결과가 화면에 오는 경로 — 중간에 파일이 없다 relayout-methods/index.ts
cases/<id>/rendered.json ──▶ replaceLayout(doc, key, original) ──▶ After 장
                             ▲ 뷰어가 브라우저에서 직접 부른다

// original 은 채점 기준으로만 넘긴다 — 답을 보고 푸는 것이 아니다.
// 좌표계를 맞춘 사본(alignDocFrame)을 받아 method 4·5·6 이 「원안에 없던 겹침」을 정의한다.

레지스트리 11개

key한 줄
method1세로 공간 재분배 (폭 고정 · 예측 0)644
method2가로 여유로 줄 수 줄이기 (최소구성 + slack · 예측 포함)1,032
method3가로 넘침 해소 (도형을 좌우로 · 안 되면 텍스트를 좁혀 줄바꿈)684
method4대치가 만든 겹침 해소 (세로로 떼어 놓는다 · 크기 고정 · 예측 0)554
method5유닛 안의 겹침 해소 (가로로 열고, 안 되면 안에서 다시 쌓는다)572
method6가독성 하한을 지키는 폰트 축소 (원안 대비 · 페이지 대비 둘 중 더 엄한 쪽)377
method1+method2두 후보를 고정점까지 번갈아 — 세로로 풀고 남은 것만 가로로259
method3+1+2가로 넘침을 먼저 없애고, 그때 생긴 세로를 기존 합본이 담는다83
method3+1+2+4크기를 다 정한 뒤 대치가 만든 겹침을 세로로 떼어 놓는다84
method3+1+2+5+4유닛 안의 겹침을 먼저 풀고, 남은 겹침을 유닛끼리 떼어 놓는다93
method3+1+2+5+4+6 전체자리를 다 써 보고 그래도 안 담기면 가독성 하한까지 글자를 줄인다78

합본이 짧은 것은 새 연산을 안 만들기 때문이다 — 앞 후보들을 순서대로 부르고 게이트만 지킨다.

레지스트리가 둘이다 — 의도된 것

relayout-core 에도 ALGORITHMS 라는 후보 목록이 있다. 계약이 다르다 — 그쪽은 run(doc, ctx): void 로 제자리 수정, 여기는 run(doc): Doc 순수 함수다. 그쪽은 후보가 아니라 대조군 (optimizeLayout)이고 CLI 에서만 돈다.

이름도 일부러 다르다 — 렌더러(엔진)도 iframe 안에서 재배치를 하고 대치 파이프라인에 tidyLayout 도 있어서, 이름이 같으면 「재배치가 됐다」가 무엇을 가리키는지 늘 되물어야 한다. 그래서 이 디렉터리가 만드는 것만 replaceLayout 이다.

§2

여섯 연산자 — 축이 다르다

여섯이 경쟁하는 관계가 아니다. 손대는 축이 서로 다르고, 무엇을 고정하는지가 곧 정체성이다. 아래 지도가 이 문서의 전부다 — 가로는 무엇을 건드리나, 세로는 줄바꿈 예측이 들어가나.

손대는 축 → ← 예측 위 — 예측 0 · 문서에 박힌 실측만 쓴다 아래 — 줄바꿈을 예측한다 · 안전장치가 필요하다 세로 가로 겹침 글자 크기 method 1 세로 유휴 여백 재분배 폭 고정 → 줄바꿈 고정 → 높이 고정 컨테이너 높이 ↑ · y 조정 method 3 ① 가로 hug 도형을 좌우로 키운다 텍스트 박스는 그대로 method 1 의 hug, 축만 바꿈 method 4 유닛 사이의 겹침 — 세로로 떼어 놓는다 크기를 안 건드린다 → 예측 0 「원안에 없던 겹침 쌍은 한 띠로 묶지 않는다」 새 알고리즘이 아니라 띠 규칙의 예외 하나 method 2 가로 확장 폭을 연다 → 줄 수 ↓ → 높이 ↓ 최소구성 w_k + slack 안전장치 넷 (§5) method 3 ② 가로 축소 폭을 좁힌다 → 줄 수 ↑ → 높이 ↑ (autoHeight) method 2 의 거울상 ①이 막혔을 때만 method 5 유닛 의 겹침 ① 가로로 연다 (method 2 를 되쓴다) ② 칼럼 나눠 안에서 다시 쌓는다 ③ 도형을 넘겨 method 1 에 넘긴다 그 유닛의 겹침이 다 사라졌을 때만 받는다 method 6 폰트 축소 사다리 0.95 → 0.90 → … 한 문서에 한 배율 되돌릴 수 없는 대가 SUCCESS 를 영영 못 준다 글자 크기를 건드리는 연산자는 하나뿐이고, 그래서 맨 뒤다.
세로 점선 위는 문서에 이미 박힌 실측만 쓰는 연산자다 — 폭을 고정하면 줄바꿈이 고정되고, 줄바꿈이 고정되면 텍스트 높이가 문서에 있다(텍스트 노드는 전부 autoHeight). 아래는 폭을 바꿔서 「몇 px 넓히면 3줄이 2줄이 되나」를 렌더 전에 답해야 하는 쪽이다.
§3

조립 순서는 왜 3·1·2·5·4·6인가

순서에 원칙이 셋 있다. ① 정확히 풀 수 있는 것을 먼저, ② 크기를 먼저 정하고 겹침을 나중에, ③ 되돌릴 수 없는 것을 맨 뒤에.

① 크기를 정한다 method 3 method 1 m 2 가로 넘침 → 세로 재분배 → 가로 확장 뒤의 둘은 고정점까지 루프 (폭이 더 안 열릴 때 멈춘다) ② 겹침을 푼다 — 안에서 밖으로 method 5 method 4 유닛 → 유닛 사이 안을 먼저 풀어야 유닛의 크기가 확정된다 여기까지 폰트 배율 = 1 원안 글자 크기가 한 톨도 안 깎인다 → 판정이 SUCCESS 가 될 수 있다 이 선을 넘으면 최선이 ACCEPTABLE ③ 그래도 못 담은 것만 method 6 — 폰트 × s 하한 = max(원안 대비 0.7, 페이지 높이 2%) 사다리를 다 내려가도 FAIL 이면 한 픽셀도 안 줄이고 입력을 그대로 돌려준다 앞의 다섯을 한 번 더 돌린다 글자가 낮아진 만큼 자리가 남고, 그 자리를 method 1·4·5 가 다시 쓴다 이 되부름이 성적의 절반 — 10건 → 15건 되부름은 한 겹뿐 — 배율이 배율 위에 쌓이면 원안 대비로 말할 수 없다 순환 의존 회피 method6.ts 는 합본을 import 하지 않고 콜백으로 받는다
method 3 → 1 → 2 안에서도 같은 원칙이 반복된다 — 예측 0인 3①1이 앞이고, 줄바꿈 예측이 필요한 3②·2가 뒤다. 순서를 뒤집으면 세로로 풀렸을 케이스에까지 예측이 섞여 왜 그런지 가를 수 없게 된다.

왜 3이 1보다 앞인가

한 줄짜리 텍스트 박스는 넘칠 때 줄바꿈하지 않고 옆으로 늘어난다. 그건 세로 문제가 아니라 method 1 이 아예 안 돈다(세로 넘침이 없으면 그대로 반환).

실측 6447600: 503px → 1399px, 높이는 57.8px 그대로. 카드 폭은 1131px — 268·375px 이 카드 밖으로 나간다. 세 후보 다 60,671px² 를 그대로 뒀다.

구멍은 순서가 아니라 연산자였다. 가로 넘침을 없애는 수가 하나도 없었다.

왜 5가 4보다 앞인가

method 4 가 다루는 단위는 유닛(배경 도형 + 그 도형이 담은 텍스트)이다. 유닛 안에서 글자끼리 포개진 것은 유닛을 어디로 보내도 안 풀린다 — 옮길 대상이 하나다.

그래서 안을 먼저 풀어 유닛의 크기를 확정하고, 그 다음에 유닛끼리 떼어 놓는다. §4

왜 6이 맨 뒤인가

앞의 다섯은 자리와 크기를 다시 나누는 후보다. 그것으로 풀리면 원안 글자 크기가 안 깎이고 판정이 SUCCESS 가 될 수 있다.

반면 method 6 이 손대는 순간 지표 ②(최소 폰트 배율)가 1 아래로 내려가고, 판정 규칙상 SUCCESS 는 영영 못 된다. 최선이 ACCEPTABLE 이다.

실측도 그 순서를 지지한다 — 넘침으로 FAIL 이던 5699884·6535388 은 0.95 한 칸이면 풀린다.

§4

유닛 — 4와 5를 가르는 것

유닛 = 함께 움직이는 최소 단위다 — 배경 도형 하나 + 그 도형이 담은 텍스트 전부. 텍스트만 옮기면 「텍스트는 자기 배경 도형 밖으로 벗어나지 않는다」가 깨지고, 도형만 키우면 글자가 따라오지 않는다. 그래서 둘을 묶어 다닌다.

유닛 사이 — method 4 유닛 A 유닛 B 세로 구간이 겹친다 한 띠 → 통째로 움직인다 → 겹친 채로 함께 간다 띠 규칙에 예외 하나 「원안에 없던 겹침으로 이어진 쌍은 한 띠로 묶지 않는다」 → placeRow 가 최소 변위로 떼어 놓는다 유닛 — method 5 유닛 하나 (카드) 제목 본문 — 포개졌다 옮길 대상이 하나 카드를 어디로 보내도 둘의 거리는 한 픽셀도 안 바뀐다 유닛 안을 본다 — 세 수 ① 가로로 연다(method 2 되쓰기) → ② 칼럼 나눠 다시 쌓는다 → ③ 도형을 넘긴다
정답 문서 아홉을 갈라 보면 여덟이 가로로 열어 푼다 — 폭을 넓히면 줄 수가 줄고, 줄 수가 줄면 높이가 줄고, 높이가 줄면 아랫글과 떨어진다. 그래서 1단계가 가로이고, 그 일을 하는 기계는 이미 있다(method 2 의 발동 조건을 한 칸 넓혔다).

2단계가 지키는 것 — 글자 덩어리의 위아래 끝

그릇을 「그 칼럼이 지금 차지한 구간」으로 잡는 것이 핵심이다. 첫 글의 위 변과 끝 글의 아래 변이 제자리에 남으므로 정렬선(지표 ③)이 안 깎이고 도형 안쪽 여백도 그대로다. 쓸 재료는 글자 사이에 이미 있던 여백뿐이다.

칼럼을 「가로로 겹치는 것끼리」 묶는 것도 규칙이다 — 나란한 셋을 세로로 쌓으면 안 된다 (6535640 실측: 같은 y 에 놓인 텍스트 셋).

§5

예측을 쓰는 대가

폭을 여는 순간 「폭 고정 → 줄바꿈 고정 → 높이 고정 → 예측 0」이 무너진다. 「폭을 몇 px 넓히면 3줄이 2줄이 되나」는 다시 렌더하기 전에 답해야 하므로 예측이다. 그래서 method 2 는 강력하지만 위험하고, 안전장치 넷을 전부 달고 있다.

01

줄 수를 짜게 센다

폭을 WRAP_SAFETY(12%) 좁다고 보고 센다. 글자폭 계수의 오차와 letterSpacing 을 세지 않는 것을 덮는 값이다.

정답 빌더와 같은 상수를 본다 — 셈법이 다르면 후보가 「줄었다」한 폭을 채점이 「그대로」로 본다.

02

이득은 실측과 견준다

후보의 높이 h_k문서에 박힌 지금 높이보다 작아야 받는다. 모델이 줄 수를 과대평가했으면 h_k 가 지금 높이와 같아져 저절로 거부된다 — 예측 오차가 「아무것도 안 함」으로 떨어진다.

03

신규 겹침 게이트 — 되돌림은 노드 단위

노드 하나를 넓힐 때마다 재고, 새 쌍이 생기면 그 노드만 되돌린다. 체인을 통째로 되돌리지 않는다.

5698327 은 도형 8개를 키워 넘침을 다 없애 놓고 새 겹침 한 쌍 때문에 여덟 개가 전부 날아갔었고, 6134703 은 696px² 짜리 겹침이 5,509px² 짜리 수정을 날렸다.

견주는 기준은 자기 입력 문서다 — 정답은 생성 단계에서 읽지 않는다.

04

한 칸 물러나기 · 렌더 재검증

거부되면 다음(더 좁은) 후보로 물러난다. 게이트가 거부할 때는 렌더 없이 예측 안에서, 렌더가 거부할 때는 실측으로.

replaceLayoutVerified 는 라운드 경계마다 실제로 렌더한다 — 두 번째 라운드의 method 1 이 보는 높이가 예측값이 아니라 렌더러가 확정한 값이 된다. 헤드리스 크롬이 필요해 node 에서만 돈다.

승계 — 게이트가 너무 엄하면 아무것도 못 고친다

hug 는 넘친 글자를 담는 일이라, 글자가 이미 이웃을 침범해 있었다면 그 침범을 도형이 물려받는다. 쌍의 이름만 바뀐 것을 「신규」로 세면 5628689 처럼 48.2px 짜리 넘침을 못 고친 채 7px 짜리 겹침을 피하게 된다. 승계에는 깊이 상한이 붙는다.

§6

채점 — 기준은 원안

재배치가 되돌리려는 상태가 원안(original.json) 이기 때문이다 — 디자이너가 정한 글자 크기·정렬선·「의도된 겹침」이 거기 있고, 대치가 무너뜨린 그것을 다시 세우는 일이 재배치다.

답을 보고 푸는 것이 아니다 — 후보의 입력은 언제까지나 rendered.json 하나뿐이고, 원안은 채점 기준으로만 본다.

지표방향
① 넘침 노드 수 / 넘침 면적(px²)낮을수록 좋음
② 최소 폰트 배율 원안 대비높을수록 좋음
③ 정렬선(가이드) 보존율 원안 대비높을수록 좋음
④ 유휴 여백 비율낮을수록 좋음
⑤ 신규 겹침 쌍 / 면적 — 원안에 없던 겹침0 이어야 함 (PASS/FAIL)
⑥ 좁은 칼럼 노드 수 — 두 줄 이상 + 줄당 3자 미만낮을수록 좋음 판정엔 미포함

판정 라벨

라벨조건
FAIL① 넘침 노드 > 원안 · ⑤ 신규 겹침 있음 · ② 폰트 배율 < 0.7 — 셋 중 하나라도
SUCCESSFAIL 아님 + ② 폰트 배율 = 1.0 + ④ 유휴 여백 ≤ 원안
ACCEPTABLEFAIL 아님 + SUCCESS 아님

왜 절대 0이 아니라 원안 대비인가

디자이너가 일부러 넣은 오버행을 벌주지 않기 위해서다. 119건에서 원안 넘침 노드가 45개 — 절대 0으로 재던 때는 그 케이스들이 손도 못 대고 FAIL 이었다.

원안은 좌표계를 맞춰서 쓴다

같은 컴포넌트를 다른 자리·배율로 앉힌 문서다(배율 = fontSizeScale, 커밋된 케이스에서 0.97~1.91).

절대 좌표를 그냥 견주면 겹침 면적이 배율²로 커져 의도된 겹침이 전부 「신규」로 잡힌다. alignDocFrame 이 원안을 렌더본과 같은 자리·배율로 옮긴다.

렌더본은 오토핏을 끄고 굽는다

오토핏을 켜면 못 담을 글이 넘침이 아니라 축소로 박힌다 — 5628689 실측: 원안 38.7px → 27.1px(70%)에 넘침 노드 0.

그 문서를 넣으면 후보가 고칠 것을 못 찾는다. 끄는 레버는 렌더 메시지의 shrinkConfigs 하나다 — ThumbnailLoad.fontScaleRange배포된 렌더러가 읽지 않는다(값만 바꿔 네 번 렌더해도 한 픽셀도 안 달라졌다).

§7

실측 111건

커밋된 케이스 111건 합계, 채점 기준 = 원안, 2026-08-26 실측. 두 측정치는 다른 문제를 재므로 눈금을 따로 둔다 — 왼쪽은 넘침, 오른쪽은 겹침 게이트다.

넘침 면적 (px²) — 낮을수록 좋음 겹침 게이트 PASS / 111 — 높을수록 좋음 before 4,107,470 34 method 1 2,607,978 40 method 2 3,204,852 36 method 3 3,315,905 35 1 + 2 1,816,735 42 3 + 1 + 2 534,454 43 3 + 1 + 2 + 4 534,454 71 3 + 1 + 2 + 5 + 4 534,454 83 3+1+2+5+4+6 368,345 97 정답(목표선) 699,729 60 / 90 — 모수가 달라 막대를 안 그린다 0 2M 4M 0 55 111 넘침은 3+1+2 에서 끝난다(4,107,470 → 534,454px², 87%↓). 그때 게이트는 43/111 뿐이다 — 넘침과 겹침은 다른 문제라서다.
값은 모두 막대 옆에 직접 적었다. +4·+5+4 세 칸의 넘침이 한 자리도 다르지 않은 것은 「넘침이 늘면 되돌린다」를 게이트로 걸었기 때문이다. 마지막 +6 만 성격이 달라 — 글자를 줄이므로 넘침까지 함께 지운다.

method 6 이 사는 것과 치르는 값

판정 구성 · 111건 3 + 1 + 2 + 5 + 4 SUCCESS 50 ACCEPT. 31 FAIL 30 + method 6 SUCCESS 50 ACCEPTABLE 47 14 FAIL 16건이 ACCEPTABLE 로 SUCCESS 는 한 건도 늘지 않는다 — 글자를 줄인 문서는 정의상 SUCCESS 가 못 되기 때문이다. 폰트 배율 평균 1.000 → 0.982. 게이트 PASS 는 83 → 97/111 로 오른다. 「담기게 만드는 대신 원안 크기를 포기한다」의 교환비가 이 두 줄이다.
막대 길이는 111건 기준 비율이고 건수를 안에 적었다. 세그먼트 사이에 2px 표면 간격을 둬 경계를 색만으로 읽지 않게 했다.

남는 것 — 재배치로 못 고치는 자리

3+1+2 가 남긴 9건(534,454px² · 14노드)은 도형을 키울 자리가 없는 케이스다. 좌우로는 이웃이, 세로로는 겹침 게이트가 막아 min-content 까지 좁혀도 글이 그릇을 넘는다. 6780937 「VS」 배지는 지름 107px 원에 7줄이 들어갔다.

정답지는 폰트를 줄여 풀지만 그 길은 후보에 없다 — 「재배치로 못 고치는 것」으로 남겨 둔 자리이고, 케이스 id 는 method3Method1Method2.test.ts 가 못박는다.

⚠️ 그 0 들은 예측 위의 0 이다. method 3 의 축소 단계가 쓰는 줄 수·높이는 렌더가 아니라 모델값이다 — 실제 렌더에서 줄이 한 줄 더 흐르면 그만큼 다시 넘친다.

§8

공용 커널 relayout-core

합본이 짧은 것처럼, 후보들도 대부분 순서를 정하는 일만 한다. 실제 계산은 relayout-core 의 순수 함수들이 하고, 축만 바꿔 재사용된다 — method 1 이 세로에 쓰는 placeRowmethod 2 가 가로에 그대로 쓴다.

모듈무엇
topology.ts위상 동결 — 무엇이 함께 움직이고 무엇이 무엇을 담고 있나. 좌표를 건드리기 전에 한 번 정해 굳힌다(열면 조합 최적화가 되어 다항시간에 못 푼다)478
measure.ts실측 — 문서에 이미 박힌 것을 읽는다. 예측이 아니라는 경계를 이름으로 못박았다174
pairing.ts텍스트 ↔ 배경 도형 짝짓기. 재배치의 최소 단위는 텍스트 하나가 아니라 「텍스트와 그것을 담은 도형」 한 쌍51
gapAlgebra.ts여백 대수 — 남은 공간을 갭에 어떻게 나눌지를 닫힌 형식으로. 축과 무관한 순수 숫자 함수135
placeRow.tsAbacus PlaceRow — 한 축에서 「겹치지 않으면서 가장 덜 움직이는」 배치를 정확히 푼다137
neighbors.ts가로 slack — 「이 박스가 좌우로 어디까지 커질 수 있나」. 가로는 이웃을 밀어내지 않는다148
feasibility.ts실현가능성 — 배치를 시도하기 전에 「담을 수 있나」를 답한다. 못 담으면 담긴 척하는 결과 대신 신호가 나온다49
gate.ts신규 겹침 게이트의 정본. 후보가 무엇을 하든 이 판정을 통과해야 한다. 승계 규칙도 여기182
geometry.ts노드를 실제로 옮기고 키우는 곳. 재배치가 문서를 건드리는 지점은 여기뿐 — boundingBox 가 부모 상대 좌표라 헬퍼를 거쳐야 한다411
textOverflow.ts넘침 판정 — 이 feature 전용. comp-sign 의 예측 모델은 fontSizeScale 을 곱하지 않아 여기 쓸 수 없다655
visualBox.tsvisual bounding box — 글자 + 그 글자에 딸린 장식(글머리 기호 띠)까지. tight 만 쓰면 기호가 도형 밖에 나가도 넘침 0으로 적힌다148
docFrame.ts좌표계 맞추기 — 원안을 렌더본과 같은 자리·배율로 옮긴다. 배율의 정본은 text.fontSizeScale146
renderProbe.ts렌더 재검증 — 예측으로 바꿔 놓은 줄바꿈을 실제로 렌더해 대본다301
metrics.ts정량 지표 일곱. absBoxMap 의 좌표계 함정 주석이 여기 있다1,193
verdict.ts케이스 하나를 한 낱말로 — SUCCESS · ACCEPTABLE · FAIL232

여백 대수 vs PlaceRow — 헷갈리면 이 두 줄

여백 대수는 「남은 공간을 갭에 어떻게 나눌까」를 묻고 목표 좌표를 낸다.
PlaceRow 는 「겹치지 않으면서 가장 덜 움직이는 배치는?」을 묻고 확정 좌표를 낸다.

둘 다 축과 무관한 순수 함수라, 세로 파스와 가로 파스가 같은 코드를 쓴다.

§9

코드 지도

경로는 miricanvas-iui/src/post-replace-relayout/ 기준이다. 편집기 를 누르면 VS Code 로 열린다 — 작업트리 코드라 GitHub 링크는 걸지 않았다.

파일무엇편집기
relayout-methods/index.ts레지스트리 11개 · replaceLayout · replaceLayoutVerified 편집기
relayout-methods/types.tsRelayoutMethod 계약 — 후보와 레지스트리가 함께 보는 커널 편집기
relayout-methods/method1.ts세로 재분배 · hugVertical · 다섯 단계 편집기
relayout-methods/method2.ts가로 확장 · 최소구성 w_k · slack · 안전장치 넷 편집기
relayout-methods/method3.ts가로 넘침 — ① hug(예측 0) · ② 축소(예측) 편집기
relayout-methods/method4.ts유닛 사이 겹침 · 띠 쪼개기 + pushApart 편집기
relayout-methods/method5.ts유닛 안 겹침 · 세 수(가로 → 다시 쌓기 → 넘기기) 편집기
relayout-methods/method6.ts 미커밋폰트 축소 · 하한 둘 · 사다리 · 되부름 편집기
…Method5Method4Method6.ts전체 파이프라인 — 78줄. 되부름 콜백을 여기서 꽂는다 편집기
relayout-core/공용 커널 15개 모듈 — §8 편집기
README.md실행법 · 실측표 · 뷰어 설명. 표에 날짜가 박혀 있다 편집기
docs/before-after-rules.md무엇을 만들어야 하는가 — §2 불변조건 · §4 알고리즘 · §8 Expected 만들기 편집기
docs/evaluation-rules.md어떻게 그리고 채점하는가 — §2 지표 · §3 판정 라벨 편집기
docs/relayout_logics.md후보별 정본 편집기

돌려 보기

miricanvas-iui 에서 뷰어는 브라우저에서 그때그때 계산한다
# 뷰어 — 케이스마다 네 장(원안 · 대치후 · 재배치 · 정답)을 겹쳐 본다
https://local.miricanvas.com:3000/post-replace-relayout

# 지표 표를 터미널에 — 위 §7 의 표를 다시 재는 법
pnpm exec tsx scripts/relayout-metrics.ts

# 한 후보만 전 케이스에 돌려 게이트를 본다 (--write 로 내보내기)
pnpm exec tsx scripts/relayout-method-run.ts