Building a professional design tool on the web | Figma Blog (opens in new tab)
Figma set out to prove that a professional, high-fidelity design tool could run reliably in the browser. The challenge was that the web exposed specialized features rather than general-purpose graphics primitives, so Figma effectively had to build “a browser inside a browser.” Its solution combined C++ compiled through Emscripten with a custom rendering engine, enabling tighter control over memory, performance, and cross-platform consistency.
Building Beyond the Web’s Original Design
- The web was originally designed for documents, with application features added later as isolated APIs.
- This limits advanced applications:
- CSS provides sophisticated text layout but does not expose or customize the layout process.
- Browsers have optimized GPU compositors, but developers cannot directly modify compositing or add custom blend modes.
- Image decoders are highly optimized but offer limited control over details such as EXIF orientation and color-space handling.
- Technologies such as WebGL and asm.js began exposing lower-level access to hardware, making demanding browser-based graphics applications practical.
C++ and Emscripten
- Figma’s editor was written in C++ and cross-compiled to JavaScript using Emscripten.
- Emscripten targeted asm.js, allowing JavaScript engines to generate predictable and compact machine code.
- This approach provided:
- Direct control over memory layout, including compact 32-bit floats and bytes instead of JavaScript’s 64-bit numbers.
- Manual allocation that avoids garbage-collection pauses and helps maintain 60 fps.
- LLVM optimization and C++ template specialization for performance approaching native code.
- More predictable execution because asm.js avoids the deoptimization points common in regular JavaScript.
Memory Constraints and Indirect Buffers
- Large contiguous typed-array allocations caused problems, especially in 32-bit Chrome on Windows, where address-space fragmentation from ASLR could prevent allocations as small as 256 MB.
- Figma created an
IndirectBufferAPI to reference external typed arrays from C++. - Moving large image and geometry buffers outside the main heap:
- Reduced fragmentation during long sessions.
- Allowed better use of limited 32-bit address space.
- Helped bypass typed-array size limits in 64-bit browsers.
- The post also points toward future improvements from WebAssembly, which would reduce asm.js parsing costs, and shared typed arrays, which would enable shared-memory multithreading.
Custom Rendering
- Figma implemented its own rendering engine to achieve fast, consistent output across platforms.
- Rather than relying entirely on browser graphics implementations, the team began building the rendering layer needed for a professional design application.
Figma’s broader recommendation is to use low-level browser capabilities such as WebGL and compiled code when standard web APIs cannot provide the required performance or control.