99 lines
3.8 KiB
TypeScript
99 lines
3.8 KiB
TypeScript
/** 도블 30초 규칙 요약 (docs/07 §5). Pictures reuse the game's own icons (art.tsx). */
|
|
import type { ReactNode } from 'react';
|
|
import { ICONS } from './art';
|
|
import type { QuickCard } from '../types';
|
|
|
|
// Icon ids (art.tsx order): 사과 0, 해 1, 별 3, 하트 4, 꽃 11, 고양이 18, 물고기 20, 열쇠 28, 모자 36, 종 38, 자동차 41, 주사위 45.
|
|
const SLOTS: [number, number][] = [
|
|
[0, 0],
|
|
[0, -26],
|
|
[24, -12],
|
|
[24, 14],
|
|
[0, 28],
|
|
[-24, 14],
|
|
[-24, -12],
|
|
];
|
|
|
|
function Icon({ art, x, y, size = 20, ring }: { art: number; x: number; y: number; size?: number; ring?: 'ok' | 'bad' }) {
|
|
const draw = ICONS[art];
|
|
return (
|
|
<g>
|
|
{ring && <circle cx={x} cy={y} r={size * 0.62} fill={ring === 'ok' ? '#bbf7d0' : '#fecaca'} stroke={ring === 'ok' ? '#16a34a' : '#dc2626'} strokeWidth={2.5} />}
|
|
<g transform={`translate(${x - size / 2} ${y - size / 2}) scale(${size / 100})`}>{draw ? draw() : null}</g>
|
|
</g>
|
|
);
|
|
}
|
|
|
|
/** A round card at (cx, cy) with up to 7 icons; `rings` marks icons by id. */
|
|
function RoundCard({ cx, cy, arts, rings = {} }: { cx: number; cy: number; arts: number[]; rings?: Record<number, 'ok' | 'bad'> }) {
|
|
return (
|
|
<g>
|
|
<circle cx={cx} cy={cy} r={50} fill="#fff" stroke="#334155" strokeWidth={2.5} />
|
|
{arts.map((a, i) => (
|
|
<Icon key={a} art={a} x={cx + SLOTS[i]![0]} y={cy + SLOTS[i]![1]} ring={rings[a]} />
|
|
))}
|
|
</g>
|
|
);
|
|
}
|
|
|
|
function Pic({ children }: { children: ReactNode }) {
|
|
return (
|
|
<svg viewBox="0 0 250 150" width={250} height={150} aria-hidden>
|
|
{children}
|
|
</svg>
|
|
);
|
|
}
|
|
|
|
const A = [18, 0, 1, 3, 11, 28, 45];
|
|
const B = [20, 41, 18, 36, 4, 38, 33];
|
|
|
|
export const quickStart: QuickCard[] = [
|
|
{
|
|
pic: (
|
|
<Pic>
|
|
<RoundCard cx={64} cy={70} arts={A} />
|
|
<RoundCard cx={186} cy={70} arts={B} />
|
|
<text x={64} y={140} textAnchor="middle" fontSize={13} fontWeight={700} fill="currentColor">
|
|
가운데 카드
|
|
</text>
|
|
<text x={186} y={140} textAnchor="middle" fontSize={13} fontWeight={700} fill="currentColor">
|
|
내 카드
|
|
</text>
|
|
</Pic>
|
|
),
|
|
alt: '그림이 여러 개 그려진 동그란 카드 두 장이 나란히 있어요',
|
|
title: '두 카드를 비교해요',
|
|
text: '동그란 카드 두 장에는 똑같은 그림이 언제나 딱 하나 있어요. 차례 없이 모두 동시에 그 그림을 찾아요.',
|
|
},
|
|
{
|
|
pic: (
|
|
<Pic>
|
|
<RoundCard cx={64} cy={70} arts={A} rings={{ 18: 'ok' }} />
|
|
<RoundCard cx={186} cy={70} arts={B} rings={{ 18: 'ok', 20: 'bad' }} />
|
|
<text x={125} y={142} textAnchor="middle" fontSize={14} fontWeight={800} fill="#16a34a">
|
|
고양이 찾았다!
|
|
</text>
|
|
</Pic>
|
|
),
|
|
alt: '두 카드 모두에 있는 고양이 그림에 초록 동그라미, 한쪽에만 있는 물고기에 빨간 동그라미가 있어요',
|
|
title: '같은 그림을 먼저 눌러요',
|
|
text: '찾은 그림을 두 카드 중 아무 쪽에서나 누르면 돼요. 가장 먼저 누른 사람만 성공이에요. 틀리면 방 규칙에 따라 잠깐 못 눌러요.',
|
|
},
|
|
{
|
|
pic: (
|
|
<Pic>
|
|
{[0, 1, 2, 3].map((i) => (
|
|
<ellipse key={i} cx={90} cy={120 - i * 14} rx={50} ry={16} fill="#fff" stroke="#334155" strokeWidth={2.5} />
|
|
))}
|
|
<Icon art={18} x={90} y={78} size={22} />
|
|
<text x={190} y={100} textAnchor="middle" fontSize={56} aria-hidden>
|
|
🏆
|
|
</text>
|
|
</Pic>
|
|
),
|
|
alt: '동그란 카드가 탑처럼 쌓여 있고 옆에 트로피가 있어요',
|
|
title: '미니게임마다 목표가 달라요',
|
|
text: '탑 쌓기는 많이 모으면, 우물은 내 카드를 먼저 비우면, 독이 든 선물은 적게 받으면, 뜨거운 감자는 벌점이 적으면 이겨요.',
|
|
},
|
|
];
|