Product Design · Frontend Engineering · Figma API

The Figma PDF export
we all needed.

FrameStack PDF — A Figma plugin built to solve the frustration of exporting multiple frames into a single PDF. From zero to v3.1, designed and engineered solo.

Solo
Role
Designer & Engineer
4
Versions
Shipped in 28 days
34%
Feature Discovery
After redesigning UX
15s
Export Time
Optimized performance
View on Figma Community
Ongoing · v1.0 through v3.1
Figma Plugin Frame to PDF Design Tools Product Design Frontend Engineering 4 Versions Shipped Figma API Solo Project Figma Plugin Frame to PDF Design Tools Product Design Frontend Engineering 4 Versions Shipped Figma API Solo Project
ClientIndependent — Figma Community
ProjectFrameStack PDF — Figma Plugin
PlatformFigma Plugin · Web
ScopeProduct Design · Frontend Engineering
Outcome4 Versions Shipped · 34% Feature Discovery Lift
Duration28 Days to v1.0, Ongoing through v3.1
The Problem & Solution

The problem nobody talked about
(but everyone had).

The Export Nightmare
Before FrameStack
  • Export gives 12 separate PDF files — one per frame.
  • Drag files to a sketchy online merger tool or Adobe Acrobat.
  • Manually reorder them, hoping it's correct.
  • Start over completely if the client asks for one revision.
With FrameStack PDF
  • Select frames and get one combined PDF instantly.
  • Outcome-based presets (e.g. "Client Deck", "Email Ready").
  • Export history with 1-click recovery without re-running export.
  • Settings persist across sessions automatically.
Who Has This Problem?
  • Freelancers: Needs professional presentation, small file size.
  • In-House Designers: Needs exact pixel dimensions, lossless quality.
  • Design Students: Needs beautiful A4 output for portfolios.
Core Insight
  • Users don't think in settings. They think in outcomes.
  • Replaced configuration hurdles with 1-tap presets.
  • One tap for common cases, one more tap for everything else.
Building v1

Getting the core right
before adding features.

The first version did one thing: combined frames into a single PDF. No presets, no cover page, no history. The goal was to validate the core pipeline worked so a non-technical designer could export in under 30 seconds.

Constraint
Context Isolation
Figma plugins run in two isolated contexts: the sandbox (code.js) and the UI (ui.html). They communicate exclusively via postMessage. Every frame image had to be exported as PNG bytes, serialized as a binary string, passed to the UI, and assembled into PDF pages by jsPDF.
Solution
Memory Safety at Scale
Exporting 20 large frames simultaneously would crash the sandbox. Solution: Sequential export threshold. Below 8 frames: export in parallel. Above 8 frames: export one at a time. Binary string encoding uses chunked 16KB slices, the documented upper bound for safe apply() calls in QuickJS.
Architecture
Message Contract & Persistence
Every message is typed via a MSG constants object to prevent mystery messages. Preferences are saved via typed round-trip patterns to figma.clientStorage. Every export is logged with its PDF bytes stored separately so previous exports can be re-downloaded instantly without re-running the pipeline.
Decisions

Three ways to solve this.
Only one shipped.

A
Server-side rendering pipeline
Send frame data to a backend, render and merge the PDF with a headless renderer, return a download link. Rejected: it means hosting and paying for a server for a free plugin, a network dependency that fails the "export in under 30 seconds" goal on slow connections, and a privacy concern — design files leaving Figma's sandbox entirely.
Adds cost, latency, and a privacy liability.
B
Lean on Figma's native multi-export + a merge step
Let Figma export each frame as before, and only build a lightweight "merge these PNGs" utility instead of a full export pipeline. Rejected: this still leaves the exact workflow that was the entire complaint — export, leave Figma, merge, reorder. It would have been a smaller build, but it would not have solved the problem.
Solves nothing the user didn't already have.
C
In-sandbox export + assembly, fully client-side
Export frame bytes inside the Figma sandbox, pass them to the UI thread over postMessage, and assemble the PDF client-side with jsPDF. No server, no extra tools, no file ever leaves the user's machine. Harder to engineer around Figma's memory limits, but it's the only option that kept the plugin free, private, and offline-capable.
This is the architecture that shipped.
UX Iteration

What the first users taught me.
Redesigning for outcomes.

Feedback wasn't about bugs, it was about UX failures. "Why is the quality slider grayed out?" "How do I add a cover page?" The plugin had no opinion about the common case, settings were labeled like engineering docs, and features were hidden behind tabs.

The Redesign Philosophy
Outcome-based presets
Introduced "Client Deck", "Email Ready", etc. One tap configures page size + compression + padding. The language describes the artifact, not the technical operation.
Reorder to match mental models
Frames first, presets second, settings third. "What am I exporting? → What kind of PDF do I need? → Export."
Make cover pages discoverable
Moved cover page toggle from a separate tab to inline under "More Options". Discovery rate skyrocketed from <8% to 34%.
Persist settings between sessions
Settings persist via figma.clientStorage. On return, the plugin opens exactly where the user left off.
Engineering Challenges

Three bugs that taught me
more than the features did.

01
Optional Chaining Broke the Entire Plugin
Bug

After a refactor, the plugin failed to load. The console showed a syntax error on user?.name. Figma's sandbox runs QuickJS, which lacked optional chaining support at the time. My local environment and Figma's sandbox were not the same.

Fix & Lesson

Replaced with standard ternary checks. Lesson: Explicit failure surfaces problems; silent failure buries them. Using typed constants ensured the plugin failed loudly.

02
"More Options" Was Expanding Into Nothing
Bug

Clicking the accordion toggle rotated the chevron, but no settings appeared. The parent panel was set to overflow: hidden, clipping the expanded content.

Fix & Lesson

Allowed panel scrolling and defined minimum heights. Lesson: Panel layout must be tested at extremes—max content, min content, and all expandable sections open simultaneously.

03
"PDF Saved" Was a Lie
Bug

Users reported missing files after seeing the "PDF saved" toast. They had clicked Cancel on the OS Save dialog. The plugin had no visibility outside its execution context.

Fix & Lesson

Changed semantics to "PDF generated — find it anytime in History." Positioned the History tab as a recovery mechanism since bytes are stored before the download dialog opens.

Design Execution

Accessibility & Visual System
in a constrained space.

Accessibility Retrofits
  • Keyboard Nav: Changed divs to <button role="checkbox"> with ARIA states.
  • Focus Traps: Escape key cancellation and focus containment for modals.
  • ARIA Regions: Added aria-live for frame selection counts and toast notifications.
Visual System
  • Brand Restraint: Brand color #0014D1 reserved strictly for action/selection.
  • Semantic Tokens: Built a two-tier token system supporting seamless Dark Mode.
  • Typography: Inter with strict scale (min 10px labels) for high-density legibility.
The Results

Four versions in 28 days.
What I learned as a Product Engineer.

4
Production Versions

Shipped sequentially across 28 days based on real user signal, not staging assumptions.

34%
Cover Page Usage

Up from 8%. A 4x lift from a single layout change moving it into the primary user flow.

0
Regression Bugs

In the core PDF export pipeline across all four versions due to disciplined architectural constraints.

The Real Lesson: FrameStack PDF is where I stopped thinking of myself as a designer who could code and started thinking of myself as a product engineer. The hard problems lived at the intersection: a UX problem (failed exports) solved by engineering (chunk size limit); an engineering architecture (tabbed layout) that caused a UX failure (undiscoverable features). Holding both sides of the problem simultaneously is the real skill.
FAQ

Common questions.

What is FrameStack PDF?

FrameStack PDF is a Figma plugin that exports multiple frames into a single PDF, solving a gap in Figma's native export options.

How was FrameStack PDF built?

It was designed and engineered solo, shipping 4 versions in 28 days from v1.0 to v3.1.

What impact did the redesign have?

Redesigning the plugin's UX lifted feature discovery by 34% and brought export time down to 15 seconds.

Where can I get FrameStack PDF?

It's available on the Figma Community, with source on GitHub.

Who built FrameStack PDF?

Designed and engineered solo by Govarthanan Selvaganessane.