북스 책장넘기기(flip) 재구축 + 모바일/태블릿/PC 최적화
개요
book.crowny.org 리더의 책장넘기기(flip) 모드가 컬럼 피치와 스크롤량 불일치로 페이지 경계서 글자가 잘리던 문제를 결정론적 transform 페이지 모델로 재구축하고, 모바일/태블릿/PC 각각 최적화. 울트라 병렬(독립 2구현 → 적대 판정)로 구현,
Chrome 헤드리스로 디바이스 매트릭스 실측 검증.
무엇을 했는지
1. 결정론적 페이지 모델 (정렬 보장)
- 컬럼/페이지: 모바일(<768px) 1열 / 태블릿·PC(≥768px) 2열 스프레드. PC(≥1024)는 스테이지폭 1100px 캡 센터링.
innerW=가용내부폭, gap=거터, cw=(innerW−(cols−1)·gap)/cols, pageWidth=innerW+gap (1·2열 공통).
.art를 .flip-track로 감싸 transform: translateX(−page·pageWidth) (네이티브 스크롤 드리프트 제거, 픽셀정확).
.art 폭을 innerW로 핀 + column-count만(column-width 제거) + .art.scrollWidth 단일 측정으로 totalPages 산출.
- 헤더(crumbs/kch/h1)는
.flip-header absolute 분리(column-span 대체), 스크롤 모드는 display:contents로 래퍼 투명화(무회귀).
2. 디바이스 최적화
- 모바일: 1쪽, 좌/우 1/3 탭존 + 스와이프(40px 임계), 100dvh−컨트롤 페이지높이, safe-area 인셋.
- 태블릿: 2쪽 스프레드, 스와이프+버튼.
- PC: 2쪽 스프레드, 스테이지 1100px 캡 센터링, hover 사이드버튼, 키보드(←→/Space/PageUp·Down).
- 공통: 페이지표시기 "n/total", resize/회전/글자크기(A±) 시 비율보존 relayout, 다크모드·--fz 유지.
3. 울트라 병렬 (독립 2구현 → 적대 판정)
- Sonnet 2명이 독립 구현 → Opus 판정자가 실제 Chrome 헤드리스로 양쪽 실측 → A(래퍼 scrollWidth 클리핑 90% 소실)·B(width-override 2-pass 5배 폭발) 양쪽 치명버그 발견 → 교정 합성(구조=A 정적, 측정/이동=B transform − width-override + innerW핀 + scrollWidth 단일측정).
검증 (Chrome 헤드리스 디바이스 매트릭스 — 실측)
?fliptest=1 자가검증: 페이지경계=컬럼경계 정렬 + total·pw≥scrollWidth + 가로오버플로 없음을 DOM에 PASS/FAIL 출력.
- 12/12 PASS: {crownyai/expert/1, book3/kid/2, ilovecrowny/om/3, crownyai/general/5} × {모바일390, 태블릿820, PC1440}.
- 페이지수 예: crownyai/expert/1 → 모바일 36p(1열), PC 14p(2열 스프레드). 둘 다 오버스크롤 0.
- 스크롤모드 무회귀, 게이트웨이 443 + ?shared=1 200.
동반 버그 2건 수정 (검증 중 발견)
- 빌드 인라인 JS escape: 소셜 세션
fbHtml이 build-reader.js의 JS 백틱템플릿 안에서 \'(단일)을 써서 출력 시 '로 깨짐 → 챕터 인라인 스크립트 전체 SyntaxError → 소셜 좋아요/추천/게이트 UI가 브라우저서 작동 안 했음(API는 curl로 통과해 잠복). \\'로 수정. flip의 \n→\\n도 동일.
- 정적 쿼리스트링 404:
정적경로()가 쿼리 미제거 → ?shared=1·?ref=·?fliptest=1 정적파일 404(공유링크 깨짐). 쿼리제거() 선적용으로 수정.
관련 파일
- 리더 빌더:
웹/build-reader.js — flip CSS(.flip-header/.flip-stage/.flip-track + display:contents 무회귀), flip JS IIFE(relayout/goPage/flipPage/setMode/스와이프·탭존·키보드/페이지표시기/?fliptest 자가검증), fbHtml escape 수정.
- 서버:
책서버.한선 — 정적경로() 쿼리제거.
- 배포:
bookagent.toau(워치독 respawn), 3책 재빌드.
- 검증 하니스:
/tmp/flip검증.sh (Chrome 헤드리스 --dump-dom, 3뷰포트).
- 백업: build-reader.js.bak.flip_20260614, 책서버.한선.bak.social_20260613.
함정/교훈 (영속화)
- build-reader.js 인라인 JS는 백틱템플릿 →
\\'·\\n 필수. 검증=출력HTML 인라인스크립트 추출 후 node -c(빌드 스크립트 node -c로는 못 잡음) + 헤드리스 dump로 body class·결과div 확인. (메모리 feedback_buildreader_inline_js_escape)
- 정적 서버 정적경로()는 쿼리제거 선적용.
- 시각 검증 불가 메커닉은 독립 2구현+적대판정(헤드리스 실측)으로 신뢰 확보 — 판정자가 코드만으론 안 보이는 측정버그를 실측으로 적발.
잔여 이슈
- 스와이프/탭존/키보드는 헤드리스 레이아웃 검증엔 안 잡힘 → 실기기 수동 확인 권장(드롭캡 단독잔류·iOS 주소창 dvh 미세변동은 기능무해).
- 크라우니브라우저(WebKit) display:contents 교차확인 권장.