TWA 래퍼를 걷어내고 Compose Multiplatform 으로 다시 만들었다. 엔진·UI·모드
전부 commonMain 한 벌이라 Android 와 iOS 가 같은 코드를 쓴다.
- engine/: 웹 JS 엔진을 Kotlin 으로 이식 (SRS+180 킥, 7-bag, T-spin, B2B,
콤보, All Clear, 점수·레벨). commonTest 28개 통과
- game/: 모드 규칙 + 중력/락딜레이/DAS/ARR 타이밍
- ui/: 네오브루탈 컴포넌트, 메인/솔로시트/인게임/결과/설정
- ui/Responsive.kt: 고정 해상도를 버리고 가용 크기에서 셀 크기·배율 계산.
폰 세로, 플립 초세로, 플립 커버(소형), 폴드 펼침, 태블릿/아이패드 가로 대응
- androidMain: resizeableActivity + configChanges 로 접기/펴기·회전 시 재시작 없음
- iosMain + iosApp/: MainViewController + SwiftUI 껍데기 + XcodeGen 설정
(실제 iOS 빌드는 macOS + Xcode 필요)
- scripts/release.sh: 버전 상승 → 테스트 → 서명 빌드 → 태그 → Gitea 릴리스 자동화
Cloudflare Pages 가 /index.html 을 / 로 308 리다이렉트하는데, 서비스워커가
그 리다이렉트 응답을 캐시해 두면 navigation 요청에 응답할 수 없어(스펙상 금지)
두 번째 실행부터 ERR_FAILED 로 앱이 아예 열리지 않았다.
- sw.js: navigation 은 네트워크 우선 + 캐시된 './' 오프라인 폴백,
프리캐시는 리다이렉트 플래그 없는 새 Response 로 복사해 저장 (tetrig-v2)
- manifest.webmanifest: start_url 을 './' 로 바꿔 리다이렉트 자체를 회피
- android/: Bubblewrap TWA 프로젝트 (kr.tkrmagid.tetrig, launchUrl '/')
- .well-known/assetlinks.json: 서명 키 SHA-256 등록 → 주소창 없는 전체화면 실행
- src/engine.js: 순수 코어 로직 (보드 10x40, 피스 7종, SRS+180 킥테이블,
T-spin/mini 판정, 콤보/B2B, 7-bag, 홀드, 고스트, 락딜레이 15회 캡)
- test/engine.test.js: 24개 단위 테스트 (킥테이블·T-spin 판정·7-bag·클리어 등) 전부 통과
- src/index.template.html + build.js: 엔진을 인라인한 단일 index.html 생성
(외부 에셋 0개). 키보드 플레이 가능 (DAS/ARR, 하드/소프트드롭, 판정 팝업)