Part of unPaper HTML
The layout grammar
One attribute, data-unpaper-lay, turns a slide’s body into a CSS grid of regions. Each region holds an ordinary block — text, a list, a chart, a table — and each converts to a native PowerPoint object at its measured position. It is a compact, composable way to describe many layouts with almost no markup.
1The idea: a slide body is a grid
Most slides stack their content top-to-bottom. To place things side by side instead, give a container data-unpaper-lay with a grid name. The container becomes a CSS grid; its direct children are the regions, filled in order. That is the entire mental model.
<div data-unpaper-lay="2l"> <div> …this is region 1 (the wide left)… </div> <div> …this is region 2 (the narrow right)… </div> </div>
Under the hood it is plain CSS Grid — nothing exotic. The grammar just names a handful of useful grid templates so they can be selected with one token instead of hand-written CSS each time:
[data-unpaper-lay="2l"] { display: grid; grid-template-columns: 7fr 5fr; gap: 42px }2The grids
Six grids cover the great majority of slide layouts. Each is just a column (and sometimes row) template:
data-unpaper-lay="2"1fr 1frTwo equal columns.
data-unpaper-lay="2l"7fr 5frWide left, narrow right — the classic “point beside its chart”.
data-unpaper-lay="2r"5fr 7frNarrow left, wide right.
data-unpaper-lay="3"1fr 1fr 1frThree equal columns (e.g. three drivers).
data-unpaper-lay="rail"4fr 8frA narrow label rail beside the main content.
data-unpaper-lay="quad"1fr 1frA 2×2 matrix — four regions.
3What goes in a region
Anything. A region is an ordinary element, so you drop the same blocks you would use anywhere — they keep all their native-conversion behaviour:
- • Text and headings → native text boxes
- •
<ul>/<ol>→ real bullet paragraphs - • a chart (
<svg>+data-unpaper-chart) → a native, data-editable chart - • a
<table>→ a native, editable table - • cards, stats, quotes → native shapes and text
4A worked example
The most common consulting layout — a written point beside the chart that proves it — is just 2l with text in the left region and a chart in the right:
<section class="slide">
<h2 class="title">Cost per deck fell as volume rose</h2>
<div data-unpaper-lay="2l">
<div>
<p>Unit economics inverted once the rules moved into the file.</p>
<ul><li>Fixed cost amortised</li><li>No per-seat drag</li></ul>
</div>
<div data-unpaper-chart='{"type":"bar","categories":["Q1","Q2","Q3"],
"series":[{"name":"Cost","values":[8,5,3]}],"axis":{"min":0,"max":10}}'>
<svg viewBox="0 0 400 260"> …bars… </svg>
</div>
</div>
</section>That converts to four native PowerPoint objects — the title, a text box, a bullet list, and a real chart — each landing exactly where the grid put it.
5How it converts (no decoder)
There is nothing to “decompile.” The converter measures the browser’s computed layout, so by the time it reads the page the grid has already resolved every region to an absolute position and size. Each region’s blocks are then re-created as native objects at those measured coordinates. The grammar needs no special handling in the converter — it is ordinary CSS that happens to be named.
6Why a grammar (not more templates)
The alternative is to ship a fixed set of pre-built layout slides. That caps variety and is expensive: every layout is a whole example slide an AI has to be shown. The grammar inverts it — a few named grids plus the block vocabulary is a dictionary of a few hundred tokens, taught once, from which an AI composes combinatorially many layouts. Fewer tokens, more layouts, and every result still lowers cleanly to native PowerPoint.
The grammar is one axis of the system; the other is the skin (colour and type). They are independent: any grid renders in any skin. A deck type(“Consulting”, “Design”) is simply a curated set of grids and compositions — a pack — laid over the same grammar.
In short: data-unpaper-lay = pick a grid; its children = regions; fill each region with any block; every region becomes a native, editable PowerPoint object. Browse the argument patterns built from these grids in the pattern library, or see the full format on the specification page.