From b8c772269cf2337a462cb3234ab40e7dead5e85c Mon Sep 17 00:00:00 2001 From: Amit Haridas Date: Mon, 14 Sep 2026 19:14:30 +0530 Subject: [PATCH] docs(plans): add ascii-art-upgrade implementation plan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 12-task TDD plan for the full-fledged ASCII Art Generator upgrade: * T1: add figlet npm dep * T2: extract + extend 17 hand-coded font tables + snapshot tests * T3: extract 19 templates + snapshot tests * T4: figlet adapter (lazy-load + cache + structured error) * T5: pure AsciiArt orchestrator (generate/listFonts/getFontMeta) * T6: IPC handler wiring in main.js via existing JSON store helper * T7: preload allow-list cleanup (drop dead show-ascii-generator* channels, add new ascii:* invoke channels) * T8: preload allow-list assertion test * T9: renderer controller (src/renderer/ascii-controller.js) * T10: standalone window HTML rewrite with searchable font picker, Copy/Save buttons, controller script tag * T11: delete in-app modal (#ascii-art-dialog, renderer.js:5942-6736, dead asciiModal, dead preload receive channels) * T12: README + final lint/format/test/build sweep Spec gap handled inline: §5 headless Electron integration test deferred to manual smoke check (spec itself says skip if no display available). Amit Haridas --- .../plans/2026-09-14-ascii-art-upgrade.md | 1223 +++++++++++++++++ 1 file changed, 1223 insertions(+) create mode 100644 docs/superpowers/plans/2026-09-14-ascii-art-upgrade.md diff --git a/docs/superpowers/plans/2026-09-14-ascii-art-upgrade.md b/docs/superpowers/plans/2026-09-14-ascii-art-upgrade.md new file mode 100644 index 0000000..ed019e1 --- /dev/null +++ b/docs/superpowers/plans/2026-09-14-ascii-art-upgrade.md @@ -0,0 +1,1223 @@ +# ASCII Art Generator Upgrade Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Promote the ASCII Art Generator from a partially-dual-implemented 5-font feature to a single-source-of-truth, 17 hand-coded + 400+ FIGlet font feature with insert / copy / save output destinations and full test coverage. +**Architecture:** Extract the algorithm from `renderer.js:5942-6736` into a pure `src/main/AsciiArt.js` module that mirrors the `DocQA`/`DailyNotes` pattern. Hand-coded font tables move into `src/main/AsciiArt.fonts.js`; templates into `src/main/AsciiArt.templates.js`; `figlet` becomes a lazy-loaded `src/main/AsciiArt.figlet-adapter.js`. A new `src/renderer/ascii-controller.js` drives the existing standalone `src/ascii-generator.html` window. The in-app modal (`#ascii-art-dialog`, `showASCIIGenerator*`, `preload.js` receive channels) is deleted; the standalone window remains the only path. `electron-store` `ascii:lastFont` (via the existing `store` JSON helper in `main.js:267-289`) remembers the last-used font. +**Tech Stack:** Electron 41.10.7 · electron-builder 26.15.3 · vanilla CommonJS · `figlet@^1.8.0` (pure JS) · Jest + jsdom · ESLint flat config · Prettier (2-space, single quotes, semicolons, 100-col). +**Spec:** docs/superpowers/specs/2026-09-14-ascii-art-upgrade-design.md + +## Global Constraints + +- Electron 41.10.7, electron-builder 26.15.3 +- Vanilla JS, no bundler. Pure modules in `src/main/`, IPC wired in `src/main.js` +- Preload allow-list at `src/preload.js` for any new IPC channels (`invoke` reuses `ALLOWED_SEND_CHANNELS`; `on` uses `ALLOWED_RECEIVE_CHANNELS`) +- Tests: Jest + jsdom. Run `npm test`, `npm run lint`, `npm run format:check` +- Single ASCII art path: standalone `BrowserWindow` only; in-app modal `#ascii-art-dialog` and dead channels `show-ascii-generator*` deleted +- New dep: `figlet` npm package (latest 1.x, pure JS, ~400 KB unpacked) +- Hand-coded font count: 17 (5 existing + 12 new) — big, small, lean, slant, isometric1-4, 3-d, 3x5, ansi-shadow, calvin-s +- New settings key: `ascii:lastFont` (via the existing `store` JSON helper in `main.js:267-289`) +- Output destinations: insert at cursor (existing, fenced code block wrapper) + copy to clipboard + save to file +- The standalone `src/ascii-generator.html` (751 lines) keeps its layout but its controller moves to a new `src/renderer/ascii-controller.js` +- Snapshot tests normalize line endings to `\n` and trim trailing whitespace +- TDD discipline: every component starts with a failing test + +## File Structure + +### Created +- `src/main/AsciiArt.fonts.js` — 17 hand-coded font tables (`HAND_CODED_FONTS`). +- `src/main/AsciiArt.templates.js` — 19 named ASCII templates (`ASCII_TEMPLATES`). +- `src/main/AsciiArt.figlet-adapter.js` — Lazy `require('figlet')` + `fontsSync()` cache + `textSync(text, font)` wrapper + structured error. +- `src/main/AsciiArt.js` — Pure orchestrator: `generate({ text, font, options })`, `listFonts()`, `getFontMeta(id)`. +- `src/renderer/ascii-controller.js` — Renderer-side controller for the standalone window. +- `tests/main/ascii-art.test.js` — Unit tests for `generate` / `listFonts` / `getFontMeta` / figlet adapter. +- `tests/main/ascii-art.fonts.test.js` — Snapshot tests per hand-coded font (HELLO + edge cases). +- `tests/main/ascii-art.templates.test.js` — Snapshot tests per template. +- `tests/main/ascii-art.figlet-adapter.test.js` — Adapter tests with `figlet` mocked. +- `tests/preload-ascii.test.js` — Allow-list assertions for new `ascii:*` channels. + +### Modified +- `package.json` — Add `"figlet": "^1.8.0"` to `dependencies`. +- `src/main.js:4005-4010` — Add `const AsciiArt = require('./main/AsciiArt');` after DocQA require. +- `src/main.js` (after line 5611, near other recent IPC handler blocks) — Register `ascii:generate`, `ascii:list-fonts`, `ascii:get-font-meta`, `ascii:save`, `ascii:copy`, `ascii:last-font` handlers. +- `src/preload.js:98-99,294-296` — Delete dead receive channels `show-ascii-generator` and `show-ascii-generator-window`. Add new invoke channels `ascii:generate`, `ascii:list-fonts`, `ascii:get-font-meta`, `ascii:save`, `ascii:copy`, `ascii:last-font` to `ALLOWED_SEND_CHANNELS`. Add `generators.ascii.*` namespace helpers. +- `src/renderer.js:2188` — Delete `const asciiModal = new ModalManager('#ascii-art-dialog');`. +- `src/renderer.js:2202` — Delete `asciiModal` entry from `window.modals`. +- `src/renderer.js:5942-6736` — Delete entire in-app modal block. +- `src/index.html:812-1028` — Delete entire `#ascii-art-dialog` modal markup. +- `src/ascii-generator.html` — Rewrite inline ``) + +**Interfaces:** +- Consumes: `src/renderer/ascii-controller.js` +- Produces: a standalone window that loads the controller, renders all 17+ fonts, and exposes Insert / Copy / Save. + +- [ ] **Step 1: Replace the inline FONTS/TEMPLATES/BOX_STYLES + generation script with a controller script tag.** In `src/ascii-generator.html`, remove the entire `` (lines ~364-749). Replace with: + ```html + + ``` +- [ ] **Step 2: Replace the text-mode font-style ` + + + ``` +- [ ] **Step 3: Add a warning element above the preview.** After the `
Preview
` line, insert: + ```html + + ``` +- [ ] **Step 4: Extend the footer buttons.** Replace the footer block (lines ~359-362) with: + ```html + + ``` +- [ ] **Step 5: Verify the file still parses.** Open the file in a browser (or `cat src/ascii-generator.html | head -10` to sanity-check the head section) — must still have the `` and the closing ``. +- [ ] **Step 6: Manual smoke.** Launch the app: `npm start` — Ctrl+Shift+A. Verify: (a) standalone window opens, (b) font picker lists 17+ entries, (c) preview updates on input, (d) Insert / Copy / Save each work end-to-end. +- [ ] **Step 7: Commit.** `git add src/ascii-generator.html && git commit -m "feat(ascii-art): standalone window uses controller + searchable picker + copy/save/insert"` + +--- + +### Task 11: Delete in-app modal markup and dead renderer code + +**Files:** +- Modify: `src/index.html:812-1028` (delete the `#ascii-art-dialog` block) +- Modify: `src/renderer.js:2188` (delete `const asciiModal = new ModalManager('#ascii-art-dialog');`) +- Modify: `src/renderer.js:2202` (delete `asciiModal,` from `window.modals`) +- Modify: `src/renderer.js:5942-6736` (delete the entire ASCII Art Generator block) + +**Interfaces:** +- Consumes: nothing. +- Produces: a `git grep` that returns zero hits for `showASCIIGenerator`, `textToASCII`, `createASCIIBox`, `getASCIITemplate`, `insertASCIIArt`, `hideASCIIGenerator`, `switchASCIIMode`, `loadASCIITemplate`, `generateASCIIPreview`, `ascii-art-dialog`, `asciiModal`, `show-ascii-generator`. + +- [ ] **Step 1: Delete the modal markup in `src/index.html`.** Remove lines 812-1028 inclusive (the entire `
…
` block). +- [ ] **Step 2: Delete the `asciiModal` instantiation in `src/renderer.js`.** Remove line 2188 (`const asciiModal = new ModalManager('#ascii-art-dialog');`). +- [ ] **Step 3: Delete the `window.modals.asciiModal` entry.** Remove line 2202 (`asciiModal,`). +- [ ] **Step 4: Delete the in-app controller block.** Remove lines 5941-6736 inclusive (the entire ASCII Art Generator block, from the `// ASCII ART GENERATOR` header comment through the `ipcRenderer.on('show-ascii-generator', …)` listener and its preceding whitespace). +- [ ] **Step 5: Verify zero residual references.** `git grep -nE "showASCIIGenerator|textToASCII|createASCIIBox|getASCIITemplate|insertASCIIArt|hideASCIIGenerator|switchASCIIMode|loadASCIITemplate|generateASCIIPreview|ascii-art-dialog|asciiModal|show-ascii-generator"` — must return no hits inside `src/`. +- [ ] **Step 6: Verify the standalone path still works.** Run `npm start`. Ctrl+Shift+A still opens the standalone window; Tools → ASCII Art Generator (if present in menu) still works; Insert button wraps in fenced code block. +- [ ] **Step 7: Commit.** `git add src/index.html src/renderer.js && git commit -m "refactor(ascii-art): delete in-app modal #ascii-art-dialog, controller, dead preload channels"` + +--- + +### Task 12: Update README and run full validation + +**Files:** +- Modify: `README.md:56` (ASCII Art Generator row) + +**Interfaces:** +- Consumes: nothing. +- Produces: README updated to reflect the new feature surface. + +- [ ] **Step 1: Update the feature row.** In `README.md`, change line 56 from: + ``` + - **ASCII Art Generator** - Create text banners and diagrams + ``` + to: + ``` + - **ASCII Art Generator** - 17 hand-coded fonts + 400+ FIGlet fonts; text banners, boxes, and templates; insert into editor, copy to clipboard, or save to file (Ctrl+Shift+A) + ``` +- [ ] **Step 2: Run the full test suite.** `npm test` — all tests pass (existing 800+ plus the ~40 new tests). +- [ ] **Step 3: Run lint.** `npm run lint` — clean. +- [ ] **Step 4: Run format check.** `npm run format:check` — if any files are mis-formatted, run `npm run format` and re-run the suite. +- [ ] **Step 5: Run Linux build.** `npm run build:linux` — succeeds without native-binding surprises from `figlet`. (If running in CI, this is automatic.) +- [ ] **Step 6: Final commit.** `git add README.md && git commit -m "docs(readme): ASCII Art Generator now 17 hand-coded + 400+ FIGlet fonts; insert/copy/save"` +- [ ] **Step 7: Sweep for forbidden markers in changed files.** `git diff --name-only HEAD~12..HEAD -- 'src/main/AsciiArt*.js' 'src/renderer/ascii-controller.js' 'src/ascii-generator.html' 'src/preload.js' 'src/main.js' 'src/renderer.js' 'src/index.html' 'package.json' 'README.md' 'tests/main/ascii-art*.test.js' 'tests/main/ascii-art.fonts.test.js' 'tests/main/ascii-art.templates.test.js' 'tests/main/ascii-art.figlet-adapter.test.js' 'tests/preload-ascii.test.js' | xargs grep -nE 'TODO|FIXME|XXX|HACK|not implemented|placeholder|stub|for now|in a real app|mock data|hardcoded for demo|coming soon'` — must return zero hits (excluding pre-existing entries unrelated to this feature). + +--- + +## Self-Review + +1. **Spec coverage:** + - Single implementation path — Task 11. + - 17 hand-coded fonts (5 existing + 12 new) — Task 2. + - figlet lazy load + cache — Task 4 (adapter) + Task 1 (dep). + - Three output destinations — Task 9 (controller) + Task 10 (HTML buttons) + Task 6 (IPC handlers). + - Comprehensive tests — Tasks 2, 3, 4, 5, 8 cover unit, snapshot, adapter, preload. + - Pure module architecture — Tasks 2, 3, 4, 5 (all in `src/main/`, no Electron imports). + - Last-used font persistence — Task 6 (`store.set('ascii:lastFont', …)`) + Task 9 (controller calls `api.lastFont`). + - Error handling — Task 4 (`AsciiArtFigletError`) + Task 6 (`ascii:copy` catches, `ascii:save` returns `{ canceled }`) + Task 9 (showWarning). + - Acceptance criteria — Task 12 sweep. + +2. **Placeholder scan:** No `TODO` / `TBD` / `FIXME` / `placeholder` / `implement later` / `fill in` markers in the plan body. The single intentional `nope` literal in test names is a test-only sentinel for "unknown" inputs and is not a placeholder. + +3. **Type consistency:** `generate`, `listFonts`, `getFontMeta`, `generateFiglet`, `listFigletFonts`, `loadFiglet`, `AsciiArtFigletError`, `HAND_CODED_FONTS`, `ASCII_TEMPLATES`, `getTemplate`, `store.get` / `store.set`, `ascii:generate` / `ascii:list-fonts` / `ascii:get-font-meta` / `ascii:save` / `ascii:copy` / `ascii:last-font`, `generators.ascii.{ listFonts, getFontMeta, generate, copy, save, lastFont }` — names match across tasks. + +4. **Open gap flagged:** The integration test in spec §Testing #5 (spawn `ascii-generator.html` in headless Electron, assert no console errors) is intentionally skipped — it requires a display server and is environmental. The spec marks this test as "Skip if no display available"; in CI this would be a manual smoke check (Task 10 Step 6) rather than a Jest test.