import { z } from "zod/mini"; import type * as THREE from "three"; export const LOGICAL_WIDTH = 256; export const LOGICAL_HEIGHT = 192; export const SCREEN_SCALE = 2; export const SCREEN_WIDTH = LOGICAL_WIDTH * SCREEN_SCALE; export const SCREEN_HEIGHT = LOGICAL_HEIGHT * SCREEN_SCALE; export const APP_COLORS = [ ["#61829a", "#ba4900", "#fb0018", "#fb8afb"], ["#fb9200", "#f3e300", "#aafb00", "#00fb00"], ["#00a238", "#49db8a", "#30baf3", "#0059f3"], ["#000092", "#8a00d3", "#d300eb", "#fb0092"], ]; const STORAGE_ID = "nds-settings"; const settingsSchema = z.object({ color: z.object({ col: z.number(), row: z.number(), }), renderingMode: z.enum(["3d", "2d"]), volume: z.number(), }); type Settings = z.infer; const defaultSettings = (): Settings => ({ color: { col: 0, row: 0 }, renderingMode: "3d", volume: 0.5, }); export const useAppStore = defineStore("app", { state: () => { let settings: Settings; const stored = localStorage.getItem(STORAGE_ID); try { settings = settingsSchema.parse(JSON.parse(stored ?? "")); } catch { settings = defaultSettings(); } return { ready: false, booted: false, userHasInteracted: false, settings, previousScreen: "home" as AppScreen, screen: "home" as AppScreen, visitedGallery: false, camera: null as THREE.Camera | null, hintsVisible: false, hintsAllowed: false, lagDetected: false, lagModalOpen: false, }; }, actions: { setColor(col: number, row: number) { this.settings.color = { col, row }; }, setRenderingMode(mode: Settings["renderingMode"]) { this.ready = mode === "2d"; this.settings.renderingMode = mode; this.lagDetected = false; this.save(); }, navigateTo(screen: AppScreen) { this.previousScreen = this.screen; this.screen = screen; const achievements = useAchievementsStore(); switch (screen) { case "projects": achievements.unlock("projects_visit"); break; case "gallery": this.visitedGallery = true; break; case "contact": achievements.unlock("contact_visit"); break; } }, allowHints() { this.hintsAllowed = true; }, disallowHints() { this.hintsAllowed = false; this.hintsVisible = false; }, showHints() { if (!this.hintsAllowed) return; this.hintsVisible = true; }, hideHints() { this.hintsVisible = false; }, setCamera(camera: THREE.Camera) { this.camera = camera; }, save() { localStorage.setItem(STORAGE_ID, JSON.stringify(this.settings)); }, }, getters: { color: (state) => ({ col: state.settings.color.col, row: state.settings.color.row, hex: APP_COLORS[state.settings.color.row]![state.settings.color.col]!, }), }, });