diff --git a/docs/MANAGED-FORK.md b/docs/MANAGED-FORK.md new file mode 100644 index 0000000..e57d170 --- /dev/null +++ b/docs/MANAGED-FORK.md @@ -0,0 +1,48 @@ +# Managed fork workflow + +This is a **managed fork** of `nicobailon/visual-explainer`. It carries local +customizations (a standard self-contained favicon, house-style notes) on top of +upstream, and stays updatable. + +## Philosophy: control over automatic + +Updates are **on-demand, not automatic**. Nothing pulls upstream behind your +back — so your local modifications and pinned behavior are never disturbed by a +surprise merge. When you *do* want to update, it's one command, and a pi agent +resolves any conflicts with full repository context. + +If a session is already current, everything just loads normally with zero work. + +## Remotes + +| Remote | Points at | Role | +|------------|------------------------------------|------------------------------| +| `origin` | `zereraz/visual-explainer` | your fork (your commits) | +| `upstream` | `nicobailon/visual-explainer` | the original project | + +## Updating + +From this clone (`~/Code/Zereraz/visual-explainer`): + +```bash +bash scripts/update-fork.sh --check # status only; never modifies +bash scripts/update-fork.sh --apply # fetch + merge upstream + push + pi update +# if conflicts (exit 20): resolve files, then: +bash scripts/update-fork.sh --continue +``` + +Or, inside pi, just run the command (loaded with this plugin): + +``` +/update-visual-explainer +``` + +The command checks first, applies if behind, and if a merge conflict occurs the +agent resolves it — **keeping both** upstream's new behavior and our additive +customizations — then commits, pushes, and refreshes the install. + +## Making your own changes + +Commit directly on `main` (small tweaks) or via a feature branch + PR to your +own fork. Because our changes are additive, upstream merges are usually clean. +`scripts/update-fork.sh` verifies the favicon customizations survived each update. diff --git a/plugins/visual-explainer/SKILL.md b/plugins/visual-explainer/SKILL.md index ed59377..ba98070 100644 --- a/plugins/visual-explainer/SKILL.md +++ b/plugins/visual-explainer/SKILL.md @@ -19,6 +19,17 @@ Generate self-contained HTML pages that explain systems, code changes, plans, da - Write files to `~/.agent/diagrams/` or the explicit eval output path. Use descriptive filenames. - Open generated pages in the browser when running normally. In Pi package installs, use `visual_explainer` with `prepare` for planning/context and `render` only after the complete HTML document exists. - The final page must be a complete self-contained HTML document, including embedded CSS and any needed JS. +- Always include the standard self-contained data-URI favicon immediately after `` (see "Favicon" below). Never leave a page without a favicon. + +## Favicon + +Every generated page must include this exact self-contained data-URI favicon, placed immediately after the `` tag. It needs no external file and is a small node-graph glyph that matches the dark/accent palette: + +```html + +``` + +If math is rendered with KaTeX, escape `<` as `<` inside `$$...$$` (e.g. `y_{<t}`); a bare `<` makes the HTML parser truncate the formula. ## Reference routing @@ -83,6 +94,16 @@ Use slides only when explicitly requested or when a command asks for slides. Sli - Do not drop content to fit a fixed slide count. Add slides instead. - Use the 10 slide types from `slide-patterns.md`: Title, Section Divider, Content, Split, Diagram, Dashboard, Table, Code, Quote, Full-Bleed. +## Reader-first defaults (pages are made to be read and re-read) + +The primary use is a reader consuming the page, often over multiple sittings. Build for that: + +- **Navigation**: ship the upgraded `SlideEngine` from `slide-deck.html` — it adds deep-link hashes (`#slide-7`), resume-where-you-left-off (localStorage), reading percent in the counter, an outline overlay (press `O`), and a keyboard help panel (press `?`). Don't ship a stripped engine. +- **Comprehension**: open each section with its one-line takeaway, then expand (TL;DR-first). End a multi-section page with a short "what to remember" recap. +- **Glossary**: wrap domain jargon in `term` so a reader can hover/tap for meaning without leaving the page. +- **Don't gate content on motion**: every slide must be fully readable even if its animation never plays; animations enhance, never reveal essential text. +- **Accessibility**: don't rely on color alone (pair with shape/label); respect `prefers-reduced-motion`; keep body text ≥ 16px with generous line-height; ensure keyboard nav reaches everything. + ## Optional generated images If `surf` is available, generated images may be embedded as base64 for hero banners, conceptual illustrations, or educational visuals. Skip images for data-heavy, structural, or Mermaid/CSS-suitable content. Pages must stand on CSS, typography, and diagrams without images. @@ -92,6 +113,9 @@ If `surf` is available, generated images may be embedded as base64 for hero bann Before delivery, verify: - complete HTML document; +- standard favicon `` present immediately after ``; +- decks use the upgraded SlideEngine (outline `O`, help `?`, deep-link + resume, reading %); +- each slide readable with animations disabled; no content depends on motion; - output written to the requested path; - no console errors when opened; - no horizontal overflow at normal desktop width; diff --git a/plugins/visual-explainer/commands/update-visual-explainer.md b/plugins/visual-explainer/commands/update-visual-explainer.md new file mode 100644 index 0000000..ead865d --- /dev/null +++ b/plugins/visual-explainer/commands/update-visual-explainer.md @@ -0,0 +1,28 @@ +--- +name: update-visual-explainer +description: Sync this visual-explainer fork with upstream, preserving local customizations; an agent resolves any merge conflicts. +--- + +Update the managed `visual-explainer` fork. This is **on-demand** — only run because the user asked. + +Managed clone location (try in order; use the first that exists): +- `~/Code/Zereraz/visual-explainer` +- the installed package dir: `~/.pi/agent/git/github.com/zereraz/visual-explainer` + +Steps: + +1. **Check first.** Run `bash scripts/update-fork.sh --check` from the managed clone. + - Exit `0` → already up to date. Tell the user "already current (fork is N commits ahead with your customizations)" and stop. + - Exit `10` → behind upstream; show the listed upstream commits, then continue. + +2. **Apply.** Run `bash scripts/update-fork.sh --apply`. + - Exit `0` → clean merge, pushed to the fork, and `pi update` refreshed the install. Report what upstream commits were merged and confirm the local customizations (favicon / house-style) survived. Done. + - Exit `20` → **merge conflict**. Do NOT abandon. Resolve it: + a. Read each conflicted file (`git diff --name-only --diff-filter=U`). + b. For each conflict, **keep the intent of BOTH sides**: upstream's new behavior AND our customizations (the favicon injection in `extension.ts`, favicon lines in `templates/*.html` and `SKILL.md`, the KaTeX `<` note). Our changes are additive — prefer integrating, not discarding. + c. After resolving every file, run `bash scripts/update-fork.sh --continue` to commit, push, and reinstall. + - Exit `2` → precondition failure (dirty tree / wrong branch). Read the message, fix it (commit/stash local work, or `git checkout main`), then retry. + +3. **Verify** after success: confirm `grep -c ensureFavicon plugins/visual-explainer/extension.ts` is non-zero and the 4 templates still contain `rel="icon"`. If a customization was lost in the merge, re-apply it and amend. + +Report concisely: what changed upstream, whether conflicts occurred, how they were resolved, and that customizations are intact. $@ diff --git a/plugins/visual-explainer/extension.ts b/plugins/visual-explainer/extension.ts index 57de38f..ab0c9c8 100644 --- a/plugins/visual-explainer/extension.ts +++ b/plugins/visual-explainer/extension.ts @@ -128,6 +128,41 @@ function outputFilename(input: string) { return /\.html?$/i.test(raw) ? raw : `${raw}.html`; } +const STANDARD_FAVICON = + ''; + +// Guarantees the house-style favicon is present, regardless of what the agent emitted. +function ensureFavicon(html: string): string { + if (/]*rel\s*=\s*["']?(?:shortcut\s+)?icon/i.test(html)) return html; + if (/<\/title>/i.test(html)) return html.replace(/<\/title>/i, `\n${STANDARD_FAVICON}`); + if (/]*>/i.test(html)) return html.replace(/]*>/i, (m) => `${m}\n${STANDARD_FAVICON}`); + return html; +} + +// Reader-safety: inside $$...$$ display math, escape < and > so the HTML +// parser doesn't treat e.g. y_{ { + const fixed = inner.replace(//g, ">"); + return `$$${fixed}$$`; + }); +} + +// Reader-safety: a complete, well-formed document for any browser/offline read. +function ensureDocMeta(html: string): string { + let out = html; + if (!/]*\blang=/i.test(out)) out = out.replace(/]*>/i.test(out)) { + if (!/]+name=["']viewport/i.test(out)) + out = out.replace(/]*>/i, (m) => `${m}\n`); + if (!/]+name=["']theme-color/i.test(out)) + out = out.replace(/]*>/i, (m) => `${m}\n`); + } + return out; +} + function assertHtmlDocument(html: string) { const trimmed = html.trim(); if (!trimmed) throw new Error("html is required"); @@ -276,7 +311,9 @@ async function renderVisualExplanation(params: VisualExplainerParams, signal?: A } signal?.throwIfAborted(); - writeFileSync(outputPath, params.html, "utf8"); + // Reader-safety pipeline: fix truncating math, complete the doc head, guarantee favicon. + const finalHtml = ensureFavicon(ensureDocMeta(fixDisplayMath(params.html))); + writeFileSync(outputPath, finalHtml, "utf8"); signal?.throwIfAborted(); diff --git a/plugins/visual-explainer/templates/architecture.html b/plugins/visual-explainer/templates/architecture.html index edc1b43..87f3548 100644 --- a/plugins/visual-explainer/templates/architecture.html +++ b/plugins/visual-explainer/templates/architecture.html @@ -4,6 +4,7 @@ Architecture Diagram — Reference Template +