first-commit
ci / Validate workspace (push) Has been cancelled
landing-page-ci / Validate landing page (push) Has been cancelled
landing-page-deploy / Deploy landing page (push) Has been cancelled
github-metrics / Generate repository metrics SVG (push) Has been cancelled
refresh-contributors-wall / Refresh contributors wall cache bust (push) Waiting to run
ci / Validate workspace (push) Has been cancelled
landing-page-ci / Validate landing page (push) Has been cancelled
landing-page-deploy / Deploy landing page (push) Has been cancelled
github-metrics / Generate repository metrics SVG (push) Has been cancelled
refresh-contributors-wall / Refresh contributors wall cache bust (push) Waiting to run
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
---
|
||||
name: blog-post
|
||||
description: |
|
||||
A long-form article / blog post — masthead, hero image placeholder,
|
||||
article body with figures and pull quotes, author byline, related posts.
|
||||
Use when the brief asks for "blog", "article", "post", "essay", or
|
||||
"case study".
|
||||
triggers:
|
||||
- "blog"
|
||||
- "blog post"
|
||||
- "article"
|
||||
- "essay"
|
||||
- "case study"
|
||||
- "newsletter"
|
||||
- "博客"
|
||||
- "文章"
|
||||
od:
|
||||
mode: prototype
|
||||
platform: desktop
|
||||
scenario: marketing
|
||||
featured: 11
|
||||
preview:
|
||||
type: html
|
||||
entry: index.html
|
||||
design_system:
|
||||
requires: true
|
||||
sections: [color, typography, layout, components]
|
||||
---
|
||||
|
||||
# Blog Post Skill
|
||||
|
||||
Produce a single long-form article page — editorial layout, no chrome.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. **Read the active DESIGN.md** (injected above). Lean into the typography
|
||||
tokens — long-form is 70% type, 20% image, 10% chrome.
|
||||
2. **Pick the topic** from the brief and write a real article — at least 600
|
||||
words across 4–6 H2 sections. No lorem ipsum.
|
||||
3. **Sections**, in order:
|
||||
- **Masthead** — small wordmark + 4–6 nav links, plain.
|
||||
- **Article header** — category eyebrow, headline (display token, large),
|
||||
deck (1–2 sentence subhead), author name + role + date.
|
||||
- **Hero image** — a 16:9 placeholder block using a DS-tinted gradient or
|
||||
solid fill (no external images). Add a 1-line caption underneath.
|
||||
- **Body** — alternating prose paragraphs with at least:
|
||||
- 1 pull quote (large display type, accent rule on the left).
|
||||
- 1 figure (image placeholder + caption).
|
||||
- 1 list (numbered or bulleted).
|
||||
- 1 inline blockquote.
|
||||
- **Author footer** — author avatar (initials in a circle), bio paragraph.
|
||||
- **Related** — 3 cards linking to other posts. Each card: tiny image
|
||||
block, title, 1-line excerpt, date.
|
||||
4. **Write** a single HTML document:
|
||||
- `<!doctype html>` through `</html>`, CSS inline.
|
||||
- Article body uses the DS body font, centered, max-width per DS layout
|
||||
rule (typically 680–720px).
|
||||
- Drop caps (`first-letter`) only if the DS mood is editorial / serif —
|
||||
skip on tech-y DSes.
|
||||
- `data-od-id` on the headline, hero, body, pull quote, related grid.
|
||||
5. **Self-check**:
|
||||
- Type hierarchy is unambiguous — H1 is clearly the headline; H2s are
|
||||
section dividers; pull quotes do not compete with H1.
|
||||
- Line length 60–75 chars for body prose.
|
||||
- Accent appears at most twice (eyebrow + pull-quote rule, or one link).
|
||||
- The page reads like a magazine, not a marketing landing.
|
||||
|
||||
## Output contract
|
||||
|
||||
Emit between `<artifact>` tags:
|
||||
|
||||
```
|
||||
<artifact identifier="post-slug" type="text/html" title="Article Title">
|
||||
<!doctype html>
|
||||
<html>...</html>
|
||||
</artifact>
|
||||
```
|
||||
|
||||
One sentence before the artifact, nothing after.
|
||||
@@ -0,0 +1,80 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Why we rewrote our sync engine in Rust — Filebase</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #fafaf9; --fg: #1c1b1a; --muted: #6b6964; --border: #e6e4e0;
|
||||
--accent: #c96442; --surface: #ffffff;
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
body { margin: 0; background: var(--bg); color: var(--fg); font: 18px/1.65 Georgia, 'Iowan Old Style', serif; }
|
||||
.wrap { max-width: 680px; margin: 0 auto; padding: 56px 28px 96px; }
|
||||
nav.top { font-family: -apple-system, system-ui, sans-serif; font-size: 13px; color: var(--muted); margin-bottom: 56px; }
|
||||
nav.top a { color: inherit; text-decoration: none; }
|
||||
.eyebrow { font-family: -apple-system, system-ui, sans-serif; font-size: 12px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--accent); margin-bottom: 14px; }
|
||||
h1 { font-size: clamp(36px, 5vw, 52px); line-height: 1.1; letter-spacing: -0.015em; margin: 0 0 20px; }
|
||||
.byline { font-family: -apple-system, system-ui, sans-serif; font-size: 14px; color: var(--muted); margin: 0 0 40px; display: flex; align-items: center; gap: 12px; }
|
||||
.avatar { width: 32px; height: 32px; border-radius: 50%; background: var(--accent); opacity: 0.18; }
|
||||
.lede { font-size: 22px; line-height: 1.5; color: var(--fg); margin: 0 0 40px; font-style: italic; }
|
||||
.hero-figure { aspect-ratio: 16/9; background: linear-gradient(135deg, var(--accent), #6b6964); border-radius: 8px; margin-bottom: 48px; opacity: 0.85; }
|
||||
p { margin: 24px 0; }
|
||||
p:first-of-type::first-letter { float: left; font-size: 64px; line-height: 0.9; padding: 6px 10px 0 0; font-weight: 600; color: var(--accent); }
|
||||
h2 { font-size: 28px; letter-spacing: -0.01em; margin: 56px 0 12px; line-height: 1.2; }
|
||||
blockquote { margin: 40px 0; padding: 0 32px; font-size: 24px; line-height: 1.4; color: var(--fg); border-left: 3px solid var(--accent); font-style: italic; }
|
||||
code { font-family: ui-monospace, monospace; background: var(--surface); border: 1px solid var(--border); padding: 1px 5px; border-radius: 4px; font-size: 0.85em; }
|
||||
pre { background: var(--surface); border: 1px solid var(--border); border-radius: 8px; padding: 16px 18px; overflow-x: auto; font: 14px/1.55 ui-monospace, monospace; }
|
||||
figure.numbers { font-family: -apple-system, system-ui, sans-serif; display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; margin: 40px -24px; padding: 28px 24px; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
|
||||
figure.numbers .stat .value { font-family: Georgia, serif; font-size: 38px; letter-spacing: -0.01em; line-height: 1; }
|
||||
figure.numbers .stat .label { font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; margin-top: 6px; }
|
||||
.endnote { font-family: -apple-system, system-ui, sans-serif; font-size: 13px; color: var(--muted); margin-top: 64px; padding-top: 24px; border-top: 1px solid var(--border); }
|
||||
.endnote a { color: var(--accent); text-decoration: none; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<article class="wrap" data-od-id="article">
|
||||
<nav class="top"><a href="#">← Filebase blog</a></nav>
|
||||
<div class="eyebrow">Engineering</div>
|
||||
<h1>Why we rewrote our sync engine in Rust</h1>
|
||||
<div class="byline">
|
||||
<div class="avatar"></div>
|
||||
<span>By Mira Hassan · April 22, 2026 · 8 min read</span>
|
||||
</div>
|
||||
<p class="lede">For two years our Go sync engine was good enough. Then video editors started joining the customer list, and the GC pauses we'd been politely ignoring turned into bug reports we couldn't ignore.</p>
|
||||
<div class="hero-figure" data-od-id="hero-figure"></div>
|
||||
|
||||
<p>The decision wasn't sudden. We'd been watching the GC pause distribution shift for six months before we admitted what the data was telling us. P50 latency was great. P99 was a horror movie. Customers syncing 30 GB of <code>.psd</code> files in active editing sessions were the ones writing in.</p>
|
||||
|
||||
<p>Rewriting an entire sync engine sounds like the kind of project a startup is told never to do. We did it anyway. Here's how it went, what surprised us, and the parts I'd do differently.</p>
|
||||
|
||||
<h2>The trigger: GC pauses we couldn't fix</h2>
|
||||
<p>Go's garbage collector is brilliant. It is also, fundamentally, a tradeoff. Our hot path allocated short-lived buffer slices on every block diff — and at our scale, on a heavy uploader, the collector ran often enough that the P99 pause crept past 50ms.</p>
|
||||
|
||||
<p>We tried the usual fixes: pooling buffers with <code>sync.Pool</code>, tuning <code>GOGC</code>, reducing allocations in the merge path. They each helped a little. None of them got us under 20ms, and the customers we cared about needed under 5.</p>
|
||||
|
||||
<blockquote>"We can't fix this in Go. We can fix it in something without a GC."</blockquote>
|
||||
|
||||
<p>Our staff engineer Sasha said this in a meeting in October. He was right. The question wasn't whether to leave Go. It was what to leave it for, and how much we could keep.</p>
|
||||
|
||||
<h2>What we kept; what we threw out</h2>
|
||||
<p>The CLI stayed in Go. The control plane stayed in Go. The bit that does block-level diffing in a hot loop on a customer's laptop — that became Rust. The boundary became a single FFI surface with a small, opinionated protocol.</p>
|
||||
|
||||
<figure class="numbers">
|
||||
<div class="stat"><div class="value">38ms → 4ms</div><div class="label">P99 sync latency</div></div>
|
||||
<div class="stat"><div class="value">62%</div><div class="label">Memory drop</div></div>
|
||||
<div class="stat"><div class="value">11 weeks</div><div class="label">From RFC to ship</div></div>
|
||||
</figure>
|
||||
|
||||
<p>The numbers above are real and from production. They are also misleading without context: the Rust port doesn't just remove the GC, it also removes a layer of abstraction we'd been carrying since the Go MVP.</p>
|
||||
|
||||
<h2>What I'd do differently</h2>
|
||||
<p>One thing: the FFI boundary. We chose <code>cgo</code> for symmetry — Go calling Rust feels right when you already have Go everywhere. But the binding ceremony is brittle, and we ate two production incidents from string lifetime mistakes before we wrote a wrapper layer that handled them once.</p>
|
||||
|
||||
<p>If I were starting today, I'd reach for <code>uniffi</code> or generate the bindings from a schema. The lessons isn't <em>don't use cgo</em>; it's <em>treat the boundary like an external API the moment you cross language families</em>.</p>
|
||||
|
||||
<div class="endnote">Filebase is hiring engineers who like writing this kind of post. <a href="#">See open roles →</a></div>
|
||||
</article>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user