first upload
This commit is contained in:
528
TETRIG-최종명세서.md
Normal file
528
TETRIG-최종명세서.md
Normal file
@@ -0,0 +1,528 @@
|
|||||||
|
# TETRIG (테트리그) — 최종 구현 명세서 v3.0
|
||||||
|
|
||||||
|
> 이 문서는 **AI(Claude)에게 구현을 맡기기 위한 핸드오프 문서**다. 지금까지 사용자와 확정한 모든 설계 결정·수치·에셋이 담겨 있으며, 이 문서 하나로 프로젝트 전체를 구현할 수 있다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. 이 문서를 받은 AI에게 — 작업 지침 (가장 먼저 읽을 것)
|
||||||
|
|
||||||
|
**무엇을 만드는가**: TETR.IO 스타일의 모바일 실시간 대전 블록 스태커 웹 게임 **"테트리그 (TETRIG)"**. 솔로 3모드 + 인원 무제한 커스텀 룸(FFA) + Glicko-2 랭크 리그전.
|
||||||
|
|
||||||
|
**산출물 2개**:
|
||||||
|
1. **클라이언트** — 단일 HTML 파일 (HTML+CSS+JS, Canvas 2D, 외부 에셋 0개, 사운드는 Web Audio 신스 생성)
|
||||||
|
2. **서버** — Cloudflare Workers 프로젝트 (wrangler 표준 구조: Durable Objects 2종 + D1 + Cron)
|
||||||
|
|
||||||
|
**작업 규칙**:
|
||||||
|
- §15 로드맵의 **Phase 순서대로** 진행하고, 각 Phase 완료 시 사용자 확인 후 다음으로 넘어간다.
|
||||||
|
- 각 Phase 산출물 = 실행 가능한 파일 + 코어 로직의 jsdom(또는 node) 단위 테스트 통과 결과.
|
||||||
|
- **이 문서의 결정사항은 이미 확정된 것이다. 재논의·재제안하지 말고 그대로 구현하라.** 문서에 값이 명시된 것은 그 값을 쓰고, 없는 것만 질문하라.
|
||||||
|
- 앱 이름 "테트리그"는 사용자가 상표 리스크를 인지하고 확정한 결정이다. **다시 경고하지 말 것.** 단, §2의 완화책(BRAND 상수 등)은 반드시 구현할 것.
|
||||||
|
- 모든 응답과 코드 내 사용자 노출 텍스트는 **한국어** (게임 용어는 SPRINT, HOLD 등 영문 허용).
|
||||||
|
- 튜닝 대상 수치(중력, TR 커브, 콤보 테이블 등)는 코드 상단에 **상수로 분리**해 나중에 조정하기 쉽게 한다.
|
||||||
|
- **이 문서와 함께 첨부되는 파일 — 반드시 함께 확인할 것**: `tetrig-ux-mockup.png`(9화면 UX 목업, **UI 구현의 시각 기준 — 가장 먼저 열어볼 것**), `tetrig-logo.svg`·`tetrig-icon.svg`(실사용 로고 에셋, 부록 A에 동일 소스 수록), `tetrig-logo.png`·`tetrig-icon.png`(로고 렌더 미리보기). §12의 좌표 명세는 목업을 수치로 보조하는 자료다 — 시각 판단은 목업 이미지를 따른다.
|
||||||
|
|
||||||
|
**절대 금지 (IP)**:
|
||||||
|
- 사용자 노출 텍스트(UI·스토어 문구·게임 내 판정 텍스트)에 "Tetris/테트리스" 단어 사용 금지 — 4줄 클리어는 **"QUAD"**
|
||||||
|
- 테트리스 관련 음악(Korobeiniki 등) 사용 금지 — 사운드는 100% Web Audio 신스
|
||||||
|
- 표준 가이드라인 피스 색상 1:1 복제 금지 — §13의 자체 팔레트 사용
|
||||||
|
- TETR.IO의 에셋·명칭(TETRA LEAGUE 등) 복제 금지
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 아키텍처 개요
|
||||||
|
|
||||||
|
```
|
||||||
|
[모바일 브라우저] [Cloudflare]
|
||||||
|
클라이언트 (단일 HTML, Canvas) ⇄ WSS ⇄ Workers
|
||||||
|
├ 게임 엔진 (SRS+, 판정, 렌더) ├ MatchmakerDO (리그 매칭 큐, 싱글턴)
|
||||||
|
├ 솔로 모드 3종 ├ GameRoomDO (경기방 — 1:1 리그 & N인 커스텀 공용)
|
||||||
|
└ 멀티/커스텀/프로필/리더보드 UI ├ D1 (계정·레이팅·전적·리더보드)
|
||||||
|
└ Cron (RD 감쇠, 시즌 처리)
|
||||||
|
```
|
||||||
|
|
||||||
|
- 클라이언트는 Cloudflare Pages(또는 Workers 정적 자산)로 호스팅. 주소는 무료 서브도메인(`*.pages.dev`)으로 시작.
|
||||||
|
- 서버는 무료 티어로 운영 가능 (DO는 SQLite 백엔드, WebSocket Hibernation 사용. WS 수신 메시지 20개=1요청 집계).
|
||||||
|
- 로컬 개발: `wrangler dev` + 브라우저 탭 여러 개로 다인전 테스트.
|
||||||
|
|
||||||
|
## 2. IP 리스크 방침
|
||||||
|
|
||||||
|
**앱 이름: 테트리그 (TETRIG) — 확정.** "TETR-" 접두어의 상표 유사성 리스크를 사용자가 인지하고 채택했다. 완화책 3가지를 구현에 내장할 것:
|
||||||
|
|
||||||
|
1. **BRAND 상수**: 앱 이름·로고 문구를 코드 전체에서 상수 1곳(`const BRAND = "TETRIG"` / `BRAND_KO = "테트리그"`)으로 관리 — 언제든 1분 내 리브랜딩 가능해야 함
|
||||||
|
2. **단계별 운용**: 개인·지인 배포는 테트리그로 진행, 스토어 출시·수익화 직전 이름 재검토 (사용자 판단 사항)
|
||||||
|
3. **이름 외 모든 표현은 자체 제작**: 모드명(SPRINT/TIME ATTACK/ENDLESS/리그전), "QUAD" 용어, §13 자체 팔레트·자체 로고·자체 신스 사운드
|
||||||
|
|
||||||
|
## 3. 화면 구조 & 내비게이션
|
||||||
|
|
||||||
|
```
|
||||||
|
테트리그 메인
|
||||||
|
├── 솔로 ──(바텀시트)──▶ SPRINT / TIME ATTACK / ENDLESS
|
||||||
|
├── 멀티 ──▶ 리그전 (매칭 큐 → 1:1 → 결과)
|
||||||
|
└── 커스텀 ──▶ 방 만들기(코드 발급→로비) / 참가하기(코드 입력→로비)
|
||||||
|
하단 탭바: 홈 · 리더보드 · 프로필 · 설정 (전 메뉴 화면 공통)
|
||||||
|
```
|
||||||
|
|
||||||
|
전체 화면 목록 (상세 좌표는 §12): ① 메인 ② 솔로 인게임 ③ 리그전 1:1 ④ 커스텀 FFA ⑤ 커스텀 로비 ⑥ 리그 결과 ⑦ 프로필(게스트→로그인) ⑧ 솔로 모드 선택 시트 ⑨ 일반전(커스텀) 결과. 추가로 리더보드·설정 화면은 동일 디자인 언어로 구성.
|
||||||
|
|
||||||
|
## 4. 게임 코어 규칙 (전 모드 공통)
|
||||||
|
|
||||||
|
- **보드**: 10열 × 40행(내부), 하단 20행만 표시. 스폰은 21~22행(숨김 영역 하단). 스폰 위치가 이미 막혀 있으면 톱아웃.
|
||||||
|
- **랜덤**: 7-bag (7종 피스를 가방 단위로 셔플).
|
||||||
|
- **넥스트**: 5개 표시. **홀드**: 1회/피스, 스왑 후 해당 피스 락다운까지 재사용 불가.
|
||||||
|
- **고스트 피스**: 항상 표시 (설정에서 끔 가능).
|
||||||
|
- **락 딜레이**: 500ms. 이동/회전 성공 시 리셋, **최대 15회**(초과 시 즉시 락).
|
||||||
|
- **중력 초기값** (튜닝 상수): 리그/커스텀 1000ms/칸 고정, SPRINT 800ms 고정, TIME ATTACK·ENDLESS는 레벨제 — 10라인=1레벨, 낙하간격(초) = `0.8^(level-1)` 근사, 하한 50ms.
|
||||||
|
- **소프트드롭 속도** = 중력 × SDF.
|
||||||
|
|
||||||
|
### 4.1 회전 시스템 — SRS + 180°
|
||||||
|
좌표 규약: 킥 오프셋 (dx, dy), **dy 양수 = 위쪽**. 회전 상태 0=스폰, 1=CW, 2=180, 3=CCW. 각 킥을 순서대로 시도해 처음 충돌 없는 위치 적용, 전부 실패 시 회전 취소.
|
||||||
|
|
||||||
|
**JLSTZ 킥테이블 (표준 SRS)**
|
||||||
|
| 전이 | 킥 순서 |
|
||||||
|
|---|---|
|
||||||
|
| 0→1 | (0,0) (-1,0) (-1,1) (0,-2) (-1,-2) |
|
||||||
|
| 1→0 | (0,0) (1,0) (1,-1) (0,2) (1,2) |
|
||||||
|
| 1→2 | (0,0) (1,0) (1,-1) (0,2) (1,2) |
|
||||||
|
| 2→1 | (0,0) (-1,0) (-1,1) (0,-2) (-1,-2) |
|
||||||
|
| 2→3 | (0,0) (1,0) (1,1) (0,-2) (1,-2) |
|
||||||
|
| 3→2 | (0,0) (-1,0) (-1,-1) (0,2) (-1,2) |
|
||||||
|
| 3→0 | (0,0) (-1,0) (-1,-1) (0,2) (-1,2) |
|
||||||
|
| 0→3 | (0,0) (1,0) (1,1) (0,-2) (1,-2) |
|
||||||
|
|
||||||
|
**I 킥테이블 (표준 SRS)**
|
||||||
|
| 전이 | 킥 순서 |
|
||||||
|
|---|---|
|
||||||
|
| 0→1 | (0,0) (-2,0) (1,0) (-2,-1) (1,2) |
|
||||||
|
| 1→0 | (0,0) (2,0) (-1,0) (2,1) (-1,-2) |
|
||||||
|
| 1→2 | (0,0) (-1,0) (2,0) (-1,2) (2,-1) |
|
||||||
|
| 2→1 | (0,0) (1,0) (-2,0) (1,-2) (-2,1) |
|
||||||
|
| 2→3 | (0,0) (2,0) (-1,0) (2,1) (-1,-2) |
|
||||||
|
| 3→2 | (0,0) (-2,0) (1,0) (-2,-1) (1,2) |
|
||||||
|
| 3→0 | (0,0) (1,0) (-2,0) (1,-2) (-2,1) |
|
||||||
|
| 0→3 | (0,0) (-1,0) (2,0) (-1,2) (2,-1) |
|
||||||
|
|
||||||
|
**180° 회전 킥 (SRS+ 계열)** — JLSTZ:
|
||||||
|
| 전이 | 킥 순서 |
|
||||||
|
|---|---|
|
||||||
|
| 0→2 | (0,0) (0,1) (1,1) (-1,1) (1,0) (-1,0) |
|
||||||
|
| 2→0 | (0,0) (0,-1) (-1,-1) (1,-1) (-1,0) (1,0) |
|
||||||
|
| 1→3 | (0,0) (1,0) (1,2) (1,1) (0,2) (0,1) |
|
||||||
|
| 3→1 | (0,0) (-1,0) (-1,2) (-1,1) (0,2) (0,1) |
|
||||||
|
|
||||||
|
I 피스 180°는 (0,0)만. O 피스는 회전해도 변화 없음(킥 불필요).
|
||||||
|
※ 킥테이블·T-spin 판정은 반드시 단위 테스트로 검증할 것.
|
||||||
|
|
||||||
|
### 4.2 판정 정의
|
||||||
|
- **T-spin**: T 피스가 **마지막 조작이 회전**으로 락다운 + T 중심 기준 4모서리 중 3칸 이상 채움(보드 밖도 채움 취급). 전면(포인팅 방향) 2모서리가 모두 채워졌으면 **T-spin**, 아니면 **T-spin mini**.
|
||||||
|
- **B2B (Back-to-Back)**: Quad·T-spin 계열 클리어가 다른 클리어(Single~Triple 일반 클리어) 없이 연속되면 유지. 판정 팝업에 B2B ×n 표시.
|
||||||
|
- **콤보**: 연속 피스가 각각 라인 클리어하면 +1씩 누적.
|
||||||
|
- **All Clear (퍼펙트 클리어)**: 클리어 후 보드가 완전히 빔.
|
||||||
|
- 판정 팝업 텍스트 예: `QUAD!`, `T-SPIN DOUBLE!`, `B2B ×2`, `ALL CLEAR!`, `3 COMBO`
|
||||||
|
|
||||||
|
## 5. 솔로 모드 3종 + 점수
|
||||||
|
|
||||||
|
| 모드 | 규칙 | 기록 |
|
||||||
|
|---|---|---|
|
||||||
|
| SPRINT | 40줄 클리어 최속 | 시간 (ms) |
|
||||||
|
| TIME ATTACK | 2분 점수 어택, 레벨 가속 | 점수 |
|
||||||
|
| ENDLESS | 무한, 게임오버 없음(톱아웃 시 보드만 리셋, 점수 유지) | 누적 점수·라인 |
|
||||||
|
|
||||||
|
**점수표 (×레벨, ENDLESS/TIME ATTACK 적용. SPRINT는 시간만 기록)**
|
||||||
|
- Single 100 / Double 300 / Triple 500 / Quad 800
|
||||||
|
- T-spin: Mini 100 / Mini Single 200 / Single 800 / Double 1200 / Triple 1600
|
||||||
|
- B2B 대상 클리어: ×1.5
|
||||||
|
- 콤보: +50 × 콤보수 × 레벨
|
||||||
|
- All Clear 보너스: Single 800 / Double 1200 / Triple 1800 / Quad 2000 (B2B Quad AC 3200)
|
||||||
|
- 소프트드롭 +1/칸, 하드드롭 +2/칸
|
||||||
|
|
||||||
|
## 6. 대전 규칙 (리그전·커스텀 공통)
|
||||||
|
|
||||||
|
**가비지 전송 테이블**
|
||||||
|
| 클리어 | 전송 줄 |
|
||||||
|
|---|---|
|
||||||
|
| Single | 0 |
|
||||||
|
| Double / Triple / Quad | 1 / 2 / 4 |
|
||||||
|
| T-spin Mini / Mini Single | 0 / 1 |
|
||||||
|
| T-spin Single / Double / Triple | 2 / 4 / 6 |
|
||||||
|
| B2B 보너스 | +1 |
|
||||||
|
| All Clear | +5 (B2B 카운트 유지) |
|
||||||
|
| 콤보 보너스 (콤보 2부터) | [1,1,2,2,3,3,4,4,4,5] 이후 5 고정 (초기값) |
|
||||||
|
|
||||||
|
- **상쇄(counter)**: 대기 중인 수신 가비지에서 내 공격량을 먼저 차감, 남은 만큼만 실제 전송.
|
||||||
|
- **투입**: 수신 가비지는 게이지에 누적 표시 → 다음 피스 락다운 시 하단 삽입. 구멍 열은 랜덤(70% 확률로 직전과 같은 열 유지 — 초기값).
|
||||||
|
- **가비지 한 번에 최대 삽입**: 8줄/회 (초과분은 대기 유지).
|
||||||
|
- **장기전 방지**: 라운드 90초 경과 후 30초마다 가비지 배율 +25% (커스텀에선 호스트가 끔 가능).
|
||||||
|
- **톱아웃** = 라운드 패배. FFA는 최후 생존자가 라운드 승리.
|
||||||
|
|
||||||
|
## 7. 커스텀 룸 — 인원 무제한 FFA
|
||||||
|
|
||||||
|
- **방 만들기**: 6자리 영숫자 코드 발급(혼동 문자 I/1/O/0 제외) → 로비. **참가하기**: 코드 입력.
|
||||||
|
- **최대 인원 제한 없음.** 2명 = 1:1, 3명+ = FFA(라운드마다 최후 생존자 승).
|
||||||
|
- 라운드 무한 반복 + 승수 누적. 호스트가 목표 승수 설정: **FT1 / FT3 / FT5** (기본 무제한 반복).
|
||||||
|
- **호스트 설정**: 가비지 배율 0.5×~2.0×, 목표 승수, 시드 모드(개인 bag 기본 / 동일 bag 공정전), 장기전 배율 on/off.
|
||||||
|
- **타겟팅**: 기본 랜덤(8초마다 자동 변경) + 상대 미니보드 탭으로 수동 지정. KO 피드 표시(`A → B 격추!`).
|
||||||
|
- KO된 플레이어는 라운드 끝까지 관전. **도중 입장 가능**(다음 라운드부터 참전). 호스트 퇴장 시 다음 입장자에게 위임.
|
||||||
|
- 레이팅 미반영(언랭크). 전적에 "커스텀" 표기. 결과창에서 **리매치 투표**(과반 동의 시 즉시 재시작).
|
||||||
|
|
||||||
|
## 8. 리그전 — 레이팅·랭크·매치메이킹
|
||||||
|
|
||||||
|
### 8.1 Glicko-2 & TR
|
||||||
|
- **Glicko-2** 전체 구현 (rating R, deviation RD, volatility σ). 초기값 R=1500, RD=350, σ=0.06, τ=0.5.
|
||||||
|
- **경기 승패로만 갱신** (라운드 무관). 경기 종료 시 서버에서 양측 동시 갱신.
|
||||||
|
- **표시용 TR (0~25,000)**: `TR = round(25000 / (1 + 10^((1600 − (R − RD)) / 300)))` — 상수 1600/300은 튜닝 대상(Phase 6에서 분포 보고 조정).
|
||||||
|
- **배치 10경기** 완료 전 TR 비공개("배치 n/10" 표시). **RD < 100일 때만 랭크 표시.**
|
||||||
|
- RD 하한 58. 7일 미접속 시 하루 +1씩 증가(최대 350) — Cron으로 일일 처리.
|
||||||
|
|
||||||
|
### 8.2 랭크 18단계 (초기 고정 TR 컷 — 운영 데이터로 조정)
|
||||||
|
```
|
||||||
|
D 0 · D+ 800 · C- 1,400 · C 2,000 · C+ 2,600 · B- 3,300 · B 4,000 · B+ 4,800
|
||||||
|
A- 5,700 · A 6,700 · A+ 7,800 · S- 9,200 · S 10,800 · S+ 12,400 · SS 14,200
|
||||||
|
U 16,500 · X 19,500 · X+ 22,500
|
||||||
|
```
|
||||||
|
(각 값 이상이면 해당 랭크. 인구가 충분해지면 퍼센타일 방식으로 전환.) 랭크 뱃지는 자체 아트, 승급/강등 연출 포함.
|
||||||
|
|
||||||
|
### 8.3 경기 형식 & 매치메이킹
|
||||||
|
- 형식: 두 플레이어 중 **높은 쪽 랭크** 기준 — A+ 이하 **FT3**, S- 이상 **FT5**. (FT7 없음 — 최대 FT5 확정)
|
||||||
|
- MatchmakerDO(싱글턴) 큐. 매칭 조건: 두 플레이어의 **글리코 R ± 2×RD 구간이 겹치면** 성사.
|
||||||
|
- 대기 30초마다 자기 구간을 ×1.2씩 확장. 120초+ 무매칭 시 "커스텀 룸에서 친구와 플레이" 안내 노출(큐 유지).
|
||||||
|
- 게스트는 리그전 참가 불가 (§9).
|
||||||
|
|
||||||
|
## 9. 계정 · 온보딩 (게스트 우선)
|
||||||
|
|
||||||
|
### 온보딩
|
||||||
|
- 첫 실행 시 가입 없이 즉시 플레이. **랜덤 게스트명 자동 부여**: `형용사+명사+숫자3` 조합 (예: "재빠른미노482"). 단어 풀은 각 20개 내외로 코드에 정의. [게스트] 뱃지 표시.
|
||||||
|
- 게스트 신원: 기기 로컬 ID(localStorage UUID) + 서버 발급 게스트 토큰.
|
||||||
|
- 게스트 가능: 솔로 전 모드, 커스텀 생성/참가. **불가**: 리그전, 리더보드 등록, 닉 변경.
|
||||||
|
|
||||||
|
### 로그인 (프로필 화면)
|
||||||
|
1. **Google 로그인**: Google Identity Services(웹 OAuth). 클라가 받은 ID 토큰을 서버로 전송 → Worker가 Google JWKS로 서명 검증 → `google_sub`로 계정 매칭/생성. ※ Play Games가 아닌 구글 계정 로그인(웹 배포 특성). 사전 준비물: Google Cloud Console OAuth 클라이언트 ID (사용자에게 발급 절차 안내할 것).
|
||||||
|
2. **이메일+비밀번호**: PBKDF2(WebCrypto, 반복 ≥100k, salt 개별) 해시. v1은 비밀번호 재설정 미지원(문구로 안내), v2에서 메일 인프라와 함께.
|
||||||
|
- **로그인 시 게스트 기록 자동 이전**: 솔로 베스트·커스텀 전적을 계정으로 병합(더 좋은 기록 우선).
|
||||||
|
- 세션: HMAC 서명 토큰(만료 30일), 자동 로그인.
|
||||||
|
|
||||||
|
### 닉네임 정책
|
||||||
|
- 로그인 유저만 변경 가능. **UNIQUE 보장**(D1), 2~12자(한글/영문/숫자/_), 실시간 중복 검사 API.
|
||||||
|
- 랜덤 게스트명 패턴은 시스템 예약(사칭 방지). 변경 쿨다운 30일.
|
||||||
|
|
||||||
|
## 10. 광고 & 수익화
|
||||||
|
|
||||||
|
- **원칙: 플레이 중 화면(②③④)에는 광고 0** — 조작 공간 보호 + 우발 클릭 방지(애드센스 정책 위반 리스크 회피).
|
||||||
|
- **하단 배너 (320×50/적응형)**: ① 메인(탭바 위), ⑤ 커스텀 로비. 자리는 §12 좌표 참고.
|
||||||
|
- **결과창 네이티브 카드 (300×250급)**: ⑥ 리그 결과, ⑨ 일반전 결과, 솔로 결과 — 모든 결과 화면 공통 슬롯.
|
||||||
|
- **전면(interstitial)**: 결과 확인 → 다음 행동 사이에만. 3판당 1회, 세션 첫 판 제외.
|
||||||
|
- **보상형**: v2.
|
||||||
|
- 구현: **AdSense 배너 + H5 Games Ads(Ad Placement API)**. 개발 중에는 광고 위치에 플레이스홀더 박스(점선 테두리 + "AD" 라벨)를 렌더하고, 실제 광고 코드는 배포 단계에서 사용자 애드센스 계정 ID로 끼운다.
|
||||||
|
- ⚠ 광고 게시 = 수익화 단계 → §2 이름 재검토 트리거 (구현 AI는 언급만, 판단은 사용자).
|
||||||
|
|
||||||
|
## 11. 조작 — 확정 배치 (390×844 기준 좌표)
|
||||||
|
|
||||||
|
**기본: 가상 버튼.** 조작 존 y612~812. 멀티터치 지원(이동 누른 채 회전 가능). touchstart 즉시 반응(클릭 지연 제거), 햅틱(vibrate 10ms) 옵션.
|
||||||
|
|
||||||
|
| 버튼 | x | y | w | h | 동작 |
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| HOLD | 16 | 612 | 144 | 56 | 홀드 |
|
||||||
|
| ↺ 좌회전 | 16 | 676 | 68 | 136 | CCW |
|
||||||
|
| ↻ 우회전 | 92 | 676 | 68 | 136 | CW |
|
||||||
|
| 180° | 168 | 612 | 54 | 56 | 180 회전 |
|
||||||
|
| 하드드롭 | 168 | 676 | 54 | 136 | 즉시 낙하+락 (마젠타 강조) |
|
||||||
|
| ◀ | 230 | 612 | 68 | 128 | 좌 이동 (홀드 시 DAS) |
|
||||||
|
| ▶ | 306 | 612 | 68 | 128 | 우 이동 (홀드 시 DAS) |
|
||||||
|
| ▼ 소프트 | 230 | 748 | 144 | 64 | 소프트드롭 |
|
||||||
|
|
||||||
|
- **핸들링 초기값**(설정 슬라이더): DAS 133ms(80~300), ARR 10ms(0~83, 0=즉시), SDF 20×(5~40).
|
||||||
|
- **옵션: 스와이프 모드**(설정 전환): 좌우 드래그=이동(거리=칸), 아래 빠른 플릭=하드, 아래 느린 드래그=소프트, 우측 탭=CW/좌측 탭=CCW, 홀드는 HOLD 박스 탭.
|
||||||
|
- 버튼 크기/투명도 3프리셋(소/중/대) 제공.
|
||||||
|
|
||||||
|
## 12. 화면별 상세 명세 (뷰포트 390×844, 세로 고정)
|
||||||
|
|
||||||
|
공통: **테마 이원화** — 메뉴·로비·결과 화면(①⑤⑥⑦⑧⑨)은 BONE(#EDE7DA) 라이트 테마, 인게임(②③④)은 INK(#17161B) 다크 테마. 팔레트·타이포·컴포넌트 규칙은 §13 디자인 시스템 v2를 따른다. 모든 메뉴 화면 하단 탭바(y764~844): 홈·리더보드·프로필·설정 (활성 탭 = SAFETY 오렌지 블록 + 잉크 보더).
|
||||||
|
|
||||||
|
**① 메인**: 상단 TETRIG 워드마크(24,46) + 우측 닉네임·랭크 칩. 시즌 바(24,76,342,40): "SEASON n · D-xx" + TR. 카드 3장(24,y,342,148 / y=132,300,468): 솔로(민트 좌측바)·멀티/리그전(마젠타)·커스텀(바이올렛), 각각 타이틀+설명+우측 쉐브론. **배너 광고(24,700,342,52)**. 탭바.
|
||||||
|
|
||||||
|
**② 솔로 인게임**: 일시정지(16,16,40,36). 상단 중앙: 모드명/시간(대)/LINES·PPS. 보드(20,92, 셀 25px → 250×500). 우측 열(292~374): HOLD 박스(82×56) → NEXT 라벨 → 넥스트 5개(각 82×54). 판정 팝업은 보드 중앙 상단에 페이드 텍스트. 조작 존 §11.
|
||||||
|
|
||||||
|
**③ 리그전 1:1**: 상단: 좌 내 칩 / 중앙 "2 : 1"+"리그전·FT3" / 우 상대 칩. 내 보드(16,86, 셀 22 → 220×440). **가비지 게이지**(244,86,10,440): 수신 대기량을 아래부터 마젠타로 채움 + 수치. 우측 열(262~374): 상대 실시간 미니보드(셀 10 → 100×200, 닉·랭크 라벨) → 내 HOLD(100×50) → NEXT 3개. 조작 존 동일. 라운드 종료 시 중앙 오버레이(승/패 + 스코어), 경기 종료 시 ⑥으로.
|
||||||
|
|
||||||
|
**④ 커스텀 FFA**: 상단 좌 "ALIVE 9/24", 우 타겟 칩("타겟: 랜덤/수동") + "미니보드 탭=타겟" 힌트. 그 아래 KO 피드 2줄. 내 보드(16,92, 셀 20 → 200×400). 우측 그리드(x 236/308, y 96/248/400): 상대 미니보드 2열(각 66×132, 닉 라벨, 타겟은 마젠타 테두리+조준 배지, KO는 회색+KO 표시), 마지막 타일 "+n명". 보드 아래 가로 스트립(y552): HOLD(70×52)+NEXT 5(각 52×52). 조작 존 동일.
|
||||||
|
|
||||||
|
**⑤ 커스텀 로비**: 헤더 "커스텀 룸"+뒤로. 코드 카드(20,70,350,124): "초대 코드" 라벨 + 코드 6자 대형(자간 넓게, 탭=복사) + [복사] 버튼 + "인원 제한 없음 · 현재 n명". 규칙 카드(20,210,350,58): 칩 3개(FTn·가비지 x.x×·bag 모드) + 호스트만 [변경]. 참가자 리스트(20,300~, 행 350×48·간격 8): 랭크칩+HOST칩+닉+준비상태(●/○). **배너 광고(20, 리스트 아래, 350×52)**. 하단 힌트 + [게임 시작](20,744,350,66, 마젠타 — 호스트) / 게스트는 [준비] 토글.
|
||||||
|
|
||||||
|
**⑥ 리그 결과**: "VICTORY"(민트)/"DEFEAT"(#FF6B6B) 대형 + "2:1 · 리그전 FT3". 레이팅 카드(30,220,330,160): TR 이전→이후 + 증감(민트/코럴) + 랭크칩 + 다음 랭크 게이지+%. 스탯 카드(30,398,330,86): APM/PPS/VS 3열. 상대 행(30,502,330,54): "vs 닉 · 랭크" + [전적 보기]. **광고 네이티브 카드(30,566,330,108)**. [다시 매칭](30,688,330,62, 마젠타) [메인으로](30,762,330,54).
|
||||||
|
|
||||||
|
**⑦ 프로필 (게스트 상태)**: 신원 카드(20,70,350,110): 아바타(블록 문양)+게스트명+[게스트]칩+"기록이 이 기기에만 임시 저장 중". 기록 카드(20,196,350,84): SPRINT/TIME ATTACK/플레이수 3열. 로그인 카드(20,300,350,262, 바이올렛 테두리): "로그인하고 이름을 가져가세요" + 혜택 3줄(고유 닉네임 / 기록·레이팅 영구 보존 / 리그전 참가) + **[Google로 계속하기]**(흰 배경 40,446,310,52) + **[이메일로 계속하기]**(40,508,310,44) + "로그인 시 게스트 기록이 계정으로 이전됩니다". 로그인 후에는 이 카드가 닉네임+[이름 변경]+로그아웃으로 대체. 탭바(프로필 활성).
|
||||||
|
|
||||||
|
**⑧ 솔로 모드 선택**: 메인 위 딤 오버레이 + 바텀시트(y404~844, 상단 핸들바): "솔로" 타이틀 + 행 3개(24,y,342,96 / y=486,594,702): SPRINT(민트바)·TIME ATTACK(앰버바)·ENDLESS(바이올렛바), 각각 설명+내 베스트+쉐브론.
|
||||||
|
|
||||||
|
**⑨ 일반전(커스텀) 결과**: "DEFEAT"(#FF6B6B) 또는 "VICTORY" + "n위/m명 · 커스텀 FFA"(1:1이면 스코어). 스탯 카드(30,220,330,86): KO/APM/PPS. **광고 카드(30,330,330,190, 300×250급)**. 순위 요약 행(30,540,330,54). [리매치 투표 n/m](30,688,330,62, 바이올렛) [로비로](30,762,330,54).
|
||||||
|
|
||||||
|
## 13. 비주얼 & 브랜드 — 디자인 시스템 v2 (NEOBRUTAL)
|
||||||
|
|
||||||
|
**방법론**: 사람 디자이너들이 실제로 쓰는 네오브루탈리즘 컴포넌트 체계(ekmas/neobrutalism-components 계열 규칙: 2px 잉크 보더, 블러 없는 하드 오프셋 섀도, 고대비 플랫 컬러, 최소 라운딩)를 기반으로, 이 게임 고유의 시그니처 **"해저드 시스템"**(가비지=위험에서 따온 45° 스트라이프 + 챔퍼컷 모서리)을 결합했다. **다크 네이비 배경·네온 글로우·그라디언트·블러 섀도·과도한 라운딩은 전면 금지** — AI 생성 티가 나는 디폴트이므로 사용하지 않는다.
|
||||||
|
|
||||||
|
### 팔레트
|
||||||
|
| 이름 | HEX | 용도 |
|
||||||
|
|---|---|---|
|
||||||
|
| BONE | #EDE7DA | 라이트 배경·밝은 패널 |
|
||||||
|
| PAPER | #E1D9C7 | 보조 패널 |
|
||||||
|
| INK | #17161B | 텍스트·보더·하드 섀도·인게임 배경 |
|
||||||
|
| SAFETY | #FF4E11 | 주 액션·공격·랭크 강조 |
|
||||||
|
| COBALT | #2B3FE0 | 리그·정보·보조 액션 |
|
||||||
|
| DWELL / DPNL / DGRID | #101015 / #1F1F26 / #26262E | 보드 웰 / 다크 패널 / 그리드 |
|
||||||
|
| SUB / DSUB | #6E6A5E / #8D8A80 | 보조 텍스트 (라이트/다크) |
|
||||||
|
|
||||||
|
### 피스 7색 (v2 확정 — 프린트 톤)
|
||||||
|
| I | O | T | S | Z | J | L | 가비지 |
|
||||||
|
|---|---|---|---|---|---|---|---|
|
||||||
|
| #3EC1B6 | #F5C531 | #A76BF2 | #7FCC4C | #F25C4C | #4C7DF2 | #F2913D | #46464F |
|
||||||
|
|
||||||
|
### 타이포 (3역할 — 구현 시 웹폰트)
|
||||||
|
- **디스플레이**: 각진 헤비 산세리프 — 'Black Han Sans'(구글 폰트, 무료) 권장 + **skewX(-8°) 이탤릭 처리**. 큰 숫자·VICTORY/DEFEAT·모드명·판정 팝업에만 절제 사용
|
||||||
|
- **본문**: 'Pretendard' 또는 시스템 산세리프
|
||||||
|
- **유틸/모노**: 'Nanum Gothic Coding' 또는 'IBM Plex Mono' — 초대 코드·TR·APM/PPS·라벨·시즌 표기
|
||||||
|
|
||||||
|
### 컴포넌트 규칙
|
||||||
|
- **패널**: 잉크 2~2.5px 보더 + **하드 오프셋 섀도(4~6px, 블러 0, 단색 잉크)** + **우하단 챔퍼컷 14px**
|
||||||
|
- **버튼**: 주 액션 = SAFETY 채움 + 잉크 텍스트·보더·섀도 / 보조 = BONE·PAPER 채움. 라운딩은 0~10px만
|
||||||
|
- **태그·랭크 뱃지**: 사각 스티커 + 잉크 보더. 랭크 뱃지는 **-3~-4° 틸트** (스티커 감성)
|
||||||
|
- **해저드 스트라이프 용법** (남용 금지 — 위험·공격·광고·난투에만): 가비지 게이지(다크: SAFETY×INK 스트라이프), 광고 슬롯 프레임(라이트: INK×BONE), 커스텀 카드 표식, DEFEAT 테이프
|
||||||
|
- **인게임 다크 패널**: #1F1F26 채움 + BONE 1.5~2px 보더, 섀도 없음(플랫 콘솔 느낌)
|
||||||
|
- **판정 팝업**: 디스플레이체 skew + SAFETY 밑줄 바 (글로우 금지)
|
||||||
|
- 연출도 플랫하게: 라인 클리어 파티클 = 사각 파편, 셰이크는 유지. 사운드 방향(Web Audio 신스)은 동일
|
||||||
|
|
||||||
|
### 로고 (부록 A v2)
|
||||||
|
- **워드마크**: BONE 바탕 + 잉크 셀 레터폼 + SAFETY 하드 오프셋 섀도. 첫 T 상단에 오렌지 T-미노(잉크 보더), **마지막 G의 모서리 셀 하나가 11° 틀어져 튀어나온 디테일**(의도된 불완전성 = 사람 손맛), 하단 해저드 테이프 + 모노 캡션 "RANKED STACK BATTLE"
|
||||||
|
- **앱 아이콘**: BONE 스퀘어클 + 잉크 T-미노(-7° 틸트) + SAFETY 하드 섀도 + 하단 해저드 밴드 + 잉크 링 보더
|
||||||
|
|
||||||
|
## 14. 서버 상세
|
||||||
|
|
||||||
|
### 14.1 구성
|
||||||
|
- **GameRoomDO** (경기당 1개, 리그·커스텀 공용): WS 허브, 가비지 원장·타겟 라우팅, 라운드/FT 관리, 시드 배포, 재접속 유예(15초, 리그는 초과 시 몰수), 리매치 투표, 결과를 D1에 기록 후 리그면 레이팅 갱신 호출.
|
||||||
|
- **MatchmakerDO** (싱글턴): 리그 큐, §8.3 규칙으로 페어링 → GameRoomDO 생성·양측 이관.
|
||||||
|
- **D1**: 아래 스키마. **Cron**: 일 1회 RD 감쇠, 시즌 마감 처리.
|
||||||
|
- N인 방 부하: 보드 스냅샷은 피스 락 시 + 플레이어당 초당 2회 상한, 방 인원이 클수록 주기 자동 완화(관전자·타겟 우선 전달). WebSocket Hibernation 사용.
|
||||||
|
- 최소 안티치트: PPS 상한(5.0), 피스당 공격량 상한, 라운드 이벤트 로그 보관(v2 정밀 검증 대비).
|
||||||
|
|
||||||
|
### 14.2 D1 스키마 초안 (구현 시 조정 가능)
|
||||||
|
```sql
|
||||||
|
CREATE TABLE users(
|
||||||
|
id TEXT PRIMARY KEY, nickname TEXT UNIQUE NOT NULL,
|
||||||
|
is_guest INTEGER NOT NULL DEFAULT 1,
|
||||||
|
email TEXT UNIQUE, google_sub TEXT UNIQUE, pw_hash TEXT, pw_salt TEXT,
|
||||||
|
created_at INTEGER, nickname_changed_at INTEGER
|
||||||
|
);
|
||||||
|
CREATE TABLE ratings(
|
||||||
|
user_id TEXT PRIMARY KEY REFERENCES users(id),
|
||||||
|
season INTEGER NOT NULL, glicko REAL, rd REAL, vol REAL,
|
||||||
|
tr INTEGER, games INTEGER DEFAULT 0, wins INTEGER DEFAULT 0, last_played INTEGER
|
||||||
|
);
|
||||||
|
CREATE TABLE matches(
|
||||||
|
id TEXT PRIMARY KEY, season INTEGER, mode TEXT, -- 'league' | 'custom'
|
||||||
|
finished_at INTEGER, room_size INTEGER,
|
||||||
|
p1 TEXT, p2 TEXT, score1 INTEGER, score2 INTEGER, -- 커스텀 FFA는 p1=본인, score1=순위
|
||||||
|
tr_delta1 INTEGER, tr_delta2 INTEGER
|
||||||
|
);
|
||||||
|
CREATE TABLE solo_records(
|
||||||
|
user_id TEXT, mode TEXT, best INTEGER, updated_at INTEGER,
|
||||||
|
PRIMARY KEY(user_id, mode)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 14.3 WebSocket 프로토콜 (JSON, 초안)
|
||||||
|
```
|
||||||
|
클라 → 서버: {t:"join", room, token} · {t:"ready"} · {t:"attack", lines, kind}
|
||||||
|
{t:"board", grid}(압축 비트필드) · {t:"topout"} · {t:"target", id}
|
||||||
|
{t:"rematch", vote} · {t:"leave"}
|
||||||
|
서버 → 클라: {t:"lobby", players[], rules} · {t:"seed", bag, mode}
|
||||||
|
{t:"round_start", n} · {t:"garbage", from, lines}
|
||||||
|
{t:"board", id, grid} · {t:"ko", who, by} · {t:"round_end", winner, score}
|
||||||
|
{t:"match_end", result, trDelta?} · {t:"rematch_state", votes}
|
||||||
|
```
|
||||||
|
가비지 계산은 클라 보고 기반이되 **서버가 원장 관리**(상쇄·라우팅·상한 검증)로 desync 방지.
|
||||||
|
|
||||||
|
## 15. 개발 로드맵 (이 순서로 진행)
|
||||||
|
|
||||||
|
| 단계 | 내용 | 완료 기준 |
|
||||||
|
|---|---|---|
|
||||||
|
| Phase 1 | 코어 엔진: 보드·피스·SRS+180 킥·7-bag·홀드·고스트·락딜레이·클리어 | 키보드로 플레이 가능 + 킥/판정 단위 테스트 통과 |
|
||||||
|
| Phase 2 | 판정·점수 + 솔로 3모드 + 솔로 결과 화면(광고 슬롯 포함) | 3모드 정상 플레이·기록 저장 |
|
||||||
|
| Phase 3 | §11 가상 버튼 + 스와이프 + 핸들링 설정 + §12 메뉴 화면들 | 모바일 브라우저 실기 조작 확인 |
|
||||||
|
| Phase 4 | 서버 뼈대: 게스트 토큰·계정(구글/이메일)·기록 이전·GameRoomDO·WS·가비지 원장 + 커스텀 1:1 | 탭 2개로 코드 방 1:1 대전 성사 |
|
||||||
|
| Phase 5 | 커스텀 FFA 확장: 다인 타겟팅·미니뷰 그리드·KO 관전·도중 입장·리매치 투표 | 탭 4개+ FFA 라운드 정상 진행 |
|
||||||
|
| Phase 6 | MatchmakerDO + Glicko-2 + TR/랭크 + 리더보드·프로필·전적 + 리그 결과 화면 | 매칭→경기→TR 반영 전체 사이클 |
|
||||||
|
| Phase 7 | 연출·사운드·시즌·광고 슬롯 연결·재접속/부하 시나리오 점검·폴리시 | v1 배포 (wrangler deploy + Pages) |
|
||||||
|
|
||||||
|
## 16. 스토어/랜딩 문구 (확정 카피)
|
||||||
|
|
||||||
|
- **태그라인**: "쌓아라, 부숴라, 올라가라." (예비: "손끝에서 터지는 실시간 블록 대전" / "리그는 열렸다. 랭크로 증명해라.")
|
||||||
|
- **짧은 설명**: 실시간 1:1 리그전부터 인원 무제한 커스텀 난투까지 — 모바일에 최적화된 대전 블록 스태커
|
||||||
|
- **전체 설명 구성**: 인트로(모바일 재설계·핸들링·랭크) → ■리그전(Glicko-2·18랭크·배치10·시즌) → ■커스텀(6자리 코드·인원 무제한·규칙 설정) → ■솔로(SPRINT/TIME ATTACK/ENDLESS) → ■손맛(SRS+·7-bag·T-spin·B2B·핸들링) → ■기록(리더보드·APM·PPS) → 클로징("배치 10경기를 끝내보세요")
|
||||||
|
- **영문 소개**: TETRIG — a real-time competitive block stacker built for mobile. Ranked 1v1 league with 18 tiers, unlimited-size custom rooms with invite codes, and solo modes with full handling customization.
|
||||||
|
- **ASO 키워드**: 블록 대전, 실시간 대전, 퍼즐 배틀, 스태커, 랭크 게임, 블록 퍼즐, 1:1 대결. ⚠ 설명·키워드에 "테트리스/Tetris" 직접 사용 금지.
|
||||||
|
|
||||||
|
## 17. 미확정 사항 (구현을 막지 않음 — 필요 시점에 사용자에게 확인)
|
||||||
|
|
||||||
|
1. 도메인: `tetrig.pages.dev` 무료로 시작. 커스텀 도메인(tetrig.com 등)은 사용자가 추후 결정
|
||||||
|
2. 시즌 길이 (제안 기본값: 2개월)
|
||||||
|
3. Google OAuth 클라이언트 ID (Phase 4 시작 시 사용자에게 발급 안내)
|
||||||
|
4. 애드센스 계정 ID (Phase 7 광고 연결 시)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 부록 A. 로고 SVG 원본 소스 (그대로 파일로 저장해 사용)
|
||||||
|
|
||||||
|
### A-1. tetrig-logo.svg (가로형 워드마크)
|
||||||
|
```svg
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1322 448" width="1322" height="448">
|
||||||
|
<defs><pattern id="hz" width="18" height="18" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
|
||||||
|
<rect width="18" height="18" fill="#EDE7DA"/><rect width="9" height="18" fill="#17161B"/></pattern></defs>
|
||||||
|
<rect width="1322" height="448" fill="#EDE7DA"/>
|
||||||
|
<rect x="87" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="139" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="191" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="139" y="139" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="139" y="191" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="139" y="243" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="139" y="295" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="132" y="184" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="132" y="236" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="132" y="288" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="80" y="80" width="46" height="46" rx="3" fill="#FF4E11" stroke="#17161B" stroke-width="3"/>
|
||||||
|
<rect x="132" y="80" width="46" height="46" rx="3" fill="#FF4E11" stroke="#17161B" stroke-width="3"/>
|
||||||
|
<rect x="184" y="80" width="46" height="46" rx="3" fill="#FF4E11" stroke="#17161B" stroke-width="3"/>
|
||||||
|
<rect x="132" y="132" width="46" height="46" rx="3" fill="#FF4E11" stroke="#17161B" stroke-width="3"/>
|
||||||
|
<rect x="279" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="331" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="383" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="279" y="139" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="279" y="191" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="331" y="191" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="383" y="191" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="279" y="243" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="279" y="295" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="331" y="295" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="383" y="295" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="272" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="324" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="376" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="272" y="132" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="272" y="184" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="324" y="184" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="376" y="184" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="272" y="236" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="272" y="288" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="324" y="288" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="376" y="288" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="471" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="523" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="575" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="523" y="139" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="523" y="191" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="523" y="243" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="523" y="295" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="464" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="516" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="568" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="516" y="132" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="516" y="184" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="516" y="236" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="516" y="288" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="663" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="715" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="663" y="139" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="767" y="139" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="663" y="191" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="715" y="191" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="663" y="243" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="767" y="243" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="663" y="295" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="767" y="295" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="656" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="708" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="656" y="132" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="760" y="132" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="656" y="184" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="708" y="184" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="656" y="236" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="760" y="236" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="656" y="288" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="760" y="288" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="855" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="907" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="959" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="907" y="139" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="907" y="191" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="907" y="243" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="855" y="295" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="907" y="295" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="959" y="295" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="848" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="900" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="952" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="900" y="132" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="900" y="184" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="900" y="236" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="848" y="288" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="900" y="288" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="952" y="288" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="1047" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="1099" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="1151" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="1203" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="1047" y="139" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="1047" y="191" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="1151" y="191" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="1203" y="191" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="1047" y="243" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="1203" y="243" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="1047" y="295" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="1099" y="295" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="1151" y="295" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="1040" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="1092" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="1144" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="1196" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="1040" y="132" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="1040" y="184" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="1144" y="184" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="1196" y="184" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="1040" y="236" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="1196" y="236" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="1040" y="288" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="1092" y="288" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="1144" y="288" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<g transform="rotate(11 1229.0 319.0)"><rect x="1209" y="297" width="46" height="46" rx="3" fill="#FF4E11" stroke="#17161B" stroke-width="3"/></g>
|
||||||
|
<rect x="80" y="350" width="216" height="12" fill="url(#hz)" stroke="#17161B" stroke-width="2"/>
|
||||||
|
<text x="312" y="361" font-family="NanumGothicCoding, monospace" font-size="15" font-weight="700" fill="#17161B" letter-spacing="2">RANKED STACK BATTLE</text>
|
||||||
|
</svg>
|
||||||
|
```
|
||||||
|
|
||||||
|
### A-2. tetrig-icon.svg (앱 아이콘 512×512)
|
||||||
|
```svg
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
|
||||||
|
<defs><pattern id="hz" width="18" height="18" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
|
||||||
|
<rect width="18" height="18" fill="#EDE7DA"/><rect width="9" height="18" fill="#17161B"/></pattern></defs>
|
||||||
|
<rect width="512" height="512" rx="96" fill="#EDE7DA"/>
|
||||||
|
<clipPath id="cp"><rect width="512" height="512" rx="96"/></clipPath>
|
||||||
|
<g clip-path="url(#cp)">
|
||||||
|
<rect x="0" y="428" width="512" height="84" fill="url(#hz)"/>
|
||||||
|
<rect x="0" y="424" width="512" height="5" fill="#17161B"/>
|
||||||
|
<g transform="rotate(-7 250.0 261.0)">
|
||||||
|
<rect x="92.0" y="162" width="104" height="104" rx="6" fill="#FF4E11" />
|
||||||
|
<rect x="210.0" y="162" width="104" height="104" rx="6" fill="#FF4E11" />
|
||||||
|
<rect x="328.0" y="162" width="104" height="104" rx="6" fill="#FF4E11" />
|
||||||
|
<rect x="210.0" y="280" width="104" height="104" rx="6" fill="#FF4E11" />
|
||||||
|
<rect x="80.0" y="150" width="104" height="104" rx="6" fill="#17161B" />
|
||||||
|
<rect x="198.0" y="150" width="104" height="104" rx="6" fill="#17161B" />
|
||||||
|
<rect x="316.0" y="150" width="104" height="104" rx="6" fill="#17161B" />
|
||||||
|
<rect x="198.0" y="268" width="104" height="104" rx="6" fill="#17161B" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<rect x="7" y="7" width="498" height="498" rx="90" fill="none" stroke="#17161B" stroke-width="10"/>
|
||||||
|
</svg>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 부록 B. UX 목업 파일 (첨부됨)
|
||||||
|
|
||||||
|
- 이 문서와 함께 **`tetrig-ux-mockup.png`** (9화면 시트, 1390×2944)가 첨부된다. **UI·레이아웃·색·버튼 배치는 이 목업을 시각 기준으로 구현**하고, §11~§13의 좌표·팔레트 수치를 함께 사용해 정확도를 맞춘다.
|
||||||
|
- 목업의 화면 번호(①~⑨)는 §12의 화면 명세 번호와 1:1 대응한다.
|
||||||
|
- 로고는 첨부된 `tetrig-logo.svg` / `tetrig-icon.svg`를 그대로 사용한다 (부록 A에 동일 소스).
|
||||||
21
tetrig-icon.svg
Normal file
21
tetrig-icon.svg
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
|
||||||
|
<defs><pattern id="hz" width="18" height="18" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
|
||||||
|
<rect width="18" height="18" fill="#EDE7DA"/><rect width="9" height="18" fill="#17161B"/></pattern></defs>
|
||||||
|
<rect width="512" height="512" rx="96" fill="#EDE7DA"/>
|
||||||
|
<clipPath id="cp"><rect width="512" height="512" rx="96"/></clipPath>
|
||||||
|
<g clip-path="url(#cp)">
|
||||||
|
<rect x="0" y="428" width="512" height="84" fill="url(#hz)"/>
|
||||||
|
<rect x="0" y="424" width="512" height="5" fill="#17161B"/>
|
||||||
|
<g transform="rotate(-7 250.0 261.0)">
|
||||||
|
<rect x="92.0" y="162" width="104" height="104" rx="6" fill="#FF4E11" />
|
||||||
|
<rect x="210.0" y="162" width="104" height="104" rx="6" fill="#FF4E11" />
|
||||||
|
<rect x="328.0" y="162" width="104" height="104" rx="6" fill="#FF4E11" />
|
||||||
|
<rect x="210.0" y="280" width="104" height="104" rx="6" fill="#FF4E11" />
|
||||||
|
<rect x="80.0" y="150" width="104" height="104" rx="6" fill="#17161B" />
|
||||||
|
<rect x="198.0" y="150" width="104" height="104" rx="6" fill="#17161B" />
|
||||||
|
<rect x="316.0" y="150" width="104" height="104" rx="6" fill="#17161B" />
|
||||||
|
<rect x="198.0" y="268" width="104" height="104" rx="6" fill="#17161B" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<rect x="7" y="7" width="498" height="498" rx="90" fill="none" stroke="#17161B" stroke-width="10"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
BIN
tetrig-logo.png
Normal file
BIN
tetrig-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
122
tetrig-logo.svg
Normal file
122
tetrig-logo.svg
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1322 448" width="1322" height="448">
|
||||||
|
<defs><pattern id="hz" width="18" height="18" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
|
||||||
|
<rect width="18" height="18" fill="#EDE7DA"/><rect width="9" height="18" fill="#17161B"/></pattern></defs>
|
||||||
|
<rect width="1322" height="448" fill="#EDE7DA"/>
|
||||||
|
<rect x="87" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="139" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="191" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="139" y="139" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="139" y="191" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="139" y="243" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="139" y="295" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="132" y="184" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="132" y="236" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="132" y="288" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="80" y="80" width="46" height="46" rx="3" fill="#FF4E11" stroke="#17161B" stroke-width="3"/>
|
||||||
|
<rect x="132" y="80" width="46" height="46" rx="3" fill="#FF4E11" stroke="#17161B" stroke-width="3"/>
|
||||||
|
<rect x="184" y="80" width="46" height="46" rx="3" fill="#FF4E11" stroke="#17161B" stroke-width="3"/>
|
||||||
|
<rect x="132" y="132" width="46" height="46" rx="3" fill="#FF4E11" stroke="#17161B" stroke-width="3"/>
|
||||||
|
<rect x="279" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="331" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="383" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="279" y="139" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="279" y="191" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="331" y="191" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="383" y="191" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="279" y="243" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="279" y="295" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="331" y="295" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="383" y="295" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="272" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="324" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="376" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="272" y="132" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="272" y="184" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="324" y="184" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="376" y="184" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="272" y="236" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="272" y="288" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="324" y="288" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="376" y="288" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="471" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="523" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="575" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="523" y="139" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="523" y="191" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="523" y="243" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="523" y="295" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="464" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="516" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="568" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="516" y="132" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="516" y="184" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="516" y="236" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="516" y="288" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="663" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="715" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="663" y="139" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="767" y="139" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="663" y="191" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="715" y="191" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="663" y="243" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="767" y="243" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="663" y="295" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="767" y="295" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="656" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="708" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="656" y="132" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="760" y="132" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="656" y="184" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="708" y="184" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="656" y="236" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="760" y="236" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="656" y="288" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="760" y="288" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="855" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="907" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="959" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="907" y="139" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="907" y="191" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="907" y="243" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="855" y="295" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="907" y="295" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="959" y="295" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="848" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="900" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="952" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="900" y="132" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="900" y="184" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="900" y="236" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="848" y="288" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="900" y="288" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="952" y="288" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="1047" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="1099" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="1151" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="1203" y="87" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="1047" y="139" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="1047" y="191" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="1151" y="191" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="1203" y="191" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="1047" y="243" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="1203" y="243" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="1047" y="295" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="1099" y="295" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="1151" y="295" width="46" height="46" rx="3" fill="#FF4E11" />
|
||||||
|
<rect x="1040" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="1092" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="1144" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="1196" y="80" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="1040" y="132" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="1040" y="184" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="1144" y="184" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="1196" y="184" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="1040" y="236" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="1196" y="236" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="1040" y="288" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="1092" y="288" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<rect x="1144" y="288" width="46" height="46" rx="3" fill="#17161B" />
|
||||||
|
<g transform="rotate(11 1229.0 319.0)"><rect x="1209" y="297" width="46" height="46" rx="3" fill="#FF4E11" stroke="#17161B" stroke-width="3"/></g>
|
||||||
|
<rect x="80" y="350" width="216" height="12" fill="url(#hz)" stroke="#17161B" stroke-width="2"/>
|
||||||
|
<text x="312" y="361" font-family="NanumGothicCoding, monospace" font-size="15" font-weight="700" fill="#17161B" letter-spacing="2">RANKED STACK BATTLE</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 8.7 KiB |
BIN
tetrig-ux-mockup.png
Normal file
BIN
tetrig-ux-mockup.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 339 KiB |
Reference in New Issue
Block a user