Remix
Это содержимое пока не доступно на вашем языке.
XenolithGraph is a WebGL editor that mounts PIXI into a <canvas>. Remix renders on the server by default; the editor has to live behind a client-only boundary.
Install
pnpm add @xenolithengine/graph-editor @xenolithengine/graph-react pixi.jspixi.js is a peer dependency.
Pattern
Use the official remix-utils <ClientOnly> (or write a 5-line one — see below).
import { ClientOnly } from 'remix-utils/client-only'
export default function EditorRoute() { return ( <ClientOnly fallback={<div style={{ height: '100vh', background: '#121212' }} />}> {() => <EditorClient />} </ClientOnly> )}import { XenolithGraph, XenolithPanel, XenolithButton, useEditor } from '@xenolithengine/graph-react'
function MyPanel() { const editor = useEditor() return ( <XenolithPanel position="top-left"> <XenolithButton onClick={() => editor.fitView()}>Fit view</XenolithButton> </XenolithPanel> )}
export default function EditorClient() { return ( <XenolithGraph className="xeno" onReady={(e) => e.loadJSON(myGraph)}> <MyPanel /> </XenolithGraph> )}If you don’t want to add remix-utils for one component, a minimal ClientOnly is:
import { useEffect, useState, type ReactNode } from 'react'
export function ClientOnly({ children, fallback = null }: { children: () => ReactNode; fallback?: ReactNode }) { const [hydrated, setHydrated] = useState(false) useEffect(() => { setHydrated(true) }, []) return hydrated ? <>{children()}</> : <>{fallback}</>}Why no SSR mode
PIXI needs a real <canvas> + GPU. There’s no headless static-HTML renderer in this library. If you need a static preview for a server-rendered route, call editor.exportImage() on the client and upload the PNG to your storage.
Loader / action gotchas
The editor’s graph data is just JSON (xenolith.v1). You can absolutely:
- Load a graph JSON in a
loaderand pass it as a prop to your<EditorClient>viauseLoaderData(). - Save a graph via a Remix
actionby callingeditor.toJSON()and POSTing to your route.
The constraint is only that the EDITOR itself stays inside <ClientOnly> — its DATA can travel through Remix’s normal data flow.