{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"webgl-portal","type":"registry:component","title":"Webgl Portal","description":"A shared portal between the DOM and the canvas.","meta":{"pro":false},"dependencies":[],"registryDependencies":["https://atelier-ui.com/r/webgl-provider.json","https://atelier-ui.com/r/agent-rules.json"],"files":[{"path":"registry/webgl-portal/webgl-portal.tsx","type":"registry:component","target":"components/webgl-portal/webgl-portal.tsx","content":"\"use client\"\n\nimport {\n    type ReactNode,\n    Suspense,\n    useEffect,\n    useId,\n    useLayoutEffect,\n    useSyncExternalStore,\n} from \"react\"\n\nconst useIsoLayoutEffect = typeof window !== \"undefined\" ? useLayoutEffect : useEffect\n\n// Minimal teleport: <In> registers children in an external store,\n// <Out> renders them — bridges across the Canvas React root the same\nfunction WebglTeleport() {\n    const items = new Map<string, ReactNode>()\n    const listeners = new Set<() => void>()\n    let snapshot: [string, ReactNode][] = []\n\n    const emit = () => {\n        snapshot = Array.from(items.entries())\n        for (const listener of listeners) {\n            listener()\n        }\n    }\n\n    const subscribe = (listener: () => void) => {\n        listeners.add(listener)\n        return () => {\n            listeners.delete(listener)\n        }\n    }\n    const getSnapshot = () => snapshot\n\n    function useItems() {\n        return useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n    }\n\n    return {\n        In({ children }: { children: ReactNode }) {\n            const id = useId()\n\n            useIsoLayoutEffect(() => {\n                items.set(id, children)\n                emit()\n                return () => {\n                    items.delete(id)\n                    emit()\n                }\n            }, [id, children])\n            return null\n        },\n        useItems,\n        Out() {\n            const list = useItems()\n            return (\n                <>\n                    {list.map(([id, node]) => (\n                        <Suspense key={id} fallback={null}>\n                            {node}\n                        </Suspense>\n                    ))}\n                </>\n            )\n        },\n    }\n}\n\nconst webglTeleport = WebglTeleport()\nconst effectTeleport = WebglTeleport()\n\nexport function WebglPortal() {\n    return <webglTeleport.Out />\n}\n\nexport { effectTeleport, webglTeleport }\n"}]}