agentsclimarketplace

Visual feedback

Skill okuegow/agent-skills/plugins/visual-feedback/skills/visual-feedback

A collection of skills for Claude Code — installable via plugin marketplace. First skill: ebay-seller (full eBay.de selling workflow).

Install
npx -y skills add okuegow/agent-skills --skill visual-feedback

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use when the user wants to give feedback on a document, concept, design, plan, or report section by section - e.g. asks for a "Review-Seite", "Feedback-Seite", a kommentierbare HTML-Version, "Feedback zu jedem Abschnitt/jeder Box/jedem Element", comment pins in SVG diagrams, or wants to annotate a deliverable and paste the collected feedback back into the chat. Also when retrofitting an existing HTML page so every element accepts comments.

SKILL.md

12.8 KB, as published. Nobody here has run it

Visual Feedback

Overview

Turn any deliverable (concept, report, design, plan) into ONE self-contained HTML review page where every meaningful element is an inline comment point. Each comment can carry a category (Question/Error/Change/Praise) and priority (Must/Optional). Comments persist in localStorage, and the user exports them as structured markdown WITH a JSON attachment (clipboard or .md file) to paste back into the chat. The chat paste-back closes the loop: the agent maps each comment to its target id and works the feedback in.

Built for multiple rounds: when you produce a follow-up version you embed a round manifest that records, per prior comment, what you did with it (addressed / declined / deferred / noted). Resolved points move into a collapsed history and stop reappearing as open fields; the page builds a per-version changelog and marks changed sections. See "Iterating across versions".

The UI defaults to English and carries a small EN/DE toggle in the toolbar; the toggle switches every visible string AND the exported markdown, and persists in localStorage under fb:lang. Category/priority are stored as stable, language- independent ids (frage/fehler/aenderung/lob, muss/optional); only their display labels translate, so the JSON block reads the same in either language.

Template: copy and adapt template.html in this skill directory. It contains the complete widget CSS/JS and one example of every target type. Do not rebuild the mechanics from scratch - that is how past pages drifted into incompatible variants. The script builds its own toolbar, toast and preview overlay, so retrofitting an existing HTML page = paste the template's widget CSS block and complete <script> into it, then only add the markers from the recipe plus data-fbkey/data-fbver on <body>. Nothing else is required.

Recipe (the page IS this)

  1. Comment points. <body> carries data-fbkey="<unique-key>" (never reuse across pages) and data-fbver="<n>" (bump on every content rewrite, or old comments stick to changed spots). Each <section> carries data-fbsec="<n> · <Titel>". Targets:

    • data-fbauto on a section/container auto-pins every p, li, blockquote, h3, h4 and every table row inside (data-fbskip excludes subtrees) - the default for prose/tables
    • data-fb="id" + data-fblabel="Label" for manual targets (cards, callouts, diagram units)
    • data-fb on SVG elements gives overlay pins with a comment panel below the diagram
    • <textarea data-fb="id"> for always-visible fields: one general-feedback field per section plus a "Gesamturteil" at the end
  2. Widget. A ✎ pin per target opens a textarea in place, plus type/priority chips. Input autosaves (debounced). The sticky toolbar (built by the script) shows a storage-status pill, an "X/Y commented" counter, an EN/DE language toggle, a filter (All/Open/Commented), jump arrows, Preview, Copy feedback, Save as .md and Reset. All labels shown here are the English default; the DE toggle swaps them (and the export) to German.

  3. Versioning + comment lifecycle (feedback rounds). Comments live under fb:<key>:v<ver>. Bumping data-fbver carries prior comments with a still- matching target into the new version - matching now also requires the target's fingerprint to still match (auto-targets by content, manual targets by their data-fblabel), so a drifted auto-target or a relabeled manual target surfaces loudly under "Nicht mehr zuordenbar" instead of silently binding to the wrong element. Auto ids are content-based (autoId hashes the element text; identical text gets a stable per-occurrence suffix), so inserting or reordering other elements no longer shifts ids. Give every <section> a stable data-fbsecid so changelog jumps survive title edits. On top of carry-forward sits an optional round manifest (<script type="application/json" id="fb-rounds">, embedded in the page) recording, per round, what you did with each prior comment - see "Iterating across versions" below. Without a manifest the page behaves exactly as before (carry everything, no history UI). Multi-tab: saves are read-modify-write merged and a storage listener syncs other tabs live (targets with a pending edit or open editor are left alone), so the common case (one reviewer, maybe a second tab) never loses data. localStorage has no real transactions, so genuinely concurrent saves from two tabs in the same instant can still drop one - the tool is built for single-reviewer use, not concurrent co-editing.

  4. Export - both ways, structured, dual-format. "Copy feedback" (navigator.clipboard with execCommand fallback), "Save as .md" (Blob download) and "Preview" all produce the same document: human-readable markdown grouped by section, PLUS a machine-readable JSON block for the agent. The markdown headings follow the UI language (English shown below; German when the DE toggle is on). The JSON block is language-independent.

    # Feedback: <page title>
    Captured on <date>
    Page: `<data-fbkey>` · Version v<data-fbver> · <n> comments
    Summary: 2× Error, 1× Question (of which 1× Must)
    
    ## <data-fbsec>
    **<data-fblabel>**
    <sub>Text · `<id>` · Error · Must</sub>
    _Ref: "<start of the commented element's text>"_
    > comment line(s)
    
    ...
    ```json
    { "page": ..., "version": ..., "comments": [ {id,type,section,label,quote,category,priority,comment,ts}, ... ], "orphans": [...] }
    
    
    When working the feedback in, prefer the JSON block: `id` is the stable anchor,
    `quote` the context, `category`/`priority` the intent (values stay
    `frage/fehler/aenderung/lob` and `muss/optional` regardless of UI language).
    
  5. Reset without dialogs. Reset is a two-click confirm inside the button itself ("Sure? Click again" / "Wirklich? Erneut klicken", auto-disarm after 3 s). The page contains zero alert() / confirm() / prompt() calls - they block the browser.

  6. Self-contained file. No CDNs, webfonts, or external requests; system font stacks (e.g. Charter/Avenir on macOS); light + dark via prefers-color-scheme; prefers-reduced-motion respected; works from file:// (in-memory fallback with a visible warning when localStorage is blocked). English UI by default with an EN/DE toggle; German strings use real Umlauten, and no text uses em-dashes.

  7. Verify, then open. Parse the HTML (python html.parser: no unclosed tags, count of data-fb targets matches plan), node --check the extracted <script>, then open with macOS open (never browser-automation tools for local files). The widget mechanics themselves are covered by the jsdom smoke test template-test.js next to the template (needs npm install jsdom, run only after changing the template, not per page).

Iterating across versions (feedback rounds)

The procedure for every follow-up version. This is what keeps answered points from reappearing as open fields and produces the change history.

  1. Read the paste-back JSON. It carries comments (open + reopened points) AND rounds (the history so far). Keep rounds - you extend it, never rebuild.
  2. Work each point in and assign exactly one status: addressed (done), declined (rejected - note with the reason is mandatory), deferred (not this round - stays a live open field), noted (acknowledged, e.g. praise - no action). If you do not act on a point, mark it deferred; never drop it silently - the page counts un-responded carried comments as "unanswered" and warns in the toolbar.
  3. Bump data-fbver (N to N+1). A manifest change without a version bump does nothing; the bump is what re-initialises the page.
  4. Author the manifest <script type="application/json" id="fb-rounds">. Copy every prior round object from the paste-back's rounds verbatim and APPEND exactly one new round: { version:N+1, basedOn:N, date, resolutions:[{id,status,comment,note,fp}], changes:[{text,section,fromComments}], changedSections:[id | {id,kind:"new"}] }. id is the prior comment's target id; copy its fp from the paste-back too (auto-targets carry a content fingerprint, manual targets a label fingerprint) so "Doch offen" can verify the target has not drifted. section/changedSections reference the stable data-fbsecid, not the visible data-fbsec text.
  5. Never leave an addressed/declined point as a live open field, and never re-emit the reviewer's old answers as pre-filled comments. The manifest, not old comment text, is how you respond. addressed/declined/noted archive the point into the history; only deferred stays live.
  6. Content-level "open questions" you authored (e.g. an "Offene Entscheidungen" box): once decided, remove them from the open section and record the decision as a changes line, so they stop showing as open.
  7. Verify (jsdom template-test.js after template edits; parse + open per recipe step 7) and open.

The reviewer gets a "Verlauf"/History button (version-grouped changes + resolutions with "Doch offen" to re-open any point you resolved), "Neu/Geändert in vN" badges on changed sections, and a check mark on resolved targets.

Identity model and accepted residuals. A comment binds to its target by a fingerprint: auto-targets by content, manual targets by their data-fblabel (so a body edit keeps the comment while a relabel orphans it loudly). What the fingerprint guarantees: inserting or reordering other elements never shifts an auto-target's binding - the occurrence-drift class of silent misassignment is closed. Two residuals remain, each narrow and of a different kind: (1) a genuine short-hash collision - two different contents hashing to the same fingerprint - could in principle misbind an auto-target; it is astronomically unlikely with the double FNV hash and not further mitigated; (2) reusing the same id and the same label for unrelated content carries onto the new element, because it is indistinguishable from a legitimate edit-in-place - a deliberate manual id+label reuse (author error). Keep manual id+label pairs meaningful and give manual targets an explicit data-fblabel, and (2) does not occur.

Common mistakes

MistakeFix
Rebuilding widget JS/CSS instead of copying the templateCopy template.html; only content and markers change
Hand-marking every paragraph with data-fbdata-fbauto on the section; hand-mark only boxes and SVG elements
Working feedback in from the prose aloneUse the JSON block: id is the stable anchor, quote the context
Reusing a manual data-fb id for different contentManual identity = id + data-fblabel (or, when unlabeled, the leading content). A changed label/content surfaces the old comment as an orphan (loud). An identical id+label pair carries by design (that is how body edits keep their comment) - so never reuse the same id+label for an unrelated element. Always give manual targets an explicit data-fblabel so body edits stay stable
SVG pins at 0/0 or drifting after resizePositioning runs via getBoundingClientRect on load AND resize - keep the template's positionSvgPins wiring intact
Table rows not commentableUse the ✎-cell + colspan-row mechanism from the template
confirm() for resetTwo-click confirm in the button (template has it)
Export as free-form plaintextGrouped markdown with data-fbsec/data-fblabel so the agent can map comments back
Only clipboard exportAlso offer the .md Blob download (clipboard can fail on file://)
Same localStorage key on two pagesUnique key per file, or comments bleed between pages
Feedback UI drowns the contentWidgets stay collapsed until toggled; content layout comes first
Re-emitting the reviewer's old answers as open comments next versionRespond via the round manifest (status + note); addressed/declined archive, only deferred stays live
Bumping content but forgetting the manifestEvery follow-up version appends one round to fb-rounds; unanswered carried comments are counted and warned
changes[].section pointing at the visible titleReference the stable data-fbsecid, not the data-fbsec display text, or jumps break after title edits
Rebuilding the rounds arrayCopy all prior rounds from the paste-back verbatim, append exactly one new round

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.