<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="atom.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://grida.co/blog/</id>
    <title>Blog Blog</title>
    <updated>2026-02-17T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://grida.co/blog/"/>
    <subtitle>Blog Blog</subtitle>
    <icon>https://grida.co/blog/img/favicon.ico</icon>
    <entry>
        <title type="html"><![CDATA[Introducing refig — a headless Figma renderer for real-world pipelines]]></title>
        <id>https://grida.co/blog/refig</id>
        <link href="https://grida.co/blog/refig"/>
        <updated>2026-02-17T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Export Figma designs to PNG/SVG/PDF without a browser. Deterministic, CI-friendly rendering from .fig or REST JSON—built for tooling, previews, and automation.]]></summary>
        <content type="html"><![CDATA[<p>Figma exports are easy—until exporting becomes <strong>infrastructure</strong>.</p>
<p>Teams start with "click Export" and end up needing <strong>thumbnails</strong>, <strong>asset pipelines</strong>, <strong>visual diffs</strong>, and <strong>repeatable builds</strong>. That's where the usual options start to hurt:</p>
<ul>
<li class="">A headless browser is slow and flaky in CI.</li>
<li class="">The Figma Images API is great, but it's still <strong>a network dependency</strong> (tokens, rate limits, availability).</li>
<li class="">Signed image URLs expire, which makes "render later" workflows fragile.</li>
<li class="">Offline or air‑gapped environments simply can't rely on API calls.</li>
</ul>
<p><strong>refig</strong> is built for that gap.</p>
<div style="padding:64.67% 0 0 0;position:relative"><iframe src="https://player.vimeo.com/video/1165652748?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479&amp;autoplay=1&amp;muted=1&amp;loop=1" frameborder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media; web-share" referrerpolicy="strict-origin-when-cross-origin" style="position:absolute;top:0;left:0;width:100%;height:100%" title="refig (headless figma renderer) demo"></iframe></div>
<h2 class="anchor anchorTargetStickyNavbar_NiBB" id="what-is-refig">What is refig?<a href="https://grida.co/blog/refig#what-is-refig" class="hash-link" aria-label="Direct link to What is refig?" title="Direct link to What is refig?" translate="no">​</a></h2>
<p><strong><code>@grida/refig</code></strong> ("render figma") is a <strong>headless Figma renderer</strong>. It turns a Figma document + node id into <strong>PNG, JPEG, WebP, PDF, or SVG</strong>—without opening Figma and without driving a browser UI.</p>
<p>It works with:</p>
<ul>
<li class=""><strong><code>.fig</code> files</strong> (offline, reproducible)</li>
<li class=""><strong>Figma REST API file JSON</strong> (<code>GET /v1/files/:key</code>) when you already have your own ingestion layer</li>
</ul>
<p>You can use it as a <strong>CLI</strong> (<code>refig</code>) or as a <strong>library</strong> in Node.js and the browser.</p>
<ul>
<li class="">Technical reference and usage: <a href="https://www.npmjs.com/package/@grida/refig" target="_blank" rel="noopener noreferrer" class=""><code>@grida/refig</code> on npm</a></li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_NiBB" id="the-idea-deterministic-rendering-you-can-build-on">The idea: deterministic rendering you can build on<a href="https://grida.co/blog/refig#the-idea-deterministic-rendering-you-can-build-on" class="hash-link" aria-label="Direct link to The idea: deterministic rendering you can build on" title="Direct link to The idea: deterministic rendering you can build on" translate="no">​</a></h2>
<p>When rendering is deterministic and programmable, a bunch of workflows become straightforward:</p>
<ul>
<li class=""><strong>Preview services</strong>: generate thumbnails for files, pages, frames, components.</li>
<li class=""><strong>Asset pipelines</strong>: treat "Export presets" as build artifacts (commit, cache, publish).</li>
<li class=""><strong>Visual regression tests</strong>: render the same node on every PR and diff outputs.</li>
<li class=""><strong>Offline archives</strong>: store <code>.fig</code> snapshots and reproduce outputs later—no tokens, no network.</li>
<li class=""><strong>In-app previews</strong>: render inside your product (browser entrypoint) to show design snapshots.</li>
</ul>
<p>In other words: refig is less about "export an image" and more about making Figma rendering a reliable building block.</p>
<h2 class="anchor anchorTargetStickyNavbar_NiBB" id="what-refig-intentionally-doesnt-do">What refig intentionally doesn't do<a href="https://grida.co/blog/refig#what-refig-intentionally-doesnt-do" class="hash-link" aria-label="Direct link to What refig intentionally doesn't do" title="Direct link to What refig intentionally doesn't do" translate="no">​</a></h2>
<p>refig is opinionated about scope so it stays composable:</p>
<ul>
<li class=""><strong>No auth / fetching</strong>: you bring your own token storage, HTTP client, and caching.</li>
<li class=""><strong>No design-to-code</strong>: this is rendering (pixels / SVG / PDF), not HTML/CSS/Flutter generation.</li>
<li class=""><strong>No editor</strong>: read + render only.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_NiBB" id="a-tiny-taste-cli">A tiny taste (CLI)<a href="https://grida.co/blog/refig#a-tiny-taste-cli" class="hash-link" aria-label="Direct link to A tiny taste (CLI)" title="Direct link to A tiny taste (CLI)" translate="no">​</a></h2>
<p>If you just want to feel what it's like:</p>
<div class="language-sh codeBlockContainer_V848 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_M3rt"><pre tabindex="0" class="prism-code language-sh codeBlock_K7_7 thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_ZOMJ"><span class="token-line" style="color:#393A34"><span class="token plain"># Render a node from a .fig export</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">npx @grida/refig ./design.fig --node "1:23" --out ./out.png</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># Or render from REST API JSON you fetched elsewhere</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">npx @grida/refig ./document.json --node "1:23" --out ./out.svg</span><br></span></code></pre></div></div>
<p>From there, most teams graduate quickly to: "render N nodes", "render on every commit", or "render on demand".</p>
<h2 class="anchor anchorTargetStickyNavbar_NiBB" id="where-this-is-headed">Where this is headed<a href="https://grida.co/blog/refig#where-this-is-headed" class="hash-link" aria-label="Direct link to Where this is headed" title="Direct link to Where this is headed" translate="no">​</a></h2>
<p>We're treating refig as a foundation for "design → build" automation:</p>
<ul>
<li class="">render outputs that are <strong>repeatable</strong></li>
<li class="">workflows that can run <strong>in CI</strong></li>
<li class="">tooling that can work <strong>offline</strong></li>
</ul>
<p>If that sounds like your problem, start with the docs (high-level) and the npm page (full API/CLI reference), then wire it into the pipeline you already have:</p>
<ul>
<li class=""><a href="https://grida.co/docs/packages/@grida/refig" target="_blank" rel="noopener noreferrer" class=""><code>@grida/refig</code> docs</a></li>
<li class=""><a href="https://www.npmjs.com/package/@grida/refig" target="_blank" rel="noopener noreferrer" class=""><code>@grida/refig</code> on npm</a></li>
</ul>]]></content>
        <author>
            <name>Universe</name>
            <uri>https://github.com/softmarshmallow</uri>
        </author>
        <category label="figma" term="figma"/>
        <category label="rendering" term="rendering"/>
        <category label="ci" term="ci"/>
        <category label="wasm" term="wasm"/>
        <category label="Skia" term="Skia"/>
        <category label="tooling" term="tooling"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[The Typography Mystery Hidden in Every Design Tool]]></title>
        <id>https://grida.co/blog/font-italic</id>
        <link href="https://grida.co/blog/font-italic"/>
        <updated>2025-09-15T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Italic isn’t a transform. It’s a font-selection problem—spanning OS/2 flags, STAT metadata, variable axes, and fallbacks.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="italic" src="https://grida.co/blog/assets/images/01-italic-toggle-a53124e5777114cbd4cf11c299bbed30.webp" width="960" height="960" class="img_rXXn"></p>
<p><em>That little <strong>Italic</strong> toggle in your design tool is doing far more than leaning letters to the right. In a professional renderer, italic is a <strong>font discovery and selection problem</strong>—and it’s messy in ways most people never see.</em></p>
<p>Clicking <strong>Italic</strong> is a request for a specific typographic design: a distinct face (often with different letterforms, spacing, and metrics), ideally authored by the type designer. To honor that request, a design tool has to navigate:</p>
<ul>
<li class="">families shipped as one file vs many files</li>
<li class="">variable fonts that may or may not expose a real italic axis</li>
<li class="">fonts that express italic via metadata (or don’t)</li>
<li class="">legacy naming conventions that conflict with modern specs</li>
</ul>
<p>In other words: the UI is simple. The decision tree is not.</p>
<blockquote>
<p><strong>Thesis:</strong> A design tool can’t “apply italic.” It can only <strong>select a font face (or instance) that represents italic</strong>, or choose a synthetic fallback.</p>
</blockquote>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_NiBB" id="what-you-think-italic-is">What you think italic is<a href="https://grida.co/blog/font-italic#what-you-think-italic-is" class="hash-link" aria-label="Direct link to What you think italic is" title="Direct link to What you think italic is" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" alt="Italic Toggle UI" src="https://grida.co/blog/assets/images/02-italic-toggle-ui-illusion-6253266940cfde28e580a8b56b506c23.png" width="1200" height="675" class="img_rXXn"></p>
<p>From the outside, italic looks like a geometric effect. But “true italic” is a separate design, not a shear transform:</p>
<ul>
<li class="">the italic <strong>a</strong> and <strong>g</strong> may change shape</li>
<li class="">spacing and kerning can be rebalanced for slanted rhythm</li>
<li class="">strokes, terminals, and proportions may be reworked for readability</li>
</ul>
<p>So a professional tool should prefer a genuine italic face when it exists. And when it doesn’t, it must decide what “italic” should mean in a way that’s consistent, debuggable, and cross-platform.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_NiBB" id="why-italic-gets-complicated-in-modern-font-families">Why italic gets complicated in modern font families<a href="https://grida.co/blog/font-italic#why-italic-gets-complicated-in-modern-font-families" class="hash-link" aria-label="Direct link to Why italic gets complicated in modern font families" title="Direct link to Why italic gets complicated in modern font families" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" alt="Italic Evolution Timeline" src="https://grida.co/blog/assets/images/03-italic-evolution-timeline-e3887cd44939d2189ea2e53deb3edfc0.png" width="1920" height="1080" class="img_rXXn"></p>
<p>Italic complexity isn’t an accident—it’s an accumulation:</p>
<ul>
<li class=""><strong>History:</strong> italic was originally a distinct handwriting-inspired style, not merely “slanted roman.”</li>
<li class=""><strong>File formats:</strong> font families evolved from separate files to large multi-style bundles to variable fonts.</li>
<li class=""><strong>Metadata:</strong> different eras standardized different signals (and not all fonts implement them correctly).</li>
</ul>
<p>Today, the same user intent (“italic”) can be represented by very different font packaging strategies.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_NiBB" id="the-family-taxonomy-how-italic-is-actually-shipped">The family taxonomy: how italic is actually shipped<a href="https://grida.co/blog/font-italic#the-family-taxonomy-how-italic-is-actually-shipped" class="hash-link" aria-label="Direct link to The family taxonomy: how italic is actually shipped" title="Direct link to The family taxonomy: how italic is actually shipped" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" alt="Font Family Italic Taxonomy" src="https://grida.co/blog/assets/images/04-font-family-italic-taxonomy-9a35ab43bead1fac1bb3434d38e4de9a.png" width="1536" height="1024" class="img_rXXn"></p>
<p>Modern font families implement italic in a small number of patterns. The table below is the practical taxonomy we use when analyzing large registries (e.g., Google Fonts).</p>
<blockquote>
<p>Read this as: <strong>same UI button, different ground truth</strong>.</p>
</blockquote>
<table><thead><tr><th>Scenario</th><th>Description</th><th>Non-Italic Examples</th><th>Italic Examples</th><th>Primary signal</th><th>Notes</th></tr></thead><tbody><tr><td><strong>1. One static font</strong></td><td>Single file; italic may be absent—or the family may be italic-only.</td><td><code>Allerta-Regular.ttf</code> (<a href="https://fonts.google.com/specimen/Allerta" target="_blank" rel="noopener noreferrer" class="">Google Fonts</a>)</td><td><code>Molle-Italic.ttf</code> (<a href="https://fonts.google.com/specimen/Molle" target="_blank" rel="noopener noreferrer" class="">Google Fonts</a>)</td><td>OS/2</td><td>Rare edge cases exist (including “italic-only” families).</td></tr><tr><td><strong>2. Many static fonts</strong></td><td>Multiple files (Regular/Bold/Italic/BoldItalic).</td><td><code>PTSerif-Regular.ttf</code>, <code>PTSerif-Bold.ttf</code> (<a href="https://fonts.google.com/specimen/PT+Serif" target="_blank" rel="noopener noreferrer" class="">Google Fonts</a>)</td><td><code>PTSerif-Italic.ttf</code>, <code>PTSerif-BoldItalic.ttf</code> (<a href="https://fonts.google.com/specimen/PT+Serif" target="_blank" rel="noopener noreferrer" class="">Google Fonts</a>)</td><td>OS/2</td><td>The traditional, still-common packaging model.</td></tr><tr><td><strong>3. One variable font</strong></td><td>A single variable font that can express italic via axes.</td><td><code>Geist-VariableFont_wght.ttf</code> (<a href="https://fonts.google.com/specimen/Geist" target="_blank" rel="noopener noreferrer" class="">Google Fonts</a>)</td><td><code>EB Garamond</code> (legacy reference) (<a href="https://fonts.google.com/knowledge/glossary/italic_axis" target="_blank" rel="noopener noreferrer" class="">Google Fonts Knowledge</a>)</td><td><code>ital</code> axis</td><td>Elegant in theory, less common in practice than people assume.</td></tr><tr><td><strong>3-1. VF + italic instances</strong></td><td>Variable font uses <code>slnt</code> plus explicitly named italic instances.</td><td><code>Recursive-VariableFont_CASL,CRSV,MONO,slnt,wght.ttf</code> (<a href="https://fonts.google.com/specimen/Recursive" target="_blank" rel="noopener noreferrer" class="">Google Fonts</a>)<br><code>RobotoFlex-VariableFont_GRAD,XOPQ,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf</code> (<a href="https://fonts.google.com/specimen/Roboto+Flex" target="_blank" rel="noopener noreferrer" class="">Google Fonts</a>)</td><td>Same files, via named instances</td><td><code>fvar.instances</code> / STAT</td><td>Italic is expressed by <strong>instances and names</strong>, not a clean “OS/2 italic” bit.</td></tr><tr><td><strong>4. Two variable fonts</strong></td><td>A Roman VF and an Italic VF, switched by style.</td><td><code>Inter-VariableFont_opsz,wght.ttf</code> (<a href="https://fonts.google.com/specimen/Inter" target="_blank" rel="noopener noreferrer" class="">Google Fonts</a>)<br><code>NotoSans-VariableFont_wdth,wght.ttf</code> (<a href="https://fonts.google.com/noto/specimen/Noto+Sans" target="_blank" rel="noopener noreferrer" class="">Google Fonts</a>)</td><td><code>Inter-Italic-VariableFont_opsz,wght.ttf</code> (<a href="https://fonts.google.com/specimen/Inter" target="_blank" rel="noopener noreferrer" class="">Google Fonts</a>)<br><code>NotoSans-Italic-VariableFont_wdth,wght.ttf</code> (<a href="https://fonts.google.com/noto/specimen/Noto+Sans" target="_blank" rel="noopener noreferrer" class="">Google Fonts</a>)</td><td>OS/2 + family packaging</td><td>Common in modern flagship families: distinct design + VF benefits.</td></tr></tbody></table>
<p>This taxonomy is the reason a single “isItalic” heuristic fails: italic may be a dedicated file, a variable axis value, a named instance, or—occasionally—an entire family.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_NiBB" id="a-professional-font-engine-needs-a-policy-not-a-trick">A professional font engine needs a policy, not a trick<a href="https://grida.co/blog/font-italic#a-professional-font-engine-needs-a-policy-not-a-trick" class="hash-link" aria-label="Direct link to A professional font engine needs a policy, not a trick" title="Direct link to A professional font engine needs a policy, not a trick" translate="no">​</a></h2>
<p>If italic were always signaled the same way, font selection would be trivial.</p>
<p>In practice:</p>
<ul>
<li class="">Some fonts set OS/2 flags reliably. Others don’t.</li>
<li class="">Some variable fonts expose an <code>ital</code> axis. Others use <code>slnt</code>.</li>
<li class="">Some fonts contain “Italic” in names without being true italic.</li>
<li class="">Some families include an italic VF as a separate file.</li>
</ul>
<p>A design tool therefore needs two things:</p>
<ol>
<li class=""><strong>A detection pipeline</strong> that can interpret multiple sources of truth.</li>
<li class=""><strong>A policy</strong> that defines what counts as “italic” when signals disagree.</li>
</ol>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_NiBB" id="gridas-italic-selection-pipeline">Grida’s italic selection pipeline<a href="https://grida.co/blog/font-italic#gridas-italic-selection-pipeline" class="hash-link" aria-label="Direct link to Grida’s italic selection pipeline" title="Direct link to Grida’s italic selection pipeline" translate="no">​</a></h2>
<p>Grida’s selection is intentionally priority-based. The goal is not to be clever; it’s to be consistent.</p>
<h3 class="anchor anchorTargetStickyNavbar_NiBB" id="priority-order">Priority order<a href="https://grida.co/blog/font-italic#priority-order" class="hash-link" aria-label="Direct link to Priority order" title="Direct link to Priority order" translate="no">​</a></h3>
<ol>
<li class=""><strong>User declaration</strong> (explicit intent wins)</li>
<li class=""><strong>OS/2 italic bit</strong> (best broad signal)</li>
<li class=""><strong>STAT table</strong> (style semantics and instance mapping)</li>
<li class=""><strong>Variable font axes</strong> (<code>ital</code>, then <code>slnt</code> with named instances)</li>
<li class=""><strong>Name table fallback</strong> (optional, logged)</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_NiBB" id="the-decision-flow">The decision flow<a href="https://grida.co/blog/font-italic#the-decision-flow" class="hash-link" aria-label="Direct link to The decision flow" title="Direct link to The decision flow" translate="no">​</a></h3>
<!-- -->
<p>Two important details:</p>
<ul>
<li class="">We treat <strong>italic</strong> as a semantic request, not as a geometric one.</li>
<li class="">When we must fall back, we do it <strong>explicitly</strong> and <strong>log</strong> the reason.</li>
</ul>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_NiBB" id="from-selection-to-rendering-a-stable-style-model">From selection to rendering: a stable style model<a href="https://grida.co/blog/font-italic#from-selection-to-rendering-a-stable-style-model" class="hash-link" aria-label="Direct link to From selection to rendering: a stable style model" title="Direct link to From selection to rendering: a stable style model" translate="no">​</a></h2>
<p>Italic detection only matters if the result can be reliably rendered, cached, and persisted.</p>
<p>The key design constraint is this:</p>
<blockquote>
<p>A stored text style should contain <strong>facts</strong> (what the user asked for, what we resolved to), not platform-specific assumptions.</p>
</blockquote>
<h3 class="anchor anchorTargetStickyNavbar_NiBB" id="fontstylekey"><code>FontStyleKey</code><a href="https://grida.co/blog/font-italic#fontstylekey" class="hash-link" aria-label="Direct link to fontstylekey" title="Direct link to fontstylekey" translate="no">​</a></h3>
<p>This structure is the bridge between selection and rendering:</p>
<div class="language-rust codeBlockContainer_V848 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_M3rt"><pre tabindex="0" class="prism-code language-rust codeBlock_K7_7 thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_ZOMJ"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token type-definition class-name">FontStyleKey</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// Core identity</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> font_family</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">String</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> font_weight</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">FontWeight</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> font_style_italic</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">bool</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// Optional precision (exact matching)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> font_style_name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">Option</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">String</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> font_postscript_name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">Option</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">String</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> font_instance_postscript_name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">Option</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">String</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> font_variations</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">Option</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">HashMap</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">String</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">f32</span><span class="token operator" style="color:#393A34">&gt;&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p><strong>Why the split matters:</strong></p>
<ul>
<li class="">The core fields cover the common case and enable fast internal resolution.</li>
<li class="">The optional fields provide exactness when it exists (static PostScript names, VF instance names, axis values).</li>
<li class="">Nothing here assumes a filesystem location or OS font registry behavior.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_NiBB" id="skia-integration-illustrative">Skia integration (illustrative)<a href="https://grida.co/blog/font-italic#skia-integration-illustrative" class="hash-link" aria-label="Direct link to Skia integration (illustrative)" title="Direct link to Skia integration (illustrative)" translate="no">​</a></h3>
<div class="language-rust codeBlockContainer_V848 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_M3rt"><pre tabindex="0" class="prism-code language-rust codeBlock_K7_7 thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_ZOMJ"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// Illustrative sketch: production code includes additional validation &amp; fallbacks.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">textstyle</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">style</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token class-name">TextStyleRec</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> ctx</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token class-name">TextStyleRecBuildContext</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">skia_safe</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token namespace" style="opacity:0.7">textlayout</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token class-name">TextStyle</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">mut</span><span class="token plain"> ts </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">skia_safe</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token namespace" style="opacity:0.7">textlayout</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token class-name">TextStyle</span><span class="token punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">new</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> font_style </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">skia_safe</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token class-name">FontStyle</span><span class="token punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">new</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token namespace" style="opacity:0.7">skia_safe</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token namespace" style="opacity:0.7">font_style</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token class-name">Weight</span><span class="token punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">from</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">style</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">font_weight</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">value</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">i32</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token namespace" style="opacity:0.7">skia_safe</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token namespace" style="opacity:0.7">font_style</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token class-name">Width</span><span class="token punctuation" style="color:#393A34">::</span><span class="token constant" style="color:#36acaa">NORMAL</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> style</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">font_style_italic </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token namespace" style="opacity:0.7">skia_safe</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token namespace" style="opacity:0.7">font_style</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token class-name">Slant</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">Italic</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token namespace" style="opacity:0.7">skia_safe</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token namespace" style="opacity:0.7">font_style</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token class-name">Slant</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">Upright</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// Variable font coordinates (if any)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">mut</span><span class="token plain"> coords </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token macro property" style="color:#36acaa">vec!</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> </span><span class="token class-name">Some</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">vars</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">style</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">font_variations </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> v </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> vars </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> tag </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">tag_from_str</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">v</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">axis</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            coords</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token namespace" style="opacity:0.7">skia_safe</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token namespace" style="opacity:0.7">font_arguments</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token namespace" style="opacity:0.7">variation_position</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token class-name">Coordinate</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                axis</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> tag</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                value</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> v</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">value</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// Always apply weight</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    coords</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">var_wght</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">style</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">font_weight</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">value</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">f32</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> variation_position </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">skia_safe</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token namespace" style="opacity:0.7">font_arguments</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token class-name">VariationPosition</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        coordinates</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> coords</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">as_slice</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    ts</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">set_font_style</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">font_style</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    ts</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">set_font_arguments</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">font_args</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    ts</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>The goal is straightforward: once italic is classified (and a recipe exists), it must round-trip into the renderer deterministically.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_NiBB" id="deep-dive-persistence-portability-and-edge-cases">Deep dive: persistence, portability, and edge cases<a href="https://grida.co/blog/font-italic#deep-dive-persistence-portability-and-edge-cases" class="hash-link" aria-label="Direct link to Deep dive: persistence, portability, and edge cases" title="Direct link to Deep dive: persistence, portability, and edge cases" translate="no">​</a></h2>
<p>Design tools aren’t browsers. They store documents, share files, and expect styles to remain meaningful over time.</p>
<h3 class="anchor anchorTargetStickyNavbar_NiBB" id="persistence-principles">Persistence principles<a href="https://grida.co/blog/font-italic#persistence-principles" class="hash-link" aria-label="Direct link to Persistence principles" title="Direct link to Persistence principles" translate="no">​</a></h3>
<ul>
<li class=""><strong>Facts only:</strong> store what’s true about the style and resolution.</li>
<li class=""><strong>Platform agnostic:</strong> no font file paths or OS-specific identifiers.</li>
<li class=""><strong>Graceful degradation:</strong> if a platform can’t locate the exact face, it should still render a sensible fallback.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_NiBB" id="real-world-pressure-points">Real-world pressure points<a href="https://grida.co/blog/font-italic#real-world-pressure-points" class="hash-link" aria-label="Direct link to Real-world pressure points" title="Direct link to Real-world pressure points" translate="no">​</a></h3>
<ul>
<li class=""><strong>Font file variability:</strong> “the same family” can ship different files per platform.</li>
<li class=""><strong>Variable font instances:</strong> the file may be constant; the <em>instance</em> is the real style.</li>
<li class=""><strong>Metadata quality:</strong> fonts in the wild are inconsistent; the pipeline must be defensive.</li>
<li class=""><strong>Performance:</strong> selection must be cacheable and fast at design-tool scale.</li>
</ul>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_NiBB" id="blink-grida-and-skia-where-selection-lives">Blink, Grida, and Skia: where selection lives<a href="https://grida.co/blog/font-italic#blink-grida-and-skia-where-selection-lives" class="hash-link" aria-label="Direct link to Blink, Grida, and Skia: where selection lives" title="Direct link to Blink, Grida, and Skia: where selection lives" translate="no">​</a></h2>
<p>A useful mental model:</p>
<ul>
<li class=""><strong>Blink</strong> (in the browser) decides fonts in the context of CSS, platform font fallback, and webfont loading.</li>
<li class=""><strong>Grida</strong> decides fonts in the context of <strong>documents</strong>, <strong>portability</strong>, and <strong>design intent</strong>.</li>
<li class=""><strong>Skia</strong> renders the result: it needs a resolved typeface + style/variation inputs.</li>
</ul>
<p>The main takeaway is that “italic” is not solved at the raster layer. It’s solved in the selection layer—before glyph shaping and rendering.</p>
<div class="language-rust codeBlockContainer_V848 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_M3rt"><pre tabindex="0" class="prism-code language-rust codeBlock_K7_7 thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_ZOMJ"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// Illustrative: classification is a policy-driven decision.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">classify_face</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">face</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token class-name">FaceRecord</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">ItalicKind</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Option</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">Recipe</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> face</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">user_font_style_italic </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token class-name">Some</span><span class="token punctuation" style="color:#393A34">(</span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">ItalicKind</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">Italic</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">None</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> face</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">os2_fsselection</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">italic</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">ItalicKind</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">Italic</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">None</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> face</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">has_ital_axis_default_one</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">ItalicKind</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">Italic</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Some</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Recipe</span><span class="token punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">ital_one</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> face</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">has_slnt_axis</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> </span><span class="token class-name">Some</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">inst</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> face</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">instance_named_italic_via_slnt_only</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">ItalicKind</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">Italic</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Some</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">inst</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">axis_recipe</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">ItalicKind</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">Normal</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">None</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_NiBB" id="real-italic-vs-synthetic-italic">Real italic vs synthetic italic<a href="https://grida.co/blog/font-italic#real-italic-vs-synthetic-italic" class="hash-link" aria-label="Direct link to Real italic vs synthetic italic" title="Direct link to Real italic vs synthetic italic" translate="no">​</a></h2>
<p>When an authentic italic face exists, it preserves typographic intent. When it doesn’t, tools often use a synthetic fallback.</p>
<p>A practical rule:</p>
<ul>
<li class=""><strong>Prefer real italic</strong> when the family provides it.</li>
<li class=""><strong>Fallback to synthetic</strong> only when there’s no reliable italic face/instance.</li>
</ul>
<p>The mistake is treating synthetic slant as equivalent. It isn’t—but it can be a reasonable fallback if communicated and applied consistently.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_NiBB" id="why-we-built-fontsgridaco">Why we built fonts.grida.co<a href="https://grida.co/blog/font-italic#why-we-built-fontsgridaco" class="hash-link" aria-label="Direct link to Why we built fonts.grida.co" title="Direct link to Why we built fonts.grida.co" translate="no">​</a></h2>
<p>To validate this pipeline at scale, we built <strong>fonts.grida.co</strong>—a font metadata indexing service used to test and audit italic behavior across large registries.</p>
<p>It provides:</p>
<ul>
<li class="">accurate PostScript name mappings</li>
<li class="">per-variant previews</li>
<li class="">variable font axis and instance introspection</li>
<li class="">searchable metadata for edge-case discovery</li>
</ul>
<p>In practice, the service acts as an externalized test harness for font selection correctness.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_NiBB" id="closing-the-small-button-with-big-consequences">Closing: the small button with big consequences<a href="https://grida.co/blog/font-italic#closing-the-small-button-with-big-consequences" class="hash-link" aria-label="Direct link to Closing: the small button with big consequences" title="Direct link to Closing: the small button with big consequences" translate="no">​</a></h2>
<p>Italic is a good example of what makes professional design tools hard: correctness is often invisible, and failure looks “almost fine.”</p>
<p>Treating italic as a first-class selection problem—backed by a clear policy, robust metadata interpretation, and stable persistence—turns a fragile UI toggle into something you can trust in real documents.</p>
<p><em>The italic button is small. The responsibility behind it is not.</em></p>]]></content>
        <author>
            <name>Universe</name>
            <uri>https://github.com/softmarshmallow</uri>
        </author>
        <category label="Canvas" term="Canvas"/>
        <category label="Skia" term="Skia"/>
        <category label="Font" term="Font"/>
        <category label="Italic" term="Italic"/>
        <category label="Typography" term="Typography"/>
        <category label="OpenType" term="OpenType"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Snapping feature on Grida Canvas]]></title>
        <id>https://grida.co/blog/snap-on-canvas</id>
        <link href="https://grida.co/blog/snap-on-canvas"/>
        <updated>2025-02-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Learn how snapping elements works on Grida Canvas]]></summary>
        <content type="html"><![CDATA[<p>In this article, we will demonstrate how snapping works on Grida Canvas. Snapping the elements on the Grida canvas
gives you consistency in spacing between elements.</p>
<p>To see the horizontal snapping in action, visit <a href="https://grida.co/canvas" target="_blank" rel="noopener noreferrer" class="">https://grida.co/canvas</a> and follow the steps below</p>
<ol>
<li class="">Create a rectangle</li>
</ol>
<p><img decoding="async" loading="lazy" alt="Horizontal snap 1" src="https://grida.co/blog/assets/images/horizontal-snap-1-47362c394981cfc25d9386d71512022e.gif" width="928" height="439" class="img_rXXn"></p>
<ol start="2">
<li class="">Select the rectangle you just added and press alt and drag towards right</li>
</ol>
<p><img decoding="async" loading="lazy" alt="Horizontal snap 2" src="https://grida.co/blog/assets/images/horizontal-snap-2-6aff92c363dc105202107884a65b484b.gif" width="927" height="436" class="img_rXXn"></p>
<p>As you drag towards right, you do not see the snapping yet because you only have two elements added so far. Snapping uses references points based on existing elements drawn on the canvas. In this case, it is horizontal i.e., along the x-axis. Make sure you keep some visible distance between these rectangles as you drag towards right, it does not have to be too far.</p>
<ol start="3">
<li class="">Repeat step 2, you will now create third rectangle. Select an existing rectangle, press alt and slowly drag this rectangle towards right. As you slowly move along the x-axis, when this third rectangle is "almost" at a distance that is same as the distance between the first and the second rectangle, you will see this rectangle snapping to the point that makes these three rectangles equidistant.</li>
</ol>
<p><img decoding="async" loading="lazy" alt="Horizontal snap 3" src="https://grida.co/blog/assets/images/horizontal-snap-3-4dbda037ae0039b2f769e72025f0abd9.gif" width="925" height="438" class="img_rXXn"></p>
<p>I said "almost" here because internally we use a metric called threshold, that defaults to 4, if your moving element (we call it agent) falls with in the range of being equally distant, the agent snaps to the point to make the elements equidistant</p>
<p><img decoding="async" loading="lazy" alt="threshold" src="https://grida.co/blog/assets/images/snap-threshold-dda0647d5be225241e6d77cdd58cad26.png" width="1262" height="804" class="img_rXXn"></p>
<h1>Snapping vertically</h1>
<p>To see the vetical snapping in action, visit <a href="https://grida.co/canvas" target="_blank" rel="noopener noreferrer" class="">https://grida.co/canvas</a> and follow the steps below</p>
<ol>
<li class="">Create a rectangle as shown below, this rectangle should be horizontal as we stack more rectangle in the next steps
to demonstrate the vertical snapping.</li>
</ol>
<p><img decoding="async" loading="lazy" alt="vertically snap 1" src="https://grida.co/blog/assets/images/vertical-snap-1-2e8034e634887e32ea2f8a7cd6de3694.gif" width="928" height="436" class="img_rXXn"></p>
<ol start="2">
<li class="">Select the rectangle you just added and press alt and drag upwards. The difference here is "dragging upwards" where as in the horizontal snapping, you would move the rectangle towards to create a clone</li>
</ol>
<p><img decoding="async" loading="lazy" alt="vertically snap 2" src="https://grida.co/blog/assets/images/vertical-snap-2-39de5d93c81848a2e5a1f6b0c0c6b495.gif" width="925" height="440" class="img_rXXn"></p>
<p>The same logic applies described in step 2, i.e., you do not see a snapping point yet. There has to be atleast two elements as a reference to calculate the space between those elements and then based on that value, we snap the elements that are arouund these two elements.</p>
<ol start="3">
<li class="">Repeat step 2, you will now create third rectangle. Select an existing rectangle, press alt and slowly drag this rectangle upward. When this third element falls in the threshold, it snaps so that all these three elements are equidistant.</li>
</ol>
<p><img decoding="async" loading="lazy" alt="vertically snap 3" src="https://grida.co/blog/assets/images/vertical-snap-3-344b0da69c54ae777b920c0b5b827e77.gif" width="928" height="436" class="img_rXXn"></p>
<h1>Snapping as you center an element</h1>
<p>To see snapping in action as you center an element, follow the steps below</p>
<ol>
<li class="">Create a vertical rectangle, make sure to position this on the left.</li>
</ol>
<p><img decoding="async" loading="lazy" alt="central snap 1" src="https://grida.co/blog/assets/images/central-snap-1-69de3574b3e5b1b4513e4b6ae31e125b.png" width="2878" height="1706" class="img_rXXn"></p>
<ol start="2">
<li class="">Closer to the top, create a horizontal rectangle as shown below</li>
</ol>
<p><img decoding="async" loading="lazy" alt="central snap 2" src="https://grida.co/blog/assets/images/central-snap-2-cc82365665b800d3e076ebea095a90a7.png" width="2878" height="1706" class="img_rXXn"></p>
<ol start="3">
<li class="">Next, create a square and slowly try to center this element using the top and left rectangles as references. As you move this square around, you will see the lines indicating that you are at center to that referencing rectangle.</li>
</ol>
<p>This below gif shows the indicating lines appearing when the square's center is aligned with top rectangle center and the left rectangle center</p>
<p><img decoding="async" loading="lazy" alt="central snap 3" src="https://grida.co/blog/assets/images/central-snap-3-97b908baff305831c9c3521521724ab8.gif" width="925" height="443" class="img_rXXn"></p>
<p>The same threshold logic applies described above, say the left rectangle center is positioned at (20,100). This is a 2D position - (x,y) on the canvas. Now let's assume your square is positioned at (100, 75). To make the centers aligned, you would move the square along the y-axis. Say, you are at (100, 96), at this point, the square snaps to (100, 100). This is because internally we have threshold of 4 units.</p>]]></content>
        <author>
            <name>Ramu Narasinga</name>
            <uri>https://github.com/ramu-narasinga</uri>
        </author>
        <category label="Canvas" term="Canvas"/>
        <category label="UX" term="UX"/>
        <category label="Surface" term="Surface"/>
    </entry>
</feed>