GAME
<title>Team Spade - 포커 규칙 가이드</title> <script src="https://cdn.tailwindcss.com"></script><style>
/* --- CSS 스타일 (화면 크기 확장 및 레이아웃 조정) --- */
:root {
--accent-color: #A855F7;
--bg-dark: #121212;
}
body {
font-family: 'Inter', 'Noto Sans KR', sans-serif;
background-color: var(--bg-dark);
color: #E0E0E0;
display: flex;
justify-content: center;
align-items: flex-start;
min-height: 100vh;
padding: 20px;
box-sizing: border-box;
}
/* 앱 컨테이너: 최대 너비 768px로 확장 */
.app-container {
max-width: 768px; /* 태블릿 크기 (패드) */
width: 100%;
background: var(--bg-dark);
border-radius: 20px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5);
padding: 30px; /* 패딩 증가 */
margin-top: 40px;
margin-bottom: 40px;
min-height: 80vh;
position: relative;
cursor: pointer;
display: flex;
flex-direction: column;
justify-content: space-between;
}
@media (max-width: 800px) {
/* 태블릿 환경에서도 가독성을 위해 패딩 유지 */
}
/* UI 애니메이션: 페이드 인 속도 0.8s */
.fade-in-out {
opacity: 0;
transform: translateY(10px);
animation: fadeIn 0.8s forwards;
}
@keyframes fadeIn {
to { opacity: 1; transform: translateY(0); }
}
.spade-icon::before { content: '\2660'; line-height: 1; }
/* --- 포커 카드 스타일링 --- */
.card-container {
display: flex;
justify-content: center;
gap: 15px;
margin: 40px 0;
height: 120px;
perspective: 1000px;
align-items: center;
}
.poker-card {
width: 70px;
height: 105px;
/* 배경색 제거 (뒷면 스타일이 전체를 덮도록 함) */
border-radius: 8px;
border: 1px solid #333;
font-size: 1.8rem;
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.4);
transition: all 0.8s ease-out;
transform-style: preserve-3d;
position: relative;
opacity: 0;
}
.card-back, .card-face {
backface-visibility: hidden;
display: flex;
justify-content: center;
align-items: center;
width: 100%; height: 100%;
border-radius: 8px;
position: absolute;
top: 0; left: 0;
}
/* 카드 뒷면: 보라색 배경, 흰색 물음표(?) */
.card-back {
background-color: var(--accent-color);
color: white;
transform: rotateY(0deg);
font-size: 2rem;
font-weight: 800; /* 물음표를 굵게 */
}
.card-face {
background-color: white; /* 카드 앞면 배경은 흰색 유지 */
color: #121212;
transform: rotateY(180deg);
flex-direction: column;
line-height: 1;
padding-top: 5px;
font-size: 1.5rem;
}
.poker-card.is-flipped { transform: rotateY(180deg); }
/* 애니메이션 속도 유지 */
@keyframes deal { 0% { opacity: 0; transform: translateY(-50px) scale(0.5); } 100% { opacity: 1; transform: translateY(0) scale(1); } }
@keyframes discard { 0% { transform: translateY(0) rotate(0deg); opacity: 1; } 50% { border-color: red; } 100% { transform: translate(50px, -50px) rotate(20deg); opacity: 0; border-color: red; } }
@keyframes replace { 0% { opacity: 0; transform: translateY(-50px) scale(0.5); } 100% { opacity: 1; transform: translateY(0) scale(1); } }
.red-suit { color: red; }
.black-suit { color: black; }
/* 터치 안내 메시지 위치 하단으로 유지 */
.touch-prompt {
position: absolute;
bottom: 30px;
left: 50%;
transform: translateX(-50%);
animation: pulse 1.5s infinite;
padding: 8px 15px;
background: #222;
border-radius: 20px;
white-space: nowrap;
font-size: 1.1rem;
}
.next-prompt { animation: none; color: #4ADE80; }
.progress-bar { height: 8px; background-color: #333; border-radius: 4px; margin-bottom: 20px; }
.progress-fill { height: 100%; background-color: var(--accent-color); border-radius: 4px; transition: width 0.8s ease-out; }
/* 텍스트 스타일: 상단에 배치되므로 강조 */
.rule-title { font-size: 2.5rem; font-weight: 800; }
.rule-description { font-size: 1.3rem; line-height: 1.6; font-weight: 400; color: #ccc;}
</style>
1/5
진행도
<div class="progress-bar">
<div id="progressFill" class="progress-fill"></div>
</div>
<div id="ruleText" class="mb-8">
</div>
<main id="ruleContent" class="flex-grow flex items-center justify-center">
</main>
<div class="touch-prompt text-gray-400 text-sm font-semibold fade-in-out" style="animation-delay: 0.8s;">
화면을 터치/클릭하여 애니메이션을 실행하세요 👉
</div>
?
?
?
?
?
${cardData[i].suit}`; cardEl.classList.add('is-flipped'); cardEl.style.transition = 'transform 0.8s ease-out'; } }, 50 + (i * 150)); } } } }, { title: "2. 교체 (버리고 받기)", description: "원하는 만큼의 카드를 버리고, **버린 수만큼 새 카드를 받습니다**.", prompt: "교체 애니메이션을 보기 위해 터치하세요.", content: `
${cardData.map((c, i) => `
?
${c.value}
${c.suit}
`).join('')}
${c.suit}
(예시: 2장 교체)
`,
action: (isFirstLoad) => {
if (!isFirstLoad) {
// 1. 카드 버리기 (K, 7)
setTimeout(() => {
const card1 = document.getElementById('card-d-1');
const card2 = document.getElementById('card-d-2');
if(card1) card1.style.animation = 'discard 1.0s forwards';
if(card2) card2.style.animation = 'discard 1.0s forwards';
}, 100);
// 2. 새로운 카드 받기
setTimeout(() => {
const newCard1 = { value: '9', suit: '♣', color: 'black-suit' };
const newCard2 = { value: 'Q', suit: '♥', color: 'red-suit' };
const card1 = document.getElementById('card-d-1');
const card2 = document.getElementById('card-d-2');
if(card1) {
card1.style.animation = 'none'; card1.style.opacity = 0; card1.classList.remove('is-flipped');
card1.innerHTML = `?${newCard1.value}${newCard1.suit}`; card1.style.animation = 'replace 0.8s forwards'; } if(card2) { card2.style.animation = 'none'; card2.style.opacity = 0; card2.classList.remove('is-flipped'); card2.innerHTML = `?${newCard2.value}
${newCard2.suit}`; card2.style.animation = 'replace 0.8s forwards'; } setTimeout(() => { if(card1) card1.classList.add('is-flipped'); if(card2) card2.classList.add('is-flipped'); }, 800); }, 1200); } } }, { title: "3. 교체 횟수 제한: 7회", description: "카드를 버리고 받는 행위는 게임당 **총 7회로 제한**됩니다. ", prompt: "횟수 차감 시뮬레이션을 보기 위해 터치하세요.", content: `
7
최대 교체 기회
${Array(7).fill().map((_, i) => `
`,
action: (isFirstLoad) => {
if (!isFirstLoad) {
const boxes = [1, 2, 3];
boxes.forEach((i, index) => {
setTimeout(() => {
const box = document.getElementById(`limit-box-${i}`);
if(box) {
box.style.backgroundColor = '#470000';
box.textContent = 'USED';
box.style.color = '#FF9999';
box.style.transition = 'background-color 0.5s, color 0.5s';
}
}, 500 * (index + 1));
});
}
}
},
{
title: "4. 진행 명령: Hit/Stay",
description: "턴이 되면 **'Hit'** (교체) 또는 **'Stay'** (멈춤) 중 하나를 선택합니다.",
prompt: "다음 규칙으로 이동하세요.",
content: `${i+1}회
`).join('')}
...
HIT
카드를 교체
STAY
교체를 멈춤
Stay 선택 시 최종 덱이 확정됩니다.
`, action: () => {} }, { title: "5. 최종 목표: 족보 완성", description: "7회 기회 내에서 'Stay'를 선언하여 **최고의 포커 족보**를 만드세요.", prompt: "가이드 종료", // 기존 버전의 콘텐츠로 복원 (p-5, text-2xl, text-sm) content: `최강의 덱
A
♠
♠
K
♠
♠
Q
♠
♠
J
♠
♠
10
♠
♠
✨ 로열 스트레이트 플러쉬
규칙 학습 완료! 즐거운 게임 되세요!
`, action: () => {} } ]; // --- 페이지 렌더링 함수 --- function renderPage(index, isActionOnly = false) { if (index >= totalPages) { alert("규칙 설명이 끝났습니다! 즐거운 게임 되세요."); currentPage = 0; pages.forEach(p => p._actionExecuted = false); renderPage(currentPage); return; } const page = pages[index]; if (!isActionOnly) { // UI 업데이트 (페이드 아웃) ruleContentEl.style.opacity = 0; ruleTextEl.style.opacity = 0; ruleContentEl.style.transition = 'opacity 0.5s'; ruleTextEl.style.transition = 'opacity 0.5s'; setTimeout(() => { // 상단 규칙 텍스트 교체 (애니메이션과 분리) ruleTextEl.innerHTML = `${page.description}
`; // 애니메이션 콘텐츠 교체 ruleContentEl.innerHTML = `${page.content}
`;
// UI 업데이트 (페이드 인)
ruleContentEl.style.opacity = 1;
ruleTextEl.style.opacity = 1;
ruleContentEl.style.transition = 'opacity 0.8s';
ruleTextEl.style.transition = 'opacity 0.8s';
// 진행도 업데이트
currentPageDisplayEl.textContent = `${index + 1}/${totalPages}`;
progressFillEl.style.width = `${((index + 1) / totalPages) * 100}%`;
// 프롬프트 업데이트
touchPromptEl.textContent = page.prompt;
touchPromptEl.classList.remove('next-prompt');
page.action(true);
}, 300);
} else {
page.action(false);
}
}
// --- 다음 페이지 이동 함수 (화면 클릭 시 호출됨) ---
function nextPage() {
const page = pages[currentPage];
// 1. 애니메이션 실행
if (page.action && !page._actionExecuted) {
renderPage(currentPage, true);
page._actionExecuted = true;
// UI를 업데이트하여 다음 클릭이 페이지 전환임을 알림
if (currentPage < totalPages - 1) {
touchPromptEl.textContent = '다음 규칙으로 이동 👉';
touchPromptEl.classList.add('next-prompt');
} else {
touchPromptEl.textContent = '가이드 종료 ✅';
touchPromptEl.classList.add('next-prompt');
}
return;
}
// 2. 페이지 전환
if (pages[currentPage]) pages[currentPage]._actionExecuted = false;
currentPage++;
renderPage(currentPage);
}
// 초기 페이지 로드
window.onload = () => {
pages.forEach(p => p._actionExecuted = false);
renderPage(currentPage);
}
</script>