import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import type { ComponentType, ReactNode } from 'react' import { AlertTriangle, Archive, ArrowDownToLine, ArrowLeft, ArrowRight, Box, Check, CheckCircle2, ChevronDown, ChevronRight, Circle, CircleDot, Clock3, Code2, Command, Copy, Download, FileBox, FilePlus2, FileText, FolderOpen, HardDrive, HelpCircle, Layers3, LayoutGrid, ListTree, Menu, MoreHorizontal, PanelBottom, PanelLeft, PanelRight, Pause, Pencil, Plus, Rotate3D, Save, Search, Settings2, SlidersHorizontal, Sparkles, SquareStack, Trash2, Undo2, Redo2, RefreshCw, Upload, UserRound, WandSparkles, X, ZoomIn, ZoomOut, } from 'lucide-react' import { menuDefinitions, pinnedWorkbenches, workbenchDefinitions, type MenuName, type WorkbenchId } from './freecadManifest' import { createMockFacade, type BitBybitViewportAdapter, type BitBybitWebCadFacade, type DocumentSnapshot, type FcstdInspection, type ModelTreeItem, type ObjectPropertySnapshot, type PropertyValue, type ShapeHandle } from './facade' type Page = 'start' | 'projects' | 'workspace' | 'import' | 'export' | 'settings' | 'help' | 'diagnostics' | 'sync' type Workbench = WorkbenchId type Icon = ComponentType<{ size?: string | number; strokeWidth?: string | number; className?: string }> const pageFromPath = (): Page => { const path = window.location.pathname if (path.startsWith('/projects')) return 'projects' if (path.startsWith('/workspace')) return 'workspace' if (path.startsWith('/import')) return 'import' if (path.startsWith('/export')) return 'export' if (path.startsWith('/settings')) return 'settings' if (path.startsWith('/help')) return 'help' if (path.startsWith('/diagnostics')) return 'diagnostics' if (path.startsWith('/sync')) return 'sync' return 'start' } const iconMap: Record = { box: Box, 'circle-dot': CircleDot, 'square-stack': SquareStack, 'file-text': FileText, 'layout-grid': LayoutGrid, layers: Layers3, archive: Archive, pencil: Pencil, copy: Copy, 'arrow-up': ArrowDownToLine, 'arrow-down': ArrowDownToLine, rotate: Rotate3D, 'sliders-horizontal': SlidersHorizontal, search: Search, upload: Upload, download: Download, 'file-plus': FilePlus2, 'code-2': Code2, 'settings-2': Settings2, 'circle-check': CheckCircle2, 'triangle-alert': AlertTriangle, eye: CircleDot, 'zoom-in': ZoomIn, 'grid-3x3': LayoutGrid, play: Check, plus: Plus, minus: X, circle: Circle, route: Rotate3D, 'git-branch': Layers3, 'layers-2': Layers3, 'flip-horizontal': ArrowLeft, repeat: Rotate3D, 'refresh-cw': Rotate3D, shuffle: MoreHorizontal, 'corner-down-right': SlidersHorizontal, scissors: X, triangle: Box, paperclip: Copy, 'move-horizontal': ArrowRight, 'move-vertical': ArrowDownToLine, magnet: CircleDot, move: ArrowRight, type: FileText, 'panels-top-left': LayoutGrid, maximize: PanelRight, table: LayoutGrid, tag: FileText, 'rows-3': ListTree, link: Copy, paintbrush: WandSparkles, pin: PanelLeft, anchor: CircleDot, split: ArrowRight, target: CircleDot, protractor: SlidersHorizontal, activity: Rotate3D, lock: Circle, spline: Rotate3D, crosshair: CircleDot, 'file-box': FileBox, } const workbenchIconKeys: Record = { 'Part Design': 'box', Part: 'box', Sketcher: 'circle-dot', Draft: 'square-stack', BIM: 'layers', TechDraw: 'file-text', Spreadsheet: 'layout-grid', Assembly: 'layers', CAM: 'settings-2', FEM: 'activity', Mesh: 'archive', Surface: 'spline', Inspection: 'search', } const workbenchMeta: Record = Object.fromEntries( Object.entries(workbenchDefinitions).map(([id, definition]) => [id, { icon: iconMap[workbenchIconKeys[id as Workbench]] || MoreHorizontal, accent: id === 'Sketcher' ? 'violet' : id === 'Part' ? 'amber' : 'cyan', description: definition.description }]), ) as Record function CuboidIcon({ size = 18, strokeWidth = 1.8, className }: { size?: string | number; strokeWidth?: string | number; className?: string }) { return } const projects = [ { name: 'Pump Housing', path: 'Local / Mechanical / Pump Housing', modified: 'Just now', objects: 18, state: 'Unsaved' }, { name: 'Mounting Bracket', path: 'Local / Concepts / Mounting Bracket', modified: 'Yesterday', objects: 9, state: 'Saved' }, { name: 'Motor Assembly', path: 'Local / Assemblies / Motor Assembly', modified: '28 Jul 2026', objects: 142, state: 'Saved' }, { name: 'Valve Body Study', path: 'Shared / Review / Valve Body Study', modified: '22 Jul 2026', objects: 31, state: 'Read only' }, ] const IconButton = ({ icon: IconComponent, label, onClick, active = false, disabled = false }: { icon: Icon; label: string; onClick?: () => void; active?: boolean; disabled?: boolean }) => ( ) const Badge = ({ tone, children }: { tone: 'cyan' | 'green' | 'amber' | 'red' | 'muted'; children: ReactNode }) => ( {children} ) function App() { const [page, setPage] = useState(pageFromPath) const [leftTab, setLeftTab] = useState<'model' | 'tasks'>('model') const [rightTab, setRightTab] = useState<'data' | 'view'>('data') const [bottomOpen, setBottomOpen] = useState(true) const [notice, setNotice] = useState('') const facade = useMemo(() => createMockFacade(), []) const [facadeState, setFacadeState] = useState(() => facade.getState()) useEffect(() => facade.subscribe((event) => { if (event.type === 'state.changed') setFacadeState(event.state) if (event.type === 'notice') { setNotice(event.message) window.setTimeout(() => setNotice(''), 2600) } }), [facade]) useEffect(() => facade.project.subscribeExternalChanges((notice) => { setNotice(`Project saved in another tab · v${notice.documentVersion}`) window.setTimeout(() => setNotice(''), 2600) }), [facade]) useEffect(() => () => facade.geometry.dispose(), [facade]) useEffect(() => { const handlePopState = () => setPage(pageFromPath()) window.addEventListener('popstate', handlePopState) return () => window.removeEventListener('popstate', handlePopState) }, []) const navigate = (next: Page, replace = false) => { const paths: Record = { start: '/start', projects: '/projects', workspace: '/workspace/pump-housing', import: '/import', export: '/export', settings: '/settings', help: '/help', diagnostics: '/diagnostics', sync: '/sync', } window.history[replace ? 'replaceState' : 'pushState']({}, '', paths[next]) setPage(next) } const openWorkspace = () => navigate('workspace') const workbench = facadeState.activeWorkbench const selectedObject = facadeState.selectedObjectId const currentWorkbench = workbenchMeta[workbench] const CurrentIcon = currentWorkbench.icon const showNotice = useCallback((message: string) => facade.notify(message), [facade]) const setWorkbench = useCallback((value: Workbench) => facade.gui.workbench.setActive(value), [facade]) const setSelectedObject = useCallback((id: string) => id ? facade.selection.select(id) : facade.selection.clear(), [facade]) return (
{page === 'workspace' ? ( { setWorkbench(value); setLeftTab('tasks') }} leftTab={leftTab} setLeftTab={setLeftTab} rightTab={rightTab} setRightTab={setRightTab} bottomOpen={bottomOpen} setBottomOpen={setBottomOpen} selectedObject={selectedObject} setSelectedObject={setSelectedObject} document={facadeState.document} facade={facade} workbenchIcon={CurrentIcon} showNotice={showNotice} /> ) : ( )} {notice &&
{notice}
}
) } function TopBar({ page, workbench, facade, onNavigate, onOpenWorkspace }: { page: Page; workbench: Workbench; facade: BitBybitWebCadFacade; onNavigate: (page: Page) => void; onOpenWorkspace: () => void }) { const [openMenu, setOpenMenu] = useState(null) const document = facade.getState().document const handleMenuCommand = (command: string) => { setOpenMenu(null) if (command === 'help' || command === 'shortcuts') onNavigate('help') else if (command === 'diagnostics') onNavigate('diagnostics') else if (command === 'preferences' || command === 'project-settings' || command === 'parameters') onNavigate('settings') else if (command === 'import') onNavigate('import') else if (command === 'export') onNavigate('export') else if (command === 'open') onNavigate('projects') else onOpenWorkspace() } return (
onNavigate('start')} role="button" tabIndex={0}>
BitBybit
CAD studio
{document.label} / {workbench}
{document.dirty ? 'Unsaved changes' : 'Saved locally'}
facade.history.undo()} disabled={!facade.history.canUndo()} /> facade.history.redo()} disabled={!facade.history.canRedo()} />
onNavigate('help')} />
) } function Workspace({ workbench, setWorkbench, leftTab, setLeftTab, rightTab, setRightTab, bottomOpen, setBottomOpen, selectedObject, setSelectedObject, document, facade, workbenchIcon: WorkbenchIcon, showNotice }: { workbench: Workbench setWorkbench: (value: Workbench) => void leftTab: 'model' | 'tasks' setLeftTab: (tab: 'model' | 'tasks') => void rightTab: 'data' | 'view' setRightTab: (tab: 'data' | 'view') => void bottomOpen: boolean setBottomOpen: (open: boolean) => void selectedObject: string setSelectedObject: (id: string) => void document: DocumentSnapshot facade: BitBybitWebCadFacade workbenchIcon: Icon showNotice: (message: string) => void }) { return (
{ facade.gui.command.execute({ commandId: 'new-document' }); showNotice('New document prepared') }} /> showNotice('Project browser opened')} /> { facade.gui.command.execute({ commandId: 'save' }); showNotice('Saved to local workspace') }} /> { void facade.app.document.recomputeAsync().then((result) => showNotice(result.status === 'completed' ? 'Recompute completed' : `Recompute ${result.status}`)) }} />
{ facade.gui.command.execute({ commandId: 'create-body' }); showNotice('Create Body task opened') }} active={workbench === 'Part Design'} /> { facade.gui.command.execute({ commandId: 'create-sketch' }); showNotice('Select a plane to create a sketch') }} />
Local workspace
{document.units} · {document.objects.length} objects · v{document.version}
Perspective
Grid 10 mm
XYZ
{bottomOpen &&
{document.recompute?.status === 'failed' ? : }Recompute {document.recompute?.status || 'idle'}{document.recompute?.order.length || 0} objects in plangeneration {document.recompute?.generation || 0}
{(document.recompute?.errors || []).slice(0, 2).map((error) =>
{error.message}{error.code}
)}
}
) } function WorkbenchNavBar({ workbench, setWorkbench, showNotice }: { workbench: Workbench; setWorkbench: (value: Workbench) => void; showNotice: (message: string) => void }) { return
Workbench{pinnedWorkbenches.map((item) => { const IconComponent = workbenchMeta[item].icon; return })}
} function FunctionRail({ workbench, facade, showNotice }: { workbench: Workbench; facade: BitBybitWebCadFacade; showNotice: (message: string) => void }) { const groups = workbenchDefinitions[workbench].groups return } function ModelTree({ document, selectedObject, setSelectedObject, showNotice }: { document: DocumentSnapshot; selectedObject: string; setSelectedObject: (id: string) => void; showNotice: (message: string) => void }) { const [expanded, setExpanded] = useState>({ origin: false, body: true, reference: false }) const itemsById = new Map(document.tree.map((item) => [item.id, item])) const childIds = new Set(document.tree.flatMap((item) => item.children || [])) return
{document.label}v{document.version}
{document.tree.filter((item) => !childIds.has(item.id)).map((item) => setExpanded((current) => ({ ...current, [item.id]: !current[item.id] }))} itemsById={itemsById} selectedObject={selectedObject} setSelectedObject={setSelectedObject} showNotice={showNotice} />)}
ValidNeeds review
} function TreeItem({ item, level, expanded, onToggle, itemsById, selectedObject, setSelectedObject, showNotice }: { item: ModelTreeItem; level: number; expanded?: boolean; onToggle: () => void; itemsById: Map; selectedObject: string; setSelectedObject: (id: string) => void; showNotice: (message: string) => void }) { const hasChildren = item.children && item.children.length > 0 const itemIcon = item.type === 'body' ? Box : item.type === 'sketch' ? CircleDot : item.type === 'feature' ? SquareStack : Layers3 const ItemIcon = itemIcon return <> {expanded && hasChildren &&
{item.children?.map((childId) => { const child = itemsById.get(childId); const ChildIcon = child?.type === 'sketch' ? CircleDot : child?.type === 'feature' ? SquareStack : Circle; return child ? :
{childId}
})}
} } function TaskPanel({ workbench, facade, showNotice }: { workbench: Workbench; facade: BitBybitWebCadFacade; showNotice: (message: string) => void }) { const definition = workbenchDefinitions[workbench] const isSketch = workbench === 'Sketcher' const activeTask = facade.task.getActive() const primitiveType = activeTask?.commandId === 'primitive' && typeof activeTask.draft.primitiveType === 'string' ? activeTask.draft.primitiveType : 'Box' return
Active command

{isSketch ? 'Edit Sketch' : definition.taskTitle}

Preview
1
{isSketch ? 'Geometry and constraints' : definition.objectType}{definition.taskSummary}
{activeTask?.commandId === 'primitive' && }
Changes remain local until the document is recomputed.
} function PropertyPanel({ facade, objectId, scope, showNotice }: { facade: BitBybitWebCadFacade; objectId: string; scope: 'data' | 'view'; showNotice: (message: string) => void }) { const object = facade.app.document.getObject(objectId) if (!object) return
No object selected
const properties = object.properties.filter((property) => property.scope === scope && !property.hidden) const groups = new Map() properties.forEach((property) => groups.set(property.group, [...(groups.get(property.group) ?? []), property])) return
{[...groups].map(([group, entries]) =>
{group}
{entries.map((property) => )}
)}
} function PropertyEditor({ facade, objectId, property, showNotice }: { facade: BitBybitWebCadFacade; objectId: string; property: ObjectPropertySnapshot; showNotice: (message: string) => void }) { const commit = (value: PropertyValue) => { try { facade.app.document.setProperty({ objectId, propertyName: property.name, value }) return true } catch (error) { showNotice(error instanceof Error ? error.message : String(error)) return false } } const formatted = `${String(property.value ?? '')}${property.unit ? ` ${property.unit}` : ''}` let editor: ReactNode if (property.readOnly) editor = {formatted} else if (property.type === 'App::PropertyBool') editor = commit(event.target.checked)} /> else if (property.type === 'App::PropertyEnumeration') editor = else if (property.type === 'App::PropertyLink') { const document = facade.app.document.getActive() const ids = [...new Set(document.tree.flatMap((item) => [item.id, ...(item.children ?? [])]))] editor = } else if (property.type === 'App::PropertyColor') editor = else if (property.type === 'App::PropertyLength' || property.type === 'App::PropertyAngle' || property.type === 'App::PropertyPercent' || property.type === 'App::PropertyFloat') editor = else editor = { if (!commit(event.target.value)) event.target.value = String(property.value ?? '') }} onKeyDown={(event) => { if (event.key === 'Enter') event.currentTarget.blur() }} /> return <>
{property.label}
{editor}
{property.expression &&
{property.expression}
} } function Viewport({ selectedObject, setSelectedObject, workbench, facade, documentVersion, recomputeGeneration, showNotice }: { selectedObject: string; setSelectedObject: (id: string) => void; workbench: Workbench; facade: BitBybitWebCadFacade; documentVersion: number; recomputeGeneration: number; showNotice: (message: string) => void }) { const hostRef = useRef(null) const adapterRef = useRef(null) useEffect(() => { const host = hostRef.current if (!host) return const adapter = facade.viewport.createAdapter() adapterRef.current = adapter let cancelled = false const shapes: ShapeHandle[] = [] let ownsShapes = false try { adapter.mount(host) } catch (error) { showNotice(`WebGL viewport unavailable: ${error instanceof Error ? error.message : 'unknown error'}`) adapter.dispose() adapterRef.current = null return } const loadGeometry = async () => { const capabilities = await facade.geometry.initialize() if (capabilities.status !== 'ready') throw new Error(capabilities.reason || 'OCCT geometry runtime unavailable') const document = facade.app.document.getActive() const featureIds = [selectedObject, 'fillet', 'pocket', 'pad'].filter(Boolean) const storedShape = featureIds.map((objectId) => facade.geometry.getObjectShape(objectId)).find((shape): shape is ShapeHandle => Boolean(shape)) if (storedShape) { const mesh = await facade.geometry.mesh(storedShape, 0.05) if (!cancelled) adapter.setMesh(mesh) return } ownsShapes = true const profile = { outer: [[-1.35, -0.7, 0], [1.35, -0.7, 0], [1.35, 0.7, 0], [-1.35, 0.7, 0]] as [number, number, number][] } const pad = await facade.geometry.pad({ profile, length: 1.6, direction: [0, 0, 1], documentId: document.id, documentVersion: document.version }) shapes.push(pad) const pocketProfile = { outer: [[-0.55, -0.32, 0], [0.55, -0.32, 0], [0.55, 0.32, 0], [-0.55, 0.32, 0]] as [number, number, number][] } const pocket = await facade.geometry.pocket({ base: pad, profile: pocketProfile, length: 1.8, direction: [0, 0, 1], documentId: document.id, documentVersion: document.version }) shapes.push(pocket) if (cancelled) { await Promise.all(shapes.map((entry) => facade.geometry.release(entry))) return } const mesh = await facade.geometry.mesh(pocket, 0.05) if (!cancelled) adapter.setMesh(mesh) } void loadGeometry().catch((error: unknown) => { if (!cancelled) showNotice(`Geometry preview unavailable: ${error instanceof Error ? error.message : String(error)}`) }) return () => { cancelled = true if (ownsShapes) void Promise.all(shapes.map((entry) => facade.geometry.release(entry))) adapter.dispose() adapterRef.current = null } }, [facade, showNotice, selectedObject, documentVersion, recomputeGeneration]) useEffect(() => adapterRef.current?.setSelection(selectedObject), [selectedObject]) return
{workbench}Body / Fillet
setSelectedObject('')}>
SelectedEdgesDatum
} function PageFrame({ page, onNavigate, onOpenWorkspace, showNotice, facade }: { page: Page; onNavigate: (page: Page) => void; onOpenWorkspace: () => void; showNotice: (message: string) => void; facade: BitBybitWebCadFacade }) { const pages: Record, ReactNode> = { start: , projects: , import: , export: , settings: , help: , diagnostics: , sync: , } return
{pages[page as Exclude]}
} function PageHeader({ eyebrow, title, description, actions, onBack }: { eyebrow: string; title: string; description: string; actions?: ReactNode; onBack?: () => void }) { return
{onBack && }{eyebrow}

{title}

{description}

{actions &&
{actions}
}
} function StartPage({ onNavigate, onOpenWorkspace, showNotice }: { onNavigate: (page: Page) => void; onOpenWorkspace: () => void; showNotice: (message: string) => void }) { return
} />
FreeCAD-compatible workspace

Model with a clear history.

Build parts through ordered features, inspect every dependency and keep your project local by default.

Feature historyParametric part
Quick access

Keep moving

onNavigate('projects')} /> onNavigate('import')} /> showNotice('Example gallery opened')} />
Recent projects

Your local workspace

{projects.slice(0, 3).map((project, index) => )}
Local storage capabilityProbe on open
BitBybit CAD Studio·FreeCAD UI baseline 1.1.1
} function QuickAction({ icon: ActionIcon, title, detail, onClick }: { icon: Icon; title: string; detail: string; onClick: () => void }) { return } function ProjectCard({ project, index, onClick }: { project: typeof projects[number]; index: number; onClick: () => void }) { return } function ProjectsPage({ onNavigate, onOpenWorkspace, showNotice }: { onNavigate: (page: Page) => void; onOpenWorkspace: () => void; showNotice: (message: string) => void }) { return
} />
/
Sort by
{projects.map((project, index) =>
{project.name}{project.path}
{project.objects} objects{project.modified}{project.state}
)}
Local storage3.4 GB of 10 GB used · Last backup just now
} function FileFlowPage({ mode, onNavigate, showNotice, facade }: { mode: 'import' | 'export'; onNavigate: (page: Page) => void; showNotice: (message: string) => void; facade: BitBybitWebCadFacade }) { const isImport = mode === 'import' const [fcstdReport, setFcstdReport] = useState(null) const [selectedFormat, setSelectedFormat] = useState<'STEP' | 'STL' | 'GLB / GLTF' | 'Web CAD package'>('STEP') const [exporting, setExporting] = useState(false) const fileInputRef = useRef(null) const inspectFile = async (file: File) => { if (!file.name.toLowerCase().endsWith('.fcstd')) { showNotice('Only FCStd inspection is connected to this import boundary'); return } try { const report = facade.project.fcstd.inspect(new Uint8Array(await file.arrayBuffer())) setFcstdReport(report) showNotice(`FCStd inspected: ${report.compatibility.level}`) } catch (error) { setFcstdReport(null); showNotice(`FCStd rejected: ${error instanceof Error ? error.message : String(error)}`) } } const exportModel = async () => { if (selectedFormat !== 'STEP' && selectedFormat !== 'STL') { showNotice(`${selectedFormat} export is not implemented yet`); return } const objectIds = ['fillet', 'chamfer', 'pocket', 'pad'] const shape = objectIds.map((objectId) => facade.geometry.getObjectShape(objectId)).find((candidate): candidate is ShapeHandle => Boolean(candidate)) if (!shape) { showNotice('Recompute a valid Part Design feature before exporting'); return } setExporting(true) try { const result = selectedFormat === 'STEP' ? await facade.geometry.exportStep(shape, `${facade.app.document.getActive().label}.step`) : await facade.geometry.exportStl(shape, `${facade.app.document.getActive().label}.stl`) const blob = new Blob([result.text], { type: result.mediaType }) const url = URL.createObjectURL(blob) const anchor = document.createElement('a') anchor.href = url anchor.download = result.fileName anchor.click() URL.revokeObjectURL(url) showNotice(`${result.format.toUpperCase()} export downloaded`) } catch (error) { showNotice(`Export failed: ${error instanceof Error ? error.message : String(error)}`) } finally { setExporting(false) } } return
onNavigate('start')} />
Step 01 / 03

{isImport ? 'Select a CAD file' : 'Select an export format'}

Local only
{isImport ? <>
Drop a model hereor browse from your device { const file = event.target.files?.[0]; if (file) void inspectFile(file); event.currentTarget.value = '' }} />STEP · IGES · STL · OBJ · PLY · FCStd
FCStd is currently a read-only metadata inspection boundary. Python/macros are isolated and never executed.
{fcstdReport &&
{fcstdReport.label} · {fcstdReport.objects.length} objects · {fcstdReport.compatibility.level}; {fcstdReport.compatibility.warnings.join(' ') || 'No compatibility warnings.'}
} :
{['STEP', 'IGES', 'STL', 'GLB / GLTF', 'Web CAD package'].map((format, index) => )}
}
} function FlowStep({ index, title, active, complete }: { index: string; title: string; active: boolean; complete: boolean }) { return
{complete ? : index}{title}
} function SettingsPage({ onNavigate, showNotice }: { onNavigate: (page: Page) => void; showNotice: (message: string) => void }) { return
onNavigate('start')} actions={} />
Off
} function SettingSection({ title, detail, children }: { title: string; detail: string; children: ReactNode }) { return

{title}

{detail}

{children}
} function SettingRow({ label, detail, children }: { label: string; detail: string; children: ReactNode }) { return
{label}{detail}
{children}
} function HelpPage({ onNavigate, showNotice }: { onNavigate: (page: Page) => void; showNotice: (message: string) => void }) { const helpItems = [{ title: 'Create a feature-based part', detail: 'Body → Sketch → Pad → Pocket → Fillet', icon: Box }, { title: 'Understand the model tree', detail: 'Objects, links, Tip and recompute states', icon: ListTree }, { title: 'Navigate the viewport', detail: 'FreeCAD CAD preset and view controls', icon: Rotate3D }, { title: 'Recover a project', detail: 'Snapshots, compatibility and backups', icon: Archive }] return
onNavigate('start')} />
⌘ K
{helpItems.map((item) => )}
Keyboard

Core shortcuts

} function Shortcut({ keyName, label }: { keyName: string; label: string }) { return
{keyName}{label}
} function DiagnosticsPage({ onNavigate, showNotice, facade }: { onNavigate: (page: Page) => void; showNotice: (message: string) => void; facade: BitBybitWebCadFacade }) { const [recovery, setRecovery] = useState<{ integrity: string; lastSavedVersion: number | null; warnings: string[] } | null>(null) const [geometry, setGeometry] = useState(() => facade.geometry.capabilities()) const document = facade.getState().document const persistence = facade.project.capabilities() const geometryTone = geometry.status === 'ready' ? 'green' : geometry.status === 'failed' || geometry.status === 'unavailable' ? 'amber' : 'cyan' const geometryValue = geometry.status === 'ready' ? 'Ready' : geometry.status === 'initializing' ? 'Loading' : geometry.status useEffect(() => { void facade.project.recovery(facade.getState().document.id).then(setRecovery).catch((error: unknown) => showNotice(`Recovery report unavailable: ${error instanceof Error ? error.message : String(error)}`)) }, [facade, showNotice]) useEffect(() => { let disposed = false void facade.geometry.initialize().then((capabilities) => { if (!disposed) setGeometry(capabilities) }).catch((error: unknown) => { if (!disposed) showNotice(`Geometry capability probe failed: ${error instanceof Error ? error.message : String(error)}`) }) return () => { disposed = true } }, [facade, showNotice]) return
onNavigate('start')} actions={} />
Runtime

Capability checks

Last checked just now
showNotice('Document diagnostics opened')} />
} function HealthCard({ label, value, detail, tone, icon: HealthIcon }: { label: string; value: string; detail: string; tone: 'green' | 'cyan' | 'amber'; icon: Icon }) { return
{label}{value}{detail}
} function DiagnosticRow({ name, value, detail, tone, onClick }: { name: string; value: string; detail: string; tone: 'green' | 'cyan' | 'amber'; onClick?: () => void }) { return } function SyncPage({ onNavigate, showNotice }: { onNavigate: (page: Page) => void; showNotice: (message: string) => void }) { return
onNavigate('start')} />
Not signed in

Local workspace

Active

Projects, recovery snapshots and cached geometry remain on this device until you explicitly export or sync them.

4projects
3.4 GBstorage used
Just nowlast backup
Optional services

Choose when to share

} function SyncRow({ title, detail, disabled }: { title: string; detail: string; disabled?: boolean }) { return
{title}{detail}
} export default App