← 목록
기타 2026-07-29 9KB 읽기 9분

크라우니 게임툴스 "레디" 출시 (gametools.crowny.org:9625)

개요

발주 디자인 핸드오프(/Users/ef/Downloads/design_handoff_ready/)를 정독해 카드게임·투표용 실시간 준비확인 도구 "레디"를 신규 구축·라이브했다. 최대 50명(기본 25)이 8.7" 갤럭시탭을 터치해 Ready를 알리고, 딜러가 전원 Ready를 확인한 뒤 게임을 시작한다. gametools.crowny.org는 게임 도구가 계속 추가될 도메인이며, 도구별 경로(/ready)로 라우팅한다.

  • 코드: /Users/ef/crowny-gametools
  • 포트: 9625 (crowny-ports.sh 등록, gateway.yaml 반영)
  • 공개: https://gametools.crowny.org 라이브 (와일드카드 *.crowny.org 인증서로 커버 — SAN 확장 불필요)

무엇을 했나

1. 계약화 (SSOT 우선)

프로토타입(Ready.dc.html)은 "디자인 레퍼런스"이지 배포 코드가 아니라는 발주 명시에 따라, 먼저 SPEC.mdAPI·화면·상태·토큰을 계약화한 뒤 그 계약으로 병렬 구현했다. 디자인 원본은 디자인이식.sh register로 물리 잠금(프로젝트명 크라우니게임툴스레디).

2. 순수 한선씨 서버 (서버.한선, 14,769 큐브)

  • 상태 SSOT = 전역 병렬배열 인메모리(룸코드·좌석수·phase·좌석비트·버전·heartbeat·바카라·갱신).
  • 좌석 ready는 문자열 비트("0"/"1")로 관리 — 배열 생성 없이 부분()+연결로 갱신.
  • 영속화는 변경 시에만 data/방.psv append, 부팅 1회만 파싱(읽기 라우트에서 분리() 0).
  • 요청마다 메모리마커/맵힙마커 복원 + 200요청마다 문자열GC()(아래 결함 참조).
  • 라우트: / /ready/{room} /dealer/{room} /trial/{room} + /api/{room/new,state,seat,seats,deal,standby,beat,config} + 정적(css/js/qr/png) + /health.

3. 실시간 동기화 = 250ms 폴링

WebSocket은 한선씨 VM 제약상 채택하지 않고 초경량 폴링으로 설계. 공개 도메인 실측 레이턴시 47~157ms → 발주 목표 <300ms 충족. 재접속·새로고침 시 서버 상태로 즉시 복원.

4. 화면 4종 (디자인 원본 그대로)

랜딩(룸 생성/참가) · 참가자(전체화면 Ready 토글, 100ms 홀드/1000ms 취소, Wake Lock, 원형 확장 0.5s) · 딜러(그리드·테이블·카운트 3레이아웃 + 인원 스테퍼 + QR) · 시험운영(컴팩트 그리드 + 좌하단 바카라 PIP).

5. 자체 구현으로 외부 의존 0

  • QR 인코더(web/qr.js): GF(256) 리드-솔로몬·8마스크 페널티 선택·BCH 포맷/버전정보까지 자체 구현.
macOS Vision(VNDetectBarcodesRequest) 디코더로 왕복 검증 5종 전부 일치(URL·코드·100자·한글·v9).
  • 바카라 엔진(바카라.한선): 서드카드 룰 SSOT. 100회 배분 실측 전 항목 PASS.

6. 한선씨 동반본 (헌법 준수)

공통.한선(좌석·타원좌표·바카라파싱·진행률·대기목록·상태텍스트·토큰) · 참가자/딜러/시험운영.한선(홀드판정·딜가능·오프라인표시·PIP) + 공통시험/화면시험/바카라시험.한선. 화면 판정 로직 44/44 PASS, HTML/JS와 판정 불일치 0.

발견·수리한 결함 (전부 실측 재현 후 수리)

#결함영향수리
1좌석 인덱스 off-by-one — 서버가 0-based로 처리?seat=3이 4번 좌석을 켬. 계약 위반1-based 규약으로 통일(seat-1), heartbeat 경로도 동일 수정
2문자열 핸들 누수 → exit43 — 8,000 요청에 480k 상한의 90% 도달폴링 서버가 수 분 내 사망부팅 후 문자열보호() + 200요청마다 문자열GC(). 재소크 20,000 요청 경고 0·크래시 0
3시험운영 노룸 오버레이 상시 노출 — 인라인 display 중복 선언(뒤가 이김)시험운영 화면 전체가 가려짐중복 제거. 타 페이지 동일 결함 없음 확인
4카운트 뷰 " / N" 임의 축소(font-size:0.5em)원본 미이행제거(부모 크기 상속)
5카운트 뷰 상단 정렬height:100%가 flex:1 부모(불확정 높이)에서 무너짐원본은 패널 세로 중앙패널을 컬럼 플렉스 + #countView{flex:1}
6시험운영 패널이 내용 높이로 축소원본은 flex:1로 남은 높이 채움패널 flex:1; padding:18px 복원
7참가자 재접속 복원이 0.5s 애니메이션을 탐발주 "즉시 복원" 위반, 복귀 중 빨강으로 보임첫 서버상태 반영만 무애니메이션(강제 리플로우로 커밋 후 transition 복원)

검증 실측

  • 서버 종단: health·룸생성·좌석·상태·deal(미전원 거부/전원 허용)·standby·config 전부 PASS
  • 재기동 복원: 프로세스 재시작 후 좌석·phase·바카라 결과까지 PSV에서 복원 확인
  • 부하: 200 요청 1.64s(8.2ms/req) — 25대 × 4Hz = 100 req/s 여유
  • 소크: 20,000 요청, 문자열 조기경고 0, 크래시 0, RSS 34MB
  • 50좌석: 그리드 6행 래핑, 겹침·붕괴 없음
  • 테이블 배치: 인접 호길이 편차비 1.058(균등), 각도 간격 9.5°~22.2°(의도적 불균등) → 원본의 "좌우 뭉침 방지" 요구 충족
  • 이탈(OFFLINE): heartbeat 8초 미수신 좌석만 점선 아웃라인 + OFFLINE 표시 확인
  • 4화면 콘솔 에러 0, 골격 게이트(doctype·charset·외부요청0) 4/4
  • 디자인 게이트: 신규색 0 · 유실색 0(판정 옴, 점수 79). 신규치수 7건은 원본에 없던 랜딩·좌석선택 화면 — 이식노트.md에 근거 기록
  • 공개 HTTPS 전 경로 200, 타 도메인 무영향(crowny.org·docs 200)

발주자 확인 대기 (원본 README Open Questions)

기본안으로 구현하고 이식노트.md·SPEC.md §4에 값을 모아 뒀다 — 회신 시 한 곳만 고치면 된다.

  1. 룸 플로우 → 4자리 코드 + 참가 URL + QR (코드 입력/QR 병행)
  2. 딜러 좌석 수동 토글 → 유지(오버라이드, 화면에 명시)
  3. 참가자 이탈 표시 → heartbeat 8초 + 점선 아웃라인 OFFLINE(신규 색 없음)

관련 파일

  • 코드: /Users/ef/crowny-gametools/ (SPEC.md·README.md·이식노트.md 동봉)
  • 상시구동: org.crowny.gametools.plist(LaunchAgent, KeepAlive)
  • 디자인 원본(잠금): /Users/ef/Downloads/design_handoff_ready/
  • 학습 래칫: crownycode에 서버·바카라·문자열핸들회수 패턴 학습 완료
  • 가드레일 갱신: 루트() 정수 반환 · 장수서버 문자열 핸들 누수 2건 추가

육안 검증 (2026-07-29 전 화면 캡처 대조)

25명 룸(18 ready)·8명 시험운영 룸으로 실제 렌더를 캡처해 원본 의도와 대조했다.

  • 랜딩 · 딜러 그리드/테이블/카운트 · 참가자 Standby/Ready · 시험운영+PIP · 딜러 다크테마 = 전부 원본 일치 확인
  • QR 실물 검증: 딜러 화면 스크린샷에서 QR 영역을 잘라 macOS Vision으로 디코딩 → http://127.0.0.1:9625/ready/NX3Y 정확히 일치
  • 다크테마는 스크래치패드 하네스(제품 파일 무수정)로 data-theme=dark 강제해 캡처 — 신호색(빨강/초록) 공통 유지 확인
  • 검증 편의 겸 실용으로 ?layout=·?qr=1 파라미터 추가(기본 동작 불변)

크라우니AI 귀속 (2026-07-30 사용자 지시)

crowny://gametools 를 크라우니AI 기본 앱으로 귀속. cad 선례를 전수 대조해 8지점 동수 배선(행만 추가하면 빈 탭 무동작이 되는 알려진 함정 회피).

지점내용
시작페이지 타일cad 타일 뒤, 아이콘 ASCII R(한글 심볼 UTF-16LE 함정 회피), 라벨 게임툴스
북마크 시드v22 블록, 중복검사 후 insert (defaultBookmarks()는 의도적 공백이라 미접촉)
주소 정규화crowny://gametools* + 별칭 게임툴스·gametools·레디·ready·크라우니게임툴스
탭 오픈caOpenGametoolsInActiveTabhttps://gametools.crowny.org
커맨드 라우팅별칭 질의 → 위 함수
런처 카드src/앱목록.psv 1행(url: 규약). 런타임에 소스경로 직접 읽어 재빌드 불필요
액센트색레디그린 rgb(20,160,95) = 서비스 자신의 Ready 신호색. crowny-browser.m·crowny-ai-engine.m 양쪽 동일값
검증: make ai 에러 0(기존 경고만) → install-ai-app.sh 재서명 → open -a CrownyAI "crowny://gametools" 로 탭이 실제로 열리고 랜딩이 렌더되는 것을 육안 확인, 사이드바에 "크라우니 게임툴스" 등록 확인. 미완: 런처 "웹 서비스" 탭 카드 육안 확인 — cliclick 클릭이 타 세션 창 포커스를 교란해 중단(카드 자체는 PSV 파싱·제네릭 디스패치로 동작 경로 확인).

잔여

  • 실기기(갤럭시탭 8.7") 다중 접속 현장 시험 미실시 — 터치 홀드 100ms/1000ms 체감, Wake Lock 실동작, 25대 동시 폴링은 현장에서만 확정 가능.
  • 테마 토글 버튼 클릭 자체(자동↔라이트↔다크 전환)는 Chrome 확장 미연결로 클릭 검증 미실시. 렌더는 양 테마 모두 확인.