1:"$Sreact.fragment" 2:I[912,["/_next/static/chunks/0m6xqag99r4k7.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"default"] 3:I[39756,["/_next/static/chunks/0m6xqag99r4k7.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"default"] 4:I[37457,["/_next/static/chunks/0m6xqag99r4k7.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"default"] 6:I[97367,["/_next/static/chunks/0m6xqag99r4k7.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"OutletBoundary"] 7:"$Sreact.suspense" a:I[97367,["/_next/static/chunks/0m6xqag99r4k7.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"ViewportBoundary"] c:I[97367,["/_next/static/chunks/0m6xqag99r4k7.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"MetadataBoundary"] e:I[68027,["/_next/static/chunks/0m6xqag99r4k7.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"default",1] :HL["/_next/static/chunks/0lvog0.ho_eay.css","style"] :HL["/_next/static/chunks/0yhuiw373ukv4.css","style"] :HL["/_next/static/chunks/0k7d_gp~xdi1r.css","style"] :HL["/_next/static/media/0c8f209abc35ee02-s.p.03rqv30url-~q.woff2","font",{"crossOrigin":"","type":"font/woff2"}] :HL["/_next/static/media/5c285b27cdda1fe8-s.p.0yo6-5yoeeudq.woff2","font",{"crossOrigin":"","type":"font/woff2"}] :HL["/_next/static/media/fad69795a077455b-s.p.08-a0qexde~kr.woff2","font",{"crossOrigin":"","type":"font/woff2"}] :HL["/_next/static/chunks/10k5l4iw31hoh.css","style"] 0:{"P":null,"c":["","work","figma-integration"],"q":"","i":false,"f":[[["",{"children":["work",{"children":[["slug","figma-integration","d",null],{"children":["__PAGE__",{}]}]}]},"$undefined","$undefined",16],[["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/chunks/0lvog0.ho_eay.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/_next/static/chunks/0yhuiw373ukv4.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","link","2",{"rel":"stylesheet","href":"/_next/static/chunks/0k7d_gp~xdi1r.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/_next/static/chunks/0m6xqag99r4k7.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/_next/static/chunks/0d3shmwh5_nmn.js","async":true,"nonce":"$undefined"}]],["$","html",null,{"lang":"en","className":"dm_serif_display_b9a480e5-module__BLJeFG__variable dm_sans_6715d0ee-module__MC7VyG__variable","data-scroll-behavior":"smooth","children":["$","body",null,{"children":[["$","$L2",null,{}],["$","$L3",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L4",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}],["$","footer",null,{"children":["$","div",null,{"className":"container","children":[["$","h2",null,{"children":["Let's work on something ",["$","em",null,{"children":"worth it."}]]}],["$","p",null,{"children":"I'm always happy to talk — whether that's a potential role, a collaboration, or just a conversation about design and where it's heading."}],["$","a",null,{"href":"https://www.linkedin.com/in/mgorm","target":"_blank","rel":"noopener noreferrer","className":"btn btn-primary","children":"Connect ↗"}],["$","small",null,{"children":["© ",2026," Matt Gorman Design"]}]]}]}]]}]}]]}],{"children":[["$","$1","c",{"children":[null,["$","$L3",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L4",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":[["$","$1","c",{"children":[null,["$","$L3",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L4",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":[["$","$1","c",{"children":["$L5",[["$","link","0",{"rel":"stylesheet","href":"/_next/static/chunks/10k5l4iw31hoh.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/_next/static/chunks/048q8gvmyw66e.js","async":true,"nonce":"$undefined"}]],["$","$L6",null,{"children":["$","$7",null,{"name":"Next.MetadataOutlet","children":"$@8"}]}]]}],{},null,false,null]},null,false,"$@9"]},null,false,"$@9"]},null,false,null],["$","$1","h",{"children":[null,["$","$La",null,{"children":"$Lb"}],["$","div",null,{"hidden":true,"children":["$","$Lc",null,{"children":["$","$7",null,{"name":"Next.Metadata","children":"$Ld"}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],false]],"m":"$undefined","G":["$e",[["$","link","0",{"rel":"stylesheet","href":"/_next/static/chunks/0lvog0.ho_eay.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/_next/static/chunks/0yhuiw373ukv4.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","link","2",{"rel":"stylesheet","href":"/_next/static/chunks/0k7d_gp~xdi1r.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]]],"S":true,"h":null,"s":"$undefined","l":"$undefined","p":"$undefined","d":"$undefined","b":"z1Ge3Eagsf2H8nk6KpEOe"} f:[] 9:"$Wf" 10:I[15385,["/_next/static/chunks/0m6xqag99r4k7.js","/_next/static/chunks/0d3shmwh5_nmn.js","/_next/static/chunks/048q8gvmyw66e.js"],"TableOfContents"] 12:I[22016,["/_next/static/chunks/0m6xqag99r4k7.js","/_next/static/chunks/0d3shmwh5_nmn.js","/_next/static/chunks/048q8gvmyw66e.js"],""] 5:["$","main",null,{"className":"case-study-module__eilb5G__main","children":["$","article",null,{"className":"container case-study-module__eilb5G__article","children":[["$","header",null,{"children":[["$","h1",null,{"children":"Figma Integration: Replacing Embeds with a Real Design Data Model"}],["$","p",null,{"className":"case-study-module__eilb5G__summary","style":{"marginBottom":32},"children":"How I designed a structured way to connect Figma files to Knapsack documentation, replacing heavy iframe embeds with stable references to design content and creating a direct link between Figma components and their coded counterparts."}],["$","div",null,{"className":"case-study-module__eilb5G__metaRow","children":[["$","div",null,{"className":"case-study-module__eilb5G__metaItem","children":[["$","div",null,{"className":"case-study-module__eilb5G__metaLabel","children":"Role"}],["$","div",null,{"className":"case-study-module__eilb5G__metaValue","children":"Director of Product Design"}]]}],["$","div",null,{"className":"case-study-module__eilb5G__metaItem","children":[["$","div",null,{"className":"case-study-module__eilb5G__metaLabel","children":"Project Date"}],["$","div",null,{"className":"case-study-module__eilb5G__metaValue","children":"November 2023"}]]}],["$","div",null,{"className":"case-study-module__eilb5G__metaItem","children":[["$","div",null,{"className":"case-study-module__eilb5G__metaLabel","children":"Platform"}],["$","div",null,{"className":"case-study-module__eilb5G__metaValue","children":"SaaS Web App"}]]}]]}],"$undefined"]}],["$","div",null,{"className":"case-study-module__eilb5G__body","children":[["$","$L10",null,{"anchors":[{"id":"overview","label":"Overview"},{"id":"role","label":"My Role"},{"id":"process","label":"Process"},{"id":"decisions","label":"Key Decisions"},{"id":"outcomes","label":"Outcomes"},{"id":"lessons","label":"Lessons"}]}],["$","div",null,{"className":"case-study-module__eilb5G__content","children":["$L11",[["$","span",null,{"className":"text-eyebrow mb-md","children":"Next Selected Work"}],["$","$L12",null,{"href":"/work/cloud-authoring","children":["Cloud Authoring: Replacing PR Handoffs with a Real Publishing Workflow","   ↗"]}]]]}]]}]]}]}] 11:[["$","section",null,{"id":"overview","className":"remark-container","children":[["$","p",null,{"className":"section-label","children":"01 — Overview & Problem"}],["$","h2",null,{"children":["What we were trying to ",["$","em",null,{"children":"solve"}]]}],["$","p",null,{"children":"Knapsack already had a way to bring Figma into documentation: teams could create iframe embeds of frames, prototypes, and components. It worked, but it created as many problems as it solved. Iframes were heavy to load, didn't behave well inside structured documentation pages, and weren't a natural fit for how teams wanted to reference their design work. More importantly, they didn't understand what they were embedding. A frame was just a URL, with no awareness of what component it represented or where it sat in the file."}],["$","p",null,{"children":"Screenshots were the other workaround. Designers exported images, authors pasted them in, and docs looked right until the design changed. There was no signal when something drifted, and no mechanism to update without repeating the manual process."}],["$","p",null,{"children":"The iframe approach also had no concept of stability. When a designer moved a frame or updated a component, anything referencing it in Knapsack either broke or changed without warning. Authors had no control over when design changes flowed into their documentation."}],["$","p",null,{"children":"[ Image: before state / problem framing — 1200×675px ]"}],["$","p",null,{"children":"[Caption: The before state. Iframe embeds and static screenshots as the primary ways to get Figma into documentation, with no stable references to the underlying design content.]"}],["$","p",null,{"children":"Beyond the documentation problem, there was a deeper gap: Knapsack components and Figma components existed in complete isolation from each other. A button component in code had no relationship to the button component in Figma. Teams had no way to see whether the design spec and the coded implementation were actually in sync."}],["$","p",null,{"children":"The deeper problem was that Knapsack docs had no real understanding of Figma content. A component page couldn't say \"this is the Figma component for Button,\" it could only say \"here's an iframe that happens to show a button.\" That distinction mattered increasingly as teams wanted to document components properly, with specs, variants, and usage guidance tied directly to the source design."}],["$","p",null,{"children":"We needed Figma to be a structured data source inside Knapsack, not just a place to grab embeds from."}]]}],"\n",["$","section",null,{"id":"role","className":"remark-container","children":[["$","p",null,{"className":"section-label","children":"02 — My Role & Team"}],["$","h2",null,{"children":["Where I fit ",["$","em",null,{"children":"in"}]]}],["$","p",null,{"children":"As Director of Product Design, I owned product definition, UX, and cross-functional alignment for this initiative end to end. That meant defining the data model, designing the selector experience, and specifying how Figma nodes would integrate with Knapsack's existing content block system."}],["$","p",null,{"children":"I worked closely with engineering throughout, defining the node model and API contract early so the team could build against a stable spec and collaborating on tradeoffs around sync performance, thumbnail caching, and graceful degradation. I also drove alignment on scope: what the integration needed to do in v1 and what we were deliberately leaving for later."}],"$L13"]}],"\n","$L14","\n","$L15","\n","$L16","\n","$L17"] 13:["$","p",null,{"children":"This was solo design work, which meant I was navigating both the user-facing experience and the underlying data model simultaneously, making sure the structure we built for engineering was one that could actually produce a good authoring experience."}] 14:["$","section",null,{"id":"process","className":"remark-container","children":[["$","p",null,{"className":"section-label","children":"03 — Process"}],["$","h2",null,{"children":["How I ",["$","em",null,{"children":"approached it"}]]}],["$","p",null,{"children":"I started by mapping what teams actually needed from Figma inside their docs. Design system owners, content authors, and developers all had different jobs: connecting files, browsing and selecting the right node, and embedding or referencing it in a way that would stay stable as the design evolved. Those jobs shaped everything that followed."}],["$","p",null,{"children":"[ Image: early explorations / whiteboard / research — 1200×675px ]"}],["$","p",null,{"children":"[Caption: Early job mapping and data model explorations. Understanding Figma's file hierarchy and how it needed to translate into Knapsack's content model.]"}],["$","p",null,{"children":"Discovery surfaced three constraints that shaped the design. First, Figma's hierarchy (file, page, frame, component, variant) had to be respected rather than flattened. Fighting the tool's own structure would make the integration fragile and confusing for authors who already knew how their files were organized. Second, large Figma files meant we couldn't load everything naively; we needed a clear model of what to sync and when to refresh. Third, whatever we built had to work within Knapsack's existing block-based documentation model, not bolt on alongside it."}],["$","p",null,{"children":"From there I moved into structure: defining a unified node model with a stable id, name, type, URL, breadcrumb path, and optional thumbnail, then designing the selector experience that would make that model navigable for authors without requiring them to leave Knapsack or manage URLs manually."}],["$","p",null,{"children":"[ Image: mid-fidelity explorations — 900×675px ]"}],["$","p",null,{"children":"[Caption: Design source selector explorations. Tree navigation, node types, thumbnail previews, and the breadcrumb path model.]"}],["$","p",null,{"children":"I validated the tree-based browsing approach with internal users and design system teams early, focusing on whether navigating the file hierarchy was more reliable than search-only or link-pasting for finding the right frame or component in a large file."}]]}] 15:["$","section",null,{"id":"decisions","className":"remark-container","children":[["$","p",null,{"className":"section-label","children":"04 — Key Decisions & Tradeoffs"}],["$","h2",null,{"children":["The calls that ",["$","em",null,{"children":"mattered"}]]}],["$","p",null,{"children":["$","strong",null,{"children":"A browseable selector over paste-a-link"}]}],["$","p",null,{"children":"The most consequential decision was building an in-app design source selector (a tree browser) rather than defaulting to \"paste a Figma link.\" The link approach would have been faster to ship, but it would have kept the burden entirely on authors: know the right link, keep it updated when files changed, re-paste when it broke. The selector inverted that. Authors browse connected files, pick the node they want, and Knapsack holds the stable reference. One selection experience that could serve multiple block types and future surfaces, rather than a per-block URL field that each team had to manage themselves."}],["$","p",null,{"children":["$","strong",null,{"children":"Components and variants as first-class node types"}]}],["$","p",null,{"children":"Treating components and variants as distinct node types rather than flattening everything to \"frame\" was more complex to build but essential to the project's goal. The difference between \"show this frame\" and \"document this component\" is meaningful for design system teams. Components have variants, usage states, and specs that don't map cleanly to frames. Building that distinction into the node model from the start meant the integration could support proper component documentation rather than just visual embedding."}],["$","p",null,{"children":["$","strong",null,{"children":"Linking Figma components to Knapsack components"}]}],["$","p",null,{"children":"Treating the Figma-to-Knapsack component relationship as a first-class concept, rather than just another embed, was what made the integration meaningful beyond documentation. Once a Figma component was linked to its Knapsack counterpart, the component's properties and variants were automatically mapped to the coded component's props and API. That mapping surfaced as a structured data view directly on the component page, giving teams a way to compare the design spec to the coded spec without leaving the doc. No manual syncing, no spreadsheet, no side-by-side Figma and Storybook tabs."}],["$","p",null,{"children":["$","strong",null,{"children":"Snapshot model over live sync"}]}],["$","p",null,{"children":"When a team connects a Figma file, Knapsack uses the Figma API to pull all the relevant content and store it in its own system. Authors work from that snapshot, not a live feed from Figma. This was a deliberate choice. A live sync would mean designs could change underneath documentation at any time, with no signal to authors and no control over when updates landed. The snapshot model inverted that: Figma content stays stable within a Knapsack branch until an author deliberately triggers a sync. That sync is an intentional action, not a background process. It gave authors the same kind of intentionality over design content that the branch workflow gave them over documentation changes. Nothing updates without someone deciding it should."}],["$","p",null,{"children":"[ Image: two options considered side by side — 1200×675px ]"}],["$","p",null,{"children":"[Caption: Paste-a-link flow (left) vs. in-app design source selector with tree browsing (right). The selector reduced author burden and gave Knapsack a structured understanding of what was being referenced.]"}]]}] 16:["$","section",null,{"id":"outcomes","className":"remark-container","children":[["$","p",null,{"className":"section-label","children":"05 — Outcomes & Results"}],["$","h2",null,{"children":["What actually ",["$","em",null,{"children":"shipped"}]]}],["$","p",null,{"children":"The Figma integration shipped as a first-class design source in Knapsack, covering the full workflow from connection to documentation:"}],["$","p",null,{"children":[["$","strong",null,{"children":"Figma-to-Knapsack component linking"}]," — Once a Figma component is linked to a Knapsack component, the integration automatically maps Figma component properties and variants to the coded component's props and API. Teams get a structured, always-current view of how the design spec relates to the implementation, directly on the component page."]}],["$","p",null,{"children":[["$","strong",null,{"children":"OAuth connection"}]," — Teams connect their Figma account via OAuth, select which files to use as design sources, and Knapsack syncs the node tree into a stable, queryable representation stored in its own system."]}],["$","p",null,{"children":[["$","strong",null,{"children":"Design source selector"}]," — An in-app browser that lets authors navigate connected files, expand the tree from page down to component and variant, and select a node without leaving Knapsack or managing a URL."]}],["$","p",null,{"children":[["$","strong",null,{"children":"New block types"}]," — Two new blocks shipped as part of this project: a tiles block for displaying a set of frames or components as a visual grid, and a component block for documenting a specific Figma component with its variants and usage context. The existing embed block remained for teams who still wanted full iframe embeds."]}],["$","p",null,{"children":[["$","strong",null,{"children":"Stable references"}]," — Docs store the node id rather than a URL, so references survive file reorganization and frame renames in Figma without breaking."]}],["$","p",null,{"children":[["$","strong",null,{"children":"Snapshot and sync"}]," — When a Figma file is connected, Knapsack pulls the content via the Figma API and stores it in its own system. Authors work from that snapshot within their branch, so designs don't change underneath them mid-edit. When they're ready to incorporate updated Figma content, they trigger a manual sync rather than picking up changes automatically."]}],["$","p",null,{"children":"[ Image: final shipped UI — 1200×675px ]"}],["$","p",null,{"children":"[Caption: The shipped design source selector and a component doc page with Figma nodes referenced via the tiles and component blocks.]"}],["$","p",null,{"children":"Teams that had been working around the iframe embed limitations (managing screenshots, copying links, re-pasting when things broke) had a structured, stable way to connect their Figma work to their documentation. Component pages could finally reference the actual Figma component, not just an iframe that happened to show one, and for the first time teams could see their design spec and coded spec side by side in a single view."}]]}] 17:["$","section",null,{"id":"lessons","className":"remark-container","children":[["$","p",null,{"className":"section-label","children":"06 — Lessons Learned"}],["$","h2",null,{"children":["What I'd do ",["$","em",null,{"children":"differently"}]]}],["$","p",null,{"children":"I'd push for earlier alignment on the data model with engineering. We got there, but some of the most productive conversations happened later in the process than they should have. Defining the node model as a shared artifact upfront, not just a design spec, would have compressed the back-and-forth during implementation."}],["$","p",null,{"children":"This project reinforced something I've carried into every integration feature since: model the domain the way the tool does. Figma's hierarchy had its own logic, and the moment we tried to simplify or abstract it too early, the design got harder to reason about. Respecting the source system's structure and then designing a good experience on top of it is almost always better than flattening it prematurely."}],["$","p",null,{"children":"The snapshot model has also become a default principle for me on any platform work where an external source of truth exists. Designing for intentional sync, where authors control when external changes flow in, keeps documentation honest and prevents the silent drift that comes from treating a live feed as a feature rather than a liability."}]]}] b:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]] 18:I[27201,["/_next/static/chunks/0m6xqag99r4k7.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"IconMark"] 8:null d:[["$","title","0",{"children":"Matt Gorman — Product Design Director"}],["$","meta","1",{"name":"description","content":"Matt Gorman is a Director of Product Design at Knapsack, working at the intersection of design, engineering, and product."}],["$","link","2",{"rel":"icon","href":"/favicon/favicon-32x32.png"}],["$","link","3",{"rel":"apple-touch-icon","href":"/favicon/apple-touch-icon.png"}],["$","$L18","4",{}]]