diff --git a/docs/superpowers/plans/2026-07-21-desktop-vue3-frontend.md b/docs/superpowers/plans/2026-07-21-desktop-vue3-frontend.md
new file mode 100644
index 0000000..051ea42
--- /dev/null
+++ b/docs/superpowers/plans/2026-07-21-desktop-vue3-frontend.md
@@ -0,0 +1,1145 @@
+# n-link Desktop — Vue 3 Frontend Port (Plan B)
+
+> **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:** Replace Plan A's throwaway verification harness with the real n-link UI, ported from Vue 2 class components to Vue 3 `
+```
+
+Note the original had `alt="name"` — a literal string, not a binding, so it rendered the word "name" for every icon. These are decorative icons beside a filename label, so `alt=""` is correct. This is a deliberate fix, not an oversight.
+
+- [ ] **Step 2: Verify every mapped asset exists**
+
+The lookup now throws on a missing file rather than failing silently at build time. Confirm the mapping matches what is on disk:
+
+```bash
+cd /home/jjureta/Projects/n-link/n-link-core/assets
+ls files/ folders/
+```
+
+Expected in `folders/`: `folder.svg games.svg images.svg music.svg scripts.svg templates.svg video.svg`
+Expected in `files/`: `binary.svg calendar.svg cfg.svg contact.svg csv.svg db.svg epub.svg exec.svg font.svg image.svg installer.svg js.svg json.svg lua.svg pdf.svg python.svg resources.svg rom.svg svg.svg txt.svg unknown.svg video.svg xml.svg zip.svg`
+
+`exec.svg` is present but unreferenced by the original mapping. Leave it unreferenced — do not invent a mapping for it.
+
+- [ ] **Step 3: Verify it compiles**
+
+Run: `cd /home/jjureta/Projects/n-link && npm run build --workspace desktop`
+Expected: succeeds. `FileIcon` is not yet imported by anything, so this only proves it parses and type-checks.
+
+- [ ] **Step 4: Commit**
+
+```bash
+cd /home/jjureta/Projects/n-link
+git add n-link-core/components/FileIcon.vue
+git commit -m "feat(core): port FileIcon to Vue 3, replace require() with import.meta.glob
+
+30 webpack require() calls replaced by a single eager import.meta.glob.
+The extension-to-icon mapping is preserved exactly, restructured from a
+switch chain into lookup tables. Fixes alt=\"name\" rendering the literal
+string 'name'."
+```
+
+---
+
+### Task 4: Port CalcInfo.vue and FileView.vue
+
+**Files:**
+- Modify: `n-link-core/components/CalcInfo.vue`, `n-link-core/components/FileView.vue`
+
+**Interfaces:**
+- Consumes: `FileIcon` (Task 3), types from `devices.ts` (Task 2).
+- Produces:
+ - ``
+ - ` void" @select="FileInfo[] => void" />`
+
+- [ ] **Step 1: Read the current sources**
+
+Both files are Vue 2 class components. Read them in full before editing:
+`n-link-core/components/CalcInfo.vue` and `n-link-core/components/FileView.vue`.
+
+- [ ] **Step 2: Port CalcInfo.vue**
+
+Convert to `