From c0c11c325ab7a79075621512ff4a29a293e31d87 Mon Sep 17 00:00:00 2001 From: Till JS Date: Sat, 21 Mar 2026 15:26:40 +0100 Subject: [PATCH] feat(whopixels): major refactor with 20 improvements across architecture, gameplay, UX, security, and i18n Split monolithic RPGScene.js (1210 lines) into modular manager classes: - WorldManager, PlayerManager, NPCManager, ChatUI, StorageManager, SoundManager, TouchControls Key improvements: - Constants config (GAME_CONFIG) replacing all magic numbers - JSDoc types + jsconfig.json for IDE type-safety - LocalStorage persistence for progress, stats, and custom avatars - Synthesized sound effects via Web Audio API - 26 NPCs (up from 10) in 3 categories - Stats/leaderboard in main menu - Pixel editor avatar integration with RPG game - Mobile touch controls (virtual joystick + interact button) - Chat UI with typing indicator and conversation history - Interactive tutorial overlay for first-time players - Floating question mark over NPCs in range - Server hardened: rate limiting, input sanitization, CORS restrictions, API timeouts, conversation history cap - Particle effect object pooling - i18n framework with DE/EN and language switcher Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/chat/apps/web/package.json | 1 + .../src/lib/stores/app-onboarding.svelte.ts | 61 + .../web/src/routes/(protected)/+layout.svelte | 7 + apps/clock/apps/web/package.json | 1 + .../src/lib/stores/app-onboarding.svelte.ts | 68 + .../apps/web/src/routes/(app)/+layout.svelte | 7 + apps/context/apps/web/package.json | 1 + .../src/lib/stores/app-onboarding.svelte.ts | 62 + .../apps/web/src/routes/(app)/+layout.svelte | 7 + apps/manadeck/apps/web/package.json | 1 + .../src/lib/stores/app-onboarding.svelte.ts | 62 + .../apps/web/src/routes/(app)/+layout.svelte | 7 + apps/picture/apps/web/package.json | 3 +- .../src/lib/stores/app-onboarding.svelte.ts | 62 + .../apps/web/src/routes/app/+layout.svelte | 7 + apps/presi/apps/web/package.json | 1 + .../src/lib/stores/app-onboarding.svelte.ts | 33 + .../apps/web/src/routes/(app)/+layout.svelte | 7 + .../src/lib/stores/app-onboarding.svelte.ts | 33 + .../apps/web/src/routes/+layout.svelte | 7 + games/whopixels/IMPROVEMENTS.md | 42 + games/whopixels/data/npc_characters.js | 119 +- games/whopixels/index.html | 15 +- games/whopixels/js/config/constants.js | 121 ++ games/whopixels/js/config/i18n.js | 183 +++ games/whopixels/js/managers/ChatUI.js | 366 +++++ games/whopixels/js/managers/NPCManager.js | 446 ++++++ games/whopixels/js/managers/PlayerManager.js | 82 ++ games/whopixels/js/managers/SoundManager.js | 101 ++ games/whopixels/js/managers/StorageManager.js | 92 ++ games/whopixels/js/managers/TouchControls.js | 165 +++ games/whopixels/js/managers/WorldManager.js | 81 ++ games/whopixels/js/scenes/BootScene.js | 36 + games/whopixels/js/scenes/GameScene.js | 244 +++- games/whopixels/js/scenes/MainMenuScene.js | 166 ++- games/whopixels/js/scenes/RPGScene.js | 1259 ++--------------- games/whopixels/jsconfig.json | 13 + games/whopixels/server.js | 373 ++--- pnpm-lock.yaml | 21 + 39 files changed, 2900 insertions(+), 1463 deletions(-) create mode 100644 apps/chat/apps/web/src/lib/stores/app-onboarding.svelte.ts create mode 100644 apps/clock/apps/web/src/lib/stores/app-onboarding.svelte.ts create mode 100644 apps/context/apps/web/src/lib/stores/app-onboarding.svelte.ts create mode 100644 apps/manadeck/apps/web/src/lib/stores/app-onboarding.svelte.ts create mode 100644 apps/picture/apps/web/src/lib/stores/app-onboarding.svelte.ts create mode 100644 apps/presi/apps/web/src/lib/stores/app-onboarding.svelte.ts create mode 100644 apps/storage/apps/web/src/lib/stores/app-onboarding.svelte.ts create mode 100644 games/whopixels/IMPROVEMENTS.md create mode 100644 games/whopixels/js/config/constants.js create mode 100644 games/whopixels/js/config/i18n.js create mode 100644 games/whopixels/js/managers/ChatUI.js create mode 100644 games/whopixels/js/managers/NPCManager.js create mode 100644 games/whopixels/js/managers/PlayerManager.js create mode 100644 games/whopixels/js/managers/SoundManager.js create mode 100644 games/whopixels/js/managers/StorageManager.js create mode 100644 games/whopixels/js/managers/TouchControls.js create mode 100644 games/whopixels/js/managers/WorldManager.js create mode 100644 games/whopixels/jsconfig.json diff --git a/apps/chat/apps/web/package.json b/apps/chat/apps/web/package.json index f9eab5ce6..c9cc9d27b 100644 --- a/apps/chat/apps/web/package.json +++ b/apps/chat/apps/web/package.json @@ -34,6 +34,7 @@ "dependencies": { "@chat/types": "workspace:*", "@manacore/shared-api-client": "workspace:*", + "@manacore/shared-app-onboarding": "workspace:*", "@manacore/shared-auth": "workspace:*", "@manacore/shared-auth-ui": "workspace:*", "@manacore/shared-branding": "workspace:*", diff --git a/apps/chat/apps/web/src/lib/stores/app-onboarding.svelte.ts b/apps/chat/apps/web/src/lib/stores/app-onboarding.svelte.ts new file mode 100644 index 000000000..891f13ed3 --- /dev/null +++ b/apps/chat/apps/web/src/lib/stores/app-onboarding.svelte.ts @@ -0,0 +1,61 @@ +import { createAppOnboardingStore, type AppOnboardingStep } from '@manacore/shared-app-onboarding'; +import { userSettings } from './user-settings.svelte'; + +/** + * Chat-specific onboarding steps + */ +const chatOnboardingSteps: AppOnboardingStep[] = [ + { + id: 'defaultModel', + type: 'select', + question: 'Welches Modell bevorzugst du?', + emoji: '💬', + gradient: { from: 'blue-500', to: 'blue-700' }, + options: [ + { + id: 'local', + label: 'Lokale Modelle', + description: 'Kostenlos, läuft auf eigenem Server', + emoji: '🏠', + }, + { + id: 'cloud', + label: 'Cloud-Modelle', + description: 'Höhere Qualität, kostenpflichtig', + emoji: '☁️', + }, + { + id: 'auto', + label: 'Automatisch', + description: 'Bestes Modell je nach Aufgabe (Empfohlen)', + emoji: '🤖', + }, + ], + defaultValue: 'auto', + }, + { + id: 'welcome', + type: 'info', + question: 'Dein Chat ist bereit!', + description: 'Hier sind einige Tipps:', + emoji: '🎉', + gradient: { from: 'primary', to: 'primary/70' }, + bullets: [ + 'Wähle verschiedene KI-Modelle je nach Aufgabe', + 'Nutze Konversationen, um Chatverläufe zu organisieren', + 'Lokale Modelle sind kostenlos und datenschutzfreundlich', + 'Cloud-Modelle bieten höhere Qualität für komplexe Aufgaben', + ], + }, +]; + +/** + * Chat app onboarding store + */ +export const chatOnboarding = createAppOnboardingStore({ + appId: 'chat', + steps: chatOnboardingSteps, + userSettings, + onComplete: async () => {}, + onSkip: async () => {}, +}); diff --git a/apps/chat/apps/web/src/routes/(protected)/+layout.svelte b/apps/chat/apps/web/src/routes/(protected)/+layout.svelte index 96a3cd4e0..5cb638b61 100644 --- a/apps/chat/apps/web/src/routes/(protected)/+layout.svelte +++ b/apps/chat/apps/web/src/routes/(protected)/+layout.svelte @@ -22,6 +22,8 @@ import { getLanguageDropdownItems, getCurrentLanguageLabel } from '@manacore/shared-i18n'; import { setLocale, supportedLocales } from '$lib/i18n'; import type { LayoutData } from './$types'; + import { chatOnboarding } from '$lib/stores/app-onboarding.svelte'; + import { MiniOnboardingModal } from '@manacore/shared-app-onboarding'; // App switcher items const appItems = getPillAppItems('chat'); @@ -235,6 +237,11 @@ {/if} + + + {#if chatOnboarding.shouldShow} + + {/if} {/if} diff --git a/apps/clock/apps/web/package.json b/apps/clock/apps/web/package.json index f96489bf3..61d10b1d5 100644 --- a/apps/clock/apps/web/package.json +++ b/apps/clock/apps/web/package.json @@ -37,6 +37,7 @@ "dependencies": { "@clock/shared": "workspace:*", "@manacore/shared-api-client": "workspace:*", + "@manacore/shared-app-onboarding": "workspace:*", "@manacore/shared-auth": "workspace:*", "@manacore/shared-auth-ui": "workspace:*", "@manacore/shared-branding": "workspace:*", diff --git a/apps/clock/apps/web/src/lib/stores/app-onboarding.svelte.ts b/apps/clock/apps/web/src/lib/stores/app-onboarding.svelte.ts new file mode 100644 index 000000000..7abf0417e --- /dev/null +++ b/apps/clock/apps/web/src/lib/stores/app-onboarding.svelte.ts @@ -0,0 +1,68 @@ +import { createAppOnboardingStore, type AppOnboardingStep } from '@manacore/shared-app-onboarding'; +import { userSettings } from './user-settings.svelte'; + +/** + * Clock-specific onboarding steps + */ +const clockOnboardingSteps: AppOnboardingStep[] = [ + { + id: 'defaultTimer', + type: 'select', + question: 'Welche Timer-Dauer nutzt du am häufigsten?', + description: 'Du kannst Timer jederzeit individuell einstellen.', + emoji: '⏱️', + gradient: { from: 'blue-500', to: 'blue-700' }, + options: [ + { + id: '5', + label: '5 Minuten', + description: 'Für kurze Pausen', + emoji: '⚡', + }, + { + id: '15', + label: '15 Minuten', + description: 'Für konzentrierte Einheiten', + emoji: '🎯', + }, + { + id: '25', + label: '25 Minuten', + description: 'Pomodoro-Technik (Empfohlen)', + emoji: '🍅', + }, + { + id: '45', + label: '45 Minuten', + description: 'Für längere Arbeitsphasen', + emoji: '🧘', + }, + ], + defaultValue: '25', + }, + { + id: 'welcome', + type: 'info', + question: 'Deine Uhr ist bereit!', + description: 'Hier sind einige Tipps:', + emoji: '🎉', + gradient: { from: 'primary', to: 'primary/70' }, + bullets: [ + 'Nutze die Stoppuhr für freie Zeitmessung', + 'Stelle Wecker für wichtige Erinnerungen', + 'Die Weltuhr zeigt mehrere Zeitzonen gleichzeitig', + 'Drücke Cmd/Ctrl+K für die Schnellsuche', + ], + }, +]; + +/** + * Clock app onboarding store + */ +export const clockOnboarding = createAppOnboardingStore({ + appId: 'clock', + steps: clockOnboardingSteps, + userSettings, + onComplete: async () => {}, + onSkip: async () => {}, +}); diff --git a/apps/clock/apps/web/src/routes/(app)/+layout.svelte b/apps/clock/apps/web/src/routes/(app)/+layout.svelte index 6f1397101..63b32a2c0 100644 --- a/apps/clock/apps/web/src/routes/(app)/+layout.svelte +++ b/apps/clock/apps/web/src/routes/(app)/+layout.svelte @@ -30,6 +30,8 @@ import { setLocale, supportedLocales } from '$lib/i18n'; import { alarmsApi } from '$lib/api/alarms'; import { timersApi } from '$lib/api/timers'; + import { clockOnboarding } from '$lib/stores/app-onboarding.svelte'; + import { MiniOnboardingModal } from '@manacore/shared-app-onboarding'; // App switcher items const appItems = getPillAppItems('clock'); @@ -314,6 +316,11 @@ emptyText="Keine Ergebnisse" searchingText="Suche..." /> + + + {#if clockOnboarding.shouldShow} + + {/if}