← RLSC — 컴포넌트의 일생

공급 라인 · 오프라인

Background Extractor

템플릿의 노드 하나하나가 쪽의 틀(slide master)인지 그 쪽의 내용(foreground)인지를 가르는 규칙 엔진. 네트워크 호출도 외부 의존도 없는 순수 계산이고, 판단의 근거는 하나다 — 여러 쪽에 걸쳐 같은 자리에 되풀이되는가.

저장소 aippt-prisonbreak 코드 src/lib/backgroundExtractor/ 갱신 2026-09-13
§0

어디에 붙나

이 절이 답하는 질문 — 이 엔진은 파이프라인의 어느 지점에서 불리나? 왜 하필 거기인가?

json_sheet_data

원본 → ALSC top level

buildSlideTemplate

어댑터 — 엔진 밖

review()

판정 엔진

toClassifications()

칸 맞추기

buildLayeredAlscFromIds

6-ALSC 조립

원본을 ALSC 로 펴는 것은 parseAsStructuredContent 이고 BE 밖이다. ML 노드별 예측은 buildSlideTemplate 으로 함께 들어간다.

붙는 자리는 extractLayout 이 아니라 computeTemplate 이다

review() 의 판정 단위가 템플릿이고 최소 세 장이 필요한데, extractLayout 은 쪽 하나만 보므로 거기서는 부를 수가 없다. 이 제약이 엔진 설계 전체를 결정한다 — 되풀이를 근거로 삼는 이상 여러 쪽을 동시에 들고 있어야 한다.

어댑터가 조용히 판정을 바꾼다

buildSlideTemplate 은 nodeType 처럼 ALSC 에 없는 칸을 채우는 것이 일이다. 안 채우면 예외가 나지 않고 판정이 조용히 달라진다 — 규칙 여섯 곳이 그 값을 읽기 때문이다. width·height 도 같은 처지로, jsd 루트에서 와야 한다.

§1

무엇을 받아 무엇을 내나

이 절이 답하는 질문 — 입출력 계약은 무엇이고, 규칙이 아무 말도 안 한 노드는 어떻게 되나?
입력

SlideTemplate

단위
템플릿 하나 = 쪽 여러 장
노드
자리 · 종류 · nodeType · 글 · 글꼴 · 자원 키
순서
ALSC top level 순서 = 원본 z index
역할표
BE 역할표 중 page_title 만 판정에 쓴다
출력

노드마다 판정 하나

slidemaster
이 쪽의 틀 — 머리말, 꼬리말, 쪽번호, 좌·우 기둥, 그 꾸밈
foreground
이 쪽의 내용
reason
왜 그렇게 봤는지 한 줄

모든 노드에 답을 하나씩 낸다

규칙이 아무 말도 안 한 노드는 foreground 로 채운다. 그렇게 하지 않으면 buildLayeredAlscFromIds 가 노드마다 경고를 찍는다. «모름»이라는 출력은 없다는 것이 이 계약의 성격이다.

입출력 계약 원문은 docs/rat-pod/background-extractor/02-schema.md, 개요는 같은 폴더 00-overview.md.

§2

판정을 가르는 생각

이 절이 답하는 질문 — 같은 크기의 같은 글자가 왜 어떤 쪽에서는 머리말이고 어떤 쪽에서는 소제목인가?

쪽 하나만 보고는 틀인지 내용인지 가릴 수 없다. 쪽 위쪽의 작은 글자는 머리말일 수도 있고 본문 소제목일 수도 있다. 가르는 것은 여러 쪽에 걸쳐 같은 자리에 되풀이되는가이다.

쪽 한 장만 보면 머리말? 소제목? — 알 수 없다 ⇒ 쪽 여러 장을 겹쳐 보면 p.1 p.2 p.3 같은 자리에 되풀이된다 → 틀
되풀이가 유일한 근거다. 그래서 최소 세 장이 필요하고, 판정 단위가 템플릿이 된다.

이 생각이 네 국면으로 펼쳐진다. 전체 마스터의 97%가 네 가장자리 자리에서 나온다.

  1. 어디에 앉았나 — 쪽 가장자리에 띠(위아래)와 기둥(좌우)을 그리고 노드마다 자리를 정한다. 띠 폭은 그 템플릿의 글자 크기로 정한다. 고정값이 아니다.
  2. 되풀이되나 — 쪽을 건너 같은 자리에 같은 것이 나오면 틀일 가능성이 높다.
  3. 다 같이 간다 — 되풀이되는 것을 한 무리로 묶고 무리 안에서 표결한다.
  4. 아닌 것을 뺀다 — 본문 그리드의 한 칸, 사진, 프레임 안 살림살이, 흩어진 장식은 가장자리에 있어도 틀이 아니다. 뺀 것은 사유와 함께 적는다.
§3

국면 1 — 자리 판별

이 절이 답하는 질문 — 띠와 기둥은 얼마나 두꺼운가? 왜 기둥이 띠보다 좁은가?
본문 영역 띠 (위) 띠 (아래) 기둥 기둥 0.22 0.12 띠 = 기준 글자 크기 × 6, 쪽의 0.22 까지 기둥 = 기준 글자 크기 × 3, 쪽의 0.12 까지 기준 글자 = 제목 후보 크기의 중앙값 영역에 들었는가 — 두 조건 ① 노드 전체가 영역 안에 든다 ② 쪽 가장자리에서 시작할 때에 한해, 밖으로 나간 몫이 50% 이하
비율은 상한이고, 실제 폭은 그 템플릿의 글자 크기가 정한다.

왜 고정값이 아닌가

큰 글씨를 쓰는 템플릿은 머리말도 두껍기 때문이다. 고정 폭으로 두면 그런 템플릿의 머리말이 띠 밖으로 나간다.

왜 모든 글자의 중앙값이 아닌가

쪽번호처럼 작은 것이 중앙값을 끌어내려 띠가 좁아진다. 그래서 제목 후보만 센다.

왜 기둥이 띠보다 좁은가

띠는 글줄이 쌓이며 행간을 먹지만 기둥은 한 열만 품는다. 같은 자를 쓰면 본문 카드 그리드의 첫 칸이 기둥으로 들어온다.

중심으로 재던 것을 왜 그만뒀나

예전에는 상자 중심으로 쟀는데, 중심만 걸치면 아무리 길어도 들어온 것으로 봤다. 쪽 한복판에서 시작해 띠를 살짝 물고 지나가는 본문 글이 머리말이 됐다. 조건 ②를 가장자리에서 시작하는 것에만 주는 이유는, 가장자리에 붙인 뱃지와 로고가 흔히 띠보다 조금 크기 때문이다.

기둥 폭 상한 0.12 는 타협이다

본문 카드 그리드를 막으려고 좁힌 값이고, 그 탓에 두꺼운 진짜 기둥을 놓친다. 실제로 가르는 것은 폭이 아니라 판이 있느냐다 — 본문 그리드의 첫 칸에는 쪽 높이를 덮는 배경 판이 없고, 왼쪽 목차 열에는 있다. 진짜 기둥의 중심은 0.03~0.05, 본문 그리드 첫 칸은 0.15~0.21 사이다.

§4

국면 2 — 자리 세우기

이 절이 답하는 질문 — 제목·머리말·쪽번호는 각각 어떻게 찾아내나? 왜 셋의 방법이 다른가?
제목 자리

제목은 템플릿 성질이다

쪽마다 거의 같은 자리에 같은 모양으로 앉는다. 쪽 하나만 보고 가장 큰 글자를 고르면 본문이 제목을 이긴다.

  1. 모든 쪽의 텍스트 후보를 한데 모은다
  2. 윗변과 상자 높이가 맞는 것끼리 자리로 묶는다. 쪽 하나에 하나만 받는다
  3. 쪽 과반을 덮는 자리만 남긴다
  4. 그중 제 쪽에서 큰 축에 드는 자리가 제목 자리다
  5. 그 자리에 없는 쪽은 제목이 없는 쪽이다 — 표지와 맺음말이 여기 든다
쪽번호

자리가 아니라 값으로 찾는다

자리가 흔들려도 값이 스스로를 증명하기 때문이다. 어떤 템플릿은 쪽번호가 열두 쪽에서 아래에 있다가 한 쪽에서만 위로 올라간다. 자리로 묶으면 그 쪽을 잃고, 값으로 묶으면 저절로 이어진다.

  1. 순수 숫자 텍스트가 후보다. '01' 도 1 과 같은 값이다
  2. 치수가 같은 것끼리 계열로 묶는다. 위치는 보지 않는다
  3. 쪽 차례에 대해 값 = 쪽 + 상수 로 떨어지면 쪽번호 수열이다
  4. 쪽을 가장 많이 덮는 계열 하나. 같으면 쪽 가장자리에 가까운 쪽
가장자리 자리 — 아홉 걸음

남은 마스터의 80%가 여기서 나온다

걸음하는 일
① 후보띠와 기둥 안의 글자. 제목과 그 주변은 뺀다
② 묶기윗변·상자 높이·가로 구역이 맞는 것끼리. 쪽 하나에 하나
②b 거울상좌우를 오가는 자리는 하나로 본다
③ 과반쪽 과반을 덮는 자리만 남긴다
④ 채움자리가 섰으면 빠진 쪽을 다시 훑는다
⑤ 비텍스트같은 자산이 과반에 되풀이되면 로고·아이콘도 머리말이다
⑦ 구분선제목을 감싼 한 쌍은 제목의 것이다
⑧ 장식 떼글자 없이 흩어진 도형 떼는 꼬리말이 아니다
⑧b 한 줄마스터 글자와 같은 줄에 앉은 것도 마스터다
⑨ 제목 자리어느 쪽에서든 타이틀로 잡힌 자리는 제목 자리다

띠로 먼저 거르고 그다음에 묶는다

순서를 바꾸면 본문 요소가 만든 자리가 먼저 낚아채서 가장자리 글자를 삼킨다. 실측에서 200 템플릿 중 143 개가 자리를 하나도 못 세웠다.

거절 장부 — 뺀 것은 «모름»이 아니다

관문에 걸려 일부러 뺀 것을 사유와 함께 적어 둔다. 자리를 못 세운 것(모름)과 가장자리가 아니라고 판단한 것(거절)은 다르다. 뒤따르는 무리 표결에서 모름은 기권이지만 거절은 전경 표여야 한다 — 어떤 템플릿에서 태그를 떼기만 하고 아무 말도 안 남긴 탓에 스물세 개가 3 대 0 으로 마스터가 된 적이 있다.

§5

국면 3 — 사다리와 무리

이 절이 답하는 질문 — 여러 규칙이 서로 다른 주장을 하면 누가 이기나?
판정 사다리 — 위에서 걸리면 아래는 안 본다

1꾸밈 임자 다툼

마스터와 전경이 같은 꾸밈을 서로 제 것이라 할 때

2사진 · 영상 · QR · 사진틀

그 자체가 내용이라 틀이 될 수 없다

3프레임 안과 테두리

프레임과 그 살림살이는 전경이다

4타이틀과 그 주변

전경이다

5남은 가장자리와 쪽번호

마스터다

①의 다툼은 문턱이 아니라 겹침으로 가린다

꾸밈을 제 위에 두는 임자가 진다. 머리말은 선을 제 아래에 두고, 쪽번호는 선과 세로로 겹쳐 옆에 두는데, 제목만 선을 제 위에 둔다. 그래서 제목이 진다.

무리 표결 (AON)

자리는 템플릿 성질인데 임자 경쟁은 쪽마다 돈다. 그래서 같은 물건이 쪽마다 다른 갈래로 간다. 무리로 묶어 표결해서 되돌린다.

규칙
표는 주장으로 던진다. 판정이 아니다 아무도 주장 안 한 쪽은 기권한다 이긴 판정을 기권한 쪽에도 준다 — 그것이 AON 이다 동점이면 그대로 둔다

무리 표결이 유일하게 올리는 규칙이다

전량에서 23,688 개를 마스터로 끌어올리고 전체 템플릿의 27%에 손을 댄다. 되풀이를 근거로 판단하는 이 시스템의 중심축이다.

무리를 짓는 열쇠 — 신원과 자리를 섞지 않는다

신원은 쪽이 바뀌어도 안 바뀌는 것이고, 자리는 쪽마다 되풀이되는 것이다. 예전에 둘을 한 열쇠에 넣어 두어서 같은 물건이 크기가 달라지면 갈리고, 다른 물건이 크기가 같으면 붙었다.

갈래신원
자원이 있는 것url 또는 shapeKey. SVG 의 85%, 사진의 100% 가 가진다
선방향과 두께. 길이는 쪽마다 달라도 같은 선이다
글뼈대(숫자와 공백을 지운 문구) + 글꼴 + 글자 크기
그 밖nodeType

색은 신원에 넣지 않는다

쪽마다 표식 하나만 색이 바뀌는 템플릿이 있다. 지금 이 쪽을 가리키는 표시인데, 색으로 가르면 그 하나가 무리에서 떨어져 나간다.

§6

국면 4 — 뒤에 서는 규칙 열다섯 단계

이 절이 답하는 질문 — 규칙의 차례가 왜 규칙의 일부인가?

자리 판별이 일단 넉넉하게 잡은 뒤, 뒷단계 규칙들이 아닌 것을 걸러낸다. 대부분 내리는 규칙이라는 것이 이 구조의 성격이다. 아래 순서로 돌고, 앞이 내린 것을 뒤가 되올리기도 한다. verdict.ts 가 이 차례의 정본이다.

차례규칙뜻판
1무리 맞추기 aon쪽마다 갈린 무리를 표로 통일한다
2쪽 안 갈림 pageaon똑같은 것이 한 쪽에 여럿인데 하나만 마스터면 그 쪽에서는 다 전경이다
—자리 흔들림 roamout⏸ 파킹 — 파이썬과 갈래를 맞췄다v4
3홀로 선 도형 lone글자 짝 없이 혼자 선 도형인데 쪽이 어수선하면 꾸밈이다
4구분선 여럿 manyline쪽을 가로지르는 긴 선이 한 쪽에 둘 이상이면 쪽 꾸밈이다
5세 줄 넘는 글 line3fore가로로 세 줄 이상인 글상자는 문단이고, 문단은 내용이다
6장 번호 chapmasterCHAPTER.01 처럼 번호만 느는 글은 쪽번호와 같은 것이다
7넘친 기둥 railspill기둥을 넘친 마스터가 전경 글자에 위아래로 붙어 있으면 그것도 내용이다v2
8쪽 꾸밈 pagedeco고유한 그림이 가장자리에 흩어져 셋 이상이면 그 쪽의 장식이다
9무리 닫기 famclose무리를 닫는다
10쪽 안 무리 inpageaon쪽 안에서 무리를 맞춘다v2
11리듬 형제 rhythm등간격으로 늘어선 형제는 하나가 강조돼 있어도 한 무리다 — 올리기만 한다v4
12마스터 곁의 그림 artnear이미 마스터인 것과 같은 축에 붙어 있고 더 작으면 그 마스터의 꾸밈이다
13머리말 위 headtop머리말 위에 같은 축으로 더 큰 전경 글자가 있으면 그 머리말은 부제목이다v1
14쪽몰림 pageburst한 무리 안에서 한 쪽에만 몰린 식구는 그 쪽의 본문이다v1
15곁 아이콘 sideicon마스터 글자 곁에 붙은 작은 아이콘은 그 마스터의 일부다 — 되돌린다v4

두 자리는 못 옮긴다

rhythm 은 inpageaon 바로 뒤여야 한다 — 앞에 두면 inpageaon 이 도로 내린다. sideicon 은 맨 끝이다 — 회수하는 자라 내리는 자들 뒤에 서야 뜻이 있다.

단계별 변화량 — 전량 14,352 장 기준

단계전경 → 마스터마스터 → 전경닿은 템플릿
무리 맞추기23,6886,6933,899
구분선 여럿014,3061,535
쪽 꾸밈05,202131
무리 닫기3,9373,1251,943
쪽 안 갈림03,910750
마스터 곁의 그림2,1580203
장 번호1,0230189
자리 흔들림 (지금은 파킹)076878
머리말 위072183
세 줄 넘는 글0564108
홀로 선 도형020718

손대는 범위가 규칙마다 크게 다르다. 무리 맞추기는 3,899 템플릿, 홀로 선 도형은 18 템플릿이다 — 후자는 특정 상황만 겨냥한 좁은 자다. 자리 흔들림 줄은 옛 값이다. v4 에서 파킹으로 되돌렸으므로 지금은 안 돈다 — 위 수치는 켜져 있던 때 잰 것이다. 출처는 docs/rat-pod/background-extractor/01-logic.md.

§7

6-ALSC 조립

이 절이 답하는 질문 — 판정 결과는 어떤 모양으로 하류에 넘어가나? 무엇이 보장되나?
입력 ALSC 쪽 하나의 노드 배열 LAYER 축 — 판정이 정한다 background_alsc foreground_alsc bg + fg == 입력  (완전분할) 누락 0 · 중복 0 · 어긋나면 예외 ROLE 축 — BE 역할표가 그대로 정한다 pageTitle pageDecoration bodyframe bodyframeDecoration 6-ALSC 여섯 통 · 모두 입력 배열 순서(원본 z index) 보존
롤 버킷의 모든 요소는 bg 또는 fg 에도 들어 있다 — 롤 축은 layer 축의 부분집합이다.

세 칸이 어긋나서 toClassifications() 가 있다

review() 가 내는 것과 buildLayeredAlscFromIds 가 받는 것이 곧바로 맞물리지 않는다. 호출부마다 손으로 메우면 서로 다르게 메우므로 한 함수에 모았다.

칸조립 함수Reviewer
단위쪽 하나의 배열템플릿 통째
elementRole롤 버킷 넷을 가른다만들지 않는다
reason객체한 줄 문자열

BE 는 밑줄 꼴(page_title), 조립 함수는 붙임 꼴(pagetitle)을 쓴다. 그 사이도 이 함수가 옮긴다.

고정판 60 장 실측

쪽 601 노드 17,117 예외 0 경고 0 순서 어긋남 0 롤이 layer 밖 0 background_alsc 2,737 foreground_alsc 14,380 ──────── 합계 17,117 = 입력 pageTitle 941 pageDecoration 1,845 bodyframe 329 bodyframeDecoration 267

checkPartition(result, page) 은 조립 함수까지 가서 예외가 나기 전에 어긋남을 잡는다 — 거기까지 가서 터지면 어느 템플릿의 어느 쪽인지 되짚기가 번거롭다.

§8

성능과 코드 지도

검증 기준은 사람이 검수 완료를 누르고 한 군데라도 고친 171 장이다(42,666 노드). 씨앗을 그대로 받은 장은 점수가 거저 나오므로 뺀다.

갈래정밀재현F1맞음놓침헛발
마스터0.9520.8660.9075,258811264

코드 지도

하는 일파일
모듈 진입src/lib/backgroundExtractor/index.ts
판정 엔진src/lib/backgroundExtractor/reviewer/review.ts
규칙 차례의 정본reviewer/core/verdict.ts
무리 짓기 (가장 큰 모듈)reviewer/core/families.ts
무리 표결reviewer/core/aon.ts
띠 · 기둥 · 판reviewer/core/zones.ts
가장자리 아홉 걸음 · 거절 장부reviewer/core/headfoot.ts
제목 자리reviewer/core/titles.ts
쪽번호 계열reviewer/core/numbers.ts
뒤에 서는 규칙reviewer/core/rules.ts · headtop.ts · burst.ts
6-ALSC 조립src/lib/backgroundExtractor/buildLayeredAlscFromIds.ts
어댑터 (엔진 밖)src/lib/backgroundExtractor/buildSlideTemplate.ts
배치 오케스트레이션src/lib/backgroundExtractor/processBackgroundExtractor.ts · src/workers/background-extractor-worker.ts

규칙 하나하나의 상세는 소스 주석에 있다 — 그 자를 정하게 만든 실제 템플릿 번호와 측정값이 함께 적혀 있으므로, 규칙을 고칠 때는 소스를 먼저 읽는 편이 빠르다. 설명 문서는 docs/rat-pod/background-extractor/ 여덟 편이고, 이 페이지의 수치는 그중 00-overview.md · 01-logic.md · 02-schema.md 에서 왔다.