feat: minimal HUD with one floating menu and objective chip

Phase 4 of turning the game into the company landing page.

- Only the menu button, a compact objective chip and the touch
  controls stay on screen; speed shows only while driving.
- The objective chip shows the next goal in one line, its distance and
  an arrow that turns towards it (replaces the compass strip); tapping
  it opens the mission list.
- One floating menu holds map, missions, status, products, real-world,
  camera, stable mode, sound, graphics, minimap, fullscreen, help,
  restart and back to the start screen. It closes on a second tap, a
  tap outside, Escape, or after an action.
- Missions, status and help open as sheets; street label, rank bar,
  status panel, toolbar and compass are gone. The minimap is optional
  and off by default.
- Share the icon set and sheet dialog between start screen and HUD.
- Layout checked for phone portrait, landscape and safe areas.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-31 08:50:29 +03:30
co-authored by Claude Opus 5.5
parent d9ae8a45da
commit 5a4dffc9a3
26 changed files with 773 additions and 621 deletions
+3 -3
View File
@@ -3,7 +3,7 @@ import { GameNode } from '@/components/shared/GameNode.jsx';
import { COMPANY } from '@/config/company.js';
import { ASSETS } from '@/config/assets.js';
import { strings } from '@/i18n/fa.js';
import { StartIcon } from './StartIcon.jsx';
import { Icon } from '@/components/shared/Icon.jsx';
import { StartOptions } from './StartOptions.jsx';
import { InfoSheet } from './InfoSheet.jsx';
@@ -49,7 +49,7 @@ export function StartScreen({ nodes, actions }) {
<nav aria-label={text.sectionsLabel} className="mt-6 flex flex-wrap gap-2">
{SECTIONS.map(([key, icon]) => (
<button key={key} type="button" className="start-chip" onClick={() => setSection(key)}>
<StartIcon name={icon} className="h-4 w-4" />
<Icon name={icon} className="h-4 w-4" />
{key === 'about' ? text.history : text.sections[key]}
</button>
))}
@@ -62,7 +62,7 @@ export function StartScreen({ nodes, actions }) {
model={nodes.install}
onAction={() => actions.emit('install')}
>
<StartIcon name="download" className="h-4 w-4" />
<Icon name="download" className="h-4 w-4" />
{text.install}
</GameNode>
</nav>