Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 12 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<p align="center">
<img src="public/assets/brand/coup-online-banner.png" alt="Coup Online" width="420">
<img src="public/assets/brand/coup-online-banner-v2.webp" alt="Coup Online" width="420">
</p>

<p align="center">
<img src="public/assets/cards/duke-v2.webp" alt="Duke card" width="70">
<img src="public/assets/cards/assassin-v2.webp" alt="Assassin card" width="70">
<img src="public/assets/cards/captain-v2.webp" alt="Captain card" width="70">
<img src="public/assets/cards/ambassador-v2.webp" alt="Ambassador card" width="70">
<img src="public/assets/cards/contessa-v2.webp" alt="Contessa card" width="70">
<img src="public/assets/cards/inquisitor-v2.webp" alt="Inquisitor card" width="70">
<img src="public/assets/cards/duke-v3.webp" alt="Duke card" width="70">
<img src="public/assets/cards/assassin-v3.webp" alt="Assassin card" width="70">
<img src="public/assets/cards/captain-v3.webp" alt="Captain card" width="70">
<img src="public/assets/cards/ambassador-v3.webp" alt="Ambassador card" width="70">
<img src="public/assets/cards/contessa-v3.webp" alt="Contessa card" width="70">
<img src="public/assets/cards/inquisitor-v3.webp" alt="Inquisitor card" width="70">
</p>

<p align="center">
Expand Down Expand Up @@ -52,7 +52,7 @@ Play Coup with 2–6 players from any device — no app install, no accounts. Cr

### Interface
- **Mobile-first** — portrait-optimized touch UI with 48px+ tap targets
- **Dark table theme** — generated tabletop backgrounds, compact illustrated cards, readable role/action labels, and character-colored borders
- **Retro-futurist table theme** — original generated character portraits, atmospheric tabletop backgrounds, readable role/action labels, and character-colored borders
- **Haptic feedback** — vibration on taps for mobile devices (with iOS Safari fallback), togglable in settings
- **Settings modal** — accessible from home, lobby, and in-game via gear icon. Controls for sound, haptic feedback (touch devices only), reduced animation, and text size (Normal / Large / Extra Large)
- **Player stats** — local lifetime stats, awards, and match history are available from the home screen
Expand Down Expand Up @@ -208,14 +208,12 @@ Coup/
│ ├── ROADMAP.md # Prioritized post-main product polish and follow-ups
│ └── REFORMATION_PLAN.md # Reformation expansion implementation plan
├── public/ # PWA icons, Open Graph image, and generated game art
│ ├── assets/ # Card, banner, and table background raster assets
│ ├── assets/ # Versioned cards, tables, wordmark, and app-icon master
│ ├── icons/ # PWA install icons
│ ├── coup-logo.png # Project/app icon used in docs
│ ├── coup-logo-transparent.png # Transparent-corner icon for docs/social art
│ ├── embed-image.png # Twitter/large-card social preview
│ ├── favicon.ico # Browser favicon
│ ├── embed-image-v3.png # Twitter/large-card social preview
│ ├── favicon-v2.ico # Browser favicon
│ ├── sw.js # Production service worker for static game assets
│ └── og-image.png # Open Graph social preview
│ └── og-image-v3.png # Open Graph social preview
├── tests/ # Test suite
│ ├── engine/ # Engine unit tests
│ └── server/ # Server unit tests
Expand Down
170 changes: 81 additions & 89 deletions docs/ASSETS.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/REFORMATION_PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ Examine flow:
- Color: Teal primary (#0d9488), light teal highlights (#5eead4)
- Animated: iris slowly pulses, magnifying glass has subtle gleam sweep

**Generated influence card art:** Reformation-enabled decks should use the same raster card-face pipeline as the base game, including `public/assets/cards/inquisitor-v2.webp` for the Inquisitor influence card. Keep the SVG `InquisitorIcon` for compact action/block controls where exact symbol readability matters.
**Generated influence card art:** Reformation-enabled decks should use the same raster card-face pipeline as the base game, including `public/assets/cards/inquisitor-v3.webp` for the Inquisitor influence card. Keep the SVG `InquisitorIcon` for compact action/block controls where exact symbol readability matters.

**FactionBadge SVGs:**
- Loyalist: Blue shield with crown silhouette (#3b82f6)
Expand Down
Binary file added public/apple-touch-icon-v2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed public/apple-touch-icon.png
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed public/assets/backgrounds/game-table-mobile.webp
Binary file not shown.
Binary file added public/assets/backgrounds/game-table-v2.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed public/assets/backgrounds/game-table.webp
Binary file not shown.
Binary file added public/assets/brand/app-icon-v2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/brand/coup-online-banner-v2.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed public/assets/brand/coup-online-banner.png
Binary file not shown.
Binary file removed public/assets/cards/ambassador-v2.webp
Binary file not shown.
Binary file added public/assets/cards/ambassador-v3.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed public/assets/cards/assassin-v2.webp
Binary file not shown.
Binary file added public/assets/cards/assassin-v3.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/cards/back-v2.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed public/assets/cards/back.webp
Binary file not shown.
Binary file removed public/assets/cards/captain-v2.webp
Binary file not shown.
Binary file added public/assets/cards/captain-v3.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed public/assets/cards/contessa-v2.webp
Binary file not shown.
Binary file added public/assets/cards/contessa-v3.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed public/assets/cards/duke-v2.webp
Binary file not shown.
Binary file added public/assets/cards/duke-v3.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed public/assets/cards/focus/ambassador-v2.webp
Binary file not shown.
Binary file added public/assets/cards/focus/ambassador-v3.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed public/assets/cards/focus/assassin-v2.webp
Binary file not shown.
Binary file added public/assets/cards/focus/assassin-v3.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/cards/focus/back-v2.webp
Binary file removed public/assets/cards/focus/back.webp
Diff not rendered.
Binary file removed public/assets/cards/focus/captain-v2.webp
Diff not rendered.
Binary file added public/assets/cards/focus/captain-v3.webp
Binary file removed public/assets/cards/focus/contessa-v2.webp
Diff not rendered.
Binary file added public/assets/cards/focus/contessa-v3.webp
Binary file removed public/assets/cards/focus/duke-v2.webp
Diff not rendered.
Binary file added public/assets/cards/focus/duke-v3.webp
Binary file removed public/assets/cards/focus/inquisitor-v2.webp
Diff not rendered.
Binary file added public/assets/cards/focus/inquisitor-v3.webp
Binary file removed public/assets/cards/inquisitor-v2.webp
Diff not rendered.
Binary file added public/assets/cards/inquisitor-v3.webp
Binary file removed public/coup-logo-transparent.png
Diff not rendered.
Binary file removed public/coup-logo.png
Diff not rendered.
Binary file added public/embed-image-v3.png
Binary file removed public/embed-image.png
Diff not rendered.
Binary file added public/favicon-16x16-v2.png
Binary file removed public/favicon-16x16.png
Diff not rendered.
Binary file added public/favicon-32x32-v2.png
Binary file removed public/favicon-32x32.png
Diff not rendered.
Binary file added public/favicon-v2.ico
Binary file not shown.
Binary file removed public/favicon.ico
Binary file not shown.
Binary file added public/icons/icon-192-v2.png
Binary file removed public/icons/icon-192.png
Diff not rendered.
Binary file added public/icons/icon-512-v2.png
Binary file removed public/icons/icon-512.png
Diff not rendered.
Binary file added public/icons/icon-maskable-512-v2.png
Binary file removed public/icons/icon-maskable-512.png
Diff not rendered.
Binary file added public/og-image-v3.png
Binary file removed public/og-image.png
Diff not rendered.
46 changes: 23 additions & 23 deletions public/sw.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
const CACHE_NAME = 'coup-assets-v2';
const CACHE_NAME = 'coup-assets-v3';
const ASSET_URLS = [
'/icons/icon-192.png',
'/icons/icon-512.png',
'/icons/icon-maskable-512.png',
'/apple-touch-icon.png',
'/assets/backgrounds/game-table.webp',
'/assets/backgrounds/game-table-mobile.webp',
'/assets/brand/coup-online-banner.png',
'/assets/cards/back.webp',
'/assets/cards/focus/back.webp',
'/assets/cards/duke-v2.webp',
'/assets/cards/assassin-v2.webp',
'/assets/cards/captain-v2.webp',
'/assets/cards/ambassador-v2.webp',
'/assets/cards/contessa-v2.webp',
'/assets/cards/inquisitor-v2.webp',
'/assets/cards/focus/duke-v2.webp',
'/assets/cards/focus/assassin-v2.webp',
'/assets/cards/focus/captain-v2.webp',
'/assets/cards/focus/ambassador-v2.webp',
'/assets/cards/focus/contessa-v2.webp',
'/assets/cards/focus/inquisitor-v2.webp',
'/icons/icon-192-v2.png',
'/icons/icon-512-v2.png',
'/icons/icon-maskable-512-v2.png',
'/apple-touch-icon-v2.png',
'/assets/backgrounds/game-table-v2.webp',
'/assets/backgrounds/game-table-mobile-v2.webp',
'/assets/brand/coup-online-banner-v2.webp',
'/assets/cards/back-v2.webp',
'/assets/cards/focus/back-v2.webp',
'/assets/cards/duke-v3.webp',
'/assets/cards/assassin-v3.webp',
'/assets/cards/captain-v3.webp',
'/assets/cards/ambassador-v3.webp',
'/assets/cards/contessa-v3.webp',
'/assets/cards/inquisitor-v3.webp',
'/assets/cards/focus/duke-v3.webp',
'/assets/cards/focus/assassin-v3.webp',
'/assets/cards/focus/captain-v3.webp',
'/assets/cards/focus/ambassador-v3.webp',
'/assets/cards/focus/contessa-v3.webp',
'/assets/cards/focus/inquisitor-v3.webp',
'/audio/velvet-court.mp3',
'/audio/court-crowned.mp3',
'/audio/plot-unraveled.mp3',
Expand Down Expand Up @@ -49,7 +49,7 @@ self.addEventListener('fetch', event => {

const url = new URL(request.url);
if (url.origin !== self.location.origin) return;
if (!url.pathname.startsWith('/assets/') && !url.pathname.startsWith('/audio/') && !url.pathname.startsWith('/icons/') && url.pathname !== '/apple-touch-icon.png') return;
if (!url.pathname.startsWith('/assets/') && !url.pathname.startsWith('/audio/') && !url.pathname.startsWith('/icons/') && !url.pathname.startsWith('/apple-touch-icon')) return;

event.respondWith(
caches.match(request).then(cached => {
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/pwa/PWAInstallPrompt.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export function PWAInstallPrompt() {
return (
<div className="fixed inset-x-3 bottom-3 z-[55] mx-auto max-w-md rounded-xl border border-coup-accent/40 bg-coup-surface/95 p-3 shadow-xl backdrop-blur">
<div className="flex items-center gap-3">
<img src="/icons/icon-192.png" alt="" className="h-10 w-10 rounded-lg" aria-hidden="true" />
<img src="/icons/icon-192-v2.png" alt="" className="h-10 w-10 rounded-lg" aria-hidden="true" />
<div className="min-w-0 flex-1">
<p className="text-sm font-bold text-gray-100">Install Coup</p>
<p className="text-xs text-gray-400">Faster launch and cached game assets on spotty Wi-Fi.</p>
Expand Down
8 changes: 4 additions & 4 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
background-image:
radial-gradient(circle at top, rgba(214,161,42,0.10), transparent 34rem),
radial-gradient(circle at bottom left, rgba(95,20,28,0.18), transparent 28rem),
linear-gradient(rgba(9,13,14,0.68), rgba(9,13,14,0.78)),
url('/assets/backgrounds/game-table.webp');
linear-gradient(rgba(9,13,14,0.42), rgba(9,13,14,0.56)),
url('/assets/backgrounds/game-table-v2.webp');
background-size: auto, auto, auto, cover;
background-position: center;
background-attachment: fixed;
Expand All @@ -30,8 +30,8 @@
background-image:
radial-gradient(circle at top, rgba(214,161,42,0.08), transparent 22rem),
radial-gradient(circle at bottom left, rgba(95,20,28,0.16), transparent 20rem),
linear-gradient(rgba(9,13,14,0.58), rgba(9,13,14,0.70)),
url('/assets/backgrounds/game-table-mobile.webp');
linear-gradient(rgba(9,13,14,0.36), rgba(9,13,14,0.50)),
url('/assets/backgrounds/game-table-mobile-v2.webp');
background-size: auto, auto, auto, cover;
background-position: center;
background-attachment: scroll;
Expand Down
9 changes: 0 additions & 9 deletions src/app/icon.svg
Diff not rendered.
12 changes: 6 additions & 6 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,19 @@ export const metadata: Metadata = {
},
icons: {
icon: [
{ url: '/favicon.ico', sizes: '32x32' },
{ url: '/favicon-32x32.png', sizes: '32x32', type: 'image/png' },
{ url: '/icons/icon-192.png', sizes: '192x192', type: 'image/png' },
{ url: '/favicon-v2.ico', sizes: '16x16 32x32 48x48' },
{ url: '/favicon-32x32-v2.png', sizes: '32x32', type: 'image/png' },
{ url: '/icons/icon-192-v2.png', sizes: '192x192', type: 'image/png' },
],
apple: '/apple-touch-icon.png',
apple: '/apple-touch-icon-v2.png',
},
openGraph: {
title: 'Coup Online',
description: 'Play Coup with friends online — bluff, challenge, and steal your way to victory in this multiplayer card game.',
siteName: 'Coup Online',
images: [
{
url: '/og-image.png',
url: '/og-image-v3.png',
width: 1200,
height: 630,
alt: 'Coup Online — Multiplayer Bluffing Card Game',
Expand All @@ -53,7 +53,7 @@ export const metadata: Metadata = {
card: 'summary_large_image',
title: 'Coup Online',
description: 'Play Coup with friends online — bluff, challenge, and steal your way to victory in this multiplayer card game.',
images: ['/embed-image.png'],
images: ['/embed-image-v3.png'],
},
};

Expand Down
6 changes: 3 additions & 3 deletions src/app/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,19 @@ export default function manifest(): MetadataRoute.Manifest {
background_color: '#090d0e',
icons: [
{
src: '/icons/icon-192.png',
src: '/icons/icon-192-v2.png',
sizes: '192x192',
type: 'image/png',
purpose: 'any',
},
{
src: '/icons/icon-512.png',
src: '/icons/icon-512-v2.png',
sizes: '512x512',
type: 'image/png',
purpose: 'any',
},
{
src: '/icons/icon-maskable-512.png',
src: '/icons/icon-maskable-512-v2.png',
sizes: '512x512',
type: 'image/png',
purpose: 'maskable',
Expand Down
36 changes: 18 additions & 18 deletions src/app/utils/assets.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
import { Character } from '@/shared/types';

export const BRAND_BANNER_ART = '/assets/brand/coup-online-banner.png';
export const TABLE_BACKGROUND_ART = '/assets/backgrounds/game-table.webp';
export const TABLE_BACKGROUND_MOBILE_ART = '/assets/backgrounds/game-table-mobile.webp';
export const BRAND_BANNER_ART = '/assets/brand/coup-online-banner-v2.webp';
export const TABLE_BACKGROUND_ART = '/assets/backgrounds/game-table-v2.webp';
export const TABLE_BACKGROUND_MOBILE_ART = '/assets/backgrounds/game-table-mobile-v2.webp';

export const CARD_BACK_ART = '/assets/cards/back.webp';
export const CARD_BACK_FOCUS_ART = '/assets/cards/focus/back.webp';
export const CARD_BACK_ART = '/assets/cards/back-v2.webp';
export const CARD_BACK_FOCUS_ART = '/assets/cards/focus/back-v2.webp';

export const CHARACTER_CARD_ART: Record<Character, string> = {
[Character.Duke]: '/assets/cards/duke-v2.webp',
[Character.Assassin]: '/assets/cards/assassin-v2.webp',
[Character.Captain]: '/assets/cards/captain-v2.webp',
[Character.Ambassador]: '/assets/cards/ambassador-v2.webp',
[Character.Contessa]: '/assets/cards/contessa-v2.webp',
[Character.Inquisitor]: '/assets/cards/inquisitor-v2.webp',
[Character.Duke]: '/assets/cards/duke-v3.webp',
[Character.Assassin]: '/assets/cards/assassin-v3.webp',
[Character.Captain]: '/assets/cards/captain-v3.webp',
[Character.Ambassador]: '/assets/cards/ambassador-v3.webp',
[Character.Contessa]: '/assets/cards/contessa-v3.webp',
[Character.Inquisitor]: '/assets/cards/inquisitor-v3.webp',
};

export const CHARACTER_CARD_FOCUS_ART: Record<Character, string> = {
[Character.Duke]: '/assets/cards/focus/duke-v2.webp',
[Character.Assassin]: '/assets/cards/focus/assassin-v2.webp',
[Character.Captain]: '/assets/cards/focus/captain-v2.webp',
[Character.Ambassador]: '/assets/cards/focus/ambassador-v2.webp',
[Character.Contessa]: '/assets/cards/focus/contessa-v2.webp',
[Character.Inquisitor]: '/assets/cards/focus/inquisitor-v2.webp',
[Character.Duke]: '/assets/cards/focus/duke-v3.webp',
[Character.Assassin]: '/assets/cards/focus/assassin-v3.webp',
[Character.Captain]: '/assets/cards/focus/captain-v3.webp',
[Character.Ambassador]: '/assets/cards/focus/ambassador-v3.webp',
[Character.Contessa]: '/assets/cards/focus/contessa-v3.webp',
[Character.Inquisitor]: '/assets/cards/focus/inquisitor-v3.webp',
};

export const CARD_ART_DIMENSIONS = { width: 512, height: 768 } as const;
export const BRAND_BANNER_DIMENSIONS = { width: 438, height: 180 } as const;
export const BRAND_BANNER_DIMENSIONS = { width: 864, height: 344 } as const;

export const CRITICAL_PRELOAD_IMAGES = [
BRAND_BANNER_ART,
Expand Down