@jxrstudios/jxr 1.0.10 → 1.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/jxr.js +6 -0
- package/dist/index.js +57 -2
- package/dist/jxr-server-manager.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/jxr-server-manager.ts +65 -2
- package/zzz_react_template/App.tsx +43 -156
- package/zzz_react_template/components/ErrorBoundary.tsx +62 -0
- package/zzz_react_template/components/ManusDialog.tsx +85 -0
- package/zzz_react_template/components/Map.tsx +155 -0
- package/zzz_react_template/components/jxr/CodeEditor.tsx +313 -0
- package/zzz_react_template/components/jxr/FileExplorer.tsx +230 -0
- package/zzz_react_template/components/jxr/IDEShell.tsx +159 -0
- package/zzz_react_template/components/jxr/LandingPage.tsx +414 -0
- package/zzz_react_template/components/jxr/LivePreview.tsx +169 -0
- package/zzz_react_template/components/jxr/PerformanceDashboard.tsx +379 -0
- package/zzz_react_template/components/jxr/TopBar.tsx +149 -0
- package/zzz_react_template/components/ui/accordion.tsx +64 -0
- package/zzz_react_template/components/ui/alert-dialog.tsx +155 -0
- package/zzz_react_template/components/ui/alert.tsx +66 -0
- package/zzz_react_template/components/ui/aspect-ratio.tsx +9 -0
- package/zzz_react_template/components/ui/avatar.tsx +51 -0
- package/zzz_react_template/components/ui/badge.tsx +46 -0
- package/zzz_react_template/components/ui/breadcrumb.tsx +109 -0
- package/zzz_react_template/components/ui/button-group.tsx +83 -0
- package/zzz_react_template/components/ui/button.tsx +60 -0
- package/zzz_react_template/components/ui/calendar.tsx +211 -0
- package/zzz_react_template/components/ui/card.tsx +92 -0
- package/zzz_react_template/components/ui/carousel.tsx +239 -0
- package/zzz_react_template/components/ui/chart.tsx +355 -0
- package/zzz_react_template/components/ui/checkbox.tsx +30 -0
- package/zzz_react_template/components/ui/collapsible.tsx +31 -0
- package/zzz_react_template/components/ui/command.tsx +184 -0
- package/zzz_react_template/components/ui/context-menu.tsx +250 -0
- package/zzz_react_template/components/ui/dialog.tsx +209 -0
- package/zzz_react_template/components/ui/drawer.tsx +133 -0
- package/zzz_react_template/components/ui/dropdown-menu.tsx +255 -0
- package/zzz_react_template/components/ui/empty.tsx +104 -0
- package/zzz_react_template/components/ui/field.tsx +242 -0
- package/zzz_react_template/components/ui/form.tsx +168 -0
- package/zzz_react_template/components/ui/hover-card.tsx +42 -0
- package/zzz_react_template/components/ui/input-group.tsx +168 -0
- package/zzz_react_template/components/ui/input-otp.tsx +75 -0
- package/zzz_react_template/components/ui/input.tsx +70 -0
- package/zzz_react_template/components/ui/item.tsx +193 -0
- package/zzz_react_template/components/ui/kbd.tsx +28 -0
- package/zzz_react_template/components/ui/label.tsx +22 -0
- package/zzz_react_template/components/ui/menubar.tsx +274 -0
- package/zzz_react_template/components/ui/navigation-menu.tsx +168 -0
- package/zzz_react_template/components/ui/pagination.tsx +127 -0
- package/zzz_react_template/components/ui/popover.tsx +46 -0
- package/zzz_react_template/components/ui/progress.tsx +29 -0
- package/zzz_react_template/components/ui/radio-group.tsx +43 -0
- package/zzz_react_template/components/ui/resizable.tsx +54 -0
- package/zzz_react_template/components/ui/scroll-area.tsx +56 -0
- package/zzz_react_template/components/ui/select.tsx +185 -0
- package/zzz_react_template/components/ui/separator.tsx +26 -0
- package/zzz_react_template/components/ui/sheet.tsx +139 -0
- package/zzz_react_template/components/ui/sidebar.tsx +734 -0
- package/zzz_react_template/components/ui/skeleton.tsx +13 -0
- package/zzz_react_template/components/ui/slider.tsx +61 -0
- package/zzz_react_template/components/ui/sonner.tsx +23 -0
- package/zzz_react_template/components/ui/spinner.tsx +16 -0
- package/zzz_react_template/components/ui/switch.tsx +29 -0
- package/zzz_react_template/components/ui/table.tsx +114 -0
- package/zzz_react_template/components/ui/tabs.tsx +64 -0
- package/zzz_react_template/components/ui/textarea.tsx +67 -0
- package/zzz_react_template/components/ui/toggle-group.tsx +73 -0
- package/zzz_react_template/components/ui/toggle.tsx +45 -0
- package/zzz_react_template/components/ui/tooltip.tsx +59 -0
- package/zzz_react_template/const.ts +17 -0
- package/zzz_react_template/contexts/JXRContext.tsx +264 -0
- package/zzz_react_template/contexts/ThemeContext.tsx +64 -0
- package/zzz_react_template/hooks/useComposition.ts +81 -0
- package/zzz_react_template/hooks/useMobile.tsx +21 -0
- package/zzz_react_template/hooks/usePersistFn.ts +20 -0
- package/zzz_react_template/index.css +518 -11
- package/zzz_react_template/lib/jxr-runtime/index.ts +201 -0
- package/zzz_react_template/lib/jxr-runtime/module-resolver.ts +520 -0
- package/zzz_react_template/lib/jxr-runtime/moq-transport.ts +267 -0
- package/zzz_react_template/lib/jxr-runtime/web-crypto.ts +279 -0
- package/zzz_react_template/lib/jxr-runtime/worker-pool.ts +321 -0
- package/zzz_react_template/lib/utils.ts +6 -0
- package/zzz_react_template/main.tsx +4 -9
- package/zzz_react_template/pages/Docs.tsx +955 -0
- package/zzz_react_template/pages/Home.tsx +1080 -0
- package/zzz_react_template/pages/NotFound.tsx +105 -0
- package/zzz_react_template/tsconfig.json +24 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JXR.js — IDE Shell (Edge OS Layout)
|
|
3
|
+
* Design: LavaFlow OS — Thermal Precision + Edge Command
|
|
4
|
+
* Full-viewport resizable panel layout: Explorer | Editor | Preview | Metrics
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { useState } from 'react';
|
|
8
|
+
import {
|
|
9
|
+
ResizablePanelGroup,
|
|
10
|
+
ResizablePanel,
|
|
11
|
+
ResizableHandle,
|
|
12
|
+
} from '@/components/ui/resizable';
|
|
13
|
+
import { FileExplorer } from './FileExplorer';
|
|
14
|
+
import { CodeEditor } from './CodeEditor';
|
|
15
|
+
import { LivePreview } from './LivePreview';
|
|
16
|
+
import { PerformanceDashboard, TerminalPane } from './PerformanceDashboard';
|
|
17
|
+
import { TopBar } from './TopBar';
|
|
18
|
+
import {
|
|
19
|
+
Files,
|
|
20
|
+
Activity,
|
|
21
|
+
LayoutPanelLeft,
|
|
22
|
+
PanelBottomClose,
|
|
23
|
+
PanelBottomOpen,
|
|
24
|
+
} from 'lucide-react';
|
|
25
|
+
import { cn } from '@/lib/utils';
|
|
26
|
+
|
|
27
|
+
type SidebarTab = 'explorer' | 'metrics';
|
|
28
|
+
|
|
29
|
+
export function IDEShell() {
|
|
30
|
+
const [sidebarTab, setSidebarTab] = useState<SidebarTab>('explorer');
|
|
31
|
+
const [showTerminal, setShowTerminal] = useState(true);
|
|
32
|
+
const [showRightPanel, setShowRightPanel] = useState(true);
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<div className="flex flex-col h-screen overflow-hidden bg-background">
|
|
36
|
+
{/* Top bar */}
|
|
37
|
+
<TopBar />
|
|
38
|
+
|
|
39
|
+
{/* Main layout */}
|
|
40
|
+
<div className="flex flex-1 overflow-hidden">
|
|
41
|
+
{/* Activity bar (icon rail) */}
|
|
42
|
+
<div className="flex flex-col items-center gap-1 w-10 bg-sidebar border-r border-sidebar-border py-2 shrink-0">
|
|
43
|
+
<button
|
|
44
|
+
className={cn(
|
|
45
|
+
'p-2 rounded transition-colors',
|
|
46
|
+
sidebarTab === 'explorer'
|
|
47
|
+
? 'text-lava bg-lava/10'
|
|
48
|
+
: 'text-muted-foreground hover:text-foreground hover:bg-muted/40'
|
|
49
|
+
)}
|
|
50
|
+
onClick={() => setSidebarTab('explorer')}
|
|
51
|
+
title="File Explorer"
|
|
52
|
+
>
|
|
53
|
+
<Files className="w-4 h-4" />
|
|
54
|
+
</button>
|
|
55
|
+
<button
|
|
56
|
+
className={cn(
|
|
57
|
+
'p-2 rounded transition-colors',
|
|
58
|
+
sidebarTab === 'metrics'
|
|
59
|
+
? 'text-lava bg-lava/10'
|
|
60
|
+
: 'text-muted-foreground hover:text-foreground hover:bg-muted/40'
|
|
61
|
+
)}
|
|
62
|
+
onClick={() => setSidebarTab('metrics')}
|
|
63
|
+
title="Runtime Metrics"
|
|
64
|
+
>
|
|
65
|
+
<Activity className="w-4 h-4" />
|
|
66
|
+
</button>
|
|
67
|
+
|
|
68
|
+
<div className="flex-1" />
|
|
69
|
+
|
|
70
|
+
<button
|
|
71
|
+
className={cn(
|
|
72
|
+
'p-2 rounded transition-colors',
|
|
73
|
+
showRightPanel
|
|
74
|
+
? 'text-lava bg-lava/10'
|
|
75
|
+
: 'text-muted-foreground hover:text-foreground'
|
|
76
|
+
)}
|
|
77
|
+
onClick={() => setShowRightPanel((v) => !v)}
|
|
78
|
+
title="Toggle preview panel"
|
|
79
|
+
>
|
|
80
|
+
<LayoutPanelLeft className="w-4 h-4" />
|
|
81
|
+
</button>
|
|
82
|
+
|
|
83
|
+
<button
|
|
84
|
+
className={cn(
|
|
85
|
+
'p-2 rounded transition-colors',
|
|
86
|
+
showTerminal
|
|
87
|
+
? 'text-lava bg-lava/10'
|
|
88
|
+
: 'text-muted-foreground hover:text-foreground'
|
|
89
|
+
)}
|
|
90
|
+
onClick={() => setShowTerminal((v) => !v)}
|
|
91
|
+
title="Toggle terminal"
|
|
92
|
+
>
|
|
93
|
+
{showTerminal ? (
|
|
94
|
+
<PanelBottomClose className="w-4 h-4" />
|
|
95
|
+
) : (
|
|
96
|
+
<PanelBottomOpen className="w-4 h-4" />
|
|
97
|
+
)}
|
|
98
|
+
</button>
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
{/* Main content area */}
|
|
102
|
+
<ResizablePanelGroup direction="horizontal" className="flex-1">
|
|
103
|
+
{/* Left sidebar */}
|
|
104
|
+
<ResizablePanel defaultSize={16} minSize={12} maxSize={28}>
|
|
105
|
+
{sidebarTab === 'explorer' ? (
|
|
106
|
+
<FileExplorer />
|
|
107
|
+
) : (
|
|
108
|
+
<PerformanceDashboard />
|
|
109
|
+
)}
|
|
110
|
+
</ResizablePanel>
|
|
111
|
+
|
|
112
|
+
<ResizableHandle className="w-px bg-border hover:bg-lava/40 transition-colors" />
|
|
113
|
+
|
|
114
|
+
{/* Center: Editor + Terminal */}
|
|
115
|
+
<ResizablePanel defaultSize={showRightPanel ? 46 : 84} minSize={30}>
|
|
116
|
+
<ResizablePanelGroup direction="vertical">
|
|
117
|
+
{/* Code editor */}
|
|
118
|
+
<ResizablePanel defaultSize={showTerminal ? 70 : 100} minSize={40}>
|
|
119
|
+
<CodeEditor />
|
|
120
|
+
</ResizablePanel>
|
|
121
|
+
|
|
122
|
+
{/* Terminal */}
|
|
123
|
+
{showTerminal && (
|
|
124
|
+
<>
|
|
125
|
+
<ResizableHandle className="h-px bg-border hover:bg-lava/40 transition-colors" />
|
|
126
|
+
<ResizablePanel defaultSize={30} minSize={15} maxSize={50}>
|
|
127
|
+
<TerminalPane />
|
|
128
|
+
</ResizablePanel>
|
|
129
|
+
</>
|
|
130
|
+
)}
|
|
131
|
+
</ResizablePanelGroup>
|
|
132
|
+
</ResizablePanel>
|
|
133
|
+
|
|
134
|
+
{/* Right: Preview + Metrics */}
|
|
135
|
+
{showRightPanel && (
|
|
136
|
+
<>
|
|
137
|
+
<ResizableHandle className="w-px bg-border hover:bg-lava/40 transition-colors" />
|
|
138
|
+
<ResizablePanel defaultSize={38} minSize={25}>
|
|
139
|
+
<ResizablePanelGroup direction="vertical">
|
|
140
|
+
{/* Live preview */}
|
|
141
|
+
<ResizablePanel defaultSize={65} minSize={40}>
|
|
142
|
+
<LivePreview />
|
|
143
|
+
</ResizablePanel>
|
|
144
|
+
|
|
145
|
+
<ResizableHandle className="h-px bg-border hover:bg-lava/40 transition-colors" />
|
|
146
|
+
|
|
147
|
+
{/* Metrics panel */}
|
|
148
|
+
<ResizablePanel defaultSize={35} minSize={20}>
|
|
149
|
+
<PerformanceDashboard />
|
|
150
|
+
</ResizablePanel>
|
|
151
|
+
</ResizablePanelGroup>
|
|
152
|
+
</ResizablePanel>
|
|
153
|
+
</>
|
|
154
|
+
)}
|
|
155
|
+
</ResizablePanelGroup>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
);
|
|
159
|
+
}
|
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JXR.js — Landing / Splash Page
|
|
3
|
+
* Design: LavaFlow OS — Thermal Precision + Edge Command
|
|
4
|
+
* Hero section showcasing JXR.js capabilities
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { useState, useEffect } from 'react';
|
|
8
|
+
import { motion } from 'framer-motion';
|
|
9
|
+
import { ArrowRight, Zap, Shield, Radio, Layers, GitBranch, Terminal, ChevronRight } from 'lucide-react';
|
|
10
|
+
import { cn } from '@/lib/utils';
|
|
11
|
+
|
|
12
|
+
const HERO_BG = 'https://d2xsxph8kpxj0f.cloudfront.net/310519663435100945/N4herHfeSthyfzuGXbFj8P/jxr-hero-bg-C2Vg2XuLuccTULNjTsLvnn.webp';
|
|
13
|
+
const WORKER_NODES = 'https://d2xsxph8kpxj0f.cloudfront.net/310519663435100945/N4herHfeSthyfzuGXbFj8P/jxr-worker-nodes-mfRehMGmXZQb9DNKC4M7MA.webp';
|
|
14
|
+
const MOQ_STREAM = 'https://d2xsxph8kpxj0f.cloudfront.net/310519663435100945/N4herHfeSthyfzuGXbFj8P/jxr-moq-stream-DJ8jFUmk7fbpGM5EwhuFYY.webp';
|
|
15
|
+
const CRYPTO_SHIELD = 'https://d2xsxph8kpxj0f.cloudfront.net/310519663435100945/N4herHfeSthyfzuGXbFj8P/jxr-crypto-shield-H4owYyan7BZhKBhnhC7z5f.webp';
|
|
16
|
+
const LOGO_MARK = 'https://d2xsxph8kpxj0f.cloudfront.net/310519663435100945/N4herHfeSthyfzuGXbFj8P/jxr-logo-mark-944pCTDiSWor8w5GuRTBUW.webp';
|
|
17
|
+
|
|
18
|
+
const FEATURES = [
|
|
19
|
+
{
|
|
20
|
+
icon: <Zap className="w-5 h-5" />,
|
|
21
|
+
title: 'Zero Build Step',
|
|
22
|
+
desc: 'JSX renders directly in the browser. No webpack, no Vite, no Bun. Pure edge execution.',
|
|
23
|
+
color: 'lava',
|
|
24
|
+
image: WORKER_NODES,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
icon: <Radio className="w-5 h-5" />,
|
|
28
|
+
title: 'MoQ Transport',
|
|
29
|
+
desc: 'Media over QUIC streaming replaces HTTP polling. Sub-RTT latency for module delivery.',
|
|
30
|
+
color: 'cyan',
|
|
31
|
+
image: MOQ_STREAM,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
icon: <Shield className="w-5 h-5" />,
|
|
35
|
+
title: 'Web Crypto Native',
|
|
36
|
+
desc: 'AES-GCM-256 module caching, ECDSA P-256 signing. Universal across all runtimes.',
|
|
37
|
+
color: 'green',
|
|
38
|
+
image: CRYPTO_SHIELD,
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
icon: <Layers className="w-5 h-5" />,
|
|
42
|
+
title: 'Worker Pool',
|
|
43
|
+
desc: 'Pre-warmed Web Worker fleet saturates all CPU cores. Priority-queued task dispatch.',
|
|
44
|
+
color: 'yellow',
|
|
45
|
+
image: WORKER_NODES,
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
const BENCHMARKS = [
|
|
50
|
+
{ label: 'Cold Start', jxr: '0ms', nextjs: '2,400ms', vite: '800ms', bun: '350ms' },
|
|
51
|
+
{ label: 'HMR Update', jxr: '<1ms', nextjs: '180ms', vite: '45ms', bun: '30ms' },
|
|
52
|
+
{ label: 'Module Load', jxr: '2ms', nextjs: '320ms', vite: '85ms', bun: '40ms' },
|
|
53
|
+
{ label: 'Build Time', jxr: 'N/A', nextjs: '45s', vite: '12s', bun: '8s' },
|
|
54
|
+
{ label: 'Memory', jxr: '18MB', nextjs: '420MB', vite: '180MB', bun: '95MB' },
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
const CODE_SAMPLE = `// JXR.js — No build step required
|
|
58
|
+
// This JSX runs directly in the browser
|
|
59
|
+
|
|
60
|
+
import { useState } from 'react';
|
|
61
|
+
|
|
62
|
+
export default function EdgeApp() {
|
|
63
|
+
const [data, setData] = useState(null);
|
|
64
|
+
|
|
65
|
+
// MoQ streaming — sub-RTT delivery
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
const unsub = moq.subscribe({
|
|
68
|
+
track: { namespace: 'jxr', trackName: 'live-data' },
|
|
69
|
+
deliveryOrder: 'ascending',
|
|
70
|
+
handler: (obj) => setData(obj.payload),
|
|
71
|
+
});
|
|
72
|
+
return unsub;
|
|
73
|
+
}, []);
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<div className="edge-app">
|
|
77
|
+
<h1>JXR Edge Runtime</h1>
|
|
78
|
+
<p>Latency: {data?.rtt}ms</p>
|
|
79
|
+
</div>
|
|
80
|
+
);
|
|
81
|
+
}`;
|
|
82
|
+
|
|
83
|
+
interface LandingPageProps {
|
|
84
|
+
onEnterIDE: () => void;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function LandingPage({ onEnterIDE }: LandingPageProps) {
|
|
88
|
+
const [activeFeature, setActiveFeature] = useState(0);
|
|
89
|
+
const [typedCode, setTypedCode] = useState('');
|
|
90
|
+
const [codeIndex, setCodeIndex] = useState(0);
|
|
91
|
+
|
|
92
|
+
// Typewriter effect for code sample
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
if (codeIndex >= CODE_SAMPLE.length) return;
|
|
95
|
+
const timeout = setTimeout(() => {
|
|
96
|
+
setTypedCode(CODE_SAMPLE.slice(0, codeIndex + 1));
|
|
97
|
+
setCodeIndex((i) => i + 1);
|
|
98
|
+
}, 12);
|
|
99
|
+
return () => clearTimeout(timeout);
|
|
100
|
+
}, [codeIndex]);
|
|
101
|
+
|
|
102
|
+
// Auto-rotate features
|
|
103
|
+
useEffect(() => {
|
|
104
|
+
const interval = setInterval(() => {
|
|
105
|
+
setActiveFeature((i) => (i + 1) % FEATURES.length);
|
|
106
|
+
}, 3000);
|
|
107
|
+
return () => clearInterval(interval);
|
|
108
|
+
}, []);
|
|
109
|
+
|
|
110
|
+
const colorMap: Record<string, string> = {
|
|
111
|
+
lava: 'text-lava border-lava/30 bg-lava/10',
|
|
112
|
+
cyan: 'text-cyan-accent border-cyan-accent/30 bg-cyan-accent/10',
|
|
113
|
+
green: 'text-success border-success/30 bg-success/10',
|
|
114
|
+
yellow: 'text-warning border-warning/30 bg-warning/10',
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
return (
|
|
118
|
+
<div className="min-h-screen bg-background overflow-x-hidden">
|
|
119
|
+
{/* ─── Hero ──────────────────────────────────────────────────────── */}
|
|
120
|
+
<section className="relative min-h-screen flex flex-col">
|
|
121
|
+
{/* Background */}
|
|
122
|
+
<div className="absolute inset-0 overflow-hidden">
|
|
123
|
+
<img
|
|
124
|
+
src={HERO_BG}
|
|
125
|
+
alt=""
|
|
126
|
+
className="w-full h-full object-cover opacity-25"
|
|
127
|
+
/>
|
|
128
|
+
<div className="absolute inset-0 bg-gradient-to-b from-background/40 via-background/70 to-background" />
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
{/* Top nav */}
|
|
132
|
+
<nav className="relative z-10 flex items-center justify-between px-6 md:px-12 py-5">
|
|
133
|
+
<div className="flex items-center gap-3">
|
|
134
|
+
<img src={LOGO_MARK} alt="JXR" className="w-8 h-8 rounded" />
|
|
135
|
+
<div>
|
|
136
|
+
<span className="text-lg font-bold text-shimmer">JXR.js</span>
|
|
137
|
+
<span className="ml-2 text-[10px] text-muted-foreground font-mono">v1.0.0-edge</span>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
<div className="flex items-center gap-4">
|
|
141
|
+
<a href="#features" className="text-sm text-muted-foreground hover:text-foreground transition-colors hidden md:block">
|
|
142
|
+
Features
|
|
143
|
+
</a>
|
|
144
|
+
<a href="#benchmarks" className="text-sm text-muted-foreground hover:text-foreground transition-colors hidden md:block">
|
|
145
|
+
Benchmarks
|
|
146
|
+
</a>
|
|
147
|
+
<button
|
|
148
|
+
onClick={onEnterIDE}
|
|
149
|
+
className="flex items-center gap-2 px-4 py-2 rounded-lg bg-lava text-lava-foreground text-sm font-semibold hover:bg-lava/90 transition-all glow-lava"
|
|
150
|
+
>
|
|
151
|
+
Open IDE
|
|
152
|
+
<ArrowRight className="w-4 h-4" />
|
|
153
|
+
</button>
|
|
154
|
+
</div>
|
|
155
|
+
</nav>
|
|
156
|
+
|
|
157
|
+
{/* Hero content */}
|
|
158
|
+
<div className="relative z-10 flex-1 flex flex-col items-center justify-center text-center px-6 py-16">
|
|
159
|
+
<motion.div
|
|
160
|
+
initial={{ opacity: 0, y: 20 }}
|
|
161
|
+
animate={{ opacity: 1, y: 0 }}
|
|
162
|
+
transition={{ duration: 0.6 }}
|
|
163
|
+
className="space-y-6 max-w-4xl"
|
|
164
|
+
>
|
|
165
|
+
{/* Badge */}
|
|
166
|
+
<div className="inline-flex items-center gap-2 px-3 py-1.5 rounded-full border border-lava/30 bg-lava/10 text-lava text-xs font-semibold">
|
|
167
|
+
<span className="w-1.5 h-1.5 rounded-full bg-lava animate-pulse" />
|
|
168
|
+
Powered by JXR Studios × DamascusAI
|
|
169
|
+
</div>
|
|
170
|
+
|
|
171
|
+
{/* Headline */}
|
|
172
|
+
<h1 className="text-5xl md:text-7xl font-black tracking-tight leading-none">
|
|
173
|
+
<span className="text-shimmer">The Edge OS</span>
|
|
174
|
+
<br />
|
|
175
|
+
<span className="text-foreground">for React</span>
|
|
176
|
+
</h1>
|
|
177
|
+
|
|
178
|
+
<p className="text-lg md:text-xl text-muted-foreground max-w-2xl mx-auto leading-relaxed">
|
|
179
|
+
JXR.js renders React directly in the browser with{' '}
|
|
180
|
+
<strong className="text-foreground">zero build step</strong>.
|
|
181
|
+
MoQ streaming, Web Crypto integrity, and a pre-warmed Worker pool
|
|
182
|
+
deliver performance that makes Next.js, Vite, and Bun look slow.
|
|
183
|
+
</p>
|
|
184
|
+
|
|
185
|
+
{/* CTA buttons */}
|
|
186
|
+
<div className="flex flex-col sm:flex-row items-center gap-3 justify-center pt-2">
|
|
187
|
+
<button
|
|
188
|
+
onClick={onEnterIDE}
|
|
189
|
+
className="flex items-center gap-2 px-6 py-3 rounded-lg bg-lava text-lava-foreground font-bold text-base hover:bg-lava/90 transition-all glow-lava w-full sm:w-auto"
|
|
190
|
+
>
|
|
191
|
+
<Terminal className="w-4 h-4" />
|
|
192
|
+
Launch IDE
|
|
193
|
+
<ArrowRight className="w-4 h-4" />
|
|
194
|
+
</button>
|
|
195
|
+
<a
|
|
196
|
+
href="#benchmarks"
|
|
197
|
+
className="flex items-center gap-2 px-6 py-3 rounded-lg border border-border text-foreground font-semibold text-base hover:border-lava/50 hover:bg-lava/5 transition-all w-full sm:w-auto"
|
|
198
|
+
>
|
|
199
|
+
View Benchmarks
|
|
200
|
+
<ChevronRight className="w-4 h-4" />
|
|
201
|
+
</a>
|
|
202
|
+
</div>
|
|
203
|
+
|
|
204
|
+
{/* Stats row */}
|
|
205
|
+
<div className="flex items-center justify-center gap-8 pt-4 text-sm">
|
|
206
|
+
{[
|
|
207
|
+
{ label: 'Cold Start', value: '0ms' },
|
|
208
|
+
{ label: 'HMR Latency', value: '<1ms' },
|
|
209
|
+
{ label: 'Build Step', value: 'None' },
|
|
210
|
+
].map(({ label, value }) => (
|
|
211
|
+
<div key={label} className="text-center">
|
|
212
|
+
<div className="text-2xl font-black text-lava font-mono">{value}</div>
|
|
213
|
+
<div className="text-[11px] text-muted-foreground uppercase tracking-wide">{label}</div>
|
|
214
|
+
</div>
|
|
215
|
+
))}
|
|
216
|
+
</div>
|
|
217
|
+
</motion.div>
|
|
218
|
+
</div>
|
|
219
|
+
|
|
220
|
+
{/* Scroll indicator */}
|
|
221
|
+
<div className="relative z-10 flex justify-center pb-8">
|
|
222
|
+
<div className="flex flex-col items-center gap-1 text-muted-foreground/40 animate-bounce">
|
|
223
|
+
<div className="w-px h-8 bg-gradient-to-b from-transparent to-lava/40" />
|
|
224
|
+
<ChevronRight className="w-4 h-4 rotate-90" />
|
|
225
|
+
</div>
|
|
226
|
+
</div>
|
|
227
|
+
</section>
|
|
228
|
+
|
|
229
|
+
{/* ─── Features ──────────────────────────────────────────────────── */}
|
|
230
|
+
<section id="features" className="py-20 px-6 md:px-12">
|
|
231
|
+
<div className="max-w-6xl mx-auto">
|
|
232
|
+
<div className="text-center mb-12">
|
|
233
|
+
<h2 className="text-3xl md:text-4xl font-black mb-4">
|
|
234
|
+
Built for the <span className="text-gradient-lava">Edge</span>
|
|
235
|
+
</h2>
|
|
236
|
+
<p className="text-muted-foreground max-w-xl mx-auto">
|
|
237
|
+
Every layer of JXR.js is designed to eliminate latency and maximize throughput
|
|
238
|
+
at the edge of the network.
|
|
239
|
+
</p>
|
|
240
|
+
</div>
|
|
241
|
+
|
|
242
|
+
<div className="grid md:grid-cols-2 gap-6">
|
|
243
|
+
{/* Feature cards */}
|
|
244
|
+
<div className="space-y-3">
|
|
245
|
+
{FEATURES.map((f, i) => (
|
|
246
|
+
<motion.div
|
|
247
|
+
key={f.title}
|
|
248
|
+
className={cn(
|
|
249
|
+
'flex items-start gap-4 p-4 rounded-xl border cursor-pointer transition-all duration-200',
|
|
250
|
+
activeFeature === i
|
|
251
|
+
? 'border-lava/40 bg-lava/5 shadow-lg'
|
|
252
|
+
: 'border-border bg-card hover:border-border/80'
|
|
253
|
+
)}
|
|
254
|
+
onClick={() => setActiveFeature(i)}
|
|
255
|
+
whileHover={{ x: 4 }}
|
|
256
|
+
>
|
|
257
|
+
<div className={cn('p-2 rounded-lg border shrink-0', colorMap[f.color])}>
|
|
258
|
+
{f.icon}
|
|
259
|
+
</div>
|
|
260
|
+
<div>
|
|
261
|
+
<h3 className="font-bold text-sm mb-1">{f.title}</h3>
|
|
262
|
+
<p className="text-xs text-muted-foreground leading-relaxed">{f.desc}</p>
|
|
263
|
+
</div>
|
|
264
|
+
</motion.div>
|
|
265
|
+
))}
|
|
266
|
+
</div>
|
|
267
|
+
|
|
268
|
+
{/* Feature image */}
|
|
269
|
+
<div className="relative rounded-2xl overflow-hidden border border-border bg-card aspect-video md:aspect-auto">
|
|
270
|
+
{FEATURES.map((f, i) => (
|
|
271
|
+
<img
|
|
272
|
+
key={f.title}
|
|
273
|
+
src={f.image}
|
|
274
|
+
alt={f.title}
|
|
275
|
+
className={cn(
|
|
276
|
+
'absolute inset-0 w-full h-full object-cover transition-opacity duration-500',
|
|
277
|
+
activeFeature === i ? 'opacity-100' : 'opacity-0'
|
|
278
|
+
)}
|
|
279
|
+
/>
|
|
280
|
+
))}
|
|
281
|
+
<div className="absolute inset-0 bg-gradient-to-t from-background/80 via-transparent to-transparent" />
|
|
282
|
+
<div className="absolute bottom-4 left-4 right-4">
|
|
283
|
+
<div className="text-sm font-bold">{FEATURES[activeFeature].title}</div>
|
|
284
|
+
<div className="text-xs text-muted-foreground mt-0.5">
|
|
285
|
+
{FEATURES[activeFeature].desc}
|
|
286
|
+
</div>
|
|
287
|
+
</div>
|
|
288
|
+
</div>
|
|
289
|
+
</div>
|
|
290
|
+
</div>
|
|
291
|
+
</section>
|
|
292
|
+
|
|
293
|
+
{/* ─── Code sample ───────────────────────────────────────────────── */}
|
|
294
|
+
<section className="py-20 px-6 md:px-12 bg-card/30">
|
|
295
|
+
<div className="max-w-4xl mx-auto">
|
|
296
|
+
<div className="text-center mb-10">
|
|
297
|
+
<h2 className="text-3xl font-black mb-3">
|
|
298
|
+
Write Once, <span className="text-gradient-lava">Run Everywhere</span>
|
|
299
|
+
</h2>
|
|
300
|
+
<p className="text-muted-foreground">
|
|
301
|
+
Standard React code. No special APIs. No framework lock-in.
|
|
302
|
+
</p>
|
|
303
|
+
</div>
|
|
304
|
+
<div className="rounded-xl border border-border bg-[oklch(0.09_0.005_260)] overflow-hidden">
|
|
305
|
+
{/* Window chrome */}
|
|
306
|
+
<div className="flex items-center gap-2 px-4 py-3 border-b border-border/50">
|
|
307
|
+
<div className="w-3 h-3 rounded-full bg-destructive/60" />
|
|
308
|
+
<div className="w-3 h-3 rounded-full bg-warning/60" />
|
|
309
|
+
<div className="w-3 h-3 rounded-full bg-success/60" />
|
|
310
|
+
<span className="ml-3 text-[11px] font-mono text-muted-foreground">App.tsx — JXR Edge Runtime</span>
|
|
311
|
+
<div className="ml-auto flex items-center gap-1.5 text-[10px] text-success">
|
|
312
|
+
<span className="w-1.5 h-1.5 rounded-full bg-success animate-pulse" />
|
|
313
|
+
Live
|
|
314
|
+
</div>
|
|
315
|
+
</div>
|
|
316
|
+
<pre className="p-6 text-xs font-mono text-foreground/80 overflow-x-auto leading-relaxed">
|
|
317
|
+
<code>{typedCode}<span className="animate-pulse text-lava">|</span></code>
|
|
318
|
+
</pre>
|
|
319
|
+
</div>
|
|
320
|
+
</div>
|
|
321
|
+
</section>
|
|
322
|
+
|
|
323
|
+
{/* ─── Benchmarks ────────────────────────────────────────────────── */}
|
|
324
|
+
<section id="benchmarks" className="py-20 px-6 md:px-12">
|
|
325
|
+
<div className="max-w-4xl mx-auto">
|
|
326
|
+
<div className="text-center mb-12">
|
|
327
|
+
<h2 className="text-3xl md:text-4xl font-black mb-4">
|
|
328
|
+
Performance <span className="text-gradient-lava">Benchmarks</span>
|
|
329
|
+
</h2>
|
|
330
|
+
<p className="text-muted-foreground">
|
|
331
|
+
JXR.js eliminates the build step entirely — making comparison almost unfair.
|
|
332
|
+
</p>
|
|
333
|
+
</div>
|
|
334
|
+
|
|
335
|
+
<div className="rounded-xl border border-border overflow-hidden">
|
|
336
|
+
<table className="w-full text-sm">
|
|
337
|
+
<thead>
|
|
338
|
+
<tr className="border-b border-border bg-card">
|
|
339
|
+
<th className="text-left px-4 py-3 text-muted-foreground font-semibold text-xs uppercase tracking-wide">Metric</th>
|
|
340
|
+
<th className="text-center px-4 py-3">
|
|
341
|
+
<span className="text-lava font-bold">JXR.js</span>
|
|
342
|
+
</th>
|
|
343
|
+
<th className="text-center px-4 py-3 text-muted-foreground font-medium text-xs">Next.js</th>
|
|
344
|
+
<th className="text-center px-4 py-3 text-muted-foreground font-medium text-xs">Vite</th>
|
|
345
|
+
<th className="text-center px-4 py-3 text-muted-foreground font-medium text-xs">Bun</th>
|
|
346
|
+
</tr>
|
|
347
|
+
</thead>
|
|
348
|
+
<tbody>
|
|
349
|
+
{BENCHMARKS.map((row, i) => (
|
|
350
|
+
<tr key={row.label} className={cn('border-b border-border/50', i % 2 === 0 ? 'bg-background' : 'bg-card/30')}>
|
|
351
|
+
<td className="px-4 py-3 text-muted-foreground text-xs font-medium">{row.label}</td>
|
|
352
|
+
<td className="px-4 py-3 text-center">
|
|
353
|
+
<span className="font-bold font-mono text-lava">{row.jxr}</span>
|
|
354
|
+
</td>
|
|
355
|
+
<td className="px-4 py-3 text-center font-mono text-xs text-muted-foreground">{row.nextjs}</td>
|
|
356
|
+
<td className="px-4 py-3 text-center font-mono text-xs text-muted-foreground">{row.vite}</td>
|
|
357
|
+
<td className="px-4 py-3 text-center font-mono text-xs text-muted-foreground">{row.bun}</td>
|
|
358
|
+
</tr>
|
|
359
|
+
))}
|
|
360
|
+
</tbody>
|
|
361
|
+
</table>
|
|
362
|
+
</div>
|
|
363
|
+
|
|
364
|
+
<p className="text-center text-xs text-muted-foreground mt-4">
|
|
365
|
+
* JXR.js has no build step — cold start is the time to first rendered pixel.
|
|
366
|
+
</p>
|
|
367
|
+
</div>
|
|
368
|
+
</section>
|
|
369
|
+
|
|
370
|
+
{/* ─── CTA ───────────────────────────────────────────────────────── */}
|
|
371
|
+
<section className="py-20 px-6 md:px-12 relative overflow-hidden">
|
|
372
|
+
<div className="absolute inset-0">
|
|
373
|
+
<img src={MOQ_STREAM} alt="" className="w-full h-full object-cover opacity-10" />
|
|
374
|
+
<div className="absolute inset-0 bg-gradient-to-r from-background via-background/80 to-background" />
|
|
375
|
+
</div>
|
|
376
|
+
<div className="relative z-10 max-w-2xl mx-auto text-center">
|
|
377
|
+
<h2 className="text-3xl md:text-4xl font-black mb-4">
|
|
378
|
+
Ready to go <span className="text-shimmer">beyond the edge</span>?
|
|
379
|
+
</h2>
|
|
380
|
+
<p className="text-muted-foreground mb-8">
|
|
381
|
+
Open the JXR IDE and start building React apps that run at the speed of the edge.
|
|
382
|
+
No installation. No build step. Just code.
|
|
383
|
+
</p>
|
|
384
|
+
<button
|
|
385
|
+
onClick={onEnterIDE}
|
|
386
|
+
className="flex items-center gap-3 px-8 py-4 rounded-xl bg-lava text-lava-foreground font-bold text-lg hover:bg-lava/90 transition-all glow-lava mx-auto"
|
|
387
|
+
>
|
|
388
|
+
<Terminal className="w-5 h-5" />
|
|
389
|
+
Launch JXR IDE
|
|
390
|
+
<ArrowRight className="w-5 h-5" />
|
|
391
|
+
</button>
|
|
392
|
+
<div className="mt-6 text-xs text-muted-foreground">
|
|
393
|
+
Powered by <span className="text-lava font-semibold">JXR Studios</span> × <span className="text-cyan-accent font-semibold">DamascusAI</span>
|
|
394
|
+
</div>
|
|
395
|
+
</div>
|
|
396
|
+
</section>
|
|
397
|
+
|
|
398
|
+
{/* Footer */}
|
|
399
|
+
<footer className="border-t border-border py-8 px-6 md:px-12">
|
|
400
|
+
<div className="max-w-6xl mx-auto flex flex-col md:flex-row items-center justify-between gap-4">
|
|
401
|
+
<div className="flex items-center gap-2">
|
|
402
|
+
<img src={LOGO_MARK} alt="JXR" className="w-6 h-6 rounded" />
|
|
403
|
+
<span className="text-sm font-bold text-shimmer">JXR.js</span>
|
|
404
|
+
<span className="text-xs text-muted-foreground">Edge OS Runtime</span>
|
|
405
|
+
</div>
|
|
406
|
+
<div className="flex items-center gap-1 text-xs text-muted-foreground">
|
|
407
|
+
<GitBranch className="w-3 h-3" />
|
|
408
|
+
<span>Built with precision by JXR Studios × DamascusAI</span>
|
|
409
|
+
</div>
|
|
410
|
+
</div>
|
|
411
|
+
</footer>
|
|
412
|
+
</div>
|
|
413
|
+
);
|
|
414
|
+
}
|