Skip to content

feat(design): render PNG exports on the canvas server instead of through tab capture #3218

Open

Description

@doblas

Before submitting

  • I searched open and closed issues and did not find a request for this feature.
  • I reviewed this request and removed credentials, tokens, private paths, hostnames, and other sensitive data.

Problem or opportunity

Follow-up from @egdev6's review of #3153 (Gentle Design canvas, export; part of #2740).

Export as PNG in the design canvas uses the browser's tab capture (getDisplayMedia): the canvas asks to share its own tab, grabs a frame and crops the artboard locally. That keeps everything in the browser, but:

  • The browser asks for permission on every export.
  • It depends on the browser and the platform. Some setups, such as some Wayland sessions, never offer the tab at all, so the export can only fail with a message.
  • What ends up in the PNG depends on the window: its zoom, its size, and how much of the artboard is on screen.

Proposed outcome

The canvas server renders an artboard to PNG itself, for example with a headless browser at the artboard's size from design.json, and at 2× for Export as PNG at 2×. The ⋯ menu then downloads the server's PNG with no capture prompt. The output is the same on every machine, and it doesn't depend on the window. Tab capture could stay as a fallback when the server cannot render.

Alternatives considered

  • Keep tab capture only. This is what ships today: it's local and needs no extra dependency, but it prompts every time and is unavailable on some platforms.
  • Render in the page with an HTML-to-canvas library. That avoids the prompt but is approximate: fonts, filters and cross-origin images often differ from the real rendering.

Additional context

Activity

  1. egdev6 commented on Nov 13, 2026

    @egdev6
    SponsorContributor

    @doblas thanks. Triage: the problem is real, but this is a large change that needs a maintainer decision before code, so I'd start with a bounded prototype.

    • Rendering at the design.json size fixes the window-size dependency, but headless output can still vary across machines (fonts, browser version, platform), and a fresh load loses the iframe's current interactive state.
    • No headless browser is a dependency today. The main choice is between driving the user's installed Chrome/Edge through a light CDP library with an isolated temporary profile (no download, but it fails without a browser or under managed policies) and shipping a managed Chromium (reproducible, but download size and maintenance; the bundled installer only allows gentle-pi's own scripts, so packaging needs checking). WSL versus Windows Chrome also needs a decision.
    • Security and limits: keep the artboard sandbox and CSP, never expose CDP or use the personal browser profile, and restrict network and navigation. Artboard sides go up to 20,000 px today, so 2× is about 6.4 GB of RGBA; we'd need size, time, memory and concurrency limits, plus process cleanup.
    • Fallback: tab capture needs transient user activation, so after waiting on the server it will likely need another click.
    • It also changes the documented promise that PNG export contacts no server.

    Suggested first slice: a prototype that settles the renderer choice, limits and platform support, without changing the export contract yet. Reusing it for PDF can come later as its own scope.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions