Skip to main content

streaming-mindmap-rendering

Implement real-time streaming mindmap rendering using Mind Elixir in web applications. Supports streaming text parsing and incremental updates.

Informations de source

Dépôt
SSShooter/obsidian-mindmap
Dernière activité de la source
13 février 2026 à 13:32
Langue détectée de SKILL.md
anglais
Étoiles
52
Forks
2

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
Streaming Mindmap Rendering
description
Implement real-time streaming mindmap rendering using Mind Elixir in web applications. Supports streaming text parsing and incremental updates.
# Streaming Mindmap Rendering This skill guides you through implementing a streaming mindmap renderer using `mind-elixir`. This technique allows you to display a mindmap that grows in real-time as data is generated by an AI model or fetched from a stream. ## Prerequisites - React (or any frontend framework, examples use React) - `mind-elixir` library ## 1. Install Dependencies First, ensure you have `mind-elixir` installed. ```bash npm install mind-elixir ``` ## 2. Component Structure Create a wrapper component for `mind-elixir` to handle the lifecycle and updates. ```tsx import MindElixir, { type MindElixirData, type MindElixirInstance } from "mind-elixir" import { useEffect, useRef } from "react" export function MindmapRenderer({ data }: { data: MindElixirData | null }) { const elRef = useRef<HTMLDivElement>(null) const meRef = useRef<MindElixirInstance | null>(null) useEffect(() => { if (!elRef.current) return meRef.current = new MindElixir({ el: elRef.current, direction: MindElixir.RIGHT }) // Initial empty state or loading state meRef.current.init( data || { nodeData: { topic: "Loading...", id: "root" } } ) return () => { // Cleanup if necessary } }, []) // Update effect useEffect(() => { if (meRef.current && data) { // Refresh the graph with new data meRef.current.refresh(data) } }, [data]) return <div ref={elRef} style={{ height: "500px", width: "100%" }} /> } ``` ## 3. Streaming & Parsing Logic The core of this skill is efficiently handling the stream and parsing potentially incomplete data. ### Data Formats Mind Elixir supports two main formats: 1. **JSON (Native)**: Hierarchical tree structure. Hard to stream because JSON is invalid until complete. 2. **Plain Text (Recommended for Streaming)**: Indentation-based or markdown-list-based text. Easier to parse partially. #### Plain Text Format Example ```text - Root Node - Child Node 1 - Child Node 1-1 - Child Node 1-2 - Child Node 1-3 - }:2 Summary of first two nodes - Child Node 2 - Child Node 2-1 [^id1] - Child Node 2-2 [^id2] - Child Node 2-3 {color: #e87a90} - > [^id1] <-Bidirectional Link-> [^id2] - Child Node 3 - Child Node 3-1 [^id3] - Child Node 3-2 [^id4] - Child Node 3-3 [^id5] - > [^id3] >-Unidirectional Link-> [^id4] - > [^id3] <-Unidirectional Link-< [^id5] - Child Node 4 - Child Node 4-1 [^id6] - Child Node 4-2 [^id7] - Child Node 4-3 [^id8] - } Summary of all previous nodes - Child Node 4-4 - > [^id1] <-Link position is not restricted, as long as the id can be found during rendering-> [^id8] ``` ### Parsing Implementation Use `mind-elixir/plaintextConverter` (or a custom parser) to convert text to the Mind Elixir JSON format. ````typescript import { plaintextToMindElixir } from "mind-elixir/plaintextConverter" // Helper to clean Markdown code blocks if your stream includes them function cleanStreamContent(content: string): string { return content .replace(/^```[\w]*\n?/gm, "") .replace(/```$/gm, "") .trim() } // State hooks in your parent component const [mindmapData, setMindmapData] = useState<MindElixirData | null>(null) const accumulatedText = useRef("") const lastRenderTime = useRef(0) // Streaming function (Generic Example) async function startStreaming(url: string) { const response = await fetch(url) const reader = response.body?.getReader() const decoder = new TextDecoder() if (!reader) return while (true) { const { done, value } = await reader.read() if (done) break const chunk = decoder.decode(value) accumulatedText.current += chunk // Throttle updates to avoid freezing the UI const now = Date.now() if (now - lastRenderTime.current > 500) { // 500ms throttle updateMindmap() lastRenderTime.current = now } } // Final update updateMindmap() } function updateMindmap() { try { const cleanText = cleanStreamContent(accumulatedText.current) const data = plaintextToMindElixir(cleanText) setMindmapData(data) // This triggers the useEffect in MindmapRenderer } catch (e) { // Ignore parse errors from incomplete chunks console.warn("Partial parse error ignored") } } ```` ## 4. Optimization Tips - **Throttling**: Do not re-parse and re-render on every single byte. Use a throttle (e.g., 200-500ms). - **Stable Root**: Ensure the parsing logic maintains a stable root ID if possible, to prevent the whole graph from flashing. - **Scroll to Last**: To follow the generation, you can programmatically scroll to the last added node. ```typescript // Scroll to last node (inside MindmapRenderer update effect) const lastNode = findLastNode(data.nodeData) // Implement traversal to find last node if (lastNode?.id) { const nodeEle = meRef.current.findEle(lastNode.id) if (nodeEle) meRef.current.scrollIntoView(nodeEle) } ``` ## 5. Integrating with AI Prompts When generating mindmaps with LLMs, instruct the model to use the plaintext format.
Voir sur GitHub