尙 SpecSnap
A zero-loss translator between "human inspects UI visually" and "AI modifies UI precisely."
Your browser doesn't support embedded video. Download the demo.
Click multiple elements on a page. SpecSnap captures them all at once with:
- Numbered badges that link the on-page overlay, the box-model panel, and the exported Markdown — the ① you see in the browser is the same ① in the file
- Inter-element gaps computed automatically (the orange "24px" / "16px" between siblings) — so AI gets spacing info, not just sizes
- Per-element box models — margin / border / padding / content with numeric labels on every side
- Viewport context attached to every capture — "120px wide" is meaningless without knowing it's on a 1440px screen
- Bilingual annotations — English terms for AI precision + 繁體中文 for humans (
padding: 16px (內邊距))
Every AI-coding interaction that touches UI hits the same wall:
- Human eyes see "that button is off"
- Human translates observation into text ("the Save button looks 8px too narrow")
- AI translates text into code change
- Something gets lost in each translation
SpecSnap removes step 2. You click what's wrong. AI reads structured data that can't be misread — viewport-qualified coordinates, box-model deltas, inter-element gaps, and the element's own semantic name.
Pre-alpha (v0.0.x) — schema may change. Locking in at v1.0.
- Inspector UI packages —
@tw199501/specsnap-inspector-core(framework-agnostic),@tw199501/specsnap-inspector-vue(Vue 3),@tw199501/specsnap-inspector-react(React 18+). Drop-in, zero-config. See Use the Inspector UI below. - Storage ladder — fs-access → ZIP (
fflate) → individual downloads, all auto-negotiated.onSaveprop overrides everything. - Release tooling —
changesetsfor coordinated lockstep versioning across the 4 published packages;dependency-cruiserCI gate enforcinginspector-corestays framework-agnostic. - Version 0.0.6 intentionally skipped to signal the "Inspector packages ship" release.
**data-i18n-key**/**data-v-source**reverse lookup — when a build-time tool has injected these attributes, core reads them intoElementIdentity.i18nKeyand.source, and the MD's Basics section emits matching lines. AI can now do i18n key lookups and source-file navigation without grep.- Tag-triggered publish workflow —
.github/workflows/publish.ymlauto-publishes oncore@*tag push onceNPM_TOKENsecret is added. SCHEMA_VERSIONbumps to'0.0.5'(first wire-format change since 0.0.2; all additions are optional fields, no breaks).
- File System Access API adapter in the playground — Copy MD writes into a user-picked folder (Chrome / Edge 86+); older browsers fall back to Downloads/
- Border subpixel display polish — DPR 1.5 screens no longer show
0.67 / 0.67 / 0.67 / 0.67in MD output; rounds cleanly to1 / 1 / 1 / 1while keeping exact precision in JSON
**toAnnotatedPNG**— one annotated PNG per frame, focus-frame isolation**toSpecSnapBundle**— disk-ready bundle: MD + PNGs namedYYYYMMDD-NN-*.pngwith relative-path refs inside the MD**filter**option on capture — exclude consumer UI chrome (panels, toolbars) from the screenshot
| Package | Status | Description |
|---|---|---|
@tw199501/specsnap-core |
0.0.7 | TypeScript library: capture + serialize (MD / JSON) + annotated PNG + disk-ready bundles + optional i18nKey / source |
@tw199501/specsnap-inspector-core |
0.0.7 | Framework-agnostic headless Inspector (element picker, pub-sub store, sequence counter, storage ladder) |
@tw199501/specsnap-inspector-vue |
0.0.7 | Drop-in Vue 3 component — <SpecSnapInspector /> |
@tw199501/specsnap-inspector-react |
0.0.7 | Drop-in React 18+ component — <SpecSnapInspector /> |
specsnap-extension |
planned | Chrome / Edge / Firefox extension wrapping core |
apps/playground |
Vite demo | Multi-select inspector demo (see screenshot above) |
Zero-config drop-in for Vue 3 or React 18+. Same panel, same on-page overlay, same captured data — whichever framework you use:
![]() | ![]() |
@tw199501/specsnap-inspector-vue | @tw199501/specsnap-inspector-react |
pnpm add @tw199501/specsnap-inspector-vue<template>
<SpecSnapInspector />
</template>
<script setup lang="ts">
import '@tw199501/specsnap-inspector-vue/styles.css';
import { SpecSnapInspector } from '@tw199501/specsnap-inspector-vue';
</script>pnpm add @tw199501/specsnap-inspector-react
import '@tw199501/specsnap-inspector-react/styles.css';
import { SpecSnapInspector } from '@tw199501/specsnap-inspector-react';
export default function App() {
return <><YourApp /><SpecSnapInspector /></>;
}
A floating trigger appears bottom-right; click to open the Inspector panel; pick elements; Copy MD sends Markdown to clipboard and saves specsnap/YYYYMMDD/ to disk (Chromium) or downloads a ZIP (everything else).
Framework-less consumers can use @tw199501/specsnap-inspector-core directly.
- Creative vision · what we're building, why, the 7 north-star principles
- Design decisions (v0 lock-in) · Q1-Q9 with reasoning
- MVP core plan — Part 1 · bootstrap + types
- MVP core plan — Part 2 · capture + serializers + ship
- Retrospective v0.0.1
- v0.0.3 core plan
- v0.0.4 + v0.0.5 closeout plan
- Node 22+
- pnpm 9.15+
- TypeScript 6+ (for contributing)
Clone, install once, then use the following commands from the repo root.
# Install workspace dependencies (first time, or after lockfile changes)
pnpm install
# Start the playground dev server — port is pinned to 5999 via vite.config.ts,
# and a predev hook kills any zombie process holding the port first
pnpm -F specsnap-playground dev
# → http://localhost:5999/
# Run every workspace's test suite (core + playground)
pnpm test
# Just the core library (82 tests)
pnpm -F @tw199501/specsnap-core test
# Just the playground (fs-access adapter logic)
pnpm -F specsnap-playground test
# Watch mode (core)
pnpm -F @tw199501/specsnap-core test:watch
# Coverage report (core) — outputs to packages/core/coverage/
pnpm -F @tw199501/specsnap-core test:coverage
# Mirrors the release gate: LF enforcement across all tracked files,
# then tsc --noEmit in every workspace
pnpm check
# Builds packages/core's dist (tsup — ESM + CJS + d.ts)
pnpm -F @tw199501/specsnap-core build
# Preview what the npm tarball will contain (no upload)
cd packages/core
npm pack --dry-run
cd ../..
# 1) Bump the version in packages/core/package.json
# 2) Update READMEs + any version-sensitive tests
# 3) Full gate — all green before tagging
pnpm check && pnpm test && pnpm build
# 4) Commit + tag
git add -A
git commit -m "release: @tw199501/specsnap-core@X.Y.Z"
git tag -a core@X.Y.Z -m "core X.Y.Z — one-line summary"
# 5) Push main + tag
git push origin main
git push origin core@X.Y.Z
# 6) Publish to npm (interactive — prompts for 2FA if not cached)
cd packages/core
npm publish
Once NPM_TOKEN is configured as a repo secret, steps 6 happens
automatically from publish.yml when
the tag is pushed.
# Everything the GitHub Actions CI runs, locally
pnpm check && pnpm test && pnpm build
MIT © tw199501


