diff --git a/frontend/src/App.css b/frontend/src/App.css
index 51c0b60..bf471d2 100644
--- a/frontend/src/App.css
+++ b/frontend/src/App.css
@@ -153,3 +153,61 @@ body {
background: rgba(255, 50, 50, 0.3);
color: #ffffff;
}
+
+/* Loading Screen */
+.loading-screen {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: #050505 url('/assets/runtime/generated/ui/loading_screen_v001.png') center/cover no-repeat;
+ position: relative;
+ z-index: 9999;
+}
+
+.loading-screen::before {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background: radial-gradient(circle at center, transparent 0%, rgba(0,0,0,0.8) 100%);
+}
+
+.loading-content {
+ position: relative;
+ z-index: 1;
+ text-align: center;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 20px;
+}
+
+.loading-spinner {
+ width: 50px;
+ height: 50px;
+ border: 3px solid rgba(255, 50, 50, 0.1);
+ border-top-color: #ff3333;
+ border-radius: 50%;
+ animation: spin 1s linear infinite;
+ box-shadow: 0 0 15px rgba(255, 50, 50, 0.4);
+}
+
+.loading-text {
+ font-family: 'Rajdhani', monospace;
+ font-size: 14px;
+ color: #ff3333;
+ letter-spacing: 4px;
+ font-weight: 700;
+ text-shadow: 0 0 10px rgba(255, 50, 50, 0.5);
+ animation: pulse 2s ease-in-out infinite;
+}
+
+@keyframes spin {
+ to { transform: rotate(360deg); }
+}
+
+@keyframes pulse {
+ 0%, 100% { opacity: 0.6; }
+ 50% { opacity: 1; }
+}
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index cadb0e9..cc949c9 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -70,12 +70,11 @@ import './App.css';
// ─── Lazy fallback ────────────────────────────────────────────
const LazyFallback: React.FC = () => (
-
- Loading...
+
+
+
+
INITIALIZING SYSTEMS...
+
);
@@ -218,11 +217,7 @@ const App: React.FC = () => {
// Show loading while checking auth
if (!authChecked) {
- return (
-
- );
+ return
;
}
// Show auth screen if not logged in (skipped in demo mode)
diff --git a/frontend/src/assets/assetManifest.ts b/frontend/src/assets/assetManifest.ts
index 2c39647..c51814c 100644
--- a/frontend/src/assets/assetManifest.ts
+++ b/frontend/src/assets/assetManifest.ts
@@ -252,6 +252,13 @@ export const environmentAssets: Record
= {
streetBackdropDay: `${ENVS}/street/block_stripplaza_day_street_v001.png`,
streetBackdropNight: `${ENVS}/street/block_stripplaza_night_street_v001.png`,
},
+ block_lasolas_miami_001: {
+ id: 'block_lasolas_miami_001',
+ displayName: 'Las Olas Boulevard',
+ topdownBg: `/assets/runtime/generated/environments/topdown/block_lasolas_topdown_v001.png`,
+ streetBackdropDay: `/assets/runtime/generated/environments/street/block_lasolas_driveby_street_v001.png`,
+ streetBackdropNight: `/assets/runtime/generated/environments/street/block_lasolas_driveby_street_v001.png`,
+ },
};
// ─── UI Icons (generated set) ────────────────────────────────
diff --git a/frontend/src/components/layout/OSShell.css b/frontend/src/components/layout/OSShell.css
index ed87e32..ecc6aed 100644
--- a/frontend/src/components/layout/OSShell.css
+++ b/frontend/src/components/layout/OSShell.css
@@ -22,7 +22,7 @@
content: '';
position: fixed;
inset: 0;
- background: url('/assets/bg_desktop.jpg') center/cover no-repeat;
+ background: url('/assets/runtime/generated/ui/os_shell_wallpaper_v001.png') center/cover no-repeat;
opacity: 0.25;
z-index: 0;
filter: brightness(0.6) saturate(1.2);
diff --git a/frontend/src/components/map/BlockModeView.tsx b/frontend/src/components/map/BlockModeView.tsx
index 6086a17..fcfca4a 100644
--- a/frontend/src/components/map/BlockModeView.tsx
+++ b/frontend/src/components/map/BlockModeView.tsx
@@ -332,7 +332,7 @@ const BlockModeView: React.FC = ({
) : viewMode === 'topdown' ? (
// Use the Phaser scene when a real satellite URL is available;
// fall back to the CSS grid for dev/no-token environments
- block.topdownBgUrl && block.topdownBgUrl.startsWith('http') ? (
+ block.topdownBgUrl && (block.topdownBgUrl.startsWith('http') || block.topdownBgUrl.startsWith('/assets/')) ? (
{}}
diff --git a/frontend/src/components/slide/PhaserSlideGame.tsx b/frontend/src/components/slide/PhaserSlideGame.tsx
index e499e96..bd5abcd 100644
--- a/frontend/src/components/slide/PhaserSlideGame.tsx
+++ b/frontend/src/components/slide/PhaserSlideGame.tsx
@@ -82,7 +82,6 @@ export const PhaserSlideGame: React.FC = ({
scene.events.on('cell_click', handleCellClick);
} catch (err) {
- // eslint-disable-next-line no-console
console.error('[PhaserSlideGame] failed to init Phaser', err);
setError(err instanceof Error ? err.message : 'Unknown Phaser error');
}
diff --git a/frontend/src/stores/npcStore.ts b/frontend/src/stores/npcStore.ts
index 48a44da..9f83771 100644
--- a/frontend/src/stores/npcStore.ts
+++ b/frontend/src/stores/npcStore.ts
@@ -119,9 +119,9 @@ function makeNPCMember(
const DEFAULT_GANGS: NPCGang[] = [
{
- id: 'npc-scorpions',
- name: 'The Scorpions',
- faction: 'eastside',
+ id: 'npc-12ocho',
+ name: '12Ocho / Twelve-O',
+ faction: 'southside',
difficulty: 2,
aggression: 65,
wealth: 40,
@@ -129,101 +129,87 @@ const DEFAULT_GANGS: NPCGang[] = [
controlledBlocks: [],
threatening: false,
lastTickAt: new Date(Date.now() - 600_000).toISOString(),
- lastAction: 'Patrolling their blocks',
+ lastAction: 'Patrolling Las Olas',
lastActionType: 'patrol',
members: [
- makeNPCMember('sc-1', 'Big Mike', 'shooter', 3),
- makeNPCMember('sc-2', 'Lil D', 'dealer', 2),
- makeNPCMember('sc-3', 'Crazy Jay', 'enforcer', 4),
- makeNPCMember('sc-4', 'Young Ace', 'shooter', 1),
+ makeNPCMember('12-1', 'Ocho', 'shooter', 3),
+ makeNPCMember('12-2', 'Lil 12', 'dealer', 2),
+ makeNPCMember('12-3', 'V-Twelve', 'enforcer', 4),
],
},
{
- id: 'npc-deadend',
- name: 'Dead End Boys',
- faction: 'westside',
- difficulty: 3,
- aggression: 80,
- wealth: 55,
+ id: 'npc-nofed',
+ name: 'No Fed, All Fed',
+ faction: 'eastside',
+ difficulty: 4,
+ aggression: 85,
+ wealth: 65,
territoryCount: 5,
controlledBlocks: [],
threatening: false,
lastTickAt: new Date(Date.now() - 1_800_000).toISOString(),
- lastAction: 'Expanding territory',
+ lastAction: 'Monitoring Federal Hwy',
lastActionType: 'expand',
members: [
- makeNPCMember('de-1', 'OG Reaper', 'enforcer', 5),
- makeNPCMember('de-2', 'Mad Tee', 'shooter', 4),
- makeNPCMember('de-3', 'Quick Shadow', 'shooter', 3),
- makeNPCMember('de-4', 'Fat King', 'dealer', 3),
- makeNPCMember('de-5', 'Baby Blade', 'dealer', 2),
- makeNPCMember('de-6', 'Dirty Smoke', 'shooter', 4),
+ makeNPCMember('nf-1', 'Fed Buster', 'enforcer', 5),
+ makeNPCMember('nf-2', 'All-Day', 'shooter', 4),
+ makeNPCMember('nf-3', 'Zero Fed', 'shooter', 4),
],
},
{
- id: 'npc-blockburners',
- name: 'Block Burners',
- faction: 'southside',
- difficulty: 1,
- aggression: 35,
- wealth: 25,
- territoryCount: 1,
+ id: 'npc-sevendown',
+ name: 'Seven Down / 7DWN',
+ faction: 'westside',
+ difficulty: 3,
+ aggression: 70,
+ wealth: 50,
+ territoryCount: 4,
controlledBlocks: [],
threatening: false,
lastTickAt: new Date(Date.now() - 3_600_000).toISOString(),
- lastAction: 'Defending their block',
+ lastAction: 'Holding SW 7th Ave',
lastActionType: 'defend',
members: [
- makeNPCMember('bb-1', 'Tiny Rock', 'shooter', 1),
- makeNPCMember('bb-2', 'Slick Stone', 'dealer', 1),
- makeNPCMember('bb-3', 'Smooth Duke', 'shooter', 2),
+ makeNPCMember('7d-1', 'Lucky 7', 'shooter', 3),
+ makeNPCMember('7d-2', 'Down-Low', 'dealer', 3),
+ makeNPCMember('7d-3', 'Seven-Up', 'enforcer', 3),
],
},
{
- id: 'npc-400boyz',
- name: 'The 400 Boyz',
- faction: 'northside',
- difficulty: 4,
- aggression: 90,
- wealth: 72,
- territoryCount: 7,
+ id: 'npc-nineside',
+ name: 'Nine Side / N9NE',
+ faction: 'westside',
+ difficulty: 2,
+ aggression: 60,
+ wealth: 35,
+ territoryCount: 2,
controlledBlocks: [],
threatening: false,
lastTickAt: new Date(Date.now() - 900_000).toISOString(),
- lastAction: 'Raiding a rival block',
- lastActionType: 'raid',
+ lastAction: 'Tagging N9 on the block',
+ lastActionType: 'patrol',
members: [
- makeNPCMember('fb-1', 'Ghost', 'enforcer', 5),
- makeNPCMember('fb-2', 'Reaper', 'shooter', 5),
- makeNPCMember('fb-3', 'Ice', 'shooter', 4),
- makeNPCMember('fb-4', 'Blade', 'enforcer', 4),
- makeNPCMember('fb-5', 'Smoke', 'dealer', 3),
- makeNPCMember('fb-6', 'Shadow', 'shooter', 4),
- makeNPCMember('fb-7', 'Duke', 'dealer', 3),
+ makeNPCMember('n9-1', 'Cloud 9', 'shooter', 2),
+ makeNPCMember('n9-2', 'Nine-Life', 'dealer', 2),
],
},
{
- id: 'npc-vipers',
- name: 'The Vipers',
+ id: 'npc-olasboys',
+ name: 'Olas Boys / OLB',
faction: 'downtown',
difficulty: 5,
aggression: 95,
wealth: 90,
- territoryCount: 10,
+ territoryCount: 8,
controlledBlocks: [],
threatening: false,
lastTickAt: new Date(Date.now() - 300_000).toISOString(),
- lastAction: 'Consolidating power',
- lastActionType: 'patrol',
+ lastAction: 'Controlling downtown Las Olas',
+ lastActionType: 'raid',
members: [
- makeNPCMember('vp-1', 'The Don', 'enforcer', 5),
- makeNPCMember('vp-2', 'Venom', 'shooter', 5),
- makeNPCMember('vp-3', 'Fang', 'shooter', 5),
- makeNPCMember('vp-4', 'Cobra', 'enforcer', 5),
- makeNPCMember('vp-5', 'Asp', 'dealer', 4),
- makeNPCMember('vp-6', 'Mamba', 'shooter', 5),
- makeNPCMember('vp-7', 'Rattler', 'shooter', 4),
- makeNPCMember('vp-8', 'Adder', 'dealer', 4),
+ makeNPCMember('ol-1', 'Olas King', 'enforcer', 5),
+ makeNPCMember('ol-2', 'Strip Boss', 'shooter', 5),
+ makeNPCMember('ol-3', 'Beach Boy', 'dealer', 4),
],
},
];
diff --git a/frontend/src/utils/demoSeed.ts b/frontend/src/utils/demoSeed.ts
index 7bb4571..bc667c1 100644
--- a/frontend/src/utils/demoSeed.ts
+++ b/frontend/src/utils/demoSeed.ts
@@ -215,8 +215,8 @@ export function seedDemoState(): void {
members: 1,
viewMode: 'topdown' as const,
pendingIncome: 0,
- topdownBgUrl: '/assets/runtime/generated/environments/topdown/block_stripplaza_topdown_v001.webp',
- streetBackdropUrl: '/assets/runtime/generated/environments/street/block_stripplaza_night_street_v001.webp',
+ topdownBgUrl: '/assets/runtime/generated/environments/topdown/block_lasolas_topdown_v001.png',
+ streetBackdropUrl: '/assets/runtime/generated/environments/street/block_lasolas_driveby_street_v001.png',
};
blockStore.upsertBlock(demoBlock);