Files
Find-Word/README.md
2026-10-14 10:01:46 +00:00

9.7 KiB
Raw Permalink Blame History

단어를 맞춰라 · Find-Word v0.2.3

소음 속에 숨은 한국어 단어를 듣고 찾는 반응형 웹 게임입니다.

Designed by OZ at Heat-T Medical Inc.

Canonical repository: OZ-Group/Find-Word. 프로젝트 자체는 private / all-rights-reserved이며 package.json의 license는 UNLICENSED입니다. LICENSE를 참고하세요. 런타임 의존성 React, ReactDOM, scheduler의 MIT 전문은 THIRD_PARTY_NOTICES.md에 보존하며, public/THIRD_PARTY_NOTICES.md가 빌드 시 dist/THIRD_PARTY_NOTICES.md로 복사됩니다. 빌드 검증기는 설치된 의존성의 라이선스 전문·버전과 세 사본을 대조합니다.

React + TypeScript strict + Vite로 만든 정적 SPA입니다. 로그인, 개인정보 저장, 분석 도구, 외부 CDN, 런타임 TTS/API 요청이 없습니다. 청각적 주의·식별 게임이며 의료적 진단·치료나 효과를 주장하지 않습니다.

실행

Node.js 최소 버전은 22.22.2 (>=22.22.2)입니다. 잠긴 jsdom 계열 의존성이 요구하는 지원 범위는 22.x의 22.22.2 이상, 24.x의 24.15.0 이상 또는 26.0.0 이상입니다. 이 중 지원되는 LTS 버전을 사용하세요. package-lock.json을 포함하므로 새 환경에서는 npm ci를 사용합니다. 이번 검증 환경은 Node 26.7.0입니다.

npm ci
npm run dev

표시되는 http://127.0.0.1:5173에서 사용합니다. 소리는 사용자가 게임 시작 · 소리 듣기를 누른 뒤에만 재생합니다. 낮은 음량부터 조절하고 헤드폰이나 스피커를 사용할 수 있습니다.

플레이

  • 골고루 풀기, 보기에서 선택, 직접 입력 중 선택합니다.
  • 8개 실제 현장 녹음 환경 중 하나를 지정하거나 라운드마다 섞어 세 곳을 방문합니다.
  • 에스의 안내가 배경에 묻힌 뒤 목표 문장이 나옵니다. 재생 후 질문에 답합니다.
  • 시작 난이도 1~5를 고르고 정확히 3문항을 같은 단계에서 풉니다. 단계 기본값은 SNR +6, +3, 0, −3, −6 dB입니다.
  • 목표 음성 SNR을 −12~+12 dB, 1 dB 간격으로 직접 조절할 수 있습니다. 재생 중 변경은 다음 재생·재청취와 남은 문제부터 적용합니다. 양수는 음성이 배경보다 크고, 0은 같고, 음수는 더 작다는 뜻입니다.
  • 다시 듣기는 감점하지 않습니다. 정답은 단계 × 100점, 연속 정답 보너스는 문항별 최대 20점, 라운드 합계 최대 30점입니다 (0 + 10 + 20점, 1단계 만점 330점).
  • 정상 결과에서 다음 단계의 새 3문항을 바로 시작합니다. 5단계에서는 같은 단계 재도전과 홈 복귀를 제공합니다. 수동 SNR은 다음 라운드에도 유지되고, 홈 복귀 시 선택한 시작 단계의 기본값으로 돌아갑니다.
  • 언제든 문제 풀이 종료를 누르면 즉시 오디오를 취소하고 응답 수·정답 수를 보여 줍니다. 무응답은 오답으로 세지 않고 정답률은 — / 응답 없음, 답하지 않은 단계는 미진행으로 표시합니다. 결과에서 처음 화면으로 돌아갑니다.
  • 결과의 SNR은 실제 마지막 청취값을 기록합니다. 점수·정답률·최고 연속 정답·단계별 결과를 확인합니다.
  • 새로고침하면 기록이 사라집니다. 결과를 브라우저나 서버에 저장하지 않습니다.

10개 유형 × 10개 단어의 100개 목표 문장을 저장했습니다. 각 세션은 유형과 단어를 섞어 출제하며 정답 위치도 섞습니다. 사전 표제어와 변형 규칙은 WORDS.md에 설명했습니다. 청취 과제는 직접 목표 식별, 연습 암호와 진짜 암호 구별, 앞 단어를 잊고 다음 단어 기억, 첫째·마지막·가운데 선택, 반복 찾기, 정정 반영, 신호 조건 적용, 오른쪽 표지 선택의 10가지입니다. 문장에 실제 보기의 오답도 포함됩니다.

검증과 정적 빌드

npm run lint
npm test
python3 -m unittest discover -s tests/python -v
npm run build
npm audit
npm run preview

lint는 ESLint와 TypeScript 검사, test는 unit/component/자산/빌드 검증기 테스트를 실행합니다. build는 dist/를 만들고 음성 101개와 현장음 8개가 manifest 해시 그대로 포함되었는지 확인합니다. 앱 콘텐츠의 예상 101개 목록과 실제 파일 집합을 독립 비교해 manifest와 폴더를 함께 줄이거나 파일을 추가한 경우도 거부합니다. 빌드에는 음성 합성 도구가 필요하지 않습니다. 런타임 MIT notice와 현장음 attribution/license notice가 dist/에 전문 그대로 포함되는지도 검증합니다.

실제 오디오·360px/1280px 화면·키보드·접근성·오류 재시도 검증:

# Chromium이 없는 개발 환경에서 한 번만 실행합니다.
npx playwright install chromium
npm run test:browser
# 이미 설치된 Chrome을 사용할 때의 대안입니다.
CHROME_PATH=/usr/bin/google-chrome npm run test:browser

Chromium sandbox는 기본으로 켭니다. sandbox를 지원하지 않는 격리된 개발 환경에서만 PLAYWRIGHT_NO_SANDBOX=1을 명시해 끌 수 있습니다. 0, false, 빈 값이나 미설정은 sandbox를 유지합니다. CHROME_PATH 지정은 sandbox를 끄지 않습니다.

브라우저 테스트는 기존 dist/를 사용하므로 소스 변경 후 먼저 빌드하세요. 실제 음성 재생이 끝나기를 기다려 몇 분이 걸립니다. 로컬 4173 포트를 테스트 중에만 열고 종료합니다. 스크린샷과 109개 WAV의 query URL·해시·디코드 결과는 test-results/에 저장합니다. 현재 리뷰 인수 기록은 .agent/evidence-v0.2.3/review-fixes/에 보존합니다. 기존 v0.1/v0.1.1 및 v0.2.3 증거는 덮어쓰지 않습니다.

음성과 문서

한국어 WAV 101개는 직접 쓴 문장을 Microsoft Edge online TTS의 ko-KR-HyunsuMultilingualNeural로 v0.1.1에서 생성했으며 WAV 바이트는 그대로 보존했습니다. edge-tts 7.3.1, rate -6%, pitch -4Hz이며 FFmpeg로 24kHz mono PCM16으로 변환합니다. 생성 시 네트워크가 필요하며 앱은 저장된 WAV만 재생합니다. 환경음은 공개 라이선스의 실제 현장 녹음 8개를 각 12초로 변환해 번들합니다. 생성 음성의 독점 권리를 주장하지 않습니다.

intro와 목표 WAV는 모두 /audio/파일명.wav?v=0.2.3로 요청합니다. src/audio/assets.ts의 자산 버전 한 곳을 사용하며, 같은 파일명으로 음성을 교체할 때 이 값을 갱신해 기존 7일 캐시와 구분합니다. 배경은 /ambience/환경.wav?v=0.2.3입니다. 제품 버전은 0.2.3입니다.

Linux에서 Python 3.11 이상과 FFmpeg를 준비한 뒤 다음 명령을 사용합니다. 클라이언트 버전을 고정해도 원격 모델 변경으로 동일 바이트 재생성은 보장하지 않습니다.

python3 -m venv .venv-audio
.venv-audio/bin/python -m pip install -r requirements-audio.txt
.venv-audio/bin/python -m pip check
npm run audio:generate

고정 venv의 Python이 101개 모두 임시 생성·검증하고 디렉터리를 원자 교체합니다. 요청별 60초 제한과 최대 3회 시도를 적용하며, 실패 시 기존 자산을 보존합니다. 청취 샘플: 안내, 행운의 사과.

현장음의 현재 privacy screening 구간은 mall 36–48초, market 24–36초, cafe 0–12초입니다. 정확한 최종 WAV의 tiny-model VAD 검사에서 세 구간 모두 segment 0개로 requiredEmptyPassed=true입니다. 이전 실패와 no-VAD 환각 가능 text 증거는 보존했으며 no-VAD 결과는 지정 VAD gate를 대체하지 않습니다. 빈 결과도 말소리·음악의 부재를 증명하지 않습니다. 독립적인 사람 청취 인증과 법적/privacy clearance는 수행하지 않았지만, 제품 소유자 Oz가 2026-10-14 제공된 8개 최종 WAV 검수 묶음을 기준으로 현재 자산 그대로 릴리스를 진행하도록 승인했습니다. 설정·해시·한계와 보존 경로는 오디오 provenance를 참조하세요.

생성 방법, 도구 라이선스, 합성 음질의 한계는 AUDIO_PROVENANCE.md를 참고하세요. 실제 음량은 출력 장치에 따라 달라지며 표기 dB는 디지털 상대값입니다.

현장음 원본은 /tmp/findword-ambience-sources에서만 보관하고 배포하지 않습니다. python3 scripts/ambience_audio.py는 승인 계획의 expectedSourceSha256·sourceBytes를 전수 확인한 뒤에만 변환합니다. 직접 미디어 길이는 directMediaDurationSeconds, 검증 상태는 sourceVerification에 보존합니다. 8 WAV·manifest·고지를 같은 파일시스템에서 staging/검증한 뒤 Linux renameat2(RENAME_EXCHANGE)로 폴더 전체를 교체합니다. symlink 출력은 거부하며 commit 전 실패/중단은 이전 폴더를 보존합니다. PD·CC0·CC BY 4.0·CC BY-SA 4.0의 정확한 출처·저작자·변환·해시는 현장음 manifest, 배포 고지에 있습니다. 시장 파생본은 CC BY-SA 4.0을 유지합니다. 외부 링크는 출처 확인용이며 앱은 이를 요청하지 않습니다.

이번 작업에서는 서버 배포와 Git commit/push를 실행하지 않습니다.