生活とツール
#ai
mindmap-markmap-viewer
Turn Markdown outlines, notes, docs, or plans into an interactive mind map — a single self-contained HTML file that opens offline anywhere (markmap.js, white-on-dark, zoom/expand/export toolbar, search that keeps matches in context). Use whenever the user asks for a mind map, markmap, or concept map, wants to visualize or diagram the structure of a document or topic, summarize notes as a navigable tree, make an outline clickable or explorable, or embed such a map in Streamlit — even when they don't literally say 'mind map'.
DeepseekModel
キュレーション済みスキル
品質 優秀 · 78
v1.0.0
取得
https://deepseekmodel.com/api/download.php?id=jaderson-bit-mindmap-markmap-viewer-skill-md&format=skill
ダウンロード .skill
標準形式。system_prompt と model_config を収録し、任意の Agent で利用可能
.skill ファイルの system_prompt フィールドの実際の内容。
name mindmap-markmap-viewer description Turn Markdown outlines, notes, docs, or plans into an interactive mind map — a single self-contained HTML file that opens offline anywhere (markmap.js, white-on-dark, zoom/expand/export toolbar, search that keeps matches in context). Use whenever the user asks for a mind map, markmap, or concept map, wants to visualize or diagram the structure of a document or topic, summarize notes as a navigable tree, make an outline clickable or explorable, or embed such a map in Streamlit — even when they don't literally say 'mind map'. Mindmap (markmap) Skill Render hierarchical Markdown as an interactive SVG mind map with markmap.js , plus three custom layers: white-font CSS , expand-by-level control , and search that filters the tree . source.md ──► filter / set expand level (Python) ──► build_html() ──► vendored markmap libs (local, offline) ──► SVG + toolbar (outline) (manipulate the text) (HTML + CSS) (transform + render in the browser) (screen) Helper functions live in scripts/render_markmap.py ; a minimal source file is in assets/example.md ; regression tests are in evals/ . Deeper docs: references/internals.md (how the helpers work) and references/lessons.md (real-world lessons + the adversarial counter-review behind the current code). When to use this skill The user asks for a mind map, markmap, or concept map of anything. Hierarchical content — an outline, notes, a plan, a document's structure, a taxonomy — should become navigable, scannable, or shareable. A map must be sent to someone or opened with no setup: the output is one self-contained .html that works offline. A mind map should be embedded in a Streamlit app. An existing markmap renders blank, white-on-white, or truncated — this skill carries the known fixes (§2). 1. Source format markmap derives hierarchy from headings ( # ) and nested list items — - , * , + , or numbered ( 1. / 1) ) — indented by 2 spaces per level. (Tabs work too; the filter treats one tab as one level.) A YAML frontmatter block controls behavior: --- markmap: colorFreezeLevel: 2 # freeze color from level 2 down (branches keep the parent color) initialExpandLevel: 2 # levels kept open; root is level 1, so 2 = root + branches (-1 = all) maxWidth: 380 # max node width in px (forces wrapping) --- # Root <- root (level 1) ## Branch A <- level 2 ### Sub-branch A1 <- level 3 - Leaf <- level 4 (bullet under a level-3 heading) - Detail <- level 5 (bullet indented +2 spaces) Presets ( apply_presets ). You don't have to hand-write the markmap: block — apply_presets(src, color=None, max_width=380) fills sensible defaults without overriding anything you set: colorFreezeLevel: 2 , maxWidth , and an initialExpandLevel sized by node count (expand-all for ≤30 nodes, else level 2). Pass color=["#7fd1ff", "#ffd479"] for a custom palette. Any key already in your frontmatter wins, so you can set one value and let presets fill the rest. Content rule — term → parent / description → child. Put the label on the node and its explanation as a child , not on one line. Prefer: - Term - description of the term over - Term — description . This keeps nodes short and the tree scannable. Node text may contain < , > , and & freely ( a < b , List<String> , even </div> ). build_html HTML-escapes the source before embedding it and the browser decodes it back, so markmap sees exactly what you wrote. (Earlier versions broke on a literal < ; that footgun is gone — don't pre-escape to < yourself or it shows up literally.) 2. Rendering (white font) The renderer is: the vendored markmap <script> s (local files), an <svg class="markmap"> plus a hidden source <div> holding the Markdown, a small init script (transform → Markmap.create → toolbar), and the CSS. See build_html() / render_markmap() in scripts/render_markmap.py , with the rationale in references/internals.md . Non-obvious points (these cost rework): Offline, single self-contained file by default. build_html inlines the vendored markmap stack (d3 + markmap-view/-lib/-toolbar, pinned exact in assets/vendor/ ) directly into the HTML — no CDN, no network, and no sibling files — so the one .html opens offline anywhere you move or share it. (That single-file default is the fix for maps that failed to load their libs when opened alone.) Pass inline=False for a smaller HTML that instead references a vendor/ folder via vendor="vendor" , which must then travel beside it. LaTeX math is not rendered in the offline bundle. markmap's KaTeX support needs window.katex , which isn't vendored, so $...$ / $$...$$ show as plain text. Everything else renders fully offline. Navigation toolbar (bottom-right): zoom in/out, fit-to-window, expand-all, collapse-all, and download as SVG / PNG . Pass toolbar=False to omit it. Expand/collapse set each node's fold then re-render with setData() and no argument — passing data re-derives fold from initialExpandLevel and would wipe the manual fold. Export snapshots the current fold state; the SVG inlines the white-font CSS + a dark backdrop so it stands alone, and PNG rasterizes at 2× (falling back to SVG if a browser refuses to rasterize the <foreignObject> labels — markmap draws node text as HTML-in-SVG, not <text> ). White font is invisible without a dark background. This is the #1 way the map "renders blank": the font is white, the surface is white, so nothing shows. A standalone .html opens on the browser's white default, and a Streamlit components.html iframe is white by default too — neither inherits the host's dark theme. So build_html paints its own dark backdrop ( background="#0e1117" by default). Only pass background="transparent" when you know the host behind the iframe is already dark and you want a seamless blend. White font + dark background travel together — never set one without the other. White font needs TWO selectors + !important . markmap draws text as SVG <text> and sometimes as <foreignObject> (HTML inside SVG). Style both or half the labels stay dark: svg .markmap text { fill : #ffffff !important ; } svg .markmap foreignObject , svg .markmap foreignObject * { color : #ffffff !important ; } Embed via an isolated iframe ( components.html in Streamlit, or a standalone .html file). Host CSS won't leak in and the map's CSS won't leak out, so the <style> goes inline in the HTML string. The source is HTML-escaped before embedding. The init script reads the Markdown from the hidden source div's textContent , which the browser decodes — so escaping round-trips losslessly. Without it, a </div> or List<String> in the outline closes the div early and silently truncates the map. 3. Expand-by-level control Don't rebuild the map — just rewrite initialExpandLevel in the frontmatter before rendering. Use set_expand_level(src, level) from the helper module: level 1/2/3 expands that many levels. level = -1 expands everything (the "expand all" button). Injection is scoped to the frontmatter and done in place : rewrite an existing initialExpandLevel , else add one under the markmap: key (block or inline form), else prepend a minimal frontmatter — but only when none exists. It never rewrites the word "initialExpandLevel" sitting in your body text, and never stacks a second --- block on top of existing frontmatter (markmap reads only the first block, so stacking would silently drop your other settings). 4. Search that filters the tree When there is a query, keep only nodes that match + their path to the root (ancestors) + their subtree (descendants) , so a hit appears in context instead of floating alone. Algorithm in filter_markmap() : Parse each line into a node. Heading level = number of # . List-item level = (last heading level) + 1 + indentation, where indentation counts 2-space or tab units ( expandtabs ), and the marker may be - / * / + /numbered. Build an explicit parent tree with a kind-aware stack — a heading is parented to the nearest shallower heading , never to a bullet, even when its # -rank numerically exceeds a bullet's level. (Heading rank and bullet indentation share one number line, so comparing raw depths mis-nests an H4 -after-a-bullet; the parent tree is what keeps ancestry correct.) Mark each node match / no-match with an accent-insensitive comparison ( _norm ). Keep every match, every ancestor (walk parent pointers up), and every descendant (any node whose ancestor chain hits a match). Rebuild the Markdown and force initialExpandLevel: -1 . _norm strips accents via Unicode NFD so "compliance", "COMPLIANCE", and accented variants all match. Zero matches yields a frontmatter-only (blank) map by design — callers branch on the returned count. 5. Minimal usage The helpers live in this skill's scripts/ directory — and the working directory is normally the user's project, not this folder , so a bare "scripts" on sys.path won't resolve. Build paths from the skill's base directory (the path announced when this skill loaded): import sys from pathlib import Path SKILL_DIR = Path( r"<this skill's base directory>" ) # announced when the skill loaded sys.path.insert( 0 , str (SKILL_DIR / "scripts" )) from render_markmap import write_mindmap, apply_presets, set_expand_level, filter_markmap Single self-contained file (recommended) — writes the .md source of truth and a fully inlined .html that opens offline anywhere, with no sibling vendor/ : src = Path( "outline.md" ).read_text(encoding= "utf-8" ) # the user's outline (sample: SKILL_DIR / "assets/example.md") src = apply_presets(src) # fill default markmap options (no override) # optional: src, n = filter_markmap(src, "branch b") # search + keep context # optional: src = set_expand_level(src, -1) # expand all write_mindmap(src, "out/mapa.html" ) # -> out/mapa.md + a self-contained out/mapa.html # smaller HTML + a sibling vendor/ folder instead: write_mindmap(src, "out/mapa.html", inline=False) Just the HTML string (e.g. to embed) — build_html(src) returns one self-contained document with the libraries inlined: from render_markmap import build_html open ( "mindmap.html" , "w" , encoding= "utf-8" ).write(build_html(src, height= 850 )) Inside Streamlit: sys.path.insert( 0 , str (SKILL_DIR / "scripts" )) # SKILL_DIR as in the setup above from render_markmap import render_markmap, set_expand_level render_markmap(set_expand_level(src, level), height= 850 ) 6. Authoring guidelines (balanced, scannable maps) The shape of a mind map carries meaning, so structure the content deliberately: 5–8 main branches off the root. Fewer feels thin; more is hard to scan at once — group related ideas under an intermediate node instead of widening the root. 3–6 children per branch , kept roughly even across branches. One giant branch beside several stubs reads as unfinished; rebalance or split it. Labels of 1–3 words. A node is a handle, not a sentence. Put the explanation on a child node (the term → parent / description → child rule from §1), never inline on the label. Balanced depth. Keep branches within ~1 level of each other; a single branch that plunges several levels deeper than its siblings unbalances the layout. Let apply_presets set the frontmatter (color, wrap width, expand level) so you don't hand-tune each map (§1). Quality checklist (run before shipping a map) Root has 5–8 branches ; none is a dumping ground. Every branch has 3–6 children , roughly balanced. Labels are 1–3 words ; long text lives on child nodes, not labels. Depth is even across branches (no lone deep tunnel). apply_presets applied, or the frontmatter set deliberately. Opened the .html with the network off (and from a different folder) — it still renders (self-contained). Searched a known term — it filters to that node + its context . The 5 lessons this skill must carry White font travels with a dark background. White on a white/transparent surface renders blank — the most common failure. build_html paints its own dark backdrop by default; only go transparent over a host you know is dark. And style both text and foreignObject * with !important , or half the labels stay dark. build_html HTML-escapes the source, so < / > / & in node text are safe and round-trip to markmap unchanged — don't pre-escape them yourself. Expansion/search work by editing the Markdown text (regex/filter), not by calling the markmap API. Keep edits scoped to the frontmatter; never stack a second --- block. initialExpandLevel: -1 = expand all. Useful search = match + ancestors + descendants , compared without accents — and ancestry comes from an explicit parent tree, because heading rank and bullet indent share one number line.
このスキルを起動するキーワード。クリックでコピーできます。
このスキルにはトリガーワードがありません。
ダウンロードした .skill に含まれるフィールド。
| フィールド | 説明 |
|---|---|
| format | フォーマット識別子(skill/v1) |
| skill_id | スキル固有 ID |
| name | スキル名 |
| version | バージョン |
| description | 説明 |
| category | カテゴリ(配列) |
| trigger_words | トリガーワード |
| tags | タグ |
| source | ソース |
| source_url | ソース URL(本ページ) |
| exported_at | エクスポート日時(ダウンロード毎) |
| system_prompt | システムプロンプト本文 |
| model_config | モデル設定:provider / model / temperature / max_tokens / top_p |
| examples | サンプル |
| install_guide | 各プラットフォームの導入説明(Coze / Dify / Claude / カスタム) |