Math.random·Date 사용 금지). 코어는 도메인을 모른다 — 오직 ALT(Abstract Layout Tree)라는 중간 표현만 보고, 어댑터가 SVG·PPTX·HTML·이미지를 ALT로 번역한다.
klic-co-kr/KLIC-Aesthete · 이름 Aesthete v1.0 · 제작 KLIC Co., Ltd(한국) · 런타임 Bun / Node ≥18 · 순수 ESM .mjs 107파일·약 4,100줄 · bun run test 244 pass · 라이선스 Modified MIT + Commons Clause + Media Restrictions(오픈소스 아님, source-available) · shallow clone 소스 직접 분석)
LLM에게 "이 디자인 괜찮아?"라고 물으면, 모델은 결론을 먼저 정하고 이유를 나중에 지어내기(합리화) 쉽다. Aesthete는 이 고리를 끊는다 — 균형·근접·여백·색조를 전부 좌표와 넓이로 계산하므로, 판정에 주관이 끼어들 자리가 없다.
그리고 측정에서 그치지 않는다. 어긋난 요소를 measure → resolve → patch → re-measure의 폐루프로 자동 보정까지 한다. 생성 에이전트의 루프 안에서 레이아웃을 점진적으로 고쳐 나가는 게 목표다.
요즘 "AI가 만든 걸 AI가 평가한다(LLM-as-judge)"가 흔하지만, 여기엔 고질병이 있다: 평가자가 언어 모델이라 편향·아부·합리화에 취약하다는 것. Aesthete가 눈에 띄는 이유는 이 문제를 정면으로, 그것도 결정론적 기하라는 급진적 방법으로 우회하기 때문이다.
균형은 Ngo의 대칭균형 공식, 근접은 게슈탈트 RANG/PDL, 색조는 보색 모멘트 평형으로 수치가 먼저 나온다. 판정은 그 수치를 동결된 루브릭(Sprint Contract)과 순수 비교해 PASS/FAIL을 낼 뿐이다. "결론을 정하고 이유를 붙이는" LLM식 실패가 코드 구조상 불가능하다.
전통적 계산 미학(IAA/IQA)은 완성된 이미지에 사후 점수만 매긴다. Aesthete는 게슈탈트·처리 유창성 같은 인지 원리를 기하로 정형화해, 에이전트가 생성 과정에 개입해 점진 개선하는 재사용 스킬로 만든다. 9개 인지 스킬 각각이 "관찰·측정·인지효과" 3계층으로 짜여 있다.
README·DESIGN이 스스로 한계를 못 박는다: export는 ALT(JSON)만 무손실이고 SVG/PPTX는 손실 재출력, docx/xlsx/image는 export 자체가 없다. 검증 코퍼스의 상관(ρ≈0.33)도 "baseline은 이기지만 인간 미학 선호의 증명은 아니다"라고 선언한다. 과대광고가 흔한 판에서, 이 절제가 오히려 신뢰를 준다.
대중적 인기 레포가 아니라 설계 사상을 공부할 레퍼런스다(별점·포크 적음, 2026-07 시점). 또 라이선스가 Modified MIT + Commons Clause + Media Restrictions라 OSI 의미의 오픈소스가 아니다(source-available). 유료 재판매(SaaS·화이트라벨) 금지, 그리고 소스·UI·파생물로 공개 미디어(유튜브·블로그 방송/리뷰) 제작에 사전 서면 동의가 필요하다 — 공개 공유 전 §7·§11의 라이선스 항목을 반드시 확인.
| 층 | 기술 | 왜 이걸 썼나 |
|---|---|---|
| 런타임 | Bun / Node ≥18 | 테스트·CLI를 bun으로 구동(bun lib/measure.mjs …). Node 호환. |
| 언어 | 순수 ESM JavaScript(.mjs) | lib/에 107개 모듈·약 4,100줄. 타입스크립트·번들러 없이 모듈 자체가 계약. |
| 스키마 검증 | ajv + JSON Schema 2020-12 | ALT·contract·report·decision·slop 등 10종 스키마, additionalProperties:false로 엄격. |
| 픽셀 보조(선택) | playwright-core · cloakbrowser | 이미지 어댑터가 픽셀에서 쿼드트리 기하를 뽑을 때만. 미학 판정 본체는 브라우저 불요. |
| 테스트 | bun:test + zero-dep golden | 스킬·어댑터·fix·slop별 39개 테스트 파일, 244 pass. 결정론이라 골든 스냅샷이 성립. |
| 순수 수학 | geometry·color·quadtree·similarity | 넓이·광도가중·복잡도·쿼드트리 여백 — 전부 0나누기·NaN 가드 포함한 자작 산술. |
Aesthete는 건축 도면 검사기 같다. 완성된 건물 사진(픽셀)을 보고 "느낌"을 말하는 게 아니라, 도면의 치수(좌표·넓이)만 보고 "무게중심이 왼쪽으로 쏠렸다", "기둥 간격이 리듬 없이 다 똑같다"를 자로 재서 지적한다. 자가 재는 값이라 검사관이 바뀌어도 결과가 같고, 뇌물이 통하지 않는다.
전체를 한 문장으로: 대상을 어댑터가 ALT로 번역 → 9개 인지 스킬이 측정해 report → 동결 루브릭(Contract)과 비교해 PASS/FAIL → 어긋나면 폐루프로 자동 보정 → 다시 도메인으로 export. 아래가 그 흐름이다.
각 스킬은 관찰·측정·인지효과 3계층이고, 우선순위 티어가 있다. P0(구조 무결성)는 하드 제약이라 미학보다 먼저다.
| 스킬 | 측정 방식 | 티어 |
|---|---|---|
collision | 쌍별 bbox 겹침 수 | P0 하드 |
boundary | 캔버스 이탈 수 | P0 하드 |
hierarchy | 폰트 스케일 단위성 × WCAG 대비 | P1 |
balance | Ngo 대칭균형 BM | P2 |
proximity | 게슈탈트 RANG + 근접붕괴 PDL | P2 |
whitespace | 점유 쿼드트리 여백률(픽셀 없음) | P2 |
harmony | 보색 모멘트 평형 | P2 |
similarity | 같은 그룹의 크기·명도·색 일관성 | P2 |
fluency | 읽기 흐름(Z/F 패턴) + 크기-중요도 기울기 | P2 |
graph.mjs는 스킬 사이의 세 관계를 선언적 엣지로 둔다: priority(상위 티어가 가독성 선점), conflict(근접↔여백처럼 대립하는 쌍을 캔버스 면적 비례로 연속 감쇠하며 타협), influence(hierarchy가 proximity로 상향 전이). 하드 임계가 아니라 동적 보상 가중치로 충돌을 조정한다.
추상 같지만 lib/skills/balance.mjs의 실제 수식은 이렇다 — 각 요소의 광학 무게 = 넓이 × 광도가중(어두울수록 무겁다) × 도형복잡도, 이를 캔버스 중심 기준 사분면 모멘트로 합산한다.
// 광학 무게 W = 넓이(a) × 광도가중(c) × 도형복잡도(s), 투명도만큼 감쇠
const c = luminanceWeight(luminanceFromStyle(n.style)) * opacity;
const w = a * c * s;
// 좌/우, 상/하 모멘트를 중심거리로 가중해 합산
if (r.nx < cx) WL += r.w * dv; else WR += r.w * dv;
if (r.ny < cy) WT += r.w * dh; else WB += r.w * dh;
// BM = 1 − (|BMv| + |BMh|)/2 → 1에 가까울수록 완벽한 평형
const BM = 1 - (Math.abs(BMv) + Math.abs(BMh)) / 2;
if (BM < 0.85) // → "가장 무거운 요소를 중심으로 옮겨라" 위반 보고
주관이 한 톨도 없다. BM < 0.85면 가장 무거운 노드를 지목하며 "왼쪽으로 쏠림(left-heavy)"까지 수치로 말해 준다.
fix.mjs는 기본적으로 P0(겹침·이탈)만 청소한다. 미학(P1/P2) 이동은 --aesthetic로 켜야 하고, 이때는 Goodhart 위험(점수는 올라도 실제 미학은 나빠질 수 있음)을 명시적으로 경고한다. 루프에는 단조 개선 게이트(나빠지면 롤백)·진동/NaN 방지가 걸려 있고, 못 고치는 것(폰트·색·의미)은 suggestionOnly로 분리해 사람/재생성에 넘긴다.
9스킬이 "얼마나 균형인가"를 연속 점수화한다면, vuln.mjs는 이산 known-bad 패턴(no-focal·no-rhythm·rainbow·even-split·ai-cliche 등)을, slop.mjs는 AI 슬롭 시그니처를 잡는다. 특히 slop은 그 유명한 indigo→violet→pink 그라디언트·이탤릭 헤딩(대표적 AI tell)·마케팅 상투어·가짜 정밀 수치를 HTML 소스에서 스캔한다. 둘 다 맥락 인식(artifact_type)으로 위양성을 억제하고, 게이트가 아닌 advisory다.
lib/가 심장 — 9스킬 + 어댑터 + 엔진 CLI들, 그리고 계약을 거는 schemas/구조가 말하는 것: 계약과 수학이 코드 곳곳에 못 박혀 있다. schemas/가 입출력을 엄격히 잠그고, DESIGN.md가 "미학 법칙·측정 규칙·도메인 한계"를 사람과 에이전트 모두 파싱할 수 있는 계약서로 둔다. skill-pre/post/gate가 에이전트용 권장 진입점이고, 나머지 엔진 CLI는 그 아래에서 각 측면을 담당한다.
평가를 언어 모델이 아니라 결정론 수식에 맡기면, 편향·아부·사후 합리화가 코드 구조상 발생할 수 없다. 자동 평가 파이프라인을 짤 때 "판정 근거를 재현 가능한 수치로 고정"하는 사고틀은 미학 밖에서도 값지다.
게슈탈트 근접·Ngo 균형·보색 조화 같은 말랑한 이론을 좌표·넓이 산술로 옮기는 법. balance.mjs의 광학 무게·사분면 모멘트가 산 예시다. "감각적 개념을 측정 가능하게 조작화"하는 연습.
SVG·PPTX·HTML을 각각 다루지 않고 중간 표현(ALT)으로 모으면, 새 도메인은 "어댑터 한 쌍"만 추가하면 된다(코어 무수정). 컴파일러·데이터 파이프라인에서 쓰는 IR 패턴을 디자인에 적용한 사례.
measure→fix→re-measure를 돌리되 나빠지면 롤백(단조 개선)·진동/NaN 방지를 거는 법. 자동 최적화 루프가 지표만 좇다 망가지는(Goodhart) 걸 어떻게 방어하는지 배운다.
lint.mjs는 승인된 색·폰트 밖의 임의 핵사코드·비표준 폰트를 정적 분석으로 잡아 CI에서 exit 1. 미학 계약과 독립된 게이트다. "규칙을 문서가 아니라 CI로 강제"하는 설계.
coverage를 measured/partial/unmeasurable로 3분할해 점수를 부풀리지 않고, 검증 상관 ρ≈0.33을 "증명이 아니라 약~중간 신호"라고 못 박는다. 자기 결과를 과대주장하지 않는 태도 자체가 배울 점이다.
bun lib/measure.mjs examples/catalog-bad.layout.json을 돌려 report.json을 열고, balance의 BM 값과 위반 메시지를 확인하라. 그다음 catalog-good과 비교하면, "수식이 실제로 무엇을 보는지"가 한눈에 들어온다.
| 항목 | 내용 |
|---|---|
| 런타임 | Bun 권장 / Node ≥18. bun install → bun run test(244 pass). |
| 의존성 | ajv(스키마) · playwright-core · cloakbrowser(이미지 어댑터 픽셀 보조). |
| 진입점 | 에이전트: skill-pre → 생성 → skill-post → decision. 엔진 직접: measure/fix/lint/…. |
| 플랫폼 | 순수 JS·브라우저 없음. 픽셀 필요 부분(이미지 영역·local-variance)은 한계 명시. |
| 라이선스 | Modified MIT + Commons Clause + Media Restrictions — 아래 주의 참조. |
| 상태 | v1.0(private 패키지). 대중 배포보다 설계 참조·에이전트 스킬 목적. |
① Commons Clause: Software를 유료로 제3자에게 제공(SaaS·호스팅·화이트라벨 포함)하는 판매가 금지된다. ② Media Restriction: 저작권자의 사전 서면 동의 없이 소스·UI·파생물로 공개 미디어 콘텐츠(유튜브·트위치·블로그의 방송·데모·리뷰·분석)를 만드는 것이 제한된다(특히 상업/자기홍보 목적). ③ 위반 시 권리가 즉시 종료된다. 이 딥다이브는 개인 학습용 정리이며, 공개 배포·미디어 제작 전에는 원 저작권자(KLIC Co., Ltd) 동의를 확인하는 것이 안전하다. © 2026 KLIC Co., Ltd.
bun lib/measure.mjs examples/catalog-bad.layout.json과 catalog-good을 각각 돌려 report의 스킬별 score·violations를 표로 정리하라. 목표: 9스킬이 실제로 무엇을 수치화하는지 감 잡기.
노드 3~4개짜리 ALT를 종이에 그리고, W = 넓이×광도가중×복잡도와 사분면 모멘트로 BM을 손계산한 뒤 balance.mjs 출력과 대조하라. 목표: "미학을 수식으로 조작화"를 몸으로 이해.
slop.mjs의 4축(palette·decoration·copy·template)을 읽고, 당신이 싫어하는 AI tell(예: 특정 상투어) 하나를 임계값 override 가능한 시그니처로 추가하라. 목표: 존재-스캔식 휴리스틱 탐지의 구조 체득.
아주 단순한 새 포맷(예: 좌표가 든 CSV)을 import(→ALT)하는 어댑터를 짜서 measure에 물려라. 목표: "코어 무수정, 어댑터만 추가"라는 도메인 불가지론을 직접 실현.
bun lib/fix.mjs examples/catalog-fixable.layout.json --contract examples/catalog.contract.json을 돌리고 fix-log.json에서 각 반복의 점수 변화·단조 게이트·skippedFixes를 따라가라. 목표: 안전한 자동 수선 루프가 어떻게 도는지 관찰.
| 주차 | 주제 | 무엇을 · 왜 |
|---|---|---|
| 1주차 | 인지 미학 이론 | 게슈탈트 법칙, Ngo 대칭균형, 처리 유창성(Reber), 보색 조화, Birkhoff M=O/C. 스킬들이 "왜 그 수식인지"의 동기를 잡는다. |
| 2주차 | 계산 기하 & 색 | bbox·넓이·광도(WCAG 대비)·쿼드트리 여백·복잡도. NaN/0나누기 가드. geometry·color·quadtree.mjs를 읽으며 과제 2 수행. |
| 3주차 | IR & 어댑터 설계 | 중간 표현으로 도메인을 통일하는 컴파일러식 사고, import/export의 비대칭(무손실 vs 손실). 과제 4로 어댑터 제작. |
| 4주차 | 결정론 시스템 & CI 게이트 | 재현성(난수·시각 금지), 골든 테스트, 단조 최적화, Goodhart 방어, 토큰 샌드박스 정적분석. 과제 5로 폐루프 관찰. |
| 5주차 | 평가·검증 방법론 | 휴리스틱 vs data-driven 미학, Spearman/Pearson 상관, Bradley-Terry 쌍체 비교, 순환성·smallSample 함정. "검증됐다"의 문턱을 배운다. |