Files
nexu-io-open-design/clipper
Tom Huang ca89845d03 feat(brands): surface the draft design system live and browse images in a lightbox (#4777)
* feat(brand-extraction): enhance programmatic extraction with reconciliation and UI improvements

- Introduced `reconcileProgrammaticExtractionTranscript` to manage the state of brand extraction transcripts, ensuring accurate status updates during extraction processes.
- Updated the `cancel-extraction` route to handle asynchronous operations, allowing for better user feedback and immediate reconciliation of extraction states.
- Enhanced the `startBrandExtraction` function to support draft design system creation, ensuring that users can see their systems immediately, even if extraction fails or is stopped.
- Improved error handling and logging for reconciliation processes, providing clearer insights into failures during brand extraction.
- Added tests to validate the new reconciliation logic and ensure that the extraction process behaves as expected under various scenarios.

These changes improve the overall user experience by providing more robust handling of brand extraction states and enhancing the visibility of the extraction process.

* feat(brand-extraction): enhance brand preview rendering and UI feedback

- Added functionality to render brand previews into projects when a draft is stopped, improving user experience by providing immediate visual feedback.
- Updated the `startBrandExtraction` function to include metadata for design system IDs and statuses, ensuring accurate tracking of brand extraction states.
- Enhanced the `renderBrandPreviewIntoProject` function to support new status types, including 'draft', allowing for better representation of brand states.
- Introduced new localization strings for draft-related messages, improving clarity for users during the brand extraction process.
- Added tests to validate the new preview rendering and status handling, ensuring robustness in the brand extraction workflow.

These changes improve the overall user experience by providing clearer feedback and enhancing the visibility of brand extraction processes.

* feat(design-kit): browse design-system images in a lightbox carousel

The image-preview lightbox showed a single static image with no way to move
between samples. Replace the single-image state with an index into the
visible, non-broken samples so the modal becomes a carousel: prev/next
chevrons, an "N / total" counter, ArrowLeft/ArrowRight keys, and wrap-around.
Broken tiles are filtered once through a shared lightboxItems memo so the
gallery and lightbox indices stay aligned with the delete handler.

* feat(brands): reveal the draft design system the moment extraction starts

A brand extraction pre-creates a draft `user:` design system, but the project
view only rendered it once the registry summary had refreshed, leaving the
Design System tab empty for the whole extraction. Build a fallback summary
from project metadata so the draft renders immediately, auto-open the Design
System tab when extraction begins or is cancelled, and hydrate the freshly
created project with its brand metadata. Draft pre-create now records the
source URL in provenance and fails loudly instead of swallowing the error.

Because ProjectView imports DESIGN_SYSTEM_TAB at module scope, every
FileWorkspace test mock must export the constant.

* fix(design-system-picker): restore fullscreen preview styles dropped in routines.css reorg

The brand-extraction routines.css reorganization accidentally removed the
`.project-ds-picker-fullscreen` rule block, its `project-ds-picker-fullscreen-in`
keyframes, and its responsive overrides. The modal-window drag guard and two
style specs still depend on those rules (the fullscreen design-system preview
must stay above modal chrome), so they went red. Restore the block verbatim to
match main.

* feat(brand-extraction): add continue extraction functionality for incomplete brands

- Introduced a new API endpoint to restart the deterministic programmatic extraction for existing brands without creating duplicates.
- Implemented a tracking mechanism for ongoing extractions to manage their state effectively.
- Enhanced the UI components to support the new continue extraction action, including loading states and callbacks.
- Updated relevant tests to ensure the new functionality works as expected and integrates smoothly with existing workflows.

These changes improve the user experience by allowing users to resume brand extractions seamlessly, enhancing the overall efficiency of the brand management process.

* feat(skills): integrate skill management into the application

- Added a new SkillDetailsModal component to display detailed information about skills.
- Enhanced the ChatComposer and HomeHero components to support skill selection and details viewing.
- Updated the ComposerPlusMenu to include a skills submenu, allowing users to search and pick skills.
- Implemented functionality to handle skill details in various components, improving user interaction with skills.
- Refactored existing components to accommodate skill-related features, ensuring a cohesive user experience.

These changes enhance the application's capabilities by providing users with better access to skill information and management, streamlining workflows involving skills.

* feat(brand-extraction): improve brand assistant message handling and UI feedback

- Enhanced the AssistantMessage component to better manage events and display content, ensuring that messages are rendered correctly based on their content and events.
- Updated the ChatPane component to hide empty brand assistant messages and improve the visibility of relevant content, enhancing user experience during brand extraction processes.
- Introduced new utility functions to determine the visibility of brand assistant events and content, streamlining the logic for displaying messages.
- Refactored the ProjectView component to handle brand browser assist confirmations more effectively, ensuring that the UI responds appropriately to user interactions.
- Added tests to validate the new message handling logic and ensure that brand extraction messages are displayed correctly.

These changes enhance the overall user experience by providing clearer feedback and improving the management of brand assistant messages during extraction workflows.

* fix(brands): address browser assist review blockers

* fix(web): restore new project modal entrypoints

* fix(web): switch to replacement brand retry conversations

* fix(web): restore skill-change preview invalidation

* fix(brand): harden retry completion flow

* fix(brand): close extraction lifecycle races

* test(e2e): wait for privacy banner dismissal

* fix(brand): guard retry startup races

* fix(brand): isolate extraction retry attempts

* fix(design-systems): clean up partial draft creation

* fix(brands): let stop supersede stalled transcript

* fix(brands): fail thin browser html retries

* fix(brands): preserve stopped html retries

* fix(brands): reject off-path browser retries

* fix(brands): expose deterministic retry in cli

* fix(brands): serialize cancel with finalization

* fix(brands): bound cancel settlement wait

* fix(brands): bound retry takeover waits

* refactor(next-step-actions): replace titles with localized keys and update related prompts

* fix(brands): retry after browser read failures

* fix(brands): accept canonical browser redirects

* fix(brands): reset retry assist stall timer

* test(web): align picker compact preview assertions

* fix(brands): harden design kit cleanup paths

* test(e2e): stabilize AMR runtime recovery checks

* feat(brands): enhance brand extraction from post-wall pages

- Introduced `browserHarvestIsUnusable` function to determine if a harvested page lacks usable brand signals, allowing for more permissive extraction from content-rich pages that may embed anti-bot widgets.
- Updated `extractBrandFromHtml` to utilize the new function, ensuring that valid post-wall pages are processed correctly.
- Enhanced `isChallengePage` to differentiate between genuine content-rich pages and bot protection interstitials, improving the accuracy of brand extraction.
- Added tests to validate the new behavior, ensuring that pages with minimal color palettes or embedded widgets are handled appropriately.

* feat(brands): improve handling of recoverable extraction states

- Refactored brand extraction logic to maintain a `needs_input` status for recoverable scenarios, such as blocked pages or mid-load content, instead of marking them as `failed`.
- Updated related functions and routes to reflect this change, ensuring that the user interface presents a calm, retryable state rather than a terminal failure.
- Enhanced tests to validate the new behavior, confirming that the system correctly identifies and manages recoverable extraction attempts.

* feat(projects): add design-system project creation from existing projects

- Implemented a new command `od project create-design-system` to duplicate a regular project as a design-system workspace, including a prompt for design-system generation.
- Enhanced the API to support the creation of design-system projects, ensuring proper metadata and file copying from the source project.
- Added a detailed prompt structure for the design-system generation process, outlining requirements and expected outputs.
- Introduced tests to validate the new functionality, ensuring that design-system projects are created correctly with the appropriate context and files.
- Updated the UI components to integrate the new design-system creation functionality, allowing users to initiate the process seamlessly.

* feat(projects): add project duplication workflow

* fix(brand): keep browser assist recovery retryable

* fix(plugins): roll back failed template duplicates

* feat(brand): enhance browser assist functionality and improve user guidance

- Introduced a new `brandBrowserAssistOdCard` function to generate browser assist cards for better user interaction.
- Updated the content structure in `reconcileProgrammaticExtractionTranscript` to include browser assist cards when applicable.
- Enhanced user guidance in error messages for stalled and stopped extraction processes, providing clearer instructions for recovery actions.
- Added tests to ensure the new browser assist card functionality is correctly integrated and displayed in the chat interface.
- Improved localization for various user prompts and messages related to browser assist actions.

* feat(design-browser): enhance design file handling and user notifications

- Added support for opening design files directly from the status message in the DesignBrowserPanel.
- Introduced a new `actionTarget` property to differentiate between design files and regular files in status messages.
- Implemented a `stopLoading` function to halt page loading when necessary, improving user experience during snapshot captures.
- Updated localization files to include new status messages and project type labels.
- Enhanced toast notifications for browser snapshots with improved styling and functionality.
- Added tests to ensure new features work as expected and do not interfere with existing functionality.

* feat(app): implement design system project creation with preset prompts

- Updated project creation logic to route through the default design router, ensuring user interaction prompts for design system selection.
- Introduced a new localization key for the design system creation prompt, enhancing user guidance.
- Adjusted plugin ID to avoid assumptions about prototypes, improving the flexibility of project creation.
- Updated tests to reflect changes in project creation behavior and ensure correct routing and prompt handling.

* feat(chat): update icon sizes and implement draft persistence in HomeView

- Increased icon sizes in ChatComposer from 13px to 16px for better visibility.
- Added localStorage persistence for the Home composer prompt and design system selection to retain user input across tab switches.
- Implemented functions to read and write drafts to localStorage, ensuring a seamless user experience.
- Cleared drafts upon run creation to prevent reappearance of previous inputs.
- Enhanced Toast component to handle auto-dismissal correctly, even with changing parent components.

* fix(pr): address review blockers

* fix(web): preserve authoring prompt confirmation

* test(daemon): cover project CLI copy commands

* fix(web): surface skill detail load failures
2026-06-30 13:22:29 +00:00
..

Open Design Web Clipper (MV3 — Chrome · Edge · Firefox)

The Open Design Web Clipper: a browser extension that captures images, screenshots, and page content from any site straight into your Open Design Library (the global asset registry).

This is a standalone subproject — it is intentionally not part of the pnpm workspace and has no build step. The files here load directly as an unpacked extension. The daemon/web TypeScript boundaries are unaffected.

Load it

  1. Start Open Design locally (pnpm tools-dev) so the daemon is listening on http://127.0.0.1:7456 (the default; change it under Advanced in the popup if you used a different --daemon-port).
  2. Open chrome://extensions, enable Developer mode, click Load unpacked, and select this clipper/ directory.
    • Edge: same steps at edge://extensions.
    • Firefox: about:debuggingThis FirefoxLoad Temporary Add-on → pick manifest.json (or run npx web-ext run --source-dir clipper).

That's it — no pairing, no codes, no tokens. The popup shows ● Connected as soon as it detects Open Design running, and you can capture right away.

The manifest carries a cross-browser background block (service_worker for Chrome/Edge, scripts for Firefox) plus browser_specific_settings.gecko for AMO. Chrome logs a harmless "unrecognized key background.scripts" warning on dev load — it runs normally, and store users never see it. Store/ASO assets and per-store copy live in store/.

Why no login?

The daemon only listens on loopback (127.0.0.1), so only programs on your own machine can reach it, and a web page can't impersonate this extension's chrome-extension:// origin. The daemon auto-trusts that origin for the /api/library/* routes, which is everything the clipper uses. Zero setup, nothing to misconfigure.

Capture

  • PopupCapture page → Library (a self-contained, high-fidelity HTML snapshot — readable stylesheets inlined, images inlined as data URIs, scripts stripped), Extract design system (a programmatic design-system HTML capture saved as a design-system Library asset), Download Figma (.json) (a structured Figma import JSON for the OD Figma plugin — see ../figma-plugin/), Pick element → capture, Pick images, or Capture screenshot (visible tab).
  • Pick element → a DevTools-style picker: hover to highlight any element, click to save it as a single self-contained HTML snapshot of that element. The page's stylesheets are kept (so the element's cascade resolves and it stays styled), the element's own images are inlined as data URIs, and the rest of the page is pruned away — leaving the element where it sat, ready to open. Esc cancels. The saved Library card is one HTML file you can open, share, or distribute as the element; its preview shows the live element with its selector + size (tag, selector, dimensions) noted beneath. No separate screenshot-plus-markup pair — just the HTML.
  • Pick images → an on-page overlay grid of every image on the page with checkboxes, Select all / Clear, and Save N to Library — so you choose exactly which images to save instead of grabbing them all.
  • On-page toolbar → an optional floating page / design-system / Figma JSON / screenshot / image / element launcher anchored top-center of the page (Figma-style), with a gap from the edge so it reads as a deliberate surface. It's hidden by default; turn it on with Show on-page bar in the popup (the preference is remembered, and the bar's ✕ hides it again). Each control shows a hover tooltip naming what it does. Grab the dotted handle on its left edge to drag the bar anywhere on the page — its position is remembered across reloads. The launcher is automatically pulled out of frame while a capture is taken, so it never ends up inside the snapshot.
  • Right-click an imageSave image to Open Design Library.

Page → design system

Extract design system is intentionally separate from full-page capture. It reads the live page with JavaScript and fills a stable design-system HTML template with:

  • logo/app-icon candidates and representative images;
  • computed typography, font-family usage, and readable @font-face rules;
  • weighted palette tokens and light/dark theme variables;
  • title, product description, headings, and keywords;
  • a small component kit (buttons, fields, cards, navigation samples) rendered from the extracted tokens.

The result is saved to the Library as kind: "design-system" with text/html bytes, so it previews like an HTML asset but filters as a design-system asset in the Library and Select from library picker.

Page → Figma JSON

Capture page → Library also computes an OD Figma capture (a JSON node-tree of frames / text / images with live geometry, fills, strokes, corner radii and shadows) from the live page and stores it alongside the HTML asset. From the Library you can later Download Figma JSON for that asset, or use Download Figma (.json) in the clipper to grab it directly without saving to the Library.

⚠️ The .od-figma.json is opened by a Figma plugin, not by dragging it in

Figma only imports its own binary .fig/.jam files, so dragging an .od-figma.json into Figma (or Drafts) shows “Unsupported file format” — that is expected. Open it in two steps instead:

  1. Install the OD Figma Import plugin once — in the Figma desktop app: Plugins → Development → Import plugin from manifest… → pick figma-plugin/manifest.json. (Same model as web-to-figma / html.to.design, which are also plugins.)
  2. Run the plugin and open the filePlugins → Development → OD Figma Import, then drop in the downloaded .od-figma.json.

Full instructions: ../figma-plugin/README.md.

A native binary .fig can't be produced outside Figma, so this is an import JSON node-tree rebuilt as editable layers by the OD Figma plugin. Fidelity is best-effort: cross-origin stylesheets that block reads, web-component shadow DOM, and tainted canvases may degrade. Image fills in any web format (SVG, WebP, GIF, …) are supported — the plugin re-encodes the ones Figma's image API can't read (everything but PNG/JPEG) to PNG on import.

Everything you capture appears in the Library tab (live, via SSE) with a Clipper source badge and a back-link to its source page.

The Capture options (under Advanced) include Inline images — on by default for the highest fidelity; turn it off for smaller, faster captures that reference images by URL instead of embedding them.

Very large, image-heavy pages are captured at reduced fidelity rather than failing — the capture is built to always fit the daemon's ingest limit:

  1. Large raster images are re-encoded smaller (downscaled + WebP) before being embedded, so most pages embed everything at a fraction of the size.
  2. If the page is still over budget, images are embedded smallest-first and the largest are left as live URLs (the HTML structure and styles are kept intact).
  3. As a last resort the secondary Figma layout capture is dropped so the HTML page itself always saves.

The popup/on-page toast notes when any of these kicked in (e.g. "some images left as links").

Permissions

  • host_permissions: <all_urls> — needed to screenshot/read images on any page, fetch+inline cross-origin page resources, and reach the loopback daemon. Standard for web clippers (Evernote, Figma).
  • scripting, tabs — capture the active tab, harvest images, and run the page-capture runtime (capture.js) on demand.
  • contextMenus — the right-click "Save image" entry.
  • downloads — save the Download Figma (.json) import file to disk.
  • storage — remember the daemon URL locally (only needed if you changed it).