Add a fallback interface for when the 3D scene cannot be rendered

Updates Scene.tsx to include a fallback UI with realm selection when WebGL is not available, and fixes TypeScript errors in TitleBar.tsx.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 9203795e-937a-4306-b81d-b4d5c78c240e
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 893e1048-aa5f-4dea-8907-56a7ccad680b
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/7c94b7a0-29c7-4f2e-94ef-44b2153872b7/9203795e-937a-4306-b81d-b4d5c78c240e/c8LGG4t
Replit-Helium-Checkpoint-Created: true
This commit is contained in:
sirpiglr 2025-12-05 22:22:25 +00:00
parent 82de4d9b41
commit a2805ea740
4 changed files with 173 additions and 5 deletions

View file

@ -52,6 +52,10 @@ externalPort = 80
localPort = 8044
externalPort = 3003
[[ports]]
localPort = 35519
externalPort = 3002
[[ports]]
localPort = 38557
externalPort = 3000

View file

@ -1,9 +1,10 @@
import { Canvas, useFrame, useThree } from "@react-three/fiber";
import { Grid, OrbitControls, Text } from "@react-three/drei";
import * as THREE from "three";
import { MathUtils, Vector3 } from "three";
import React, { useMemo, useRef, useState } from "react";
import React, { useMemo, useRef, useState, useEffect } from "react";
import { motion } from "framer-motion";
import { useNavigate } from "react-router-dom";
import { useNavigate, Link } from "react-router-dom";
type Gateway = {
label: string;
@ -241,7 +242,145 @@ function SceneContent() {
);
}
function FallbackUI() {
return (
<div
style={{
width: "100vw",
height: "100vh",
background: "linear-gradient(135deg, #030712 0%, #0f172a 50%, #1e1b4b 100%)",
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
fontFamily: "Inter, sans-serif",
color: "#e5e7eb",
padding: 20,
}}
>
<motion.div
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
style={{ textAlign: "center", marginBottom: 40 }}
>
<h1 style={{ fontSize: 48, fontWeight: 700, marginBottom: 8, letterSpacing: "0.05em" }}>
AeThex OS
</h1>
<p style={{ fontSize: 16, opacity: 0.7, letterSpacing: "0.1em" }}>
Select Your Realm
</p>
</motion.div>
<div
style={{
display: "grid",
gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))",
gap: 16,
maxWidth: 900,
width: "100%",
}}
>
{gateways.map((gw, i) => (
<motion.div
key={gw.label}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.4, delay: i * 0.1 }}
>
<Link
to={gw.route}
style={{
display: "block",
padding: "24px 20px",
borderRadius: 16,
border: `2px solid ${gw.color}40`,
background: `${gw.color}10`,
textDecoration: "none",
color: "#e5e7eb",
textAlign: "center",
transition: "all 0.3s ease",
}}
onMouseEnter={(e) => {
e.currentTarget.style.borderColor = gw.color;
e.currentTarget.style.transform = "translateY(-4px)";
e.currentTarget.style.boxShadow = `0 8px 30px ${gw.color}30`;
}}
onMouseLeave={(e) => {
e.currentTarget.style.borderColor = `${gw.color}40`;
e.currentTarget.style.transform = "translateY(0)";
e.currentTarget.style.boxShadow = "none";
}}
>
<div
style={{
fontSize: 18,
fontWeight: 600,
letterSpacing: "0.1em",
color: gw.color,
}}
>
{gw.label}
</div>
</Link>
</motion.div>
))}
</div>
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.6, delay: 0.5 }}
style={{ marginTop: 40 }}
>
<Link
to="/login"
style={{
padding: "12px 24px",
borderRadius: 10,
border: "1px solid #38bdf8",
background: "rgba(14, 165, 233, 0.12)",
color: "#e0f2fe",
fontWeight: 600,
textDecoration: "none",
backdropFilter: "blur(6px)",
}}
>
Connect Passport
</Link>
</motion.div>
</div>
);
}
function checkWebGLSupport(): boolean {
try {
const canvas = document.createElement("canvas");
const gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
return !!gl;
} catch {
return false;
}
}
export default function Scene() {
const [webglSupported, setWebglSupported] = useState<boolean | null>(null);
const [webglError, setWebglError] = useState(false);
useEffect(() => {
setWebglSupported(checkWebGLSupport());
}, []);
if (webglSupported === null) {
return (
<div style={{ width: "100vw", height: "100vh", background: "#030712" }} />
);
}
if (!webglSupported || webglError) {
return <FallbackUI />;
}
return (
<div
style={{
@ -299,6 +438,11 @@ export default function Scene() {
shadows
camera={{ position: [0, 3, 12], fov: 50, near: 0.1, far: 100 }}
gl={{ antialias: true }}
onCreated={({ gl }) => {
gl.domElement.addEventListener("webglcontextlost", () => {
setWebglError(true);
});
}}
>
<SceneContent />
</Canvas>

View file

@ -1,4 +1,4 @@
import { useState } from "react";
import { useState, CSSProperties } from "react";
export default function TitleBar() {
const [pinned, setPinned] = useState(false);
@ -19,11 +19,12 @@ export default function TitleBar() {
padding: "0 12px",
background: "#050814",
color: "#9ca3af",
// @ts-ignore - Electron-specific property
WebkitAppRegion: "drag",
borderBottom: "1px solid #0f172a",
letterSpacing: "0.08em",
fontSize: 12,
}}
} as CSSProperties}
>
<div style={{ fontFamily: "Space Mono, monospace" }}>AeThex Terminal</div>
<div
@ -31,8 +32,9 @@ export default function TitleBar() {
marginLeft: "auto",
display: "flex",
gap: 8,
// @ts-ignore - Electron-specific property
WebkitAppRegion: "no-drag",
}}
} as CSSProperties}
>
<button
onClick={() => call("togglePin")}

View file

@ -142,6 +142,24 @@ https://supabase.aethex.tech/auth/v1/callback
- `https://aethex.foundation/**`
- `https://supabase.aethex.tech/auth/v1/callback`
## Recent Changes (December 5, 2025)
- ✅ **Electron Desktop App Support**: Added desktop application framework
- `electron/main.js` - Main Electron process with window management
- `electron/preload.js` - Secure IPC bridge for frontend communication
- `electron-builder.yml` - Build configuration for packaging
- `client/components/DesktopShell.tsx` - Desktop wrapper with title bar
- `client/components/TitleBar.tsx` - Custom title bar with pin/minimize/maximize/close
- `client/pages/Overlay.tsx` - File watcher overlay for development tools
- ✅ **3D Scene Landing Page**: New immersive realm selector
- `client/components/Scene.tsx` - Three.js/React Three Fiber 3D scene
- Animated gateway meshes for each realm (Nexus, GameForge, Foundation, Labs, Corp)
- Camera rig with smooth transitions on realm selection
- WebGL fallback UI when 3D rendering isn't available
- ✅ **Utility Services**: New backend services
- `services/pii-scrub.js` - PII scrubbing utility for privacy
- `services/watcher.js` - File watcher for development workflow
- ✅ **TypeScript Fixes**: Fixed THREE namespace import and WebkitAppRegion typing
## Recent Changes (December 4, 2025)
- ✅ **RealmSwitcher Alignment Fix**: Fixed realm IDs to match ARMS taxonomy
- Old IDs (`game_developer`, `client`, `community_member`, `customer`) replaced with ARMS IDs (`labs`, `gameforge`, `corp`, `foundation`, `devlink`, `nexus`, `staff`)