trictrac/doc/client_web_design_proposals_alternative.md

382 lines
18 KiB
Markdown
Raw Permalink Normal View History

2026-04-08 20:40:47 +02:00
# client_web — Alternative Design Proposals: Neon Arcade Future
A second aesthetic direction: bold, playful, unapologetically modern. Where the first proposal channels an 18th-century gaming salon, this one asks: *what if trictrac ran on a holographic table in a Tokyo arcade, 2089?*
This document proposes a complete visual redesign with no obligation to mirror physical game objects. The priority is delight, readability, and memorability.
---
## Aesthetic Direction: "Holographic Arcade"
**Core concept**: The board floats in dark space as a self-illuminated slab. Fields pulse with neon light. Checkers are luminous marbles that leave light trails as they move. Scoring events trigger particle explosions. Every interaction has a micro-animation.
**The one unforgettable thing**: When a hole is won, the entire board floods with a colour wave — a full-screen shimmer that fades in 800ms — like a pinball machine tilting into multiball.
**Color palette**: Built on darkness, with high-saturation accents — cyan, magenta, gold. Not gradients on white (the generic AI aesthetic); instead, near-black backgrounds with glowing, luminous elements.
**Typography**: [Space Grotesk](https://fonts.google.com/specimen/Space+Grotesk) is overused. Instead:
- Display: [Syne](https://fonts.google.com/specimen/Syne) — geometric, confident, slightly alien
- Numerics: [DM Mono](https://fonts.google.com/specimen/DM+Mono) — for scores, dice values, field numbers — crisp monospace with personality
- UI labels: [Outfit](https://fonts.google.com/specimen/Outfit) — friendly, modern, clear at small sizes
```css
:root {
/* Base */
--void: #09090f; /* near-black with blue tint */
--surface: #12121f; /* board slab */
--surface-raised: #1a1a2e; /* panels, cards */
--surface-glass: rgba(255,255,255,0.05); /* glassmorphism */
/* Neon accents */
--cyan: #00e5ff;
--cyan-dim: #0099bb;
--magenta: #e040fb;
--gold: #ffd740;
--gold-dim: #c8a820;
--green-neon: #69ff47;
--orange-neon: #ff6d3a;
/* Player colors */
--player-white: #e8e0ff; /* soft violet-white */
--player-black: #1a0040; /* deep indigo-black */
--player-white-glow: #b39ddb;
--player-black-glow: #7c4dff;
/* Typography */
--font-display: 'Syne', sans-serif;
--font-mono: 'DM Mono', monospace;
--font-ui: 'Outfit', sans-serif;
/* Glow radii */
--glow-sm: 0 0 8px;
--glow-md: 0 0 16px;
--glow-lg: 0 0 32px;
}
```
---
## 1. Board: A Floating Holographic Slab
**Concept**: The board is a dark rectangular surface that appears to float — slight perspective tilt (CSS `perspective` + `rotateX(3deg)`), a thin neon border (1px cyan on top, 1px dimmer on bottom for depth), and a subtle inner glow that makes the board feel luminous from within.
```css
.board {
background: var(--surface);
border: 1px solid var(--cyan-dim);
box-shadow:
0 0 0 1px rgba(0,229,255,0.1),
0 0 40px rgba(0,229,255,0.08),
0 24px 60px rgba(0,0,0,0.8);
transform: perspective(1200px) rotateX(2deg);
transform-origin: center bottom;
border-radius: 4px;
}
```
The board background gets a very subtle **noise texture overlay** (SVG `<feTurbulence>` or a PNG grain layer at 3% opacity) — just enough to prevent it from looking like a flat rectangle, giving it material presence.
The center bar and side bars become **glowing dividers**: 4px wide, gradient from `var(--cyan)` at top to `var(--magenta)` at bottom, with a matching glow.
---
## 2. Fields: Neon Triangles with Zone Color Identity
Triangular fields (CSS `clip-path: polygon`) are essential here — they're geometric and modern, not just historically authentic.
Each quarter gets its **own neon color identity**, using a very dark base with a glowing triangle border:
| Quarter | Fields | Primary accent | Secondary (alternating) |
|---------|--------|---------------|------------------------|
| Small jan | 16 | `#00e5ff` (cyan) | `#0077aa` (dim cyan) |
| Big jan | 712 | `#7c4dff` (violet) | `#4a2a99` (dim violet) |
| Return jan | 1318 | `#e040fb` (magenta) | `#991a99` (dim magenta) |
| Last jan | 1924 | `#ffd740` (gold) | `#aa8800` (dim gold) |
The field itself is dark (`#14141f`). The color lives in a **glowing triangle border** — achieved with a layered `clip-path` + `::before` pseudo-element 2px larger that shows through as the border, with a CSS `filter: blur(3px)` outer glow:
```css
.field {
background: #14141f;
clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
position: relative;
}
.field::before {
content: '';
position: absolute;
inset: -2px;
background: var(--field-accent-color);
clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
filter: blur(4px);
opacity: 0.4;
z-index: -1;
}
```
**On hover (clickable fields)**: the glow intensifies (`opacity: 0.9`, `filter: blur(6px)`) and the field interior lightens slightly. A ripple animation radiates outward from the click point.
**Selected field**: the entire field interior fills with a semi-transparent neon color — not just the border — and a 2px dashed animated border spins around it (`animation: spin-border 1s linear infinite`).
---
## 3. Checkers: Luminous Marbles
Forget CSS circles with radial gradients. Each checker is a **glowing orb** with:
- A dark, slightly translucent core
- A radial highlight in the upper-left (simulating a point light source)
- A colored halo that radiates outward onto the field triangle
- A subtle inner reflection ring
```css
.checker.white {
background: radial-gradient(circle at 35% 30%,
#ffffff,
#c8c0e0 40%,
#8878c0 70%,
#3a2a60
);
box-shadow:
inset 0 2px 6px rgba(255,255,255,0.8),
inset 0 -2px 4px rgba(0,0,0,0.4),
0 0 12px rgba(179,157,219,0.6), /* violet-white glow */
0 0 24px rgba(124,77,255,0.3); /* outer violet halo */
}
.checker.black {
background: radial-gradient(circle at 35% 30%,
#7c4dff,
#4a2d99 40%,
#1a0a40 70%,
#09040f
);
box-shadow:
inset 0 2px 6px rgba(124,77,255,0.5),
inset 0 -2px 4px rgba(0,0,0,0.8),
0 0 12px rgba(124,77,255,0.7),
0 0 24px rgba(124,77,255,0.3);
}
```
**Stack depth**: A stack of N checkers renders with each checker offset by 6px vertically and slightly scaled (0.97× per level deeper), creating genuine 3D stack depth without any 3D CSS transform. The count label floats above as a monospace number in `var(--gold)`.
**Selection animation**: On click to select, the top checker of the stack does a quick `scale(1.2) translateY(-8px)` bounce (150ms spring easing), then settles at `scale(1.1) translateY(-4px)` while selected.
**Movement animation**: When a move is confirmed (board state diff), selected checkers do a **light-trail arc** — a bezier path from origin field center to destination, with a fading cyan streak left behind (`box-shadow` animated along the path via `@property` interpolation or JS Web Animation API). Duration: 300ms.
---
## 4. Dice: Holographic Crystals
Replace the SVG ivory dice with **translucent crystal cubes**:
- Each die face is a dark glass square with a thin neon border
- Pips are glowing dots — cyan for normal, gold for doubles
- The die face has a subtle `backdrop-filter: blur(4px)` on a glass background
```css
.die-face rect {
fill: rgba(255, 255, 255, 0.04);
stroke: var(--cyan);
stroke-width: 1.5;
rx: 6;
filter: drop-shadow(0 0 6px var(--cyan));
}
.die-face circle {
fill: var(--cyan);
filter: drop-shadow(0 0 4px var(--cyan));
}
```
**Double dice**: Both pips and borders switch to `var(--gold)`, with a stronger glow (`drop-shadow(0 0 8px var(--gold))`).
**Roll animation**: 600ms sequence —
1. Both dice **shatter outward** (`scale(0) rotate(720deg)`, opacity 0 → 1) appearing from nothing
2. During 400ms they rapidly cycle through face values (random pips swap every 60ms via CSS `animation`)
3. Final 200ms they decelerate and **snap** to the rolled values with a brief flash pulse
**Used die**: Fades the border to `rgba(255,255,255,0.1)` and dims pips to `rgba(255,255,255,0.2)` — the die goes "offline." A thin strikethrough line appears diagonally.
---
## 5. The Hole Tracker: Orbital Rings
Instead of progress bars, score and hole progress are visualised as **concentric orbital rings** beside each player's name panel — inspired by loading spinners, but static and data-driven.
- **Outer ring** (thick, 6px): hole progress. 12 segments, each one lights up as a hole is won. Segments are `var(--gold)` when won, near-invisible dark when empty.
- **Inner ring** (thin, 3px): point progress within the current hole. Continuously filled arc from 0° to (points/12 × 360°). Color: `var(--cyan)` for the active player, `var(--magenta)` for the opponent.
The arc fills animate with `stroke-dashoffset` transition (0.4s ease-out) on every point gain.
**Bredouille state**: The outer ring segments pulse — a slow `opacity: 0.6 → 1 → 0.6` sinusoidal glow — as long as bredouille is active. A small flag icon (⚑) in `var(--gold)` appears beside the ring.
---
## 6. Scoring Events: Light Shows
### Hole won — Full-board colour wave
A `position:fixed` `::after` overlay expands from the scoring player's side of the board:
- Radial gradient expanding from one edge: `rgba(255,215,64,0)``rgba(255,215,64,0.15)``rgba(255,215,64,0)`
- Duration: 800ms, ease-in-out
- Simultaneously: the scoring player's orbital rings segments animate sequentially (each segment snaps on with a 50ms delay)
- A large centered text `"+1 TROU"` in `var(--font-display)` at 3rem scales from 60% to 110% with `opacity: 0 → 1 → 0`, duration 1.2s
### Bredouille — The cascade
On top of the hole wave, add:
- A **confetti burst** of small colored squares (pure CSS: 20 `<span>` elements with randomised `animation-delay` and `translate`/`rotate` keyframes) in cyan, magenta, gold
- The `"+1 TROU"` text instead reads `"BREDOUILLE ×2"` in `var(--magenta)`
- The board border flashes: `border-color` cycles cyan → magenta → gold → cyan over 0.6s
### Jan scored — Notification card
Each jan scored gets a **toast card** that slides in from the right edge:
- Dark glass background (`rgba(26,26,46,0.95)`) with a left border in the jan's quarter color
- Jan name in `var(--font-ui)` bold, points in `var(--font-mono)` large
- Progress: `"+4 pts"` in cyan, `"+6 pts (double)"` in gold
- Cards stack vertically if multiple jans fire; each staggered by 80ms
- Auto-dismiss with a rightward slide-out after 3s
### Hit scored — Ripple on the target checker
When a hit is scored on a specific field, that field's checker emits a **sonar ripple**:
- 3 concentric rings expand from the checker's center, each `opacity: 1 → 0, scale: 1 → 2.5`
- Color: cyan for true hits, magenta for false hits (giving to opponent)
- Duration: 600ms per ring, staggered by 200ms
---
## 7. Player Panels: Glassmorphism Cards
Replace the cream `background: #f5edd8` panels with **glass cards** floating above the void:
```css
.player-score-panel {
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.1);
border-top: 1px solid rgba(255, 255, 255, 0.2); /* top catches light */
backdrop-filter: blur(12px) saturate(1.5);
border-radius: 12px;
box-shadow:
0 8px 32px rgba(0, 0, 0, 0.4),
inset 0 1px 0 rgba(255, 255, 255, 0.08);
}
```
**Active player panel**: the border glow of the active player's card brightens: `border-color: var(--cyan)` with `box-shadow: 0 0 16px rgba(0,229,255,0.2)`. A tiny animated pulse on the left edge (`width: 3px, animation: pulse 1.5s ease-in-out infinite`) indicates it is their turn.
**Player name**: Displayed in `var(--font-display)` at 1.1rem. A small colored dot (cyan for player 1, magenta for player 2) precedes the name — acts as the "you" indicator without needing a text suffix.
---
## 8. Status Bar: Dynamic Ambient Messaging
Replace the single plain-text status line with a **contextual bar** that changes character per game stage:
| Stage | Style | Color |
|-------|-------|-------|
| Waiting for opponent | Slow pulsing dots animation `... ` | Dim white |
| Your turn (roll) | "YOUR MOVE" in `var(--font-display)` with a blinking cursor | Cyan |
| Opponent's turn | Subtle shimmer on text | Dim magenta |
| Move selection | "SELECT CHECKER ①" with animated underline on "SELECT" | Cyan |
| Hold or Go | "SCORE!" with a spinning star ✦ | Gold |
| Paused (continue) | The bar has a pulsing amber background strip | Amber |
| Game over | Text cycles through all player colors | Full rainbow |
The bar itself is 3px tall and spans the full board width, showing a **neon progress shimmer** during the opponent's turn (a traveling gleam, like CSS `animation: shimmer` on a gradient).
---
## 9. Jan Zone Awareness: Neon Underlay
Rather than labels, the four quarters glow with their zone color in the background of the board — very subtle, just 4% opacity fills under the triangles:
```css
.board-quarter-small-jan { background: rgba(0, 229, 255, 0.04); }
.board-quarter-big-jan { background: rgba(124, 77, 255, 0.04); }
.board-quarter-return-jan { background: rgba(224, 64, 251, 0.04); }
.board-quarter-last-jan { background: rgba(255, 215, 64, 0.04); }
```
When hovering a scoring-notification row that references a specific jan (e.g. "Big jan conserved"), the corresponding quarter's background pulses from 4% → 15% opacity for 600ms. This replaces the arrow overlay with a spatial, zone-level highlight — more legible and visually coherent.
---
## 10. Rest Corner: The Crown Field
Field 12 (White) and 13 (Black) get a distinct appearance:
- The triangle is outlined in `var(--gold)` instead of its quarter's color
- A small **crown SVG** (⚜ or ♛) floats centered in the triangle at 30% opacity when empty, brighter when held
- When the player holds the corner (2 checkers there), the triangle interior fills with a very subtle gold shimmer animation (`background-position: 0% → 100%` on a diagonal gradient, 2s loop)
- When the corner is available to be taken *par puissance*, the crown pulses at 1Hz
---
## 11. Login Screen: Warp Speed Entrance
**Hero**: A dark void with an animated **particle field** — small white/cyan dots drifting slowly, like stars. Pure CSS with 50 `<span>` elements (or a single `<canvas>` for performance), each with randomised `animation-delay` and drift keyframe.
**Title**: "TRICTRAC" in `var(--font-display)` at 5rem, with a **chromatic aberration effect** — three slightly offset copies in cyan, magenta, and white, blended with `mix-blend-mode: screen`. The word appears with a `clip-path: inset(100% 0 0 0) → inset(0% 0 0 0)` reveal animation (the text "rises" into view).
**Tagline**: `"XVIIIe siècle · En ligne · ∞"` in `var(--font-mono)` at 0.85rem, appearing letter-by-letter with a 20ms interval.
**Mode cards**: Instead of three buttons, three **holographic tiles** in a row:
- Each is a glass card with an icon, label, and a colored accent strip on the bottom
- On hover: the card lifts (`translateY(-4px)`) and the bottom strip color floods the card (low opacity fill)
- CREATE: cyan accent; JOIN: violet accent; vs BOT: orange accent
**Room code input**: Dark glass input with a cyan border glow on focus, monospace font for the code, no placeholder text (just a blinking cursor showing it's ready). The input border animates a traveling gleam on focus.
---
## 12. Game-Over Screen: Score Reveal Ceremony
Instead of a modal over a frozen game, the game-over sequence is a **full-page takeover**:
1. **Board fades out** (800ms fade): the board dims to 20% opacity
2. **Score card rises** from the bottom: a tall glass card with both players' hole counts displayed large in `var(--font-display)``"8"` vs `"3"` — in their respective colors
3. **Winner highlight**: the winning number scales up to 200% with a gold burst radiation behind it
4. **Bredouille annotation**: if applicable, `"× 2"` appears beside the number with a magenta glow, then the number updates to the effective doubled count
5. **Continue options**: two buttons slide up last — "QUIT" and "REJOUER" — with the rejouer button pulsing in cyan
---
## 13. Global Micro-Interactions
These apply throughout and give the interface a consistently tactile feel:
- **Button press**: `scale(0.96)` on `:active`, 80ms, then spring back. No `opacity` change — scale is more physical.
- **Button focus**: neon outline ring animated in from 0 to full radius (not the browser default outline).
- **Panel hover**: glass cards shift `box-shadow` slightly for a lifted feel.
- **Page load**: all elements stagger in with a `translateY(10px) → 0 + opacity 0 → 1`, each component with a `animation-delay` offset (board: 0ms, panels: 100ms, side panel: 200ms).
- **Custom cursor** (optional): replace the default cursor with a small circle that trails slightly behind the real cursor position — creates a luxurious "lag" feeling. Pure JS: interpolate cursor position toward mouse position at 80% each frame.
---
## Implementation Notes for Leptos/WASM
### What's straightforward in pure CSS
- All color variables, glass panels, glow effects, orbital rings (SVG `stroke-dashoffset`)
- Dice roll animation (CSS keyframes)
- Toast slide-ins (CSS `@keyframes` + `animation`)
- Confetti (CSS `@keyframes` on positioned `<div>` elements)
- Particle field on login (CSS-only with many `<span>` elements)
### What needs a small JS/WASM component
- **Board perspective tilt** with mouse-tracking (subtle parallax) — `mouse_position` signal driving CSS custom property
- **Checker light-trail movement** — needs previous/next board diff, then Web Animation API or `requestAnimationFrame`
- **Chromatic aberration on title** — CSS filter or SVG filter, but the animation needs JS timing
### What needs Rust/Leptos state
- **Board diff for animation**: store previous `[i8; 24]` alongside current in `GameScreen` as a `Memo`, compute moved checkers
- **Event timing for sequences**: hole-won wave → score reveal → dismiss must be orchestrated; a `RwSignal<Option<AnimationState>>` in `GameScreen` drives each phase
### Progressive approach
The proposals above can be adopted incrementally. Suggested order:
1. CSS variables + dark theme + Syne/DM Mono fonts → immediate impact, zero logic change
2. Glass panels, neon borders, glow effects → pure CSS
3. Orbital ring score tracker → SVG component
4. Triangular fields + zone colors → `board.rs` structural change
5. Dice animation → CSS keyframes in `die.rs`
6. Toast notifications → new `toast.rs` component
7. Hole-won wave → CSS overlay + Leptos signal
8. Checker animation → board diff + Web Animation API