diff --git a/LabyrinthPro.png b/LabyrinthPro.png
new file mode 100644
index 0000000..4590583
Binary files /dev/null and b/LabyrinthPro.png differ
diff --git a/MazeMaster.png b/MazeMaster.png
new file mode 100644
index 0000000..1e3f887
Binary files /dev/null and b/MazeMaster.png differ
diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md
new file mode 100644
index 0000000..e4cb603
--- /dev/null
+++ b/docs/ARCHITECTURE.md
@@ -0,0 +1,56 @@
+# Architecture: Labyrinth Solver V2
+
+This document details the system design, directory structures, worker pipelines, and state management flow of the Labyrinth Solver.
+
+## Core Component Diagram
+```mermaid
+graph TD
+ App[src/App.tsx] --> AppHeader[src/components/AppHeader.tsx]
+ App --> MainLayout[Main View Grid]
+
+ MainLayout --> LeftSidebar[Setup Panel Widget]
+ MainLayout --> CentralHero[Board.tsx & Tile.tsx]
+ MainLayout --> RightSidebar[Solver Panel Widget]
+
+ App --> Worker[src/solver.worker.js]
+ Worker --> Pathfinder[src/solver.js - BFS Engine]
+
+ App --> HistoryHook[useLabyrinthHistory.ts]
+ App --> StorageHook[useLabyrinthStorage.ts]
+ App --> AudioSystem[utils/audio.ts - Web Audio API]
+```
+
+## Folder Structure (Modernized V2)
+
+To reduce technical debt and maximize maintainability, files are grouped logically by concern:
+
+```
+src/
+├── assets/ # Raw svg / graphic resources
+├── components/ # React markup and presentation
+│ ├── ui/ # Radix & Shadcn UI primitive blocks
+│ ├── board/ # Board rendering & Tile renderers
+│ ├── panels/ # Left and Right panels (Setup / Solver widgets)
+│ └── modals/ # Dialog views (MoveHistory, Settings, PhotoScan)
+├── hooks/ # State & behavior lifecycle code
+├── lib/ # Adapters, utilities, and helper code
+├── utils/ # Base services (e.g. Synthesized Audio system)
+├── types.ts # Common type interfaces
+├── solver.js # Core BFS search calculations
+├── solver.worker.js # Off-thread Web Worker wrapper
+└── main.tsx # App render mounting
+```
+
+## System Modules
+
+### 1. Web Worker Pipeline
+Complex pathfinder searches run inside `solver.worker.js` (Web Worker).
+- **Communication Protocol**: JSON messages containing the serialized 7x7 board state, players' current target coordinates, active pawn color, and search depth parameters (`maxTurns`).
+- **Response**: The solver returns a sorted list of best moves, each featuring path coordinates (`pawnPath`), arrow directions, and explanations.
+
+### 2. State & History Synchronization
+- **`useLabyrinthHistory`**: Keeps deep cloned snapshots of `AppGameState` to manage custom undo/redo actions.
+- **`useLabyrinthStorage`**: Provides quick read/write tools to standard `localStorage` to save game slots and sync setup options.
+
+### 3. Native Web Audio Synth
+Audio feedback is synthesized dynamically using the Web Audio API in `src/utils/audio.ts` (minimizing app footprint by not packing static mp3/wav files).
diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
new file mode 100644
index 0000000..f52732a
--- /dev/null
+++ b/docs/CHANGELOG.md
@@ -0,0 +1,22 @@
+# Changelog: Labyrinth Solver Redesign
+
+All notable changes to the Labyrinth Solver V2 will be documented in this file.
+
+## [2.0.0] - Modernized Design & Refactored Architecture
+
+### Added
+- Created V2 Master Plan, Design System guidelines, and updated Architecture specs.
+- Designed premium application frame shell (desktop sidebar layout, mobile drawer layouts).
+- Integrated framer-motion animations for sidebar transitions and tile shifts.
+- Implemented high-contrast Light/Dark mode themes.
+- Added **3D Isometric Perspective View**: Live 3D board tilting with card/badge billboarding to stand upright towards the camera.
+- Added **3D Board Tray Platform**: Grid board tilts inside a real 3D play tray styled in Neo-Brutalism thick borders and shadows, scaling responsively utilizing `w-full h-full aspect-square` grids.
+- Added **Rounded Pathway Tubes**: Replaced blocky pathways with smooth white plastic tubes with highlight bevels and drop-shadow styling.
+- Added **Glossy Peg Pawns & Gold Coins**: Pawns render as glossy spherical 3D pegs, and treasures render as circular gold medallions.
+- Added **Soft-Neumorphic Shadows**: Standard 2D view renders tiles and buttons with double-shadow highlights (`shadow-neumorphic`) for a soft, pillow-like extruded look.
+- Added **Neo-Brutalist Styling**: Cards and buttons utilize thick black borders and flat offset solid shadows (`neo-brutalism-card` and `neo-brutalism-button`).
+
+### Changed
+- Unified all tiles to render as a consistent warm stone gray clay block with thick black outlines (pawn starts retain colors for game logic).
+- Removed temporary Dashboard widgets panel.
+- Refactored color system to map shadcn/ui semantic variables (background, card, border) to theme-aware values, eliminating hardcoded dark panels in light mode.
diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md
new file mode 100644
index 0000000..8a7ff84
--- /dev/null
+++ b/docs/DECISIONS.md
@@ -0,0 +1,38 @@
+# Decisions Log: Labyrinth Solver V2
+
+This document records the Architectural Decision Records (ADRs) for Project Phoenix.
+
+---
+
+## ADR 1: Unified Component Organization
+
+### Context
+The original project placed all UI components (board, tiles, settings dialog, setup panel, side sheets) inside a flat `src/components/` directory. As the application grows in features, this clutter makes it harder to identify visual modules and reuse styles.
+
+### Decision
+Segregate components into functional subfolders under `src/components/`:
+- `board/`: Contains the board grid space (`Board.tsx`, `Tile.tsx`, and relevant helper cards).
+- `panels/`: Houses sidebar panels (`SetupPanel.tsx`, `SolverPanel.tsx`, `StatsPanel.tsx`).
+- `modals/`: Houses full screen and overlay dialogs (`SettingsDialog.tsx`, `BoardScanModal.tsx`, `MoveHistoryDialog.tsx`, `WelcomeGuide.tsx`).
+- `ui/`: Standard reusable design primitives.
+
+### Consequences
+- Imports will be cleaner and localized.
+- Easier to navigate component dependencies.
+- Avoids namespace clutter.
+
+---
+
+## ADR 2: Responsive Workspace Grid
+
+### Context
+The board is the hero element of the game (~70% visual focus on desktops). We need a layout that handles both ultra-wide screens and compact mobile devices (portrait screens, touch inputs).
+
+### Decision
+We will construct a CSS Grid wrapper in `App.tsx` that splits the layout:
+- **Desktop (md and above)**: A 3-column grid of `[Setup Sidebar (Left)] [Board (Center)] [Solver & Analysis (Right)]`.
+- **Mobile / Portrait**: A vertical stacks system where the board is centered at the top, and bottom-sheets / sliding drawer panels display Setup/Solver actions.
+
+### Consequences
+- Optimizes board layout constraints dynamically.
+- Eliminates overlapping widgets or double scrollbars.
diff --git a/docs/DESIGN_SYSTEM.md b/docs/DESIGN_SYSTEM.md
new file mode 100644
index 0000000..5a167de
--- /dev/null
+++ b/docs/DESIGN_SYSTEM.md
@@ -0,0 +1,44 @@
+# Design System: Labyrinth V2 (Project Phoenix)
+
+This document defines the visual layout guidelines, typographic hierarchy, color systems, and animation guidelines for the redesigned browser game.
+
+## Visual Archetype: Sleek Desktop in the Browser
+The design system takes cues from high-performance desktop tools (Linear, Raycast, Apple Sonama), utilizing space, glassmorphism, subtle micro-animations, and minimal borders to create a calm, professional experience.
+
+---
+
+## 🎨 Color Palette
+
+### 🟢 Base Colors (Dark Theme First)
+- **Background**: `stone-950` (#0c0a09) — Neutral deep slate.
+- **Surface**: `stone-900` (#1c1917) — Raised panels and cards.
+- **Muted Surface**: `stone-900/50` — Secondary list elements.
+- **Borders**: `stone-800` (#292524) — Clean, thin hairline boundary.
+- **Foreground Text**: `stone-50` (#fafaf9) — High contrast text.
+- **Muted Text**: `stone-400` (#a8a29e) — Secondary description text.
+
+### 🟡 Brand & Accent Theme Tint
+- **Default Theme Color**: Amber Orange (`#f59e0b`).
+- Custom accent colors can be specified in settings (synchronized into CSS variables `--theme-color`, `--theme-color-rgb`, and `--theme-glow`).
+
+---
+
+## 📐 Spacing & Layout
+- **The 70% Board Rule**: The Labyrinth board occupies ~70% of the desktop viewport space. Side panels split the remaining 30%.
+- **Borders**: Always `1px` width using `--color-border` (`stone-800`). Avoid heavy dividers.
+- **Border Radius**: Use `0.75rem` (`rounded-xl`) for panel containers and cards; `0.5rem` (`rounded-lg`) for buttons and small badges.
+
+---
+
+## ✍️ Typography
+- **Primary Font**: Inter / system-ui (clean, readable interface elements).
+- **Display Font**: Outfit / system-ui (headers and titles).
+- **Line Heights**: Relaxed line spacing for text descriptions; tight heights for compact metrics cards.
+
+---
+
+## 🎭 Animations & Transitions
+- **Hover effects**: Translate up by `1px` with a subtle glow increase.
+- **Slide animations**: Smooth translations when inserting the spare tile.
+- **Pawn movement**: Fast, snappy cubic-bezier offsets (`cubic-bezier(0.16, 1, 0.3, 1)`) to avoid trailing delays.
+- **Spring parameters**: `stiffness: 300, damping: 30` for interactive overlays.
diff --git a/docs/MASTER_PLAN.md b/docs/MASTER_PLAN.md
new file mode 100644
index 0000000..e0738ae
--- /dev/null
+++ b/docs/MASTER_PLAN.md
@@ -0,0 +1,72 @@
+# Master Plan: Labyrinth Solver V2 Modernization
+
+This document tracks the execution phases for Project Phoenix—the complete modernization of the Labyrinth Solver.
+
+## Progress Overview
+
+- [x] **Phase 1: Project Audit & Assessment** (Done)
+- [x] **Phase 2: Architectural Design** (Done)
+- [x] **Phase 3: Design System Definition** (Done)
+- [x] **Phase 4: Shell & Frame Implementation** (Done)
+- [x] **Phase 5: Board Modernization** (Done)
+- [x] **Phase 6: Solver Widgets Integration** (Done)
+- [x] **Phase 7: Animation & UX Polish** (Done)
+- [x] **Phase 8: Release Review & Verification** (Done)
+
+---
+
+## Phase Details & Checklists
+
+### Phase 1: Project Audit & Assessment
+- [x] Examine existing React app and folder structure.
+- [x] Identify strengths and weaknesses of the current UI.
+- [x] Review typescript types, state hooks, and solver integrations.
+- [x] Document audit findings in `docs/ARCHITECTURE.md`.
+- [x] Record baseline layout, design system issues, and target layout metrics.
+
+### Phase 2: Architectural Design
+- [x] Design decoupled, modular component structure.
+- [x] Establish folder design in `docs/ARCHITECTURE.md`.
+- [x] Move board setup, solver state, and utility code into clean directories.
+- [x] Plan state synchronization model and background worker pipelines.
+- [x] Create ADRs in `docs/DECISIONS.md`.
+
+### Phase 3: Design System Definition
+- [x] Set up unified CSS variables and dark/light tokens in `docs/DESIGN_SYSTEM.md`.
+- [x] Define premium styling variables: typography (Outfit/Inter), spacing, border radius, and glassmorphism.
+- [x] Define animation guidelines with framer-motion and vanilla transitions.
+- [x] Check compatibility of Tailwind v4 configs with our design variables.
+
+### Phase 4: Shell & Frame Implementation
+- [x] Create core layout skeleton (Sidebar + Main Board View + Right Panels).
+- [x] Implement responsive behavior (Side sheets for mobile, expanded grids for desktop).
+- [x] Rebuild Navigation header with premium styling (Glassmorphism, custom toggles).
+- [x] Implement user settings dialog, local storage configurations, and audio mute settings.
+- [x] Build theme toggle (Light / Dark) supporting clean color palettes.
+
+### Phase 5: Board Modernization
+- [x] Re-engineer `Board` and `Tile` components.
+- [x] Add smooth animations for sliding rows/columns (Framer Motion).
+- [x] Refine drag-and-drop tiles (dnd-kit integration) with smooth drag indicators.
+- [x] Implement clean hover previews for paths, reachable nodes, and active targets.
+- [x] Clean up board rotation animation support.
+
+### Phase 6: Solver Widgets Integration
+- [x] Create current objective card showing target card details and stats.
+- [x] Build "Best Move" suggestion widget with a visual route preview.
+- [x] Build "Alternative Moves" list and rankings with collapsible path details.
+- [x] Rebuild statistics panel and turn history widgets.
+- [x] Rebuild player hands manager and setup settings widgets.
+
+### Phase 7: Animation & UX Polish
+- [x] Add micro-animations to all interactive buttons, cards, and list items.
+- [x] Implement keyboard shortcut overlays and smooth sheet animations.
+- [x] Verify accessibility, standard ARIA labels, and keyboard navigation.
+- [x] Test mobile response, scroll indicators, and swipe behaviors.
+
+### Phase 8: Release Review & Verification
+- [x] Perform a full codebase review for clean, strict TypeScript.
+- [x] Clean up redundant code, styles, and comments.
+- [x] Run full test suites (`vitest`) and type checking.
+- [x] Verify deployment configuration for Vercel.
+- [x] Certify full project completion.
diff --git a/docs/TODO.md b/docs/TODO.md
new file mode 100644
index 0000000..d2fc5b2
--- /dev/null
+++ b/docs/TODO.md
@@ -0,0 +1,23 @@
+# Todo List: Labyrinth Solver V2
+
+This document tracks immediate task checklists for development and testing.
+
+## Active Tasks
+
+### Phase 1: Audit
+- [x] Review current components, folders, and tests.
+- [x] Create baseline design and documentation system.
+
+### Phase 2: Architecture
+- [x] Refactor component subdirectories (`components/board`, `components/panels`, `components/modals`).
+- [x] Re-route component imports inside `App.tsx` and test files.
+
+### Phase 3: Design System
+- [x] Establish styling properties in `index.css`.
+- [x] Confirm layout spacing variables are compatible with Tailwind v4.
+
+### Phase 4 & Beyond
+- [x] Implement V2 shell UI (layout, navigation header, control widgets).
+- [x] Implement V2 board design (animations, previews, indicators).
+- [x] Implement V2 solver panels & details layout.
+- [x] Verify test suite passes (`npm test`).
diff --git a/index.html b/index.html
index 6a89e8d..6802f51 100644
--- a/index.html
+++ b/index.html
@@ -8,6 +8,10 @@
+
+
+
+
Labyrinth Game Solver
diff --git a/src/App.tsx b/src/App.tsx
index 7b1cc2b..63a3259 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -13,16 +13,16 @@ import {
} from "@dnd-kit/core";
import { SHIFT_ARROWS, TREASURES, DEFAULT_PAWN_POSITIONS } from "./constants";
import type { TileData, SolverSolution } from "./types";
-import { Board } from "./components/Board";
-import { Tile } from "./components/Tile";
+import { Board } from "./components/board/Board";
+import { Tile } from "./components/board/Tile";
import { Button } from "./components/ui/button";
-import { SolverPanel } from "./components/SolverPanel";
-import { SetupPanel } from "./components/SetupPanel";
-import { BoardScanModal } from "./components/BoardScanModal";
-import { MoveHistoryDialog } from "./components/MoveHistoryDialog";
-import { StatsPanel } from "./components/StatsPanel";
+import { SolverPanel } from "./components/panels/SolverPanel";
+import { SetupPanel } from "./components/panels/SetupPanel";
+import { BoardScanModal } from "./components/modals/BoardScanModal";
+import { MoveHistoryDialog } from "./components/modals/MoveHistoryDialog";
+import { StatsPanel } from "./components/panels/StatsPanel";
import { AppHeader } from "./components/AppHeader";
-import { WelcomeGuide } from "./components/WelcomeGuide";
+import { WelcomeGuide } from "./components/modals/WelcomeGuide";
import { Dialog, DialogContent } from "./components/ui/dialog";
import { useLabyrinthGame } from "./hooks/useLabyrinthGame";
import { useStopwatch } from "./hooks/useStopwatch";
@@ -98,6 +98,24 @@ export default function App() {
() => localStorage.getItem("labyrinth_welcome_dismissed") !== "true"
);
+ const [is3D, setIs3D] = useState(() => {
+ try {
+ return localStorage.getItem("labyrinth_3d") === "true";
+ } catch {
+ return false;
+ }
+ });
+
+ const toggle3D = useCallback(() => {
+ setIs3D((prev) => {
+ const next = !prev;
+ try {
+ localStorage.setItem("labyrinth_3d", String(next));
+ } catch {}
+ return next;
+ });
+ }, []);
+
// ── Solver worker ─────────────────────────────────────────────────────────────
const [solutions, setSolutions] = useState([]);
const [hoveredSolution, setHoveredSolution] = useState(null);
@@ -731,9 +749,7 @@ export default function App() {
// ── Render ────────────────────────────────────────────────────────────────────
return (
-
-
-
+
@@ -780,13 +798,15 @@ export default function App() {
onDragStart={handleDragStart}
onDragEnd={handleDragEnd}
>
-
+
@@ -827,13 +847,14 @@ export default function App() {
allObtainedTreasures={Object.values(game.obtainedTreasures).flat()}
activeTargetTreasureId={game.playerActiveTargets[game.activePawn]}
activePlayers={game.activePlayers}
+ is3D={is3D}
/>
{/* Tablet & desktop side panel (md+) */}
{!isMobile && (
-
+
{game.isGameStarted ? (
@@ -995,7 +1016,7 @@ export default function App() {
game.looseTiles.find((t) => t.id === activeId) ||
game.grid.flat().find((t) => t?.id === activeId)!
}
- className="w-14 h-14 sm:w-16 sm:h-16 md:w-20 md:h-20 lg:w-24 lg:h-24 shadow-2xl shadow-black ring-4 ring-theme-primary/50"
+ className="w-14 h-14 sm:w-16 sm:h-16 md:w-20 md:h-20 lg:w-24 lg:h-24 shadow-[6px_6px_0_0_#000000] rotate-3"
/>
) : null}
,
@@ -1037,7 +1058,7 @@ export default function App() {
{/* Stats dialog */}
{toastText && (
diff --git a/src/components/AppHeader.tsx b/src/components/AppHeader.tsx
index a4441cf..88ba3a2 100644
--- a/src/components/AppHeader.tsx
+++ b/src/components/AppHeader.tsx
@@ -2,12 +2,12 @@ import { useState } from "react";
import type { TileData, PlayerMap } from "../types";
import { PAWNS, TREASURES } from "../constants";
import { Button } from "./ui/button";
+import { Tooltip } from "./ui/tooltip";
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "./ui/dialog";
-import { SettingsDialog } from "./SettingsDialog";
+import { SettingsDialog } from "./modals/SettingsDialog";
import { cn } from "../lib/utils";
import { playClickSound } from "../utils/audio";
import {
- Compass,
Undo2,
Redo2,
Volume2,
@@ -18,8 +18,6 @@ import {
Unlock,
Settings2,
HelpCircle,
- Timer,
- PauseCircle,
Clock,
} from "lucide-react";
@@ -56,8 +54,13 @@ export interface AppHeaderProps {
elapsedTime?: string;
isTimerPaused?: boolean;
onToggleTimer?: () => void;
+ is3D?: boolean;
+ onToggle3D: () => void;
}
+const iconBtnCls =
+ "neo-brutalism-button bg-card text-foreground w-8 h-8 flex items-center justify-center rounded-lg cursor-pointer transition-all hover:bg-stone-200 hover:text-stone-950";
+
const STEPS = [
{
id: "setup" as const,
@@ -73,17 +76,16 @@ const STEPS = [
},
];
-
export function AppHeader({
isGameStarted,
canUndo,
canRedo,
isMuted,
showStats: _showStats,
- baseTheme,
+ baseTheme: _baseTheme,
activePlayers,
activePawn,
- looseTiles,
+ looseTiles: _looseTiles,
canStartGame,
accentColor,
setAccentColor,
@@ -107,193 +109,145 @@ export function AppHeader({
elapsedTime,
isTimerPaused = false,
onToggleTimer,
+ is3D: _is3D,
+ onToggle3D: _onToggle3D,
}: AppHeaderProps) {
const [showEndGameConfirm, setShowEndGameConfirm] = useState(false);
const currentStep = isGameStarted ? "game" : "setup";
- const editionLabel =
- typeof window !== "undefined" && !!(window as { electronAPI?: unknown }).electronAPI
- ? "Desktop Edition"
- : "Web Edition";
-
- const movableTilesRemaining = Math.max(0, looseTiles.length - 1);
- const tilesPlaced = Math.max(0, 33 - movableTilesRemaining);
- const phaseLabel = isGameStarted
- ? "Play phase • Slide, then move"
- : looseTiles.length <= 1
- ? "Setup complete"
- : `${tilesPlaced}/33 tiles placed`;
- const subtitle = [editionLabel, phaseLabel].filter(Boolean).join(" • ");
-
-
-
return (
<>
- {/* Left — branding */}
-
-
-
-
-
-
- Labyrinth Game Solver
- Labyrinth
-
-
- {subtitle}
- {isGameStarted && elapsedTime && (
-
- • {isTimerPaused ? "⏸" : "⏱"} {elapsedTime}
-
- )}
-
-
-
+ {/* Left — brutalist title linking to GitHub */}
+
+
+ Labyrinth Solver
+ Labyrinth
+
+
- {/* Center — Step Nav */}
-
-
-
- {STEPS.map((s) => {
- const isActive = s.id === currentStep;
- const isDisabled = s.id === "game" && !isGameStarted && !canStartGame;
- return (
+ {/* Center — Step Nav (timer baked into Play Game button) */}
+
+
+ {STEPS.map((s) => {
+ const isActive = s.id === currentStep;
+ const isDisabled = s.id === "game" && !isGameStarted && !canStartGame;
+ const showTimer = s.id === "game" && isActive && elapsedTime;
+ return (
+
- );
- })}
-
+
+ );
+ })}
- {isGameStarted && elapsedTime ? (
-
- ) : (
-
- {phaseLabel}
-
- )}
- {/* Right — compact toolbar */}
-
+ {/* Right — toolbar */}
+
- {/* Randomize layout (desktop & tablets) */}
+ {/* Randomize layout (setup only, desktop) */}
{!isGameStarted && onRandomizeBoard && (
-
+
+
+
)}
- {/* Pawn score pills — only during game */}
+ {/* Pawn score chips — only during game */}
{isGameStarted && activePlayers.length > 0 && (
-
+
{activePlayers.map((pawnId) => {
const pawn = PAWNS.find((p) => p.id === pawnId);
- const obtained =
- (obtainedTreasures as Record
)[pawnId] ?? [];
+ const obtained = (obtainedTreasures as Record)[pawnId] ?? [];
const hand = (playerHands as Record)[pawnId] ?? [];
const total = obtained.length + hand.length;
+ const isActive = pawnId === activePawn;
return (
-
-
- {obtained.length}
- {total > 0 ? `/${total}` : ""}
-
+
{obtained.length}
+ {total > 0 &&
/{total}}
- {/* Hover tooltip */}
-
+ {/* Hover tooltip — styled, matching existing card */}
+
-
+
{pawn?.name ?? pawnId} — {obtained.length} collected
{obtained.length === 0 && hand.length === 0 && (
-
- No cards assigned
-
+
No cards assigned
)}
{obtained.map((id) => {
const t = TREASURES.find((x) => x.id === id);
return (
✓
-
- {t?.name ?? id}
-
+ {t?.name ?? id}
);
})}
@@ -301,24 +255,11 @@ export function AppHeader({
const t = TREASURES.find((x) => x.id === id);
return (
-
+
{i === 0 ? "▶" : "·"}
-
- {t?.name ?? id}
- {i === 0 ? " ← next" : ""}
+
+ {t?.name ?? id}{i === 0 ? " ← next" : ""}
);
@@ -327,126 +268,95 @@ export function AppHeader({
);
})}
+
)}
{/* Desktop actions toolbar */}
-
-
-
-
-
-
-
- {isGameStarted && onOpenHistory && (
+
+
+
+
+
+
+ {isGameStarted && onOpenHistory && (
+
+
+
)}
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
+
-
-
-
-
-
+
{
+ onOpenChange={(open: boolean) => {
if (open) onOpenSettings();
else onCloseSettings();
}}
@@ -455,10 +365,12 @@ export function AppHeader({
if (!isMuted) playClickSound();
onToggleMute();
}}
- baseTheme={baseTheme}
+ baseTheme={_baseTheme}
setBaseTheme={onSetBaseTheme}
accentColor={accentColor}
setAccentColor={setAccentColor}
+ is3D={_is3D}
+ onToggle3D={_onToggle3D}
/>
@@ -466,15 +378,11 @@ export function AppHeader({
{/* End Game confirmation dialog */}