Easy-to-manage touch screens
무료 오픈소스 터치스크린으로 USB 설정 가이드, 드래그‑드롭 편집기, 로컬 제어를 제공하며 Home Assistant용으로 제작되었습니다
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기무료 온라인 팀짜기·조짜기 프로그램 — 랜덤 팀 배정, 명단 저장, 승패 기록과 무작위 추첨
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
SvelteKit으로 만든 root 사이트, Team Maker, QR 코드·구슬 레이스 도구와 Markdown 블로그를 한 저장소에서 관리합니다. 새 페이지도 공통 컴포넌트와 토큰을 사용합니다. 컴포넌트를 선택하거나 스타일을 바꿀 때 컴포넌트 목록·사용 예시의 관련 부분을 참고하세요. npm run check:ui는 UI 규칙, npm run test:ui는 검사기와 hook을 검증합니다. 활성화된 hook은 변경 파일을 검사하므로 같은 내용의 수동 검사를 반복할 필요는 없습니다. hook 연결을 설치하거나 진단할 때만 해당 문서의 연결 절차를 확인하세요. QR 화면은 src/lib/qr-code/components/, 구슬 레이스 화면은 src/lib/marble-race/components/에서 기능별로 관리합니다. route는 상태·주요 동작·전체 배치를 담당합니다.README 전문 보기 ↗
SvelteKit으로 만든 root 사이트, Team Maker, QR 코드·구슬 레이스·대진표 도구, 칼바람 아수라장 증강 가이드와 Markdown 블로그를 한 저장소에서 관리합니다.
새 페이지도 공통 컴포넌트와 토큰을 사용합니다. 컴포넌트를 선택하거나 스타일을 바꿀 때 컴포넌트 목록·사용 예시의 관련 부분을 참고하세요. npm run check:ui는 UI 규칙, npm run test:ui는 검사기와 hook을 검증합니다. 활성화된 hook은 변경 파일을 검사하므로 같은 내용의 수동 검사를 반복할 필요는 없습니다. hook 연결을 설치하거나 진단할 때만 해당 문서의 연결 절차를 확인하세요.
QR 화면은 src/lib/qr-code/components/, 구슬 레이스 화면은 src/lib/marble-race/components/, 대진표 화면은 src/lib/bracket/components/, 아수라장 가이드 화면은 src/lib/aram-mayhem/components/에서 기능별로 관리합니다. route는 상태·주요 동작·전체 배치를 담당합니다.
개발 서버와 localhost·127.*·[::1]의 정적 preview에서는 탭 제목 앞에 [로컬]을 붙이고 favicon을 주황색으로 표시합니다. 내부 페이지 이동에도 유지됩니다. theme-color를 지원하는 브라우저에서는 브라우저 UI에도 주황색을 적용합니다. 일반 데스크톱 브라우저의 탭 배경색은 사이트에서 강제로 바꿀 수 없습니다. 실제 배포 주소의 제목·favicon·색상은 유지합니다. 구현은 src/lib/local-preview.js입니다.
홈은 src/routes/+page.svelte, 최신 글 데이터는 src/routes/+page.server.js, 공통 오류 안내는 src/lib/components/organisms/ErrorPage.svelte에서 관리합니다. 정적 404와 SvelteKit 오류 화면이 같은 안내를 사용합니다. 공통 기본 CSS와 글꼴 선언은 src/lib/styles/에 있습니다. 글꼴은 사이트 안의 SUIT·SUITE 파일로 제공하며 외부 CDN에 요청하지 않습니다. Team Maker는 작은 글꼴을 먼저 받고 이름을 입력할 때 전체 글꼴로 보완합니다.
홈·Team Maker·ASMR 구슬 레이스 공유 이미지는 1200×630 PNG입니다. scripts/generate_site_assets.js의 문구와 카드 배치를 수정한 뒤 아래 명령을 실행하세요. 생성에는 Playwright Chromium이 필요합니다. static/favicon.svg를 수정해도 같은 명령으로 PNG·ICO를 다시 만듭니다.
npx playwright install chromium
npm run generate:assets
홈 이미지는 static/images/site-open-graph-1200x630.png, Team Maker 이미지는 static/images/team-maker-open-graph-1200x630.png입니다. 공개 이미지 파일은 배포에 필요하므로 원본 코드와 함께 commit합니다. Team Maker 이미지에는 가상 참가자 6명만 사용합니다. 공유 서비스에 이전 이미지가 남으면 배포 후 해당 서비스에서 링크 미리보기 캐시를 갱신하세요.
배포 라이선스의 원본 경로는 설치된 파일명의 대소문자까지 일치시켜야 합니다. npm test의 라이선스 경로 검사가 macOS에서도 Linux 배포 환경의 대소문자 오류를 잡습니다.
현재 자체 코드는 MIT를 따릅니다. 저작권자는 Lake (hjh3311504)입니다. 템플릿 정리 후 홈·공통 UI를 원본과 대조한 적용 근거를 기록했습니다.
글꼴, 외부 아이콘, 기존 Team Maker 이미지와 보존용 설계 자료는 자체 코드의 MIT 범위와 구분합니다. SUIT·SUITE는 OFL 1.1, 홈 GitHub 아이콘은 Bootstrap Icons의 MIT 고지를 유지합니다. 기존 Team Maker 이미지와 보존용 설계 자료에는 이번 MIT를 적용하지 않습니다. 정확한 경로와 조건은 출처·라이선스 목록을 확인하세요. build의 /licenses/에는 자체 MIT와 외부 글꼴·아이콘·실행 의존성의 원문을 함께 포함합니다.
이 저장소가 시작된 Matheus Fantinel의 SvelteKit Static Blog Template과 과거 commit의 GPLv3 조건은 변경하지 않습니다.
Team Maker 바로 사용하기 — 이름을 입력하면 참가자를 고르게 나누는 무료 온라인 팀짜기·조짜기 프로그램입니다. 같은 팀·다른 팀 규칙, 명단 저장, 승패 기록과 무작위 추첨을 지원합니다.
홈의 도구 선택 안내는 각 도구의 용도와 한계를 설명하며 운영자·공개 소스·출처·문의로 연결합니다. 팀 메이커는 10명의 3팀 배정과 규칙·명단 재사용, QR은 참여 주소의 A4 12개 인쇄, 구슬 레이스는 10명 중 4~6번째 도착자 추첨을 예제로 제공합니다. 모두 가상 이름을 사용하며 정적 HTML에 포함합니다.
기능을 바꾸면 해당 안내와 REQ·화면 문서도 함께 갱신하세요. 팀 메이커의 인원 균형을 실력 균형으로 표현하거나 구슬 레이스의 동일 당첨 확률을 보장하지 마세요. 광고 심사 결과와 출처 확인 범위·남은 항목은 콘텐츠 점검 기록에 정리했습니다. 이번 보강은 AdSense 승인을 보장하지 않습니다.
Node.js와 npm을 설치한 뒤 아래 명령을 실행하세요.
npm install
npm run dev
http://localhost:5173/http://localhost:5173/team-makerTeam Maker의 전체 배치는 src/routes/team-maker/+page.svelte에 있습니다. 기능별 화면은 src/lib/team-maker/components/, 화면 동작은 src/lib/team-maker/에서 관리하며 SvelteKit이 함께 build합니다.
src/routes/team-maker/+page.svelte는 검색 메타 정보, 구조화 데이터, 안내·FAQ, 전체 배치, 저장 실패 안내와 mountTeamMaker(pageRoot) 연결을 담당합니다.
아래 Svelte component는 모두 src/lib/team-maker/components/ 안에 있습니다. 동작 파일은 src/lib/team-maker/를 기준으로 적었습니다.
| 수정할 화면 | Component | 동작 파일 |
|---|---|---|
| 참가자 입력·명단·배정 규칙 목록 | ParticipantsSection.svelte | participants.js |
| 나누는 방식·인원 설정·팀 만들기 버튼 | TeamSettingsSection.svelte | participants.js, results.js |
| 팀 결과·팀 이름 수정·누적 당첨자 | TeamResultsSection.svelte | results.js, history.js |
| 오늘 기록·기록 관련 버튼 | TodayHistorySection.svelte | history.js |
| 참가자 일괄 추가 | BulkAddDialog.svelte | participants.js |
| 같은 팀·다른 팀 규칙 지정 | AssignmentRuleDialog.svelte | participants.js |
| 명단 저장·불러오기 | RostersDialog.svelte | rosters.js |
| 추첨·효과음 버튼·당첨자 | WheelDialog.svelte | wheel.js, audio.js |
| 전체 기록·전체 통계 | HistoryDialog.svelte | history.js |
| 참가자 통계 | PlayerStatsDialog.svelte | history.js |
| 삭제 등 확인창 | ConfirmDialog.svelte | dialogs.js |
현재 화면 component는 마크업을, JavaScript는 상태·이벤트와 목록·표·팀 카드·돌림판의 내용을 담당합니다. JavaScript가 채우는 컨테이너는 비워 두며, 초기 연결에 필요한 화면과 dialog는 pageRoot 안에 렌더링합니다. HTML 계층이나 ID·class·data 속성을 바꿀 때는 이를 사용하는 선택자와 접근성 연결도 함께 맞춰야 합니다. TeamResultsSection의 assetsBase prop은 결과 안내 이미지의 경로를 전달합니다.
아래 JavaScript 파일은 모두 src/lib/team-maker/ 안에 있습니다.
| 수정할 내용 | 파일 |
|---|---|
| 초기 상태, 기능 연결, 저장 후 전체 갱신, 화면 종료 | app.js |
| 저장 데이터 정리, 복원과 저장 오류 | storage.js |
| 참가자 입력·삭제, 배정 규칙, 팀 수 설정 | participants.js |
| 팀 생성·결과 표시, 팀 이름 수정, 결과 복사, 대진표로 보내기 | results.js |
| 명단 저장·불러오기·삭제 | rosters.js |
| 순위 기록·취소, 팀 이름·당첨 기록 반영, 참가자 통계 | history.js |
| 돌림판, 당첨자 추가·삭제, 축하 효과 | wheel.js |
| 효과음 생성·중지, 소리 설정 | audio.js |
| dialog 열기·닫기, 확인창, 스크롤 잠금 | dialogs.js |
| 화면 없이 실행하는 팀 배정·순위·통계 계산 | core.js |
| 동적 버튼과 화면 이동 효과 | ui.js |
| 이벤트·타이머·화면 갱신 예약 해제 | lifecycle.js |
| ID 생성과 작은 값 변환 함수 | utils.js |
app.js가 각 기능을 만들고 필요한 상태 접근 함수와 동작 함수를 전달합니다. 기능 간 동작은 이 연결 지점에서 전달하고, 공통 계산과 도우미 파일은 직접 import하는 구조입니다.getState()는 현재 화면이 사용하는 같은 저장 상태 객체를 반환합니다. 각 기능은 필요한 필드를 갱신하며 객체 전체를 교체하지 않습니다. 실제 저장은 전달받은 persist()나 saveAndRender()로 요청합니다.app.js의 runtime에 둡니다. 한 기능만 쓰는 검색어, 선택 상태, 타이머와 효과음은 해당 기능 안에 둡니다.connect()로 이벤트를 연결합니다. 연결 전에는 다른 기능의 동작을 호출하지 않습니다.wheel-sound.js가 CSS와 같은 감속 곡선으로 통과 시각을 계산합니다. 최소 약41.67ms 간격으로 일부 핀을 골라 초당 최대24회 재생합니다. 다음 재생 간격이 이전보다 짧아지지 않도록 핀을 고르고, 마지막 핀도 이 규칙을 유지해 재생합니다. audio.js는 실제 transition의 현재 시각에 맞춰70ms 길이의 짧은 ‘툭’ 음원(wheel-pin-tuk.wav)을 예약합니다. 음소거·바로 뽑기·화면 종료 시 예약도 중지하며, 소리를 다시 켜면 남은 핀부터 이어집니다. 동작 줄이기 설정에서는 회전음을 생략합니다.createLifetime()을 통해 등록합니다. destroy()에서 예약 작업을 취소하고, dialog와 효과음처럼 별도 정리가 필요한 자원도 해제합니다. 비동기 작업을 기다린 뒤에는 lifetime.active로 화면이 아직 열려 있는지 확인합니다.mountTeamMaker(root, { openBracket })는 기존처럼 화면 종료 함수를 반환합니다. Svelte의 onMount가 이 함수를 받아 route를 떠날 때 실행합니다. openBracket은 결과의 ‘대진표 만들기’가 팀을 넘긴 뒤 /bracket으로 이동하는 함수입니다.src/routes/team-maker/team-maker.css는 CSS를 불러오는 진입점입니다. 실제 규칙은 src/lib/team-maker/styles/에 있습니다.
| 파일 이름 | 역할 |
|---|---|
base.css, common*.css | 테마·공통 요소·반응형 화면 |
participants*.css | 참가자·규칙·팀 수 설정 |
results*.css | 팀 결과와 누적 당첨자 |
history*.css | 오늘 기록·전체 기록·통계 |
dialogs*.css | dialog와 명단·확인창 |
wheel*.css | 돌림판·축하 효과 |
content.css | 검색 안내와 FAQ |
기존 적용 순서를 보존하기 위해 일부 기능은 보완 파일로 나누었습니다. import 순서를 바꾸면 같은 요소에 적용되는 CSS 우선순위도 확인하세요. 여러 기능에 걸친 공통 규칙은 common*.css에서 관리합니다. build 검증은 src/lib/team-maker/ 아래의 JavaScript, Svelte와 CSS를 하위 폴더까지 모두 검사합니다.
docs/design/에는 자료별 최신본만 둡니다. 번호별 package, snapshot과 manifest는 만들지 않습니다.
| 자료 | 역할 |
|---|---|
ia.md | 현재 화면 구성과 이동 흐름 |
screens/ | 현재 화면별 동작과 연결 요구사항 |
handoff/ | 마지막으로 전달받은 시안과 자산 |
claude-design-DSN.md | 마지막 Claude Design 요청 기록 |
현재 설계는 IA와 화면 문서에서 확인하고, 실제 동작은 코드와 브라우저에서 확인합니다. handoff와 마지막 요청문에는 과거 조건이 포함될 수 있습니다. 새 handoff를 받으면 기존 폴더 전체를 교체하세요. 파일을 덧붙여 이전 전달본의 파일을 남기지 마세요. 구현을 수정할 때마다 handoff를 다시 생성하지는 않습니다. 다음 Claude Design 요청은 같은 요청문 파일의 본문과 참조 경로를 검토해 갱신하세요.
UI 요구사항의 design_ref는 docs/design/ 기준 화면 경로 목록입니다. 화면이 1개여도 [screens/SCR-WEB-001.md]처럼 적습니다. 공통 요구사항은 관련 화면을 모두 연결하고, 각 화면 문서의 연결 REQ에도 같은 요구사항을 적습니다. design_status는 기존처럼 pending, approved, deferred를 사용합니다. 승인 상태를 바꿀 때는 사용자 요청 등 실제 근거를 관련 commit이나 PR 설명에 남기세요. commit 자체가 승인을 뜻하지는 않습니다. 이 기록 절차가 이미 요청받은 구현에 별도 시안 승인을 요구하는 것은 아닙니다.
설계 검사는 Python 3와 PyYAML이 필요합니다. PyYAML이 없다면 별도 Python 가상환경에 python3 -m pip install pyyaml로 설치하세요.
python3 scripts/verify_ui_design.py docs/requirements docs/design --all
python3 scripts/verify_ui_design.py docs/requirements docs/design --mode inventory
python3 scripts/verify_ui_design.py docs/requirements docs/design --requirement REQ-WEB-020
python3 -m unittest discover -s tests/design -p 'test_*.py'
전체 검사는 모든 UI 요구사항의 승인 상태와 문서 연결을 확인합니다. 목록 검사는 모든 UI 요구사항의 상태를 확인하고, 화면 검사는 승인된 항목의 연결 범위로 제한합니다. 승인된 항목과 무관한 작성 중 화면은 검사하지 않습니다. 승인된 항목이 없으면 설계 폴더가 없어도 목록 검사를 실행할 수 있습니다. 요구사항별 검사는 지정한 항목과 관련 화면의 연결을 확인합니다. 관계없는 항목의 미승인 상태는 실패 사유가 아닙니다. --requirement를 여러 번 지정할 수 있습니다. handoff와 manifest는 검사에 필요하지 않습니다.
과거 설계와 요청문은 Git 이력에서 확인하세요.
git log --oneline -- docs/design
git log --follow -- docs/design/claude-design-DSN.md
아래 명령의 <commit>을 확인할 commit hash로 바꾸세요. 삭제 전 자료는 정리 이전 commit과 당시 파일 경로를 사용합니다.
git show '<commit>:docs/design/screens/SCR-WEB-001.md'
git show '<commit>:docs/design/claude-design-DSN-009.md'
git show '<commit>:docs/design/packages/DSN-010/manifest.yaml'
이전 DSN 형식의 검증이 필요하면 해당 commit의 자료와 script를 함께 사용하세요. 최신 script의 package 지정 옵션은 제거했습니다. 과거 commit 자체는 삭제하지 않으므로 이번 정리는 현재 파일 목록을 줄이며 Git 전체 이력의 용량까지 줄이지는 않습니다.
로컬에서는 변경한 기능에 필요한 검사만 실행합니다. 전체 검사는 GitHub의 PR workflow에서 실행합니다. 문서 변경은 포맷·연결 검사, 로직 변경은 관련 단위 테스트, 화면 변경은 정적 검사와 관련 브라우저 검사를 선택하세요.
# 관련 단위 테스트만 실행
node --test tests/marble-race/audio.test.js
# build가 필요할 때: build1회 후 관련 브라우저 검사
npm run test:e2e:team-maker -- tests/team-maker-e2e/navigation.spec.js
# 같은 코드로 build를 이미 마쳤다면 재build 없이 검사
npm run test:e2e:built -- tests/team-maker-e2e/navigation.spec.js
두 브라우저 명령을 연달아 실행할 필요는 없습니다. test:e2e:built는 현재 코드로 만든 build가 있을 때만 사용하세요. npm run build 뒤에 test:e2e:team-maker를 실행하면 사전 실행 명령 때문에 build가 반복됩니다.
npm test는 CSS 진입점·중첩 폴더의 홀수 px 글자 크기 검사와 팀 분배·배정 규칙, 저장 데이터 복원과 실패 처리, 이벤트·예약 작업 해제를 검사합니다. npm run test:e2e:team-maker는 production build를 만든 뒤 Chromium에서 참가자 편집, 명단 저장, 승패 기록, 추첨, 새로고침, route 재진입, 예약 삭제 취소, 밝은·어두운 테마의 버튼 hover와 비활성 상태, 모바일과 키보드 흐름을 검사합니다. 처음 실행할 때 Chromium이 없다면 npx playwright install chromium을 먼저 실행하세요. npm run verify:team-maker는 root 페이지, SvelteKit이 생성한 Team Maker route와 bundle, 상대 자원 경로, 제품 코드의 외부 HTTP 자원 사용 여부를 검사합니다. 홀수 px 글자 크기는 CSS 진입점과 src/lib/team-maker/styles/ 하위의 모든 CSS에서 검사하며, 위반한 파일 경로와 값을 표시합니다.
build 후 scripts/optimize_images.js가 PNG·JPEG 원본에서 WebP와 AVIF를 생성합니다. Team Maker의 월계관·통계·축하 아이콘은 2026-10-25부터 직접 작성한 SVG(static/images/team-maker/*.svg)라서 변환하지 않고 개발 서버와 production에서 같은 파일을 사용합니다. 경로는 assetUrl()로 만듭니다.
SVG의 viewBox 비율은 이전 PNG와 같게 맞춰 기존 CSS 크기에서 배치가 바뀌지 않게 합니다. 당첨 아이콘은 같은 SVG를 CSS 마스크로 사용합니다. E2E 테스트는 SVG 요청과 마스크 경로를 확인합니다.
.github/workflows/pages.yml은 실행 시점에 따라 작업을 나눕니다.
| 시점 | 실행 작업 | 배포 |
|---|---|---|
| PR 생성·갱신 | lint·정적 검사·전체 단위 테스트·build1회·전체 브라우저 검사·정적 결과 검증 | 없음 |
main push·매일 예약 실행 | build1회·정적 결과 검증·Pages 업로드·공개 주소 확인 | 실행 |
main 수동 실행 | main push와 동일 | 실행 |
| 다른 branch 수동 실행 | 실행하지 않음 | 없음 |
전체 검사를 통과한 PR을 거쳐 머지하세요. 머지 후에는 최종 코드의 배포 파일을 새로 만들되 오래 걸리는 테스트를 반복하지 않습니다. 직접 main에 push하면 전체 검사를 거치지 않으므로 일반 작업은 PR을 사용합니다. build나 정적 결과 검증이 실패하면 배포하지 않습니다. 배포 뒤에는 /, /team-maker, /qr-code, /marble-race, /bracket, /aram-mayhem, /aram-mayhem/master-yi, /aram-mayhem/augments/armored-impact, /blog, /about, /privacy, /rss.xml, /sitemap.xml의 응답을 확인합니다.
PR에서는 site-build가 정적 파일을1회 만들고, checks가 lint·정적 검사·전체 단위 테스트를 병렬로 실행합니다. 브라우저 검사는 같은 build 파일을 내려받습니다. 성능·시간 보존 검사는 전용 실행 환경에서 실행하고, 일반 브라우저 검사는4개 환경에 나눕니다. 각 환경 안에서는 기존처럼 검사1개씩 실행합니다.
구슬1000개 성능 측정에서는 동영상 녹화와 Playwright 추적을 끕니다. 검사 도구의 CPU 부하가 경기 속도·화면 갱신 측정에 섞이는 것을 줄이기 위한 설정입니다. 성능 기준은 그대로 적용하며, 실패 분석은 MARBLE_PROFILE·MARBLE_TRACE로 별도 수집합니다. 일반 브라우저 검사의 녹화·추적 설정은 유지합니다.
일반 검사의 배치는 node scripts/plan_browser_shards.js로 만듭니다. 이전 PR의 실행 시간을 기준으로 긴 파일과 실제 경기 종료 검사4개를 분산합니다. 새 검사는 자동으로 포함하며, 생성한 목록을 Playwright로 다시 읽어 누락·중복을 검사합니다. 보고서는 browser-1~browser-4에 저장합니다. 측정 시간은 배치용이며 테스트 조건·제한 시간·재시도 횟수는 유지합니다.
build는 모든 필수 작업의 성공을 확인하는 마지막 검사입니다. 실패·취소·예상 밖 생략이 있으면 실패합니다. 변경 이유와 측정 기준은 PR 브라우저 검사 분산 결정을 참고하세요.
검사 결과 이름 build는 유지합니다. 검사·배포 분리 결정에 변경 이유와 확인 범위를 기록합니다.
GitHub 저장소의 Settings → Pages → Build and deployment → Source는 GitHub Actions로 설정해야 합니다.
참가자, 설정, 저장 명단과 승패 기록은 현재 브라우저의 localStorage에만 저장됩니다. 생성된 팀 결과는 새로고침 뒤 복구하지 않습니다. 결과를 대진표로 보낼 때만 팀 이름과 팀원 이름을 lake.bracket.import.v1에 잠깐 저장하고, 대진표 화면이 읽은 즉시 지웁니다. 제품 코드는 참가자 데이터를 외부 서버로 보내지 않습니다.
Cloudflare Web Analytics의 무료 서비스를 사용합니다. 동의 버튼 없이 쿠키 없는 방문 횟수·페이지 조회수를 집계합니다. 통계는 Cloudflare 계정에서만 확인하며 홈페이지에 숫자나 관리자 화면을 추가하지 않습니다. 구현은 src/lib/analytics/, 연결은 src/routes/+layout.svelte입니다. GA4 태그는 실행하지 않습니다.
hjh3311504.github.io를 등록하세요. GitHub Pages와 현재 주소를 그대로 사용합니다. 도메인 이전과 별도 서버는 필요하지 않습니다.data-cf-beacon 안에 있는 token 값을 복사하세요. 사이트 식별용 공개 토큰이며 Cloudflare API 비밀 키와 다릅니다.| 변수 | 값 |
|---|---|
PUBLIC_CF_WEB_ANALYTICS_TOKEN | 발급된32자리 사이트 토큰 |
PUBLIC_ANALYTICS_ORIGIN | https://hjh3311504.github.io (마지막 슬래시 없음) |
main build만 운영 설정을 사용합니다. 둘 중 하나가 없거나 잘못되면 태그를 실행하지 않습니다. 변경 후 build·배포해야 적용됩니다. 이전 PUBLIC_GA_MEASUREMENT_ID는 더 이상 읽지 않습니다. PR build는 예약 도메인·가짜 토큰을 사용하며 운영 배포에 사용하지 않습니다. 로컬 설정 목록은 .env.example을 참고하세요.
src/routes/+layout.server.js에서 전달하며 초안·예약 글은 제외합니다. 개발 서버와 로컬 preview에서도 실행하지 않습니다.https://static.cloudflareinsights.com/beacon.min.js를 문서마다1회 불러옵니다. spa: true로 내부 이동과 뒤로·앞으로 이동을 공식 태그가 측정합니다. 사이트 코드에서 조회 요청을 중복 전송하지 않습니다. query·hash만 바꾼 이동의 집계 여부도 공식 태그를 따르며, 이전 GA4의 경로별 중복 제거와 다를 수 있습니다.juno.develog.analytics-consent:v1의 denied는 계속 존중합니다. 이 경우 Cloudflare 태그도 요청하지 않습니다. 기존 allowed도 쿠키 없이 측정하며 _ga 쿠키만 삭제합니다. 다른 탭에서 이전 선택이 바뀌면 현재 문서를 새로고침해 반영합니다. 저장하지 않은 화면 상태는 초기화될 수 있습니다.Cloudflare의 Web Analytics → 등록한 사이트에서 기간과 경로를 선택하세요. Visits는 방문 횟수이며 중복을 제거한 사람 수가 아닙니다. Page views는 페이지 조회수입니다. 운영 배포 뒤 홈·도구·블로그를 방문하고 다른 페이지로 이동하거나 탭을 떠난 후 보고서를 확인하세요. 반영에는 몇 분이 걸릴 수 있습니다.
현재 최근6개월의 통계를 조회할 수 있습니다. 장기 보관 시 공식 API 등으로 별도 보관해야 하며 이번 변경에는 자동 내보내기를 포함하지 않습니다. 이전 GA4 데이터는 Cloudflare로 옮겨지지 않으며 자동 삭제하지 않습니다. 연동 전 방문도 복원하지 않습니다.
전체 수집을 중단하려면 PUBLIC_CF_WEB_ANALYTICS_TOKEN을 비우고 다시 build·배포하세요. 이미 열려 있는 이전 문서는 닫거나 새로고침해야 합니다. 공식 태그는 문서가 열려 있는 동안 동작하며 개별 종료 API를 제공하지 않습니다.
npm run test:analytics
# 가짜 설정으로 build1회와 관련 브라우저 검사를 실행합니다.
PUBLIC_CF_WEB_ANALYTICS_TOKEN=00000000000000000000000000000000 PUBLIC_ANALYTICS_ORIGIN=https://analytics.example npm run test:e2e:team-maker -- tests/team-maker-e2e/analytics.spec.js tests/team-maker-e2e/footer.spec.js
# 같은 build가 이미 있다면 재build하지 않습니다.
npm run test:e2e:built -- tests/team-maker-e2e/analytics.spec.js tests/team-maker-e2e/footer.spec.js
브라우저 검사는 모든 외부 요청을 가로채고 Cloudflare 태그를 시험용으로 대체합니다. 태그 연결·수집 제외·안내·도구 동작을 확인하며 Cloudflare 내부 집계를 검증하지 않습니다. 가짜 설정이 없는 build에서는 활성화 검사를 생략하고 PR에서는 실패합니다. 공식 태그의 요청 검증은 수집 주소를 가로채 실제 계정으로 보내지 않고 진행하세요. 운영 집계 완료 여부는 배포 후 Cloudflare 보고서에서 별도로 확인해야 합니다.
오류 화면의 뒤로·앞으로 가기 검사는 문서가 분리되는지도 확인합니다. 공식 태그로 전송 내용까지 검사하려면 공식 CDN에서 내려받은 파일 경로를 지정하세요. 이 검사도 수집 요청은 가로채므로 운영 통계에 기록되지 않습니다. 태그 파일은 저장소에 넣지 않습니다.
curl --fail --silent --show-error https://static.cloudflareinsights.com/beacon.min.js -o /tmp/cloudflare-beacon.js
CF_ANALYTICS_BEACON_PATH=/tmp/cloudflare-beacon.js npm run test:e2e:built -- tests/team-maker-e2e/analytics.spec.js --grep '문서를 공유하지'
공식 근거: 설치, SPA 측정, 집계 기준, 보관·쿼리 제외·제한.
src/routes/+layout.svelte가 공개 페이지의 <head>에 AdSense 코드를 넣습니다. 게시자 ID는 src/lib/data/meta.js의 adsenseClient이며 static/ads.txt와 같아야 합니다. 대상은 방문 통계의 공개 경로(src/lib/analytics/tracker.js의 basePaths와 공개 글)입니다. /privacy(adsenseExcludedPaths), 404·오류 화면, 초안·예약 글과 개발 서버에는 넣지 않습니다. /privacy는 Google CMP 동의 메시지에 연결하므로 광고 코드를 두면 안 됩니다. npm run verify:team-maker가 이 조건을 검사합니다.
승인 전에는 수동 광고 칸을 만들지 않습니다. 승인 뒤 광고 위치는 AdSense의 자동 광고 설정이나 별도 디자인 승인으로 정하세요. 브라우저 검사는 tests/team-maker-e2e/helpers/adsense.js로 AdSense 요청을 막거나 빈 응답으로 바꿉니다.
사이트 등록은 이 GitHub Pages root 도메인을 기준으로 진행하세요. static/ads.txt는 /ads.txt로 배포되므로 root 사이트 전체에 영향을 줍니다.
모든 공개 페이지 footer는 /about(소개·문의)과 /privacy(개인정보처리방침)로 연결합니다. 결정 배경은 ADR과 콘텐츠 점검 기록에 있습니다.
src/routes/privacy/+page.svelte의 방침과 적용일, REQ-WEB-027을 함께 갱신하세요.pub-3102141816876720이 실제 애드센스 계정의 게시자 ID인지 확인하세요. 유럽 등 동의가 필요한 지역의 동의 창은 AdSense의 ‘개인정보 보호 및 메시지’에서 Google CMP로 켜세요.noindex이며 홈 canonical을 포함하지 않습니다. GitHub Pages의 /404 직접 요청은 HTTP 200일 수 있으므로 배포 후 존재하지 않는 주소의 HTTP 404도 확인하세요.공개 주소는 /qr-code, 로컬 주소는 http://localhost:5173/qr-code입니다. 정적 결과는 build/qr-code.html입니다. 홈·공통 메뉴·sitemap에서 연결합니다.
src/routes/qr-code/+page.sveltesrc/routes/qr-code/qr-code.csssrc/lib/qr-code/qr.jslake.qr-code.bookmarks.v1에 최대 30개 저장합니다. 마지막 삭제 1건을 취소할 수 있습니다.npm test는 QR 입력 용량·북마크 복원·다운로드 파일 이름, SUIT 700 제목 윤곽선, SVG 독립 렌더링과 QR 해독도 검사합니다.npm run verify:team-maker는 QR 정적 페이지·검색 정보·sitemap과 광고 미실행도 검사합니다.QR과 Team Maker의 번호가 있는 섹션 제목은 SectionHeader의 step 속성으로 번호 배지를 표시합니다. 배지와 제목 스타일은 공통 ui.css에서 관리합니다. QR 미리보기 배경·캡션·빈 상태는 화면 테마를 따릅니다. 스캔용 QR 사각형과 저장·인쇄 이미지는 흰 바탕과 검정 무늬를 유지합니다. 북마크 X 버튼의 오른쪽 여백은 8px입니다.
한글 조합 중인 마지막 글자도 미리보기에 즉시 표시합니다. 조합 중에는 입력창 값을 그대로 유지하고 조합이 끝나면 10자 제한을 적용합니다. 미리보기와 저장에 사용하는 제목은 조합 중에도 최대 10자입니다.
미리보기 아래 버튼은 PNG·SVG 저장 → 이미지 복사·크게 보기 → 북마크에 저장·인쇄 순서로 2개씩 3줄에 배치합니다. SVG 저장은 보라색입니다. QR과 Team Maker의 제목·설명은 ToolPageHeader, 운영자·개인정보처리방침은 ToolPageFooter를 함께 사용합니다. QR 북마크의 RemoveRowButton은 Team Maker 참가자 삭제와 같은 X 아이콘과 공통 ui.css 스타일을 사용합니다.
미리보기·PNG·SVG 제목은 모두 로컬 SUIT 700을 사용합니다. 미리보기 캡션은 선택·복사할 수 있는 일반 HTML 텍스트입니다. 제목은 1줄이며 기본 글자 크기는 데스크톱 22px, 모바일 20px입니다. 입력값을 즉시 표시하고 좁은 화면에서만 넘치지 않도록 글자를 줄입니다. PNG·SVG는 같은 윤곽선과 배치를 공유합니다. SUIT에 없는 이모지 등의 글자만 미리보기와 PNG에서 시스템 글꼴로 표시하고 SVG 저장은 제한합니다. 로딩 실패 때는 SVG 다시 시도를 제공합니다.
주소를 수정하면 200ms 뒤 QR 무늬를 갱신하고, 제목을 수정하면 제목의 지원 여부와 배치만 갱신합니다. 최종 이미지는 PNG·SVG 저장 버튼을 눌렀을 때 해당 형식만 만듭니다. 복사는 클릭 시, 인쇄는 설정 창의 인쇄하기 클릭 시 PNG를 만들고 크게 보기는 미리보기를 재사용합니다. 출력 도중 입력이 바뀌어도 파일과 이름은 클릭 당시 내용을 유지합니다.
미리보기 QR은 최대 280px입니다. 캡션 영역은 데스크톱 48px·모바일 44px이며 짧거나 빈 제목에도 같은 높이를 유지합니다. 제목은 가로·세로 가운데에 배치합니다. 빈 상태에서는 위쪽 정사각형에 SVG 아이콘만, 아래쪽 캡션에 ‘QR 코드가 여기에 나타납니다’만 각각 가운데 표시합니다. 주소 입력 요청 문구와 60자 측정용 문단은 제거했습니다. 데스크톱에서는 입력·북마크 열과 미리보기 카드의 높이를 맞춥니다. 북마크 목록은 남은 공간에서 스크롤하며 모바일에서는 세로로 배치합니다. 입력 하단 안내·입력 지우기·상시 상태 문구·북마크 저장 위치 배지는 표시하지 않습니다. qr-feedback의 고정 공간도 없으며 저장·복사 실패와 SVG 안내를 필요한 경우에만 작업 버튼 아래에 표시합니다. 오류가 나타나면 카드 높이가 늘어날 수 있습니다. 처리 중인 버튼에는 aria-busy를 적용합니다.
저장·복사·인쇄 출력은 너비 1,024px, QR 영역 768px, 위쪽 여백 32px입니다. 제목은 64px·최대 너비 896px의 1줄이며 QR 아래 32px를 띄운 높이 88px 영역의 정가운데에 배치합니다. PNG·SVG는 글자의 실제 윤곽선 경계로 위치를 계산하며 미지원 글자의 PNG도 실제 글자 경계로 가운데 맞춥니다. 제목이 있으면 파일 높이는 952px입니다. 제목이 없으면 높이는 832px입니다.
인쇄 버튼은 공용 Dialog로 배열 선택 창을 엽니다. A4 세로 1장에 현재 QR과 제목을 1열×1행(기본 1개), 3열×4행(12개), 5열×6행(30개)으로 반복합니다. 선택은 페이지를 떠나기 전까지 유지합니다. 설정을 열거나 배열을 바꿀 때는 이미지를 생성하지 않습니다. 인쇄하기를 누른 순간의 내용을 PNG로 한 번 생성하고 모든 칸에서 재사용합니다. 준비 실패는 선택 창에서 알리며 취소한 작업이 나중에 인쇄 창을 열지 않도록 처리합니다.
인쇄 여백은 10mm, 칸 간격은 4mm, 영역은 190mm×276mm입니다. 각 인쇄 칸 전체에는 검정 실선 0.2mm와 내부 여백 2mm를 적용합니다. 테두리와 여백은 칸 크기에 포함하며 다운로드 파일에는 테두리가 없습니다. 이미지는 비율을 유지해 칸 가운데 맞추며 1개 인쇄의 최대 너비는 140mm입니다. PDF 검증은 A4·배율 100%·머리글/바닥글 없음으로 실행합니다. 실제 프린터의 용지와 배율은 브라우저 인쇄 창에서 조정하세요.
fontkit의 WOFF2 가변 글꼴 오류를 피하기 위해 Vite 설정에서 scripts/prepare_qr_font.js를 실행합니다. 기존 SUIT WOFF2를 .svelte-kit/qr-font/SUIT-Variable.ttf로 풀며 글꼴 내용은 바꾸지 않습니다. 이 생성 파일은 Git에 추가하지 않습니다. 개발 서버와 build에서 자동 생성합니다. 글꼴 원본을 바꾸면 개발 서버를 다시 시작하세요.
src/lib/qr-code/title.js는 제목 준비·지원 검사, title-input.js는 10자 입력·복원 검증, title-layout.js는 한 줄 제목 상태, image-layout.js는 출력 크기·좌표, title-outline.js는 SUIT 윤곽선, font-loader.js는 지연 로딩·캐시·재시도를 담당합니다. QrPreview.svelte는 QR 경로와 제목 문자열을 따로 받습니다. createQrImage(qrPath, preparedTitle, format)은 준비된 상태로 선택한 형식의 Blob만 반환하며 QR을 다시 계산하지 않습니다. QR 안내와 Team Maker 하단 안내의 접기·펼치기 디자인은 공통 ui.css에서 관리합니다. 기본 마커를 숨기고 CSS 삼각형과 제목을 세로 가운데 맞추며 간격은 12px입니다.
공개 주소는 /bracket, 로컬 주소는 http://localhost:5173/bracket입니다. 정적 결과는 build/bracket.html입니다. 홈·공통 메뉴·sitemap에서 연결하고, Team Maker 결과의 ‘대진표 만들기’ 버튼으로도 들어옵니다. 요구사항은 REQ-BRACKET, 화면은 SCR-WEB-008을 따릅니다.
src/routes/bracket/+page.sveltesrc/routes/bracket/bracket.csssrc/lib/bracket/bracket.jssrc/lib/bracket/teams.jssrc/lib/bracket/components/BracketTeamsSection.sveltesrc/lib/bracket/storage.jssrc/lib/bracket/layout.jssrc/lib/bracket/components/lake.bracket.v1에 입력 중인 팀 목록과 대진표 1개를 저장합니다. 변경 200ms 뒤 저장하고, 화면을 떠나거나 숨길 때 남은 변경을 바로 저장합니다. 저장 값이 손상되면 안내하고 새로 시작합니다.tests/team-maker-e2e/bracket.spec.js, 단위 테스트는 tests/bracket/에 있습니다.허브 주소는 /aram-mayhem, 챔피언 공략은 /aram-mayhem/챔피언id(예: /aram-mayhem/master-yi), 증강 공략은 /aram-mayhem/augments/증강id(예: /aram-mayhem/augments/armored-impact)입니다. 로컬 주소는 http://localhost:5173/aram-mayhem입니다. 정적 결과는 build/aram-mayhem.html, build/aram-mayhem/챔피언id.html, build/aram-mayhem/augments/증강id.html입니다. 홈·소개·공통 메뉴에서 허브로 연결하고, sitemap에는 허브와 챔피언·증강 공략을 모두 넣습니다. 요구사항은 REQ-ARAM, 화면은 SCR-WEB-009, 결정은 가이드 추가 ADR과 챔피언별 주소 ADR, 증강별 공략 ADR을 따릅니다.
docs/research/aram-mayhem/의 JSON. 조합은 champions.json, 빌드는 builds.json, 증강 빌드 운영 방법은 build-play.json, 신발은 boots.json, 추가 추천 증강은 champ-extras.json, 디시 글 정보는 community-posts.json, 챔피언 없이 정리한 증강 공략은 augment-guides.json, 챔피언·증강·아이템 별명은 aliases.json에서 고칩니다.npm run generate:aram-mayhem을 실행하면 src/lib/aram-mayhem/guide-data.json과 static/images/aram-mayhem/이 다시 만들어집니다. 두 결과를 함께 commit합니다. 내려받은 원본은 .cache/aram-mayhem에 남고 Git에서 제외합니다. 찾지 못한 챔피언·증강·아이템이 있으면 생성이 실패합니다.DDRAGON_VERSION(현재 16.21.1)으로 Data Dragon을, 그 앞 두 자리(16.21)로 CommunityDragon을 고정합니다. 패치가 바뀌면 이 값도 함께 고칩니다.Q·W·E·R, 키만 보이려면 [E]), 증강·아이템 이름, 스킬 가속·방어구 관통력·마법 관통력, 모루가 자동으로 타일이 됩니다. 스킬 이름 뒤 조사는 생성할 때 받침에 맞춥니다. 나누기 규칙은 src/lib/aram-mayhem/text.js입니다.aliases.json의 챔피언 목록은 Data Dragon의 한국어 챔피언 전체(현재 173명)와 같아야 합니다. 가이드에 없는 챔피언도 미리 넣고, 별명이 없으면 빈 배열로 둡니다. 띄어쓰기만 다른 이름은 검색창이 자동으로 찾으므로 넣지 않습니다. 빠지거나 틀린 이름이 있으면 생성이 실패합니다.src/lib/aram-mayhem/seo.js가 페이지 제목·검색 설명·구조화 데이터를 데이터에서 만듭니다. 챔피언 제목 예: 증바람 마스터 이(마이) 공략. 증강·템트리·패치는 검색 설명에 넣습니다. 증강 공략을 만들 증강과 허브 링크의 한 줄 소개는 AUGMENT_PAGE_HOOKS에서 고릅니다. 챔피언 조합 없이 1코어만 추천하는 증강(운명의 무기)과 증강의 다른 템트리(장갑 충격의 쇠사슬 조끼 6개)는 augment-guides.json에 적습니다. 다른 템트리는 그 증강 빌드가 있는 챔피언 공략에도 탭으로 붙습니다. 이 페이지는 출처를 보여 주지 않습니다. FAQPage 구조화 데이터는 쓰지 않습니다.src/routes/aram-mayhem/+page.svelte(허브·챔피언 타일·예전 #챔피언id 주소 이동), src/routes/aram-mayhem/[champion]/(챔피언 공략·검색창), src/routes/aram-mayhem/augments/[augment]/(증강 공략), aram-mayhem.css(스타일), src/lib/aram-mayhem/guide.js(이름·별명·초성 검색, 빌드 비교, 허브 타일 줄임말 TILE_NAMES), src/lib/aram-mayhem/components/(고르기·검색 버튼과 검색 창·빌드·조합 카드)evidence에만 둡니다.공개 주소는 /marble-race, 정적 결과는 build/marble-race.html이다.
*2를 붙인5줄로 총10명이며 저장된 명단은 유지한다. 최소 구슬 수는2개다. 고정 참가 상한 없이 토끼*10을 지원한다. 같은 이름도 고유 번호로 별도 당첨된다. 게임의 당첨 인원 단위는 명으로 표시한다.max(4, round(12 × √(전체 구슬 수 / 30)))로 정한다.2/10/30/60개 경기의 전체 일반 블록은320/560/960/1360개다. 준비 화면도 전체 인원으로 높이를 계산하며200ms 입력 묶음을 사용한다.일반 블록과 크랙 왁스의 재생성을 비활성화한다. 파괴된 자리는 경기 종료까지 비어 있고 복구 예고 윤곽도 표시하지 않는다. 새 경기에서는 블록을 다시 채운다. 교차 배치·둥근 모서리·재질별 물리는 유지한다.max(1, round(5 × sqrt(구슬 수 / 30)))이다.2/30/60/1000개 경기에서는 각각1/5/7/29회다. 독립 충돌마다 파괴 전부터 소리를 내며 납작해지고, 파괴된 뒤에는 재생성하지 않는다. 젤리 연못은 같은 높이에 좌·중앙·우3개로 나눈다. 각 연못은 폭152·깊이140이며, 사이에 폭120의 우회로2개를 둔다. 연못에 들어간 구슬만 저항과 진입음을 받는다.| 맵·ID | 일반 재질 순서 |
|---|---|
도각도각 키보드 · keyboard | 도각1 → 도각2 → 도각3 → 도각4 |
톡톡 나무공방 · crunch | 나무 → 코르크 → 도각 키보드1 → 뽁뽁이 |
뽁뽁 물놀이 · soft | 물방울 → 개구리 → 오리 → 팝잇 |
화면 조립은 src/routes/marble-race/+page.svelte, 설정은 settings.js, 맵·재질은 catalog.js, 물리는 physics.js, Worker 연결·증분 전송은 worker-client.js·race-worker.js·transport.js, 결승 연출은 director.js, 카메라·표시 보간·그림·음향은 camera.js·presentation.js·renderer.js·audio.js가 담당한다. 200개 이상 실제 경기의 그림은 display-renderer.js·render-worker.js가 별도 Worker에서 만들며, 준비 화면·작은 경기·미지원 브라우저는 기존 Canvas 방식을 사용한다. 준비 목록의 지연 생성은 preview-order.js가 담당한다. 경기와 순위 카드의 번호 구슬은 marble-painter.js를 공유한다. 새 재사용 화면은 src/lib/marble-race/components/에 있다. 도감 이미지는 게임과 같은 tile-painter.js를 쓴다.
이전 결승 원호·겹침 보정·전체 준비 화면의 결정과1000개 성능 분석은 파동·결승 접촉·전체 미리보기 ADR에 기록했다.이전32회 보정의60개 밀집 검사에서는 겹침1 이하를 확인했지만, 당시1회 보정은 같은 한도를 보장하지 못했다.1000개를 결승에 모은 시험에서는 반복 접촉 계산으로 실제 경기 진행이 느려진다. 화면fps와 물리 상태 갱신·실제 경기 진행 속도를 함께 평가한다. 이전20° 벽·순위6열·전기 그림 재사용은 스킬 그림 비용과 완만한 결승 ADR을 따른다. 이후 회전축의 왼쪽 이동과 스킬음 음량 절반 조정은 왼쪽 회전바와 스킬음 ADR을 따른다.
기존 설정 키 lake.marble-race.v1과 맵 별칭을 유지한다. 내 맵은 lake.marble-race.custom-maps.v1에 저장하며 처음 방문하거나 손상·삭제된 맵을 참조하면 도각도각 키보드로 시작한다. 유효한 기존 맵 선택은 유지한다. 서버로 참가자 정보를 보내지 않는다.
npm run test:marble-race는 입력·저장·특수 장치·복구·충돌·Worker 동일성·90경기 완주를 검사한다. node scripts/measure_marble_race.js는 구간별 분포와 우승 편향을 비교할 원시 데이터를 출력한다. --large는 필요할 때만 수동 실행하며2/30/60/100/300/1,000개 경기를600초까지 관측한다. 기본 검사에는 포함하지 않는다. 기본3개 맵·2/30/60개·난수10개는120경기초 내 완주해야 한다. 결승15초는 별도 목표로 초과 횟수·최댓값을 계속 기록한다. 결승 입구60개 밀집은 시작 각도4가지에서60경기초 내 전원 완주하고, 출구 앞에 대기 구슬이 있는데8.8경기초 동안 도착이 없으면 배출 정체로 실패한다. 기존 밀집30초 초과 인원도 기록한다.1,000개 전원 완주 자동 검사는 실행 시간이 길어 삭제했다. 빠른 입력·전송량 검사와5초간의 화면 응답·순위 목록 부분 렌더링 검사는 유지한다. 변경 이유는 장시간 완주 테스트 삭제 ADR을 따른다. 시간 기준 변경을 속도 개선으로 표시하지 않는다. 이전60초 목표의 실패는 새 목표의 결과와 구분한다. 결승 구조를 유지한 시간 기준과 전송량 측정은 결승 대기·증분 전송 ADR에 기록한다.
화면 검사는 npx playwright test tests/team-maker-e2e/marble-race.spec.js tests/team-maker-e2e/marble-expansion.spec.js를 사용한다. 첫 출력 전용 검사는 playwright.marble-audio.config.js를 따른다. 측정 환경과 실제 결과는 새 결정 기록에 남긴다. 음원 출처와 프로젝트 MIT 라이선스는 구분한다. 이전 음원과 ADR은 보존한다.
음원 제작 도구·상세 작업 기록·청음 후보는 .context/에만 보관한다. 공개 저장소에는 사용 음원과 파일명, 원음 출처·제작자·라이선스·파일 해시 및 게임 재생 코드를 관리한다.
도각2는 기존 도각3의 두 파일(thock3-v3-1.wav·thock3-v3-2.wav)을 A→B 순서로 번갈아 재생한다. 도각3은 기존 도각2 단음(thock2-v1.wav), 도각4는 이전 도각3 단음(thock3-v2.wav)을 사용한다. 도각1을 포함한 일반 재질별 한도는3개이며 전체 동시6개 한도를 함께 적용한다. 전체 소리 합계는6개까지 허용하며 미리듣기·특수 장치·팡파레도 같은 한도를 공유한다. 최소 시작 간격28ms·기존 음량·특수 장치 제한을 유지한다.
도각 키보드2·3은 도감과 커스텀 맵에서 사용할 수 있다. 저장한 커스텀 맵의 타자기 구역은 도각 키보드2로 자동 연결하며 명단·맵 이름·구역 순서는 보존한다.
찰칵 키보드는 도감·커스텀 맵 선택과 음원 목록에서 제거한다. 관련 음원과 선택 JSON은 배포하지 않는다.
불씨는 일반 도감과 커스텀 맵 선택에서 비활성화한다. 나무공방의 찰칵 자리와 저장된 커스텀 맵의 불씨·찰칵 자리는 도각 키보드1로 연결한다. 기존 맵 이름·명단·나머지 구역은 보존한다.
맵 선택은 아이콘·한 줄 이름·선택 표시로 구성하며 목록 아래 설명은 표시하지 않는다. 종료 뒤 맵을 바꾸거나 선택된 커스텀 맵을 수정·삭제하면 새 맵의 준비 화면으로 돌아간다. 명단·당첨 방식·음량은 유지한다. 일반11종 뒤에 얼음 경사판·크랙 왁스·젤리 연못을 같은 도감에서 제공하며 특수 장치도 실제 경기 그림을 공유한다.
미니맵은100×300px(모바일64×220px)이다. 마우스를 올리거나 터치하는 동안 탐색하며 이탈·해제 시 자동 추적으로 복귀한다. 방향키·Home·End 탐색과 Escape·포커스 이탈 복귀도 지원한다. 준비·일시정지·종료에서도 사용할 수 있고 결승 배속·판정은 계속 유지된다. 순위는 A안 레이스 티켓을 적용한2·4·6열 카드이며 보이는 행만 그린다. 상단 띠에 등수와 진행률 또는 도착 상태를 표시한다. 본문에는36px 번호 구슬과 이름을 세로로 묶어 가로·세로 중앙에 배치한다. 이름은 화면에서 읽히는 글자8개까지 표시하고 초과하면 점3개(...)를 붙인다. 결합 이모지는 한 글자로 센다. 전체 이름은 title·접근성 이름·검색·결과 복사에 유지한다. 구슬 색을 반영한 상단 띠와 하단 진행 막대를 사용하며 선택한 카드에는 테두리와 추적 표시를 둔다. 별도 번호 줄은 없다. 준비 화면은 전체 구슬을 Worker에서 나누어 생성하며 실제 출발과 같은 번호·색·위치를 사용한다. 현재 배율에서 화면 이동·미니맵으로 전체 구슬을 확인한다. 큰 미리보기는 명단 변경·자리섞기·경기 시작 시 취소한다. 순위 명단은 전체를 스크롤·검색하며 필요한 카드만 만든다. 검색·카드 추적·전체 결과 복사는 유지한다. 직접 추적한 구슬은 검색 중에도 맨 위 왼쪽 첫 카드에 표시하며 실제 등수와 결과 복사 순서는 유지한다.
node scripts/measure_marble_balance.js는3개 맵×2/10/20/30/60/100개×난수10개의180경기를 비교한다. --large는 필요할 때만 수동 실행하며300/1000개를 각 맵에서600경기초까지 관측한다. 첫번째·여러명3명·n번째(중간 순번)·마지막을 기록한다. 배속을 반영한 계산상 재생 시간과 CPU 실행 시간을 구분하며 실제 브라우저 시간을 대신하지 않는다. 최신 결과와 남은 한계는 화면·경기 길이·음향 개선 ADR을 따른다.
여러명 당첨은 시작·끝 숫자 입력창2개로 도착 순위 범위를 지정한다. 시작4·끝6이면 4~6이며 가운데 ~는 입력하지 않는다. 이 경우4·5·6번째만 당첨되고 범위 앞 순위는 축하하지 않는다. 6~6도 허용한다. 이전 여러명 인원 설정은 1~인원으로 복구하며 범위는 기존 설정 키의 rangeText에 저장한다. 내부 multiple ID는 유지한다.
화면 이름은 ASMR 구슬 레이스, 검색 제목은 ASMR 구슬 레이스 | 이름 적힌 구슬로 뽑는 무료 추첨 도구다. 다른 서비스명 제거 결정을 따른다.
검색 설명·공유 정보·구조화 데이터와 가이드 내용은 src/lib/marble-race/page-content.js에서 관리한다. RaceGuide.svelte는 공용 DisclosureSection으로 사용법·당첨 방식·수업/방송 활용·FAQ를 표시한다.
화면 소개·홈 카드·사용법·FAQ에 이름이 적힌 구슬을 굴려 도착 순서로 당첨자를 정하는 용도를 설명한다. 다른 서비스 이름을 검색어로 쓰지 않으며 npm run verify:team-maker가 홈과 구슬 레이스 HTML에서 확인한다. 앱 이름과 제작자 정보는 유지한다. 가이드는 JavaScript 실행 전의 정적 HTML에 포함한다. robots와 sitemap의 기존 공개 경로를 유지하며 검색·AI 답변에 노출될 순위나 시점은 보장하지 않는다.
공유 이미지는 scripts/generate_site_assets.js에서 생성한다. 변경 뒤 npm run generate:assets와 build 검증을 실행한다.
화면 읽기용 경기·당첨 안내는 경기장 내부에 둔다. .marble-page .sr-only가 적용되어 화면에는 숨겨지고 전체화면에서도 읽을 수 있다.
도감은 BlockLibrary.svelte에서 공용 Section 카드로 제공한다. 기본12종과 특수3종을 구분하고 선택 맵의 기본 블록에는 라벨을 붙인다. 설명은 한 줄이며 크랙 왁스의 충돌 횟수도 같은 줄에 표시한다.
홈 카드와 공통 드로워의 프로젝트 순서는 팀 메이커 → 대진표 → ASMR 구슬 레이스 → QR 코드다. 홈 아이콘은 팀 메이커 청록색·대진표 주황색·구슬 레이스 파란색·QR 코드 보라색 배경과 흰 선을 사용하고, 드로워 아이콘은 밝은 테마에서 검은색 계열·어두운 테마에서 밝은 단색을 사용한다.
출발 구슬은 한 줄에 최대26개를 같은 높이에 배치하고 초과 인원은 다음 줄로 이어진다. 배속 버튼 오른쪽의 자리섞기는 출발 준비 중에만 사용할 수 있다. 명단과 설정은 유지하고 출발 위치를 다시 섞는다. 미리보기와 실제 출발은 같은 난수를 사용하며 전체 미리보기의 구슬 자리는 실제 경기와 같다. 자리 난수는 저장하지 않는다.
출발 준비 화면에서 배속·자리섞기 옆의 스킬 사용 ON/OFF를 선택한다. 상태 글자의 공간을 고정해 ON/OFF 전환 시 버튼 크기를 유지한다. 기본은 ON이고 경기·일시정지·준비 로딩 중에는 변경할 수 없다. 경기 시작 시 Worker에 설정을 확정하며 진행 요청으로는 바꾸지 않는다. 선택한 상태는 기존 localStorage 설정의 skillsEnabled에 저장하고 다음 방문에 복원한다. 이전 설정에 항목이 없거나 올바른 불리언 값이 아니면 ON으로 시작하며 저장된 OFF는 유지한다. ON이면 경기2초 이후 구슬마다 기본 발동률0.005(초당 약0.5%)로 스킬을 사용한다. 발동할 때 파동·번개·바람 중 하나를 같은 확률로 고르며 구슬별8경기초 대기 시간을 공유한다. 파동의 반경은180이다. 가까운 구슬에 더 큰 바깥 방향 속도를 주며 발사자·도착·동결 구슬은 제외한다. 기본 밀어내는 힘은780이고, 피격 뒤0.65경기초 동안 수평 감쇠를1.5에서0.6으로 줄이며 수평 속도 한도1000·하강 한도900을 적용해 더 멀리 날아가게 한다. 이후 기존 한도로 돌아간다. 위치를 옮기지 않고 기존 벽·블록 충돌을 유지한다. 파동은0.45경기초 동안 표시하고 동작 줄이기에서는 확대 없이 옅은 원으로 표시한다. 경기 시간과 별도 난수를 사용해0.25·1·2배속의 같은 경기 시각 결과를 유지한다. 번개는 반경240 안에서 가장 가까운 상대를 겨냥하고 없으면 경기 전체에서 유효한 상대 하나를 같은 확률로 고른다. 시전자·도착·고정 구슬을 제외하며 전체에도 대상이 없으면 발동과 대기 시간을 만들지 않는다. 대상 선택에는 스킬 전용 난수를 사용한다. 번개는 노란 빛과 밝은 중심선, 불규칙한 잔가지와 낙뢰 지점의 불꽃으로 표시한다. 경기장 상단에서 대상 위치까지 폭32의 번개를0.35경기초 표시하며 공의 반지름을 포함해 발동 순간 한 번 피격을 판정한다. 번개에 닿은 구슬은 속도를0으로 만들고2경기초 제자리에 고정한다. 흰 전기 고리와 전기선을 표시하고 충돌·정체 해소로 움직이지 않으며 해제 뒤 중력으로 움직인다. 바람은 좁은 뿌리에서 위로 넓어지는 어두운 회색 토네이도로 표시한다. 겹쳐진 나선과 가는 연기 곡선이 회전하며 위로 솟아오른다. 동작 줄이기에서는 상승·회전 없이 고정된 토네이도를 표시한다. 바람은 시전 위치의 공 아래에 폭120·높이240으로1경기초 남고 다른 공을 초당650의 초기 속도로 위로 날린다. 같은 바람은 공마다 한 번만 작용하며 도착·고정 구슬을 제외한다. 벽과 블록 충돌을 유지한다. 동작 줄이기에서는 번쩍임과 빠른 이동 효과를 줄인다.
도감 제목은 도감으로 표시하고 기본 블록·특수 블록 아래에 스킬 영역을 둔다. 파동·번개·바람3종은 같은 카드·그리드와 소리 미리듣기를 제공한다. 파동은 경기 그림을 사용하고 번개·바람은 구슬 없는 번개 모양·바람 모양 아이콘을 사용한다. 스킬 발동 순간에만 해당 효과음을 한 번 내며 표시 중 반복하지 않는다. 스킬 ON일 때 경기 준비·재개·음소거 해제에서 음원을 준비한다. 미리듣기와 경기에서 파동 pulse-whoosh-deep-v2.wav·번개 lightning-v1.wav·바람 gust-v1.wav를 공유하며 음정·속도는 배속과 무관하다. 스킬음은 같은 종류를 포함해 보이는 발동마다 한 번씩 모두 재생한다. 동시 재생 수·재생 간격·한 프레임의 선택 제한을 적용하지 않는다. 일반 음향의 동시6개·최소28ms 제한에서도 제외한다. 실제 경기 화면과 파동의 원·번개의 세로 줄기·바람의 상승 범위가 겹칠 때 재생한다. 기존 음향 높이800 제한이나 화면 밖52의 감쇠는 스킬에 적용하지 않는다. 카메라 이동으로 효과 범위가 완전히 화면 밖으로 벗어나면 재생 중인 스킬음을12ms에 걸쳐 줄여 끈다. 지나간 발동은 화면에 다시 들어와도 재생하지 않는다. 미리듣기는 카메라 범위와 무관하며 스킬음 개수·간격 제한도 없다. 음소거·볼륨·일시정지·종료 정리는 유지한다. 일반 충돌음·장치음·축하음은 기존 제한을 유지하며 스킬음과 재생 자리를 공유하지 않는다.
결승 겹침은1/120초 물리 단계가 끝날 때 연결된 구슬 묶음과 벽·회전바를 함께 보정한다. 결승에 들어간 구슬과 연결된 이웃을 대상으로 하며 회전바 접촉이 없어도 검사한다.0.1초 대기는 제거한다. 미도착 구슬이64개를 넘으면 벽 보정 뒤 실제 남은 겹침이0.5 이하인지 확인해 조기 종료한다.64개 이하는 기존 보정 중 오차0.15 기준을 유지한다. 최대512차례와 실제·표시 겹침1 이하 검사 기준은 유지한다. 위치·속도 숫자 배열과 가까운 쌍·연결 정보·벽 후보를 재사용하며 이동량이 탐색 여유의 절반을 넘으면 후보를 다시 찾는다. 서로 파고드는 상대 속도만 제거하고 반발·효과음·스킬은 반복 적용하지 않는다. 보정 후 중앙 통로 진입과 골인을 판정한다. 회전바의 압력은 연결된 번개 구슬에도 전달하되 정지 시간과 자체 속도0을 유지한다. 얼음 고정과 도착 구슬은 이동시키지 않는다. 화면 보간도 같은 접촉 보정을 쓰며 실제 위치·속도·고정 기록·순위는 바꾸지 않는다. 200개 이상 경기의 결승에서는 기본 충돌이 반발 속도를 처리하고 단계 끝의 연결 접촉 처리가 위치 보정을 맡아 중복 벽 탐색을 줄인다. 200개 이상 경기의 내부 이동 분할 상한은 출발부터8을 사용하고199개 이하는4를 유지한다. 반지름13보다 작게 유지하며 기본1/120초 물리 간격과 빠른 이동의 추가 분할은 그대로다. 2026-09-26 사용자 승인에 따라 큰 경기의 기존 난수 경로·당첨 결과는 달라질 수 있으나 같은 경기 시각의 배속별 결과는 같아야 한다. 블록 각도·크기와 구슬 주변 격자 범위를 재사용하고 회전·크기·격자·경기 변경 시 다시 계산한다. Worker 내부 시계가 경기 시간을 누적하고 화면의 수신 확인 없이 기본12ms 또는8물리 단계씩 계산을 이어간다. 계산할 시간이 남으면 MessageChannel로 다음 처리를 예약한다. 화면 수신 확인은 일반 상태1개만 대기하게 제한하며 충돌·스킬 이벤트는 다음 상태에 모아 보존한다. 정지는 최종 상태를 요청 번호로 확인하고, 재개는 그 응답 뒤 진행한다. 배속 전환 전후의 시간과 정지 전 잔여 시간을 보존한다. 새로 지난 시간과 잔여 시간을 모두 보존하며80ms를 넘는 화면 지연도 버리지 않는다. 한 물리 단계의 계산이12ms를 넘을 수 있으므로 응답 시간의 상한을 보장하지는 않는다. Worker의 현재 결정은 화면 응답과 독립적인 Worker 계산을 따른다. 출발 이동 분할은 대규모 경기의 이동 분할 조정을 따른다. 보정1회와 성능·겹침의 차이는 결승 추가 보정1회에 기록했다. 현재 보정은 결승 연결 접촉과 보간 겹침 해소와 결승 보정 조기 종료와 충돌 탐색 재사용을 따른다.
이전 회전축 이동과 추가 보정 대상은 회전바 주변 보정과 왼쪽 위 이동을 따른다.
번개 정지 중에도 결승 회전바는 구슬을 밀어낸다. 남은 정지 시간과 전기 효과는 유지하고, 바가 떨어지면 옮겨진 위치에서 멈춘다. 번개가 풀리면 새 위치에서 낙하한다. 얼음판 고정에는 이 예외를 적용하지 않는다.
도착 순위에서 추적 중인 카드를 다시 클릭하면 추적을 해제하고 자동 따라가기로 돌아간다. Enter·Space도 같은 방식으로 동작한다.
결승 경사30°와 회전 주기13.2경기초의 결정·완주 시험은 결승 경사30°와 회전 감속에 기록했다.
오른쪽 경사를20°로 되돌린 결정은 오른쪽 결승 경사를20°로 복원에 기록했다.
구슬 충돌 격자·탐색 후보·이전 위치를 재사용하고 물리 계산 요청을 화면 갱신과 분리한다. 결승 벽 관통 수정 외에는 같은 난수의 실제 경기 결과를 유지한다.1000개 성능 검사는 화면 그리기 횟수와 실효 배속을 함께 확인한다. 자세한 결정은 대규모 경기 계산과 화면 주기 분리를 따른다.
화면 상태는 최대60회/초로 묶되 물리 계산은 계속 처리한다. 결승 밀집 보정의 이동 경로도 벽 충돌로 검사하고, 중앙 입구를 지난 구슬만 골인을 인정한다. 표시 보간도 둥근 통로 모서리를 가로지르지 않게 한다. 상태 전달60회와 결승 벽 통과 방지에 결정과 검증 범위를 기록했다.
현재 회전축과 경사는 회전축 x160과 통로 밖 반동을 따른다. 바 길이는448이며, 연장 범위와 마지막 구슬 완주 검증은 회전바 길이448로 연장에 기록했다. 최신 충돌 계산 최적화와 측정 한계는 구슬 충돌 이웃 재사용과 결승 계산 비용 축소를 따른다.
홈의 둘러보기 맨 위에서 블로그로 이동할 수 있습니다. 블로그 아이콘은 회색빛 파란색 배경으로 구분합니다. 소개 바로 아래의 최신 블로그 글에는 공개 글을 게시일 내림차순으로 최대9개 표시합니다. 제목은 모두 표시하고 요약은 최대2줄로 줄입니다. 같은 날짜는 slug순으로 정렬합니다. 제목·요약·종류·게시일과 전체 글 링크를 제공하며, 공개 글이 없으면 준비 안내를 표시합니다. 새 글을 공개하고 다시 build·배포하면 홈 목록도 갱신됩니다.
블로그 목록은 /blog, 글 상세는 /blog/<slug>, 구독 주소는 /rss.xml입니다. 마지막 슬래시는 사용하지 않습니다. 정적 결과는 build/blog.html, build/blog/<slug>.html, build/rss.xml입니다. SvelteKit의 페이지 이동용 __data.json도 글 목록·상세·도구별 폴더에 생성됩니다. 도구 HTML은 기존처럼 build/team-maker.html 등의 형태를 유지합니다. 기존 도구와 블로그 목록·공개 글을 같은 sitemap에 포함합니다.
글은 content/blog/*.md에 작성합니다. 저장소 파일을 서버 전용 코드가 build할 때 읽으므로 운영 서버와 관리자 화면은 필요하지 않습니다. markdown-it과 yaml은 글을 해석하는 개발 의존성이며 브라우저에 포함하지 않습니다. 프로그램 이름과 사용 주소, 글 주제, 작성자는 src/lib/blog/catalog.js, 검증과 본문 변환은 src/lib/server/blog.js에서 관리합니다.
content/blog/team-maker-introduction.md를 참고해 새 파일을 만듭니다. 기존 공개 글을 복사했다면 먼저 published: false로 바꾸세요.## 제목부터 시작합니다.npm run dev를 실행하고 /blog의 ‘로컬 초안 미리보기’에서 확인합니다. 저장 후 새로고침하면 변경 내용이 반영됩니다.published: true로 바꾸고 관련 검사를 실행합니다.main에 merge하면 GitHub Pages에 게시됩니다. 에이전트는 별도 요청 없이 PR을 merge하거나 외부에 게시하지 않습니다.---
slug: team-maker-introduction
# slug는 주소에 사용하는 고유 이름입니다. 제목을 바꿔도 유지하세요.
title: '팀 메이커: 참가자를 여러 팀으로 나누기'
summary: '이름을 입력하고 배정 규칙을 설정해 모임의 팀을 만드는 방법입니다.'
program: team-maker
category: introduction
publishedAt: '2026-09-29'
published: false
# 실제 본문을 수정한 날에만 추가합니다.
# updatedAt: '2026-09-30'
# image: /images/blog/team-maker-guide.png
# imageAlt: '참가자10명을3팀으로 나눈 결과'
---
블로그는 도구 사용법과 파일·이미지·데이터 문제 해결 가이드를 다룹니다. program은 선택 항목입니다. 관련 프로그램이 있을 때만 team-maker, qr-code, marble-race, bracket 중 하나를 지정하세요. category는 글의 주제입니다. introduction(도구 소개), tool(도구 활용), image(이미지·사진), data(데이터·텍스트), file(파일·링크) 중 하나를 고르세요. 프로그램과 관계없는 가이드는 program을 생략하고 다루는 대상에 맞는 주제를 지정합니다. 주제를 나눈 이유는 AdSense 재심사 결정에 있습니다. 작성자는 현재 사이트 운영자인 Lake를 공통으로 사용합니다. 기능 변경을 알리는 글에는 실제 적용일 releaseDate: '2026-09-29'와 존재하는 버전 version: '1.2.0'을 선택적으로 넣을 수 있습니다. 버전이 없다면 생략하세요.
날짜는 따옴표로 감싼 YYYY-MM-DD 형식이며 한국 시간 자정을 기준으로 판정합니다. published: true는 공개 승인, publishedAt은 공개일입니다. 미래 날짜라면 예약 상태로 두었다가 공개일 이후 build부터 포함합니다. published: false는 날짜가 지나도 초안입니다. 수정일은 게시일보다 빠를 수 없고 실제 수정일만 작성합니다. build가 날짜를 덮어쓰지 않습니다.
공개할 준비가 된 글에 서로 다른 publishedAt과 published: true를 설정하세요. 다음 예는 2026년10월7일 한국 시간 자정 이후의 build부터 공개합니다.
publishedAt: '2026-10-07'
published: true
.github/workflows/pages.yml이 매일 한국 시간 00시17분(UTC 15시17분)에 main을 다시 build하고 검증·배포합니다. 별도 서버·비밀 키·외부 예약 서비스는 필요하지 않습니다. 변경 사항이 기본 branch인 main에 반영돼 있고 GitHub Actions와 Pages가 활성화돼 있어야 작동합니다. 로컬의 예약 설정만으로 운영 사이트가 바뀌지는 않습니다.
GitHub Actions는 실행이 지연되거나 누락될 수 있습니다. 실제 공개 시점은 해당 날짜 이후 성공한 배포가 끝난 때입니다. 실패하면 다음 정기 실행 또는 Actions의 수동 실행으로 다시 배포할 수 있습니다. 공개일이 지난 예약 글은 다음 성공한 build에서 함께 공개되며, 원문의 공개일을 바꾸지는 않습니다. 공개 저장소에서 60일간 활동이 없으면 예약 workflow가 비활성화될 수 있으므로 장기 운영 시 Actions 상태를 확인하세요. GitHub 예약 실행 안내
미래 예약 글은 목록·홈 최신 글·관련 글·본문 경로·클라이언트 데이터·RSS·sitemap에서 제외합니다. 개발 서버에서는 ‘로컬 초안·예약 미리보기’에서 날짜와 내용을 확인할 수 있습니다. 예약을 취소하려면 published: false로 바꾸고 다시 반영하세요. 이미 배포된 글을 되돌리는 경우에는 변경을 배포한 뒤에야 운영 사이트에서 내려갑니다.
published는 반드시 true 또는 false로 적습니다. 초안과 미래 예약 글은 배포 결과의 HTML·JavaScript·데이터·sitemap·RSS에서 제외합니다. 공개 GitHub 저장소에 올린 초안·예약 원문은 누구나 볼 수 있습니다. 비공개 메모와 민감한 내용을 넣지 마세요. static/의 파일은 글 공개 여부와 관계없이 배포되므로 비공개 자료를 두지 마세요. 예약 글에 연결한 예제 파일도 미리 접근할 수 있습니다.
공개 글을 비공개로 바꾸려면 published: false로 변경하고 다시 배포하세요. 기존 주소는 이후404가 됩니다. 이미 저장된 검색 결과·외부 캐시·Git 이력까지 삭제되지는 않습니다. 다시 공개할 때는 기존 slug를 유지하세요.
표, 목록, 인용, 링크와 코드 블록을 사용할 수 있습니다. 본문은 ##부터 작성하며 본문 제목이3개 이상이면 목차가 생깁니다. 원시 HTML과 Svelte 문법은 실행하지 않습니다. 코드 블록은 언어 이름을 붙일 수 있지만 구문별 색상 기능은 추가하지 않았습니다.
이미지는 static/images/blog/에 넣고 으로 연결하세요. 영문·숫자·하이픈·밑줄로 파일명을 작성하세요. 서버는 파일 존재 여부와 대체 텍스트를 검사합니다. 대표 이미지도 같은 로컬 경로 규칙을 사용하며 imageAlt가 필요합니다. 대표 이미지를 지정하지 않으면 링크 공유에는 사이트 공통 OG 이미지를 사용합니다. 본문에 공통 이미지를 억지로 표시하지는 않습니다. 출처·라이선스는 THIRD_PARTY_NOTICES.md 규칙을 따릅니다.
이미지만 있는 문단에는 처럼 캡션을 붙일 수 있습니다. 캡션은 이미지 아래에 작은 글씨로 표시합니다. 문장 안에 들어간 이미지의 설명은 기존 도움말로 유지합니다.
프로그램을 지정한 글에서만 관련 프로그램으로 연결합니다. 같은 프로그램의 공개 글은 자동으로 연결되며 프로그램이 없는 글은 같은 주제의 글로 연결됩니다. 소개 글을 먼저 보여주고 나머지는 최신순으로 최대4개 표시합니다. 프로그램 화면에는 해당 프로그램의 공개 글이 있을 때만 관련 글 영역이 나타납니다.
아래는 구조 예시입니다. 대괄호 내용을 실제 확인한 사실로 바꾸세요. 검증하지 않은 기능·성능·가격·사용자 수·후기는 공개하지 마세요.
도구 소개 (category: introduction):
## 어떤 상황에서 필요한가요?
[해결하는 문제와 대상 사용자]
## 이렇게 시작하세요
[실제로 따라 할 수 있는 단계와 프로그램 링크]
## 사용 전에 알아두세요
[확인한 사용 조건·저장 방식·제한]
도구 활용과 문제 해결 가이드 (category: tool, image, data, file):
## 준비하기
[이번 글에서 만들 결과와 필요한 준비]
## 따라 해보기
1. [실제 입력 예시]
2. [화면에서 실행할 동작]
## 결과 확인하기
[예상 결과와 실수하기 쉬운 부분]
기능 변경 안내 (도구 글이면 category: tool):
## 무엇이 바뀌었나요?
[이전과 달라진 동작]
## 왜 바꿨나요?
[확인된 문제와 변경 이유]
## 사용자가 할 일이 있나요?
[필요한 조치 또는 별도 조치 없음]
소개 글은 현재 기능의 기준 글로 관리하세요. 기능이 바뀌면 관련 소개·가이드·프로그램 화면 안내를 함께 점검하세요. 과거 업데이트 글은 당시 기록을 유지하고 최신 소개·가이드로 연결하세요. 모든 글에 같은 항목을 억지로 넣을 필요는 없습니다.
npm run test:blog
npm run check
# 최신 코드로 build한 결과가 없을 때만 실행합니다.
npm run build
npm run verify:blog
npm run verify:team-maker도 마지막에 블로그 정적 결과를 검사합니다. verify:blog는 최신 build의 production 렌더러를 임시 글 폴더에서 실행해 공개 글·초안404·빈 목록도 검사합니다. 저장소 글과 배포 결과를 수정하거나 다시 build하지 않습니다. PR의 단위 테스트에는 test:blog가 포함됩니다. 중복 slug·누락 정보·잘못된 날짜·없는 프로그램·없는 이미지·공개 여부 오류는 파일명과 원인을 표시하며 build를 실패시킵니다. 초안도 글 정보 검증 대상입니다.
src/routes/blog/+page.sveltesrc/routes/blog/[slug]/+page.sveltesrc/lib/blog/src/lib/server/blog.jssrc/routes/rss.xml/+server.js, src/routes/sitemap.xml/+server.jsscripts/verify_blog_build.js, scripts/verify_blog_render.js화면을 바꾸면 접근성 snapshot을 먼저 확인하고 모바일·데스크톱·긴 제목·표·코드·두 테마·키보드·JavaScript 비활성 상태를 확인하세요. 초안만 있는 경우와 글이 없는 경우도 확인하세요. 팀 메이커 소개 글1개는 사용자 요청에 따라 공개 상태입니다. 새 글은 검토를 마칠 때까지 초안으로 작성하세요. 목록·상세의 RSS 구독은 footer의 개인정보처리방침 옆에 있습니다.
/blog와 공개 글 주소를 직접 열고 새로고침하세요./sitemap.xml, /rss.xml, /robots.txt에 실제 공개 주소가 반영됐는지 확인하세요./sitemap.xml을 제출하세요.계정 연결과 소유권 확인은 해당 계정의 권한이 필요합니다. 로컬 build·검사 통과는 실제 배포·검색 등록·AI 노출 확인과 다릅니다. 검색과 AI 추천은 보장하지 않습니다. 별도의 AI 전용 파일은 필수 조건으로 취급하지 않으며 특정 서비스 대응이 필요하면 해당 공식 안내를 확인하세요. 검색 접근 허용과 AI 학습용 접근 허용을 구분하세요.
공유용 정보는 제공하지만 실제 링크 미리보기는 공유 서비스와 캐시에 따라 달라집니다. 방문 통계와 개인정보 모달은 공통 정책을 따릅니다. 이번 작업에서는 기존4개 화면의 수집 범위를 블로그로 넓히거나 새 추적 항목을 추가하지 않습니다.
공개 글이0개이면 SvelteKit의 미생성 경로 검사에서 /blog/[slug]만 허용합니다. 공개 글이1개라도 있거나 다른 경로가 빠지면 build를 실패시킵니다. 이 처리는 scripts/blog_prerender.js에서 검사하며 adapter의 strict 설정은 유지합니다.
QR 인식·브라우저 저장·CSV 열 구분 글의 예제 생성과 검증 방법은 재현 안내를 따릅니다. 원고의 공개일과 예제의 실제 측정일을 구분합니다.
챔피언 검색 버튼이나 / 키로 검색 창을 열어 다른 챔피언으로 갑니다.tests/team-maker-e2e/aram-mayhem.spec.js, 단위 테스트는 tests/aram-mayhem/에 있습니다.OverlayCard의 남색 카드 스타일을 사용하며 StageOverlay는 배치를 담당한다. 일시정지와 종료 확인은 하나의 패널로 제공한다. 계속하기 또는 종료하고 설정 변경을 선택하며, 종료하면 경기를 이어갈 수 없고 참가자와 설정은 유지된다는 안내를 함께 표시한다. 별도 종료 확인창은 열지 않는다. 시작·재개 시 준비 상태는 게임 상단에 표시하며 별도 로딩 창은 띄우지 않는다. 준비 취소는 설정 영역에서 제공하며 게임 하단에는 준비 취소 버튼을 띄우지 않는다. 시작·계속하기 버튼은 준비 중에도 같은 요소·문구·폭을 유지하고 중복 클릭만 막는다. 게임 하단에는 일시정지·계속하기만 표시하고 종료는 일시정지 창에서 선택한다.frost-freeze-v1.wav를 얼어붙는 순간 한 번 재생한다. 미리듣기와 경기는 같은 파일을 사용하며 접촉 지속 중에는 반복하지 않는다.