| name | eduitit-mathmon-lesson |
| description | Use when building, planning, auditing, fixing UI overlap/overflow or weak visual hierarchy, or extending an Eduitit 매스몬 math game 차시(lesson) single-HTML package in the `ai mart` workspace, including focal learning-area sizing, information-density space allocation, peer-lesson benchmark review, browser-size regression QA, and reward/effect animation polish — triggers like 차시 만들어, 새 게임 만들어, N단원 N차시 제작, 게임 빌드, UI 겹침 고쳐, 글자 넘쳐, 핵심 상자 키워, 시각적 우선순위 봐줘, 정보량에 비해 작아, 기존 차시와 비교해, 매스몬 게임 추가, 효과 넣어. |
Eduitit 매스몬 차시 빌더
/Users/yubyeongju/ai mart 작업실에서 매스몬 수학 게임 한 차시를 단일 실행 HTML 패키지로 만들거나 확장할 때 따르는 절차다. 이 스킬은 "어떻게 만드는가(공정)"를 담는다. "왜·무엇을(정체성·철학·로드맵)"은 작업실의 AGENTS.md와 CLAUDE.md가 같은 내용으로 공유하는 루트 하네스 문서가 단일 기준이다.
이 스킬을 쓰는 때
- 새 차시(
3-2-<단원>-<차시>-<영문짧은이름>) 게임을 만든다.
- 기존 차시의 화면·문제·보상을 크게 바꾼다.
- 기존 차시의 효과, 보상 연출, 결과 측정감을 강화한다.
- 기존 차시와 비교해 학습 조작·진행감·보상·결과·검증에서 빠진 부분을 감사한다.
- 차시 상세 계획(
PLAN.md)을 세운다.
- 트리거:
차시 만들어, 새 게임 만들어, N단원 N차시 제작, 게임 빌드, 기존 차시와 비교해, 부족한 부분 체크해, 매스몬 게임 추가, 효과 넣어.
teacher-facing SaaS·관리자 화면에는 적용하지 않는다(그건 eduitit-service-polish). 배포/푸시는 eduitit-main-release를 함께 쓴다.
시작할 때 선언
- 적용 스킬:
eduitit-mathmon-lesson.
- 대상 차시: 학년-학기-단원-차시, 게임명(매스몬으로 시작), 배움주제, 성취기준.
- 복제 기준 파일(보통
3-2-1-2-mathmon-rocket-charge/index.html = 최신 엔진).
- 건드리지 않을 범위(다른 차시·단원, 학생 화면 외 서비스).
절대 규칙 (루트 하네스 문서 「핵심 설계 철학」 강제)
매 차시는 아래를 모두 만족해야 한다. 하나라도 "아니오"면 설계를 고친다.
- 계산 = 행동의 도구: 문제 → 보상 → 결과. 계산은 예측 가능, 보상은 예측 불가능.
- 무작위성 유지: 랜덤 보상은 빼지 않는다(기대감+긴장감 동반).
- 정답 ≠ 전부: 최고 등급은 얻기 어렵게. 정답은 유리하되 유일한 통로 아님. 빈손 금지 + 운으로 도약 가능.
- "다음엔 더 멀리": 차시 자체 완결형 등급 결과로 재도전 동기를 만든다(도감 없음 — 모아두는 백엔드 만들지 않음).
- 학생 화면에
AI Mart 등 내부 용어 노출 금지. 게임 제목은 매스몬으로 시작.
- 한 화면 한 행동: 초3 학생이 3초 안에 지금 할 일 하나를 말할 수 있어야 한다. 문제 화면에서 동시에 요구하는 행동은 하나만 두고, 기본 화면은 큰 문제·현재 단계 조작판·한 줄 지시문·선택지만 남긴다.
- 단계 정답 확인 필수: 정답 선택 뒤 다음 단계나 보상 모달로 바로 넘기지 않는다. 현재 계산판·칸·블록이 정답값으로 바뀌고, 짧은 확인 문구가 보인 뒤 넘어간다. 마지막 단계는 보상 모달 전에 완성식이나 완성값을 먼저 보여 주고, 가능하면 학생이 확인 버튼을 눌러 보상으로 넘어가게 한다.
- 현재 보상과 다음 목표 연결: 숫자 변화만 보여 주지 말고 현재 보상과 다음 목표를 연결한다. 보상 화면에서 이번에 얻은 장소·물건·단계를 보여 주고, 결과 화면에서 다음에 노릴 목표를 이어 보여 준다.
- 학생 사고 필수: 한 화면 한 행동을 반복 클릭으로 축소하지 않는다. 학생이 수·위치·관계·순서·분해 방법 중 하나를 판단해 답을 직접 만들게 한다. 시스템이 정답을 자동 분배하고 학생은 끝날 때까지 누르기만 하면 실패다. 숫자를 보지 않아도 완료할 수 있는지 검사하고, 가능하면 다시 설계한다.
- 교과서식 표현·찰나 상태 필수: 계산 순서와 자리 배치는 교과서 풀이와 맞아야 한다. 자리 숫자와 실제 값을 구별하고, 오답·정답 확인·전환 상태를 각각 실제 화면으로 검사한다. 브랜드·단원 배지, 글씨 크기, 기호와 숫자 간격, 겹침 0건은 다른 장점으로 상쇄할 수 없다.
- 판단 밀도·조작 예산 필수: 수학적 판단 횟수와 물리 입력 횟수를 따로 센다. 학생이 답을 이미 결정한 뒤 같은 뜻의 물건 놓기를 세 번 이상 되풀이한다면, 새 판단이 생기는 이유를 증명하지 못하는 한 실패다. 학생이 답을 먼저 확정하고 시스템은 그 답에 따른 반복 배치를 확인 애니메이션으로 보여 준다. 학생의 답 없이 시스템이 정답을 만드는 자동 풀이는 여전히 금지한다.
- 겹침 회귀 차단 필수: 사용자가 겹침·넘침·잘림을 발견한 화면은 즉시 실패 증거로 등록한다. 그때의 실제
innerWidth×innerHeight, DPR, Stage 실제 렌더 크기와 상태를 기록하고 lesson.json > qa.viewports 및 전용 QA에 이름 있는 영구 회귀 항목으로 추가한다. 비슷한 크기나 기본 두 화면만 다시 보고 끝내지 않는다.
- 버튼 존재 이유·학습 기여 필수: 학생 풀이 흐름의 모든 선택지·확인·마지막 버튼은
누르기 전 아직 결정되지 않은 것, 누르며 하는 수학적 판단, 누른 뒤 새로 보이는 관계나 결과를 설명할 수 있어야 한다. 이미 화면과 앞 단계가 답을 하나로 결정했다면 그 값을 다시 고르게 하지 말고 자동 완성·확인 연출로 보여 준다. 시작·설정·닫기 같은 전역 이동 버튼은 수학 판단 대상에서 제외하지만, 눌렀을 때의 상태 변화는 분명해야 한다.
- 학습 주인공 면적 필수: 문제 화면의 1·2·3순위 요소를 먼저 선언하고, 1순위 학습 대상이 콘텐츠 레이어에서 가장 큰 면적·글자·대비를 가져야 한다. 장식 배경이나 보조 패널 때문에 핵심 계산판·조작판·선택지가 좁은 열에 갇히면 실패다. 서로 연결된 식·표현이 둘 이상 들어간 핵심 패널은 실제 Stage 폭의
65% 미만이면 재설계하고, 예외가 필요하면 대안 캡처와 이유를 PLAN.md/REPORT.md에 남긴다.
- 상태 전환 중심축 필수: 문제 대기·정답 확인·마지막 완료 사이에서 핵심 계산판이 다른 열로 이동하거나 폭이 줄면 실패다. 완료식과 다음 행동 상자는 핵심 계산판과 같은 중앙 축·작업 영역 폭을 유지하고, 실제 rect 좌우 경계와 중심 차이를
1px 이하로 자동 검사한다.
겹침 0건 완료 게이트
- 자동 검사는 텍스트와 버튼만 보지 않는다. SVG/Canvas 계산판의 실제 바깥 표면, 문제 카드, 지시문, 피드백, 선택지/숫자판, 모달, 투명 hitbox의
getBoundingClientRect()를 함께 재고 형제 영역 교차가 0px인지 확인한다.
- SVG는 바깥 배경 도형의 실제 rect와 모든
<text>의 getBBox()/렌더 rect를 검사한다. SVG 요소 자체의 상자만 맞고 내부 그림이 지시문 위로 넘으면 실패다.
- 계산판→지시문→선택지처럼 세로로 잇는 영역은 명시적인 grid track과
overflow: hidden/contain 경계를 두고, 각 경계에 눈에 보이는 간격을 확보한다. z-index로 겹친 부분을 가리는 방식은 수정으로 인정하지 않는다.
- 문제 대기, 대표 오답 양방향, 각 단계 정답 확인, 다음 단계 대기, 마지막 확인, 닫힌/열린 보상, 결과, 설정 모달을 각각 독립 상태로 검사한다. 한 상태라도 캡처·수치 검사가 빠지면 완료가 아니다.
- 사용자가 올린 실패 화면은 고친 뒤 같은 화면 크기와 같은 상태로 다시 캡처한다. 재현할 수 없거나 실제 브라우저 크기를 확인하지 못했으면 PASS로 기록하지 않는다.
- 지원 범위 밖처럼 좁은 창에서도 Stage는 16:10 contain으로 축소되어야 한다. 공간 부족을 이유로 패널을 겹치게 재배치하지 않는다.
REPORT.md에는 실패 증거 크기, 수정 전 충돌 대상, 수정 후 최소 간격, 회귀 테스트 이름과 캡처 경로를 남긴다.
빌드 파이프라인
- 계획: 해당 차시 폴더에
PLAN.md를 먼저 쓴다 → references/plan-template.md.
- 폴더:
_templates/lesson-package를 3-2-<단원>-<차시>-<영문짧은이름>으로 복사.
- 자산:
_shared/에서 eduitit-logo-mark.png와 필요한 배포용 자산만 복사. 매스몬은 반드시 eduitit-mathmon-assets 스킬과 _shared/mathmon/MATHMON_ASSET_CONTRACT.md를 먼저 적용하고, 새 매스몬은 _shared/mathmon/<pack-id>/에 원본 등록 후 차시 폴더에는 WebP 배포본만 복사한다(10종 전부 복사 불필요 — 도감 없음). 첫 화면 커버용으로 기존 매스몬 WebP를 따로 얹지 말고, 매스몬이 필요하면 cover-generated.webp 생성 프롬프트에 포함한다.
- 엔진 복제: 최신 기준 차시(
3-2-1-2-...)의 index.html을 복제해 개조. 재사용 함수 맵 → references/engine-and-images.md.
- 개조 3종만: ① 문제 생성기 ② 보상/등급 라벨 ③ 테마 이미지. 점수·콤보·단계선택·등급 뼈대는 그대로.
- 효과 설계: 단계 정답, 보상 이동, 중심 오브젝트 변화, 랜덤 이벤트 충격, 결과 측정에 효과를 배치한다 →
references/effect-design.md.
- 이미지: 필요한 RasterStage 이미지를 생성하고 WebP로 배포 변환 →
references/engine-and-images.md.
- Humanizer 학생 문구 QA: 학생에게 보이는 문구를 모두 뽑아
humanizer 스킬(/Users/yubyeongju/.agents/skills/humanizer/SKILL.md) 기준으로 AI 문체·번역투·어려운 한자어를 걷어낸다. 초3 학생이 소리 내어 읽어도 바로 이해되는 행동어로 바꾸고, 바뀐 문구가 화면에 맞는지 브라우저 캡처로 확인한다.
- 기준 차시 비교:
references/verification.md의 기준 차시 비교 항목에 따라 강점별 비교군을 고르고, 수학적 판단 수와 정답 경로의 최소·중앙값·평균·최대 물리 입력 수를 따로 계산한다. 현재 실행본의 오답·각 단계 정답 확인·전환 상태까지 실제 화면과 코드 증거로 BENCHMARK_AUDIT.md를 작성한다. 자동 검사 통과나 오래된 스크린샷만으로 완료 판정하지 않는다.
- 문서:
README.md, REPORT.md 작성, screenshots/에 첫·설명·문제·보상·결과 화면 저장. 현재 흐름과 다른 예전 증거는 _archive/로 옮긴다.
- 등록:
manifest.json에 차시 추가, 루트 README.md 시리즈 표에 행 추가.
- 화면 계약 대조:
SERIES_CONTRACT.md와 한 줄씩 대조(첫 화면 3요소·배지 위치·중심 보상 1개·문제 화면 과밀 금지).
- 한 화면 한 행동 3초 검사: 문제 화면 스크린샷에서 학생이 볼 기본 요소가 큰 문제·현재 단계·한 줄 지시·선택지뿐인지 확인한다. 풀이판 해석, 탭 선택, 힌트 읽기, 보상 확인, 선택지 고르기를 한 화면에서 동시에 하게 만들면 즉시 줄인다.
- 학습 주인공 면적 검사: 1·2·3순위 요소와 각 실제 rect, Stage 대비 폭·면적 비율, 정보 묶음 수를 기록한다. 흐림/눈가늘임 상태와 3초 보기에서 1순위 학습 대상이 먼저 보이지 않으면 장식·중첩 패널을 줄이고 핵심 영역을 키운다.
- Stage 비율 검사: 모든
index.html이 16:10/1280×800 계약을 지키는지 루트에서 node scripts/check-stage-ratio.mjs 실행.
- 상태 이미지 세트 QA: 한 슬롯에서 바뀌는 생성 이미지 세트가 있으면 개수 계약, 치수, 컨택시트, 브라우저 렌더 크기, 데스크톱/태블릿 캡처를 확인한다. 한 장이라도 필수 슬롯 수가 빠지거나 잘리면 세트 전체 실패다.
- 겹침 회귀 검사:
references/verification.md의 표면 경계·상태별 충돌 검사를 실행하고, 사용자가 발견한 모든 화면 크기가 qa.viewports에 남아 있는지 확인한다.
- 검증·배포:
references/verification.md 통과 → 배포는 eduitit-main-release + GitHub Pages, 공개 URL curl -I -L 200 확인.
화면 골격 (모든 차시 동일)
첫 화면 → 설명 → 문제 풀이 → 보상 → 결과
세부 규칙은 SERIES_CONTRACT.md가 단일 기준. 첫 화면 3요소(제목·한 줄 목표·시작 버튼), 브랜드/단원/배움주제 배지 위치, 중심 보상 1개, 결과=차시 자체 완결형 등급은 고정.
설명 화면 이해 계약
설명 화면은 예쁜 포스터가 아니라 학생이 게임을 시작하기 전 꼭 알아야 할 약속이다. 새 차시를 만들거나 기존 설명 화면을 크게 바꿀 때는 아래 네 가지가 화면 안에서 바로 보여야 한다.
- 풀이 방법: 이번 차시 문제를 어떻게 풀지 한눈에 보여 준다. 단계는 2~3개로 제한하고, 예시는 실제 차시 문제와 같은 구조를 쓴다.
- 문제 수: 한 판에 몇 문제를 푸는지 보여 준다. 현재 표준은
10문제이며, 다르면 차시 문서와 화면에 같은 숫자로 맞춘다.
- 보상 연결: 정답을 맞히면 무엇을 얻는지 보여 준다. 정답은 보상 기회를 늘리지만 최고 결과를 보장한다고 말하지 않는다. 랜덤 보상 때문에 좋아질 수도, 조금 아쉬울 수도 있음을 학생 말로 짧게 보여 준다.
- 최종 목표: 마지막에 무엇을 확인하는지 보여 준다. 예: 상자 점수와 매스몬, 로켓 도착 행성, 도착 섬, 완성한 로봇.
설명 화면은 반드시 두 장으로 간다. 한 장 안에 풀이법과 보상/최종 목표를 모두 넣는 방식은 실패다. 이미지가 예뻐도 학생이 어떻게 풀지?와 왜 풀지?를 나눠 이해하지 못하면 다시 만든다.
설명 1: 어떻게 풀어요? → 풀이 단계와 예시
설명 2: 무엇을 얻어요? → 10문제, 보상, 차시 안의 최종 결과
설명 이미지 프롬프트를 만들 때도 같은 계약을 따른다. 생성 이미지가 학생에게 보이는 문구를 직접 담는다면 exact Korean text와 no extra text를 명시하고, 생성 뒤 한글 철자를 캡처로 검수한다. 철자가 틀리거나 문구가 너무 많으면 같은 슬롯에서 재생성한다. HTML/CSS로 새 포스터를 로컬 합성해 때우지 않는다.
설명 화면 아래 행동 버튼은 크기를 고정한다. 1280×800 Stage 기준 보이는 버튼 표면은 가로 400-460px, 세로 110-145px를 기본으로 하고, 중앙 x좌표 640, y좌표 665-735 안전영역 안에 둔다. 버튼 라벨은 문제 시작, 연료 넣기, 점프 시작, 합체 시작, 다음처럼 1~4단어로 짧게 쓴다. 실제 클릭은 같은 좌표의 HTML button 또는 hitbox가 맡고, 버튼 표면이 이미지 안에 있으면 HTML은 새 보이는 텍스트를 추가하지 않는다.
설명 화면 문구는 Humanizer 학생 문구 QA 대상이다. 보상 구조, 최종 목표, 랭킹 시스템, 랜덤 이벤트 같은 제작자 말은 쓰지 말고, 상자 점수, 연료, 바람, 합체 에너지, 마지막에 도착한 곳 보기처럼 화면 안 물건과 행동으로 말한다.
로컬 합성 금지
- 생성형 이미지처럼 보여야 하는 화면·타이틀·보상·결과 자산을 로컬 폰트, Pillow, canvas, SVG, CSS 캡처, 기존 PNG/WebP 겹치기 같은 로컬 합성으로 만들지 않는다.
- 첫 화면 커버에서 기존 매스몬 PNG/WebP를
.cover-mathmon 같은 별도 <img>로 배경 위에 붙이지 않는다. 매스몬이 첫 화면에 필요하면 cover-generated.webp를 만들 때 배경·소품·조명과 함께 한 장면으로 생성한다.
- 로컬 합성은 사용자가 먼저 명시적으로 허락한 경우에만 예외로 쓴다. 허락 없이 "최종 화면에서는 한 장 이미지처럼 보인다"는 이유로 로컬 합성 산출물을 생성형 이미지 자산처럼 연결하면 실패다.
- 문제 화면 상단에 목표 지도, 진행 지도, 보상 도달 경로처럼 학생의
다음엔 더 멀리 기대감을 만드는 큰 시각 장치를 둘 때는 3차시 play-map-strip-generated.webp 방식을 기준으로 삼는다. CSS 도형, SVG, 회색 실루엣, 로컬에서 그린 아이콘 반복으로 목표 세계를 때우면 실패다. 배경/섬/로봇/장소/최종 목표 실루엣은 image_gen/GPT Image 등 생성형 bitmap 자산으로 만들고, HTML은 현재 위치 마커, 짧은 라벨, 접근성 hitbox처럼 동적으로 바뀌는 최소 오버레이만 맡긴다.
- 상단 목표 지도 자산은 원본
*-source.png와 학생용 *-generated.webp를 함께 보관한다. 예: 3차시 play-map-strip-source.png + play-map-strip-generated.webp, 4차시 로봇 목표판 play-robot-goal-strip-source.png + play-robot-goal-strip-generated.webp. 크롭, 리사이즈, WebP 변환처럼 생성 원본의 의미를 바꾸지 않는 후처리는 허용하지만, 새 캐릭터·목표물·패널·문구를 로컬에서 그려 붙이면 로컬 합성으로 본다.
- 특히 결과 화면처럼 고정 문구·버튼·캐릭터·배경을 한 장으로 보여 달라는 요청은 image_gen/GPT Image 등 생성형 이미지 도구로 한 장면을 생성하는 것이 기본이다. 섬 이름, 도착 라벨, 칭찬 문구, 다시하기 버튼처럼 매 판 똑같은 요소는 생성 이미지 안에 포함한다. 매 판 달라지는 값이라도 경우의 수가 고정된 정답 수
0/10~10/10은 공용 생성형 이미지 세트 _shared/result-count/result-correct-*-generated.webp를 우선 사용하고, CSS/SVG/HTML 폰트로 크게 그리지 않는다. 점수·연료·힘처럼 값 범위가 넓은 숫자만 최소 HTML/SVG 오버레이로 남긴다.
- 결과 화면의 큰 결과명은 3차시
무지개섬 도착!처럼 생성 이미지 안의 타이포그래픽 타이틀 아트가 기준이다. 천왕성 도착, 초거대 로봇!, 사자몬 같은 유한한 결과 라벨을 HTML/SVG/CSS 폰트로 크게 그리면 실패다. 결과 라벨이 여러 단계라면 단계별 result-*-generated.webp 전체 장면을 만들거나, 독립 생성형 타이틀 자산을 만들어 얹고, JS는 이미지 src와 숨김 접근성 텍스트만 바꾼다.
- 모든 결과 화면에서 정답 수를 보여 줄 때는
<img class="result-correct-art" src="../_shared/result-count/result-correct-N-generated.webp" alt="" aria-hidden="true"> 패턴을 쓴다. 실제 접근성 값은 기존 결과 요약이나 숨김 텍스트에만 둔다. JS는 correctCount를 0..10 범위로 clamp한 뒤 이미지 src만 바꾸고, 보이는 0/10 텍스트 노드나 SVG <text>를 남기지 않는다. 기존 호환을 위해 내부 계산용 텍스트가 필요하면 opacity="0" aria-hidden="true" 또는 visually-hidden으로만 둔다.
- 결과 배경에 빈 카드 슬롯, 빈 패널, 버튼 자리, 점수칸처럼 CSS/HTML 텍스트를 맞춰 넣기 위한 구조가 이미 박혀 있으면 그 배경은 리마스터 기준으로 재사용하지 않는다. 1차시처럼 기존 배경이 결과 카드와 다운로드 카드 자리를 전제로 만들어졌다면, 새 기준에서는 배경부터 다시 생성해 보상 장면과 큰 결과 타이틀이 한 장면 안에서 자연스럽게 보이게 한다.
- 결과 화면에서 생성 이미지 위에 큰 반투명 CSS 카드,
backdrop-filter blur 패널, CSS 제목/본문, CSS로 그린 큰 버튼을 얹어 결과 라벨을 처리하면 로컬 합성 우회로 보고 실패 처리한다.
- 결과 라벨이 4단계처럼 유한하게 바뀌면 단계별 결과 이미지 또는 독립 생성형 타이틀/버튼 자산을 만들고, JS는 이미지
src만 바꾼다. resultTitle, resultSummary, resultNext 같은 HTML 텍스트는 visually-hidden 접근성 값이나 점수·연료·힘처럼 매 판 계산되고 범위가 넓은 최소 정보에만 쓴다.
- 사용자가 "이미지에는 글자를 넣지 말라"는 이미지 계획을 줬더라도 고정 결과 라벨·칭찬·버튼을 CSS 카드로 대체하지 않는다. 생성 이미지 안의 글자 금지와 CSS 결과 카드 금지가 충돌하면 구현 전에 계획을 바로잡는다.
- 생성형 결과 라벨/버튼 자산 표준을 쓰는 차시는
<main class="game">에 data-result-visual-standard="generated-assets"를 선언한다. 이 표식이 있으면 공통 하네스가 .result-card 같은 CSS 결과 카드, 보이는 resultTitle 텍스트, 생성형 버튼 아트 누락을 실패로 본다.
- 결과 화면을 통째 이미지로 요구받거나
result-final-*-generated.webp가 도착 상태별 완성 장면이면 <main class="game">에 data-result-render-mode="fullscene-score-slot"도 선언한다. 이 모드에서 보이는 HTML은 공용 정답 수 이미지 아트(.result-correct-art)와 투명 다시하기 hitbox뿐이며, #finalCorrectText는 숨김 접근성 값으로만 둔다.
fullscene-score-slot의 정답 수 이미지는 이미지 안 빈 점수칸에 맞춘 RasterStage 슬롯으로 배치한다. 생성 이미지마다 빈칸 위치가 다르면 data-result-island 같은 상태별 슬롯을 명시한다. 중앙 정렬은 CSS 좌표값만 확인하면 실패다. 1280×800과 1024×768 스크린샷 픽셀에서 정답 수 이미지 중심과 이미지 속 빈 점수칸 중심을 비교해 확인한다.
fullscene-score-slot 모드에서 .result-stats, .result-stat, .result-card, .result-copy, 보이는 CSS 제목/본문/버튼 장식이 있으면 실패다. 점수 박스 라벨도 이미지와 HTML 양쪽에서 보이지 않게 한다.
- 결과 화면의 버튼을 이미지 안에 그린 경우에도 실제 클릭과 접근성을 위한 HTML 버튼 또는 hitbox는 같은 위치에 둔다. 단, 이 hitbox가 새 시각 요소를 로컬에서 그려 붙이는 방식이 되면 로컬 합성으로 본다.
- 혼합형 ResultStage: 결과 화면에 멋진 보상 장면과 정확한 동적 정보가 함께 필요하면
data-result-render-mode="hybrid-generated-dynamic"을 쓴다. 생성 이미지는 로봇·섬·행성·무대·빛·감정, 큰 결과명, 고정 버튼 장식을 맡고, SVG viewBox="0 0 1280 800" 오버레이는 점수·연료량·힘처럼 매 판 실제 값 범위가 넓은 짧은 동적 UI만 맡는다. 정답 수는 값이 11개로 고정되어 있으므로 공용 result-correct-*-generated.webp 이미지 아트를 우선 사용한다. 혼합형이어도 도착한 곳, 이번 합체 같은 작은 라벨은 보조 수준이어야 하며, 화면의 주인공인 결과명은 생성형 타이틀/장면이어야 한다.
- 혼합형 결과 화면의 생성 프롬프트에는
no text, no letters, no numbers, no score board, no stats cards, no table, no buttons, no UI panels를 기본으로 넣는다. 이미지 안에 남겨도 되는 것은 세계 안의 자연스러운 빛, 받침대, 홀로그램 빔, 빈 에너지 장치처럼 텍스트가 없는 장면 소품뿐이다.
- 혼합형에서 SVG 오버레이는 새로운 CSS 카드가 아니라 정밀 UI 레이어다. 모든 보이는 SVG 텍스트는 1-3개 짧은 값으로 제한하고, 긴 칭찬·고정 결과 라벨·버튼 장식은 생성형 결과 이미지나 독립 생성형 타이틀/버튼 자산으로 처리한다. 동적 값이 4개 이상 필요해지면 결과 화면이 아니라 순위판/대시보드 패턴으로 분리한다.
- 혼합형 QA는 생성 이미지 품질과 SVG 정렬을 따로 본다. 1280×800과 1024×768 캡처에서 보상 장면이 먼저 보이고, SVG
<text>의 getBBox()가 의도한 UI 영역 밖으로 나가지 않으며, 점수·통계 카드가 결과 보상보다 시각적으로 앞서지 않아야 한다.
- 1단원 결과 화면을 리마스터할 때는 3차시를 품질 기준으로 삼는다. 1차시는 배경부터 재생성해 카드 슬롯 없는 결과 장면으로 만들고, 2차시와 4차시는
천왕성 도착!, 초거대 로봇! 같은 큰 결과명을 생성형 타이틀/장면으로 바꾼다. 정답 수는 공용 생성 이미지 세트를 쓰고, SVG/HTML 폰트는 점수, 연료, 합체 힘처럼 범위가 넓어 이미지 세트로 만들기 어려운 값에만 남긴다.
- 배경 제거, 크롭, WebP 변환, 용량 최적화처럼 생성형 원본의 의미를 바꾸지 않는 후처리는 허용된다. 단, 새 문구·버튼·캐릭터·패널을 로컬에서 그려 붙이는 순간 로컬 합성으로 본다.
유한 상태 이미지 세트 QA 계약
상단 목표 지도, 보상 점수, 결과 등급, 정답 수, 버튼 변형처럼 정해진 개수의 생성 이미지가 같은 UI 슬롯에서 바뀌면 유한 상태 이미지 세트로 본다. 이 작업은 단일 이미지 작업보다 QA가 더 엄격하다.
- 먼저 세트 계약을 쓴다. 예:
6장, 승인된 캔버스/표시 슬롯 치수, 각 장 로봇 슬롯 6개, 현재 로봇 1개 컬러, 나머지 5개 실루엣, 상하 잘림 없음, 가로 배치 유지.
- 사용자가 크기나 배너 높이를 지정하면 그 숫자가 기준이다. 중간에 크기를 바꿔야 한다고 판단되면 구현 전에 이유를 말하고 확인한 뒤, 마지막으로 승인된 숫자로 계약을 갱신한다.
- 생성 이미지를 연결하기 전, 모든 상태 이미지를 실제 표시 비율로 묶은 컨택시트를 만든다. 파일명, 상태명, 치수가 함께 보여야 한다.
- N장 세트는 N장 전부를 눈으로 확인한다. 로봇 6단계 배너라면 6장 모두 로봇 6개가 보여야 하며, 특정 상태만 5개면 치수 검사가 통과해도 실패다.
- 같은 슬롯의 이미지들은 같은 가로 배치, 같은 세로 기준선, 같은 여백 체계를 가져야 한다. 한 장만 찌그러지거나 좌우가 줄거나 주인공 위치가 튀면 다시 만든다.
- 세로 공간이 부족하면 이미지를 좌우로 줄이거나
object-fit: fill로 누르지 않는다. 배너 슬롯 높이와 아래 문제/패널 높이를 다시 배분하고, 위 검정 빈칸·아래 흰 줄·회색 여백 같은 가장자리 결함이 0건이어야 한다.
- 브라우저 QA는 실제 시작 흐름으로 해당 화면까지 들어가서 한다.
naturalWidth/naturalHeight, 렌더된 박스 크기, object-fit, aspect-ratio, 캐시 버전을 확인하고, 컴퓨터 화면과 태블릿 가로 화면을 캡처한다.
REPORT.md에는 상태 이미지 세트 QA를 별도로 남긴다. 현재 runtime 크기, 세트 개수, 컨택시트 경로, 브라우저 화면 크기, 필수 슬롯 전수 확인 결과를 적는다.
정밀 동적 UI 화면 계약
전국 순위판, 대시보드, 표, 여러 행 목록처럼 매 판 달라지는 값이 많고 정확한 정렬이 필요한 화면에는 아래 패턴을 쓴다.
- 생성 이미지 안에 박스, 카드, 행, 버튼 껍데기, 빈 텍스트 슬롯을 그려 넣고 그 위에 HTML/SVG 글자를 맞추지 않는다. 이 방식은 폰트 렌더링·브라우저 축소·이미지 여백 차이 때문에 반복해서 깨진다.
- 생성 이미지는
축하 배경, 무대, 불꽃, 매스몬 장식, 분위기만 맡긴다. 프롬프트에는 no text, no letters, no numbers, no UI panels, no leaderboard board, no cards, no table rows, no buttons, no empty boxes, no signs, no labels를 명시한다.
- 순위판, 내 기록 박스, 행 배경, 스크롤 영역, 버튼 표면, 보이는 글자는 하나의 SVG
viewBox="0 0 1280 800" 컴포넌트가 그린다. 배경 이미지와 UI를 같은 SVG 좌표계 안에 두어 Stage가 줄어도 함께 줄어들게 한다.
- 실제 클릭은 같은 좌표의 투명 HTML
button hitbox가 맡는다. 버튼 안에 보이는 HTML 텍스트를 넣지 말고, 접근성용 aria-label만 둔다.
- 하단 행동 버튼은 중앙 정렬만 맞으면 통과가 아니다. SVG 버튼 rect, 라벨, HTML hitbox 중심이 실제 브라우저 렌더 기준으로 맞아야 하고, 버튼 외곽선·그림자가 보드 하단선이나 리스트 패널 경계에 걸치면 실패다. 구현자는 사용자가 숫자를 주지 않아도
getBoundingClientRect()로 버튼 바닥, 보드/패널 경계, hitbox 위치를 직접 재고 겹침 0px과 눈에 보이는 여백을 확보한다.
- 긴 이름·긴 상태 문구는 렌더러에서 정해진 글자 수로 말줄임한다. 글자를 맞추려고 viewport 폭 기준 글자 크기를 계속 줄이지 않는다.
- 목록은 고정 높이 row 슬롯 안에서 4행처럼 안정적으로 보여 주고, 10위까지 같은 SVG 리스트 안에서 wheel/pointer 스크롤로 확인하게 한다.
- 이 패턴은 동적 UI가 많은 화면을 위한 예외다. 결과 라벨·칭찬·고정 버튼 장식처럼 유한하고 고정된 시각 요소는 여전히 생성형 결과 이미지/타이틀/버튼 자산으로 처리한다.
- QA는 CSS 좌표값만 보지 않는다. 1280×800, 1024×768, 사용자가 올린 문제 크기와 비슷한 브라우저 크기에서 캡처하고, SVG
<text>의 getBBox()가 Stage와 의도한 보드 영역 밖으로 나가지 않는지 확인한다. 버튼이 있으면 SVG 버튼 rect, 보이는 라벨, 투명 hitbox의 실제 화면 좌표를 함께 기록하고, 보드/패널 경계선과 겹치지 않는지 확인한다. 보이는 HTML 버튼 텍스트, foreignObject, 제작자 용어, 금지 문구도 0건이어야 한다.
랭킹 비활성화 정책 (강제)
사용자가 계획 변경을 명시하기 전까지 3학년 2학기 1~6단원에는 랭킹 기능을 만들거나 노출하지 않는다.
- 학생 화면의
랭킹, 순위, 전국 순위 문구와 안내, 결과 화면 진입 버튼, 순위 화면을 모두 숨긴다.
- 점수 제출, 세션 생성, 순위 조회 등 랭킹 API 요청을 보내지 않는다. API 주소가 주입되어도 기본값은 비활성화한다.
- 새 차시, 리마스터, 복제 작업에서
scoreboard, leaderboard, ranking UI·상태·자산·필수 흐름을 추가하지 않는다.
- 기존 코드나 자산은 호환·복구용으로 남길 수 있지만 학생 흐름과 네트워크 요청에서는 닿을 수 없어야 한다.
- 설명 2의 목표는 차시 안의 보상과 마지막 결과만 말한다. 다른 학생과 비교하거나 전국 기록을 확인한다는 약속을 넣지 않는다.
- QA 필수 흐름은
cover → tutorial-1 → tutorial-2 → play → reward → result로 끝낸다. 결과 화면에 랭킹 버튼이 보이지 않고 랭킹 API 요청이 0건인지 확인한다.
- 다시 도입하려면 사용자가 계획 변경을 명시한 뒤 이 정책,
AGENTS.md, CLAUDE.md, 런타임 가드를 같은 변경 묶음으로 갱신한다.
첫 화면 커버는 기본적으로 generated-title-overlay 표준을 따른다. 새 차시와 생성형 시작 버튼으로 이관한 차시는 <main class="game" data-cover-standard="generated-title-overlay" data-cover-start-standard="generated-button-art" data-cover-start-asset="shared-canonical-v1">를 선언한다. cover-generated.webp는 글자 없는 대표 장면 배경으로 .raster-bg에 object-fit: cover로 깐다. 게임명은 생성형 이미지로 만든 title-*-generated.webp를 .hero-title-art로 얹고, 한 줄 목표는 짧은 HTML 텍스트로 둔다. 시작 버튼의 보이는 면은 CSS 텍스트 버튼이 아니라 공용 생성형 버튼 자산(../_shared/mathmon/cover-start-button/start-button-generated.webp)으로 둔다. 실제 조작은 <button class="cover-start-button" id="startButton" aria-label="시작"><img class="start-button-art" src="../_shared/mathmon/cover-start-button/start-button-generated.webp" alt="" aria-hidden="true"></button>처럼 같은 크기의 HTML 버튼이 맡는다.
첫 화면에 매스몬이 필요하면 커버 배경과 분리된 컷아웃을 얹지 않는다. cover-generated.webp 생성 프롬프트에 매스몬을 처음부터 포함해 배경·소품·빛과 같은 톤으로 만들고, HTML은 제목 아트·목표·생성형 시작 버튼·접근성 hitbox만 얹는다. 최신 엔진을 복제할 때 남아 있는 .cover-mathmon 구조는 새 차시 기준이 아니라 이관 전 호환 흔적이다.
시작 버튼은 공용 생성 자산 mathmon-cover-start-button-v1만 쓴다. start-button-source.png, start-button-generated.png, start-button-generated.webp는 _shared/mathmon/cover-start-button/에서 한 세트로 관리한다. 새 차시나 큰 커버 수정에서 버튼을 새로 생성·복제·색 변경·재가공하지 않는다. 1280×800 Stage 기준 표시는 360×152px, 작은 화면 최소 300×127px, aspect-ratio: 1611 / 680으로 고정하며, 표시 아트와 HTML hitbox의 실제 브라우저 경계가 같아야 한다. 배치는 목표 아래 14-24px 간격을 기본으로 하고, 공용 버튼 자체의 교체는 사용자가 명시적으로 승인한 브랜드 변경에서만 허용한다.
cover-generated.webp 한 장 안에 제목·목표·시작 버튼을 구워 넣거나, 커버 전체를 누르는 cover-art/cover-start-hitbox 투명 클릭 영역을 새 차시에 쓰지 않는다. 버튼 크기의 HTML 버튼은 접근성과 클릭을 위해 필요하지만, 보이는 버튼 표면을 CSS 배경/텍스트로 새로 그리면 실패다. 기존 generated-title-overlay 차시 중 아직 .primary-button으로 시작하는 화면은 개별 이관 전까지 data-cover-start-standard="compatibility-primary-button"로 분류하고, 새 차시 복제 기준으로 삼지 않는다. 아직 마이그레이션하지 않은 포스터형 기존 차시는 data-cover-standard="legacy-raster-poster"로 예외임을 명시한다.
주요 행동 버튼 통일 규격
- 시작·설명 시작·보상 열기·결과 다시처럼 화면 흐름을 바꾸는 큰 행동 버튼은 승인된 공용 버튼 계열의 시각 언어를 따른다. 기본은 밝은 금빛 가로 캡슐, 두꺼운 이중 테두리, 아래쪽 입체 그림자, 짧고 굵은 한글 라벨이다. 숫자 선택지, 설정, 닫기 같은 작은 조작에는 이 규격을 억지로 적용하지 않는다.
시작은 공용 mathmon-cover-start-button-v1, 결과의 다시는 공용 결과 버튼을 그대로 쓴다. 뜻이 다른 버튼에 기존 글자 자산을 재사용하거나 CSS로 글자만 덮지 말고, 같은 계열의 독립 생성형 PNG/WebP 버튼 아트를 만든다.
- 차시별 큰 행동 버튼은 생성 원본 또는 크로마키 PNG, 배경 제거 PNG, 실행 WebP를 함께 보관한다. HTML
<button>에는 보이는 텍스트를 중복하지 않고 aria-label만 남기며, 자식 <img aria-hidden="true">가 버튼 면 전체를 채우게 한다.
- 같은 차시의 큰 행동 버튼은 비율·높이·광택·테두리 두께·그림자 방향을 나란히 비교한다. 이미 승인된
시작·다시와 한 계열로 보이지 않거나, object-fit: fill로 자산 자체 비율을 바꾸면 실패다.
- 브라우저에서 버튼 아트와 HTML hitbox의
getBoundingClientRect() 중심·너비·높이 차이를 각각 1px 이하로 확인한다. 1280×800과 1024×768에서 주변 계산판·문구·패널과 교차가 0px이고 터치 영역이 최소 42×42px인지 캡처와 수치로 남긴다.
첫 화면 제목은 단순 큰 HTML 텍스트로 끝내지 않는다. 사용자가 그림으로, GPT Image, 제목 이미지를 요구하면 기존 커버 배경은 유지하고, 제목 부분만 독립 래스터 타이틀 아트(title-logo-generated.webp, title-poster-generated.webp 등)로 생성해 얹는다. 전체 커버를 제목 이미지로 갈아엎거나 HTML/CSS/SVG로 흉내 내지 않는다. 실제 제목은 visually-hidden 텍스트로 남긴다. 생성형 이미지 제목은 캡처로 한글 철자와 배경 위 배치 상태를 검수하고, 철자 오류·어색한 자산·생성 실패 중간 결과를 화면에 남기지 않는다.
중요: 첫 화면 제목 자산은 반드시 image_gen/GPT Image 등 생성형 이미지 도구로 만든 결과여야 한다. 시작 버튼은 이미 승인된 공용 mathmon-cover-start-button-v1을 쓴다. 사용자가 명시적으로 승인한 공용 버튼 교체가 아니라면 시작 버튼을 새로 생성하지 않는다. 제목 원본(title-*-source.png 또는 title-*-chromakey.png)과 공용 버튼의 원본·PNG·WebP 세트는 함께 보관한다. node scripts/check-stage-ratio.mjs가 공용 버튼 참조와 원본 보관 조건을 검사한다.
문제 화면 과밀 금지 계약
- 한 화면 한 행동 게이트: 학생이 화면을 보고
지금은 무엇 하나만 하면 돼?에 바로 답해야 한다. 답이 몫을 고른다, 남은 별을 고른다, 검산값을 고른다처럼 하나로 나오지 않으면 실패다.
- 문제 화면은 설명서가 아니라 현재 한 단계의 수학 행동을 고르는 화면이다.
- 한 문제 화면에서 학생에게 요구하는 행동은 하나여야 한다.
층을 보며 진행도 확인하기, 계산판 해석하기, 힌트 읽기, 선택지 고르기, 보상 상태 보기처럼 여러 행동을 동시에 요구하면 실패다.
- 기본으로 펼쳐 둘 수 있는 학습 요소는
큰 문제, 현재 단계 조작판, 한 줄 지시문, 선택지뿐이다.
- 레이아웃 전에
1순위 학습 대상, 2순위 보조 정보, 3순위 상태·장식을 적는다. 정보 묶음 수는 글자 수가 아니라 학생이 연결해서 읽어야 하는 수·라벨·관계·표현의 독립 묶음으로 센다.
- 1순위 학습 대상은 콘텐츠 레이어에서 가장 큰 단일 영역이어야 한다. 장식 배경은 Stage 전체에 깔 수 있지만 핵심 계산판을 좁은 열로 밀어내거나, 보조 카드가 더 넓고 더 선명해지면 실패다.
- 검산판처럼 연결된 식·표현이 둘 이상 들어간 한 패널은 실제 Stage 폭의
65% 이상을 기본값으로 둔다. 미만이면 글자를 줄이지 말고 장식 폭·중첩 테두리·보조 라벨을 먼저 줄여 패널을 키운다.
- 브라우저에서 핵심 패널과 주요 보조 영역의
getBoundingClientRect()를 재고 영역/우선순위/정보 묶음 수/width/height/Stage 폭 비율/Stage 면적 비율/판정 표를 REPORT.md에 남긴다.
- 3초 보기와 흐림/눈가늘임 검사를 한다. 세부 글자를 읽지 않아도 큰 문제·현재 조작·선택지 중 현재 1순위가 가장 먼저 보여야 한다.
- 현재 행동과 직접 연결되지 않는 정보는 기본으로 접는다. 보상 상태, 전체 풀이 흐름, 다음 단계 예고, 긴 진행판은 작은 완료 칩·접힌 힌트·보상 뒤 화면으로 보낸다.
- 개념 설명판, 풀이 해설판, 힌트판, 계산 미리보기, 보상 상태판을 한 화면에 동시에 펼치지 않는다.
- 화면을 보고 학생이
지금은 무엇 하나만 하면 돼?에 한 문장으로 답하지 못하면 레이아웃 문제가 아니라 설계 실패로 보고 다시 줄인다.
- 화면을 보고 학생이
무엇을 생각해서 결정해야 하지?에 답하지 못해도 설계 실패다. 행동 수를 줄이는 과정에서 수학적 결정을 함께 없애지 않는다.
- 직접 조작은 답을 대신 만들어 주는 애니메이션이 아니다. 학생이 한 바구니 몫, 놓을 칸, 수의 분해, 비교 관계처럼 정답을 구성하고, 애니메이션은 그 답이 전체에 성립하는지 확인한다.
- 수학적 판단과 물리 입력을 따로 센다. 같은 분배 규칙을 정한 뒤 물건마다 같은 목적지를 계속 누르는 것은 입력 수가 늘어도 새로운 사고가 아니다. 학생이 답을 확정한 뒤의 반복 배치는 시스템이 차곡차곡 보여 주고, 학생은 그 결과를 검증한다.
- 같은 뜻의 물건 놓기·누르기가 연속 세 번 이상이면
왜 매번 새 판단이 필요한가?를 감사 문서에 답한다. 답하지 못하면 조작을 줄인다. 문제 은행 전체에서 정답 경로의 최소·중앙값·평균·최대 입력 횟수를 기록한다.
- 각 단계는
왜 지금 이 계산을 하지?에 화면 속 수와 물건으로 답해야 한다. 설명 화면이 클릭·드래그 사용법만 보여 주고 단계의 수학적 목적을 보여 주지 않으면 실패다.
- 문제 풀이·확인·마지막 버튼마다
버튼/상태, 누르기 전 모르는 것, 필요한 수학적 판단, 누른 뒤 보이는 증거, 배움에 보태는 점, 유지/제거를 표로 적는다. 새 판단도 새 관계 해석도 없으면 버튼을 제거한다.
- 검산처럼 올바른 관계에서
몫×나누는 수+나머지=처음 수가 반드시 성립하고 처음 수가 이미 보이면, 마지막에 처음 수를 다시 고르거나 입력시키지 않는다. 완성값은 계산판이 처음 수 자리로 돌아오는 연출로 자동 표시한다.
- 결정되기 전의 몫·곱한 값·나머지·검산식 중 하나를 학생이 고르거나 만들게 하고, 그럴듯하게 틀린 검산식을 비교·고치게 하여 배움이 일어나게 한다. 이미 결정된 값을 재입력하는 것은 단계 수만 늘린다.
- 마지막 행동 버튼은 학생이 만든 상태를 한 번 검증하거나, 완성된 수학 관계를 충분히 본 뒤 아직 알 수 없는 랜덤 보상을 여는 경우에만 둔다. 보상 버튼은 새 수학 입력인 척하지 말고
자물쇠 열기, 상자 보기처럼 실제 상태 변화를 말한다.
- 확인 버튼을 여러 번 눌러 정답 범위를 좁히는 추측 경로를 막는다.
1개 담고 확인 → 2개 담고 확인처럼 순서대로 시험하면 풀리는 화면은 실패다. 학생이 물건의 목적지·수·관계를 먼저 완성하고, 확인은 완성된 답을 검증하는 한 번의 행동이어야 한다.
- 학생이 만들 수 있는 그럴듯한 오답 상태를 최소 1개 두고, 오답 뒤에는 현재 물건으로 부족·초과·불균형을 보여 준다. 정답 경로만 있는 조작은 문제로 인정하지 않는다.
- 단계형 문제는 현재 단계만 크게 보여 주고, 이전 단계는 작은 완료 칩으로 접으며, 다음 단계는
? 또는 잠금 상태로 둔다.
- 정답을 고른 뒤에는 클릭한 선택지 색만 바뀌고 끝나면 실패다. 현재 계산판·칸·블록이 정답값으로 바뀌고,
맞았어요 같은 짧은 확인 문구가 보여야 한다.
- 마지막 단계 뒤에는 보상 모달이 정답 확인을 덮지 않게 한다. 완성식이나 완성값이 학생 눈에 먼저 들어온 뒤,
바람 보기, 상자 열기처럼 차시 소재에 맞는 버튼으로 보상에 들어가게 한다.
- 원리는 긴 문장이 아니라 블록·칸·스티커·화살표·자리값 묶음 같은 시각 조작으로 보여 준다.
- 힌트는 기본으로 닫고, 열어도 지금 단계 힌트 1개만 보여 준다.
- 스크린샷을 보고 "문제보다 패널이 많다", "문장이 여러 줄이다", "무엇을 눌러야 할지 바로 안 보인다"면 완성하지 말고 즉시 덜어낸다.
기준 차시 비교·증거 최신성 계약
- 새 차시, 학습 조작 변경, 대형 화면 변경 뒤에는
references/verification.md의 기준 차시 비교 항목을 읽고 강점별 기준 차시와 비교한다.
- 3학년 2학기 1단원 1~4차시를 기본 비교군으로 삼되, 한 화면을 통째로 복제하지 않는다. 보상 손익, 계산 구조, 진행감, 단계 확인처럼 잘된 기능을 각각 기준으로 쓴다.
- 수학적 판단, 한 화면 한 행동, 오답 이유의 시각화, 마지막 완성값 확인, 겹침 0건, 랜덤 보상, 재도전 동기는 다른 장점으로 상쇄할 수 없는 강제 통과 항목이다.
- 설명 그림의 물건 수·묶음 수·식은 실제 수학 관계와 정확히 맞아야 한다. 보기 좋은 그림이어도 수량 관계를 잘못 읽게 하면 실패다.
- 계산판의 자리 숫자와 학생에게 말하는 실제 값을 구별한다. 예를 들어 십의 자리 몫 칸은
1이어도 선택지와 확인 문구는 몫 10으로 쓰며, 7십 같은 낯선 표기는 문제 은행 전체에서 금지한다.
- 문제 화면에는 왼쪽
에듀잇티 수학 게임과 같은 상단 줄의 단원 배지가 있어야 한다. 표지에만 브랜드가 있고 문제 화면에서 사라지면 부족이다.
- 오답, 정답 확인, 다음 단계 대기, 마지막 완성값을 각각 독립 상태로 고정해 캡처한다. 지시문과 피드백,
? 칸, 숫자와 화살표가 찰나에라도 겹치면 실패다.
- 사용자가 올린 화면과 비슷한 창 크기를 기본 1280×800·1024×768에 추가하고, 실제 렌더 글씨 크기·기호 간격·터치 영역을 잰다.
- 학습 조작을 바꿀 때는 모델, 화면, 설명, 문구, 테스트, 문서, 스크린샷을 같은 변경 묶음으로 갱신한다.
- 자동 검사 결과와 실제 화면 증거를 구분한다. 데스크톱·태블릿에서 오답 양방향, 정답 확인, 마지막 확인, 보상, 결과를 눈으로 확인한다.
- 비교표는
필수 계약, 기준 차시 대비, 제품 선택을 구분한다. 기준 차시의 오래된 구조를 그대로 복제하거나, 현재 차시가 더 잘한 직접 조작·오답 피드백을 하향 평준화하지 않는다.
- 실제 실행 WebP를 모두
decode()한 뒤 캡처한다. 파일 치수와 원본 PNG가 정상이어도 실행 화면에서 글자·아이콘·버튼 면이 비면 실패이며, 화면 크기별 캡처 결과가 다르면 증거 세트를 다시 만든다.
- 감사 시
index.html과 설정이 참조하는 런타임 자산을 git ls-files와 대조한다. 로컬에는 있지만 추적되지 않은 필수 자산이 하나라도 있으면 배포 준비는 ❌ 부족으로 판정한다.
- 현재 흐름과 다른 예전 스크린샷·전용 QA·문서는 현재 증거와 섞지 않는다. 삭제하지 말고
_archive/에 버전을 남겨 보관한다.
- 감사 결과는
✅ 통과, 🟡 일부 통과, ❌ 부족, ⏸ 선택과 P0/P1/P2로 기록한다. 백엔드나 화면 복잡도를 늘리는 선택 항목은 임의 구현하지 않고 사용자에게 결정받는다.
Humanizer 학생 문구 QA 계약
- 화면 구현 뒤에는 반드시
humanizer 스킬을 읽고 적용한다. Codex 세션의 스킬 목록에 보이지 않아도 /Users/yubyeongju/.agents/skills/humanizer/SKILL.md와 필요한 references/ 문서를 직접 읽는다.
- 대상 문구는 첫 화면 목표 문장, 설명 화면 단계, 문제 지시문, 선택지, 힌트, 오답 피드백, 보상 모달, 결과 칭찬, 다운로드 카드 문구,
aria-label 중 학생에게 읽힐 수 있는 말이다.
- Humanizer의 AI 문체 기준(번역투, 불필요한 한자어, 명사 과다, 3박자 반복, 경직된 문장)을 보되, 최종 판단은 초3 학생이 이해하는가에 둔다.
- 제작자 용어를 화면 말로 바꾼다. 예:
핵심 곱은 필요하면 0 뗀 곱, 생산량은 테마에 맞춰 공장 힘이나 모은 힘, 출하 등급은 상자가 간 곳, 0 토큰은 0, 불량 처리는 고칠 상자처럼 보이는 물건과 행동으로 바꾼다.
- 한 문장에는 행동 하나만 담는다.
계산하고 붙여요처럼 두 행동이 들어가면 단계로 나누거나 더 짧게 쓴다.
- 모달 문구는 Humanizer QA 뒤에도 한 덩어리만 남긴다. 제목·본문·버튼이 같은 뜻을 반복하면 실패다.
- 문구를 바꾼 뒤에는 브라우저 캡처에서 줄바꿈, 버튼 폭, 카드 안 텍스트 넘침을 다시 확인한다.
효과 설계 계약
- 효과는 장식이 아니라 수학 행동이 게임 세계를 바꿨다는 신호여야 한다.
- 효과를 넣거나 다듬을 때는
references/effect-design.md를 읽고, 단계 정답·보상 이동·중심 오브젝트 변화·랜덤 이벤트 충격·결과 측정 중 어디에 붙일지 먼저 정한다.
- 효과가 문제·현재 단계·한 줄 지시·선택지를 가리면 즉시 줄인다.
- 중심 보상은 하나만 유지한다. 효과를 별, 코인, 하트 같은 별도 보상 체계처럼 추가하지 않는다.
- 모든 큰 효과는
prefers-reduced-motion 대응과 브라우저 캡처 검증을 거친다.
보상/피드백 모달 문구 계약
- 모달은 설명서가 아니라 짧은 결과 신호다. 버튼을 제외한 보이는 텍스트는 큰 결과 라벨 또는 변화량 1개로 줄인다.
- 긴 설명 문장, 제목+본문+버튼의 3중 문구, 같은 뜻의 반복은 기본 노출하지 않는다. 필요한 설명은 숨김 접근성 텍스트나 결과 뒤 화면으로 보낸다.
- 같은 모달 안에서
출하!와 출하 보기, 결과와 결과 보기처럼 같은 단어를 반복하면 실패다. 버튼은 다음, 보기, 다시처럼 다음 행동만 말한다.
- 랜덤 이벤트의 차이는 긴 문구가 아니라 이미지, 아이콘, 변화량, 짧은 모션으로 구분한다.
마지막 결과 화면 결속 계약
- 10문제를 끝낸 뒤의 마지막 결과 화면은 배경 위에 결과명·다음 목표·정답 수·다시하기를 각각 흩어 놓지 않는다. 이유 없이 공중에 떠 보이는 독립 UI는 실패다.
- 결과 장면의 주인공은 완성된 세계(농장·로봇·섬 등)와 하나의 결과판이다. 결과판 안에 결과명, 짧은 다음 목표, 정답 수, 다시하기를 같은 세로 축으로 묶어 학생이 한 번에 읽게 한다.
- 결과판은 배경 장면과 겹쳐도 장면의 빈 공간에 안정적으로 놓고, 테두리·그림자·안쪽 여백으로 하나의 물건처럼 보여야 한다. 단순히 절대 좌표로 글자·숫자·버튼만 띄워 놓는 방식은 금지한다.
- 기준 차시가 있을 때는 결과 화면의 결속 구조를 먼저 비교한다. 예를 들어
3-2-1-4-mathmon-fusion처럼 왼쪽 완성 장면과 오른쪽 결과판이 역할을 나누는 구조는, 테마에 맞게 바꾸되 흩어진 UI보다 우선 검토한다.
- 결과판 안에서도 시각 우선순위는
결과명 → 정답 수 → 다시하기다. 다음 목표는 보조 정보로만 두며, 결과명이나 다시하기보다 크거나 더 멀리 떨어져 보이면 실패다.
Stage 비율 계약
- 모든 차시는
16:10 Stage, 기준 제작 크기 1280×800으로 만든다.
- 모든
index.html의 <main class="game">에는 data-stage-ratio="16:10"과 data-stage-size="1280x800"을 둔다.
- 기본 Stage CSS는
.stage-shell이 width: min(1280px, calc((100dvh - 48px) * 1.6), 100%);, aspect-ratio: 16 / 10;을 담당하고, .screen은 position: absolute; inset: 0; width: 100%; height: 100%;로 Stage를 채우게 한다.
- PC와 태블릿 가로에서는 Stage를 contain 방식으로 맞추고, 남는 영역은 바깥 배경 여백으로 처리한다.
- 설정/소리 같은 전역 조작 버튼은 Stage 밖에 fixed로 띄우지 말고
.stage-shell 안의 상단 오른쪽 보조 슬롯에 작게 둔다. top-row/hud는 그 공간만큼 비워 버튼이 배지·문제·선택지를 가리지 않게 한다.
- 새 차시와 큰 수정 차시는
<main class="game" data-settings-standard="modal-controls">를 선언하고, 오른쪽 위 버튼은 .settings-toggle 원형 SVG 톱니바퀴로 만든다. 화면에 설정/소리 글자를 직접 넣지 말고 aria-label="설정 열기"를 둔다. 아직 이관하지 않은 차시는 레거시 .sound-toggle을 보존할 수 있지만 새 복제 기준은 아니다.
- 전역 버튼 위치는 모든 화면에서 완전히 같아야 한다.
.stage-shell에 --sound-button-size, --sound-gap, --sound-reserve: calc(var(--sound-button-size) + var(--sound-gap));를 두고, .settings-toggle/레거시 .sound-toggle은 top: var(--stage-inset); right: var(--stage-inset); width/height: var(--sound-button-size);만 쓴다. 화면별 transform, active-screen별 위치 보정, 하단 고정은 금지한다.
- 설정 모달은
.stage-shell 안에 role="dialog" aria-modal="true" aria-labelledby="settingsTitle"로 둔다. 보이는 문구는 설정, 배경 소리, 효과 소리, 방법 다시 보기, 처음부터, 닫기처럼 짧게 유지하고, 움직임 줄이기는 넣지 않는다. 모달은 열 때 첫 토글에 focus, 닫을 때 설정 버튼으로 focus 복귀, Escape 닫기, Tab 순환을 지원한다.
- 오디오 상태는
bgmEnabled와 sfxEnabled로 분리한다. BGM은 mathmon-audio-bgm-enabled, 효과음은 mathmon-audio-sfx-enabled에 저장하고, playSample()은 효과음 설정만 본다. 브라우저 QA용 __mathmonAudioQa에는 getPrefs()와 setPrefs({ bgmEnabled, sfxEnabled })를 둔다.
방법 다시 보기는 기존 설명 화면을 복습 모드로 재사용하고 버튼 문구를 계속하기로 바꾼다. 계속하기를 누르면 저장한 화면으로 돌아가며 문제/보상/결과 상태를 초기화하지 않는다. 처음부터는 확인 상태(처음부터 할까요?)를 거친 뒤 보상 모달·타이머를 정리하고 첫 화면으로 돌아간다.
.stage-shell .top-row는 right: calc(var(--stage-inset) + var(--sound-reserve));, .stage-shell .hud는 padding-right: var(--sound-reserve);로 같은 슬롯을 공유한다. 화면별로 단원 배지와 설정/소리 버튼 사이 간격이 달라지면 실패다.
.top-row는 top: var(--stage-inset); left: var(--stage-inset); right: calc(var(--stage-inset) + var(--sound-reserve)); height: var(--sound-button-size); gap: var(--sound-gap);를 명시하고 inset 축약을 쓰지 않는다. 문제 화면 .hud는 align-items: start; min-height: var(--sound-button-size);로 오른쪽 배지가 전역 버튼보다 위아래로 흔들리지 않게 한다.
- 브랜드/단원/상태 배지와 작은 보조 버튼은 글자보다 상자가 먼저 보이면 실패다.
flex: 0 0 auto; width: fit-content; max-width: max-content; min-height: var(--sound-button-size); padding: 0 var(--top-control-pad-x); gap: var(--top-control-icon-gap); white-space: nowrap;를 기본으로 쓰고, 안정 슬롯이 꼭 필요한 경우를 제외하고 min-width로 빈 공간을 크게 만들지 않는다.
- 아이콘+텍스트 배지는 아이콘 크기, 글자 크기, gap, 좌우 패딩을 함께 줄인다. 아이콘만 있는 전역 버튼은 텍스트 pill로 만들지 말고 원형/정사각 아이콘 버튼으로 둔다.
- 새 차시를 만들거나 화면을 크게 고친 뒤에는 반드시
node scripts/check-stage-ratio.mjs를 통과시킨다.
성취기준 표기 주의
- 루트 로드맵 표의 성취기준 코드(
[4수0X-XX])는 2022 개정 3~4학년군 기준 안내용이다.
- 차시 문서(
README.md/REPORT.md)에 코드를 박기 전 교육부 고시(제2022-33호) 수학과 원문과 한 번 더 대조한다.
- 단원·차시 묶음은 교과서마다 다를 수 있으니 학교 교과서가 정해지면 그 배열에 맞춘다.
단일 레포 원칙
- 별도 공개 레포를 만들지 않는다. 이 작업실 GitHub 레포지토리 하나를 원본이자 Pages 배포 기준으로 운영한다.
- 필요한 게임 폴더만 GitHub Pages artifact에 포함하고, 공개 URL은
curl -I -L로 HTTP 200을 확인한다.
- 작업실 원본은 PNG 보관, 학생용
index.html은 WebP 같은 경량 포맷을 우선 참조한다. 자세한 검증·배포는 references/verification.md와 eduitit-main-release 참고.
참고 파일
references/plan-template.md — 차시 PLAN.md 템플릿(구조·화면 수·생성 이미지·검증).
references/lesson-prompts.md — 24개 차시별 제작 프롬프트와 문제 화면 과밀 방지 공통 프롬프트.
references/engine-and-images.md — 2차시 재사용 함수 맵 + RasterStage/WebP 이미지 패턴.
references/effect-design.md — 효과를 줄 위치, 물질감·보상 이동·랜덤 이벤트 충격·결과 측정 기준.
references/verification.md — 기준 차시 비교, 실제 화면 증거, 빌드·배포 검증 체크리스트.
.claude/skills/eduitit-mathmon-assets/SKILL.md — 매스몬 캐릭터·팩·카탈로그·결과 카드 자산 관리 절차.
_shared/mathmon/MATHMON_ASSET_CONTRACT.md — Codex와 Claude가 함께 따르는 매스몬 자산 계약.
_shared/mathmon/STYLE_GUIDE.md — 매스몬 팩 생성·중복 방지·이미지 분위기 기준.