SilkLayout
SilkLayout is a Ruby-native HTML/CSS layout engine that renders documents to PDF.
The long-term goal is to make PDF generation feel natural inside Ruby apps without
delegating layout to a browser engine. The project is currently on the 0.2
pre-release track: useful for experimentation, regression testing, and early
document rendering, but not yet 1.0 or browser-spec complete.
Current Status
SilkLayout is pre-1.0, so support is described as current, partial, or unsupported rather than as a browser compatibility promise.
| Area | 0.2 status | Notes |
|---|---|---|
| HTML parsing | Current | Nokogiri document parsing, text nodes, attributes, inline styles, <style> blocks, linked stylesheets, and base URLs. |
| CSS cascade | Current | Crass parsing, selector matching, specificity, inheritance, inline styles, and !important; unsupported selectors fail closed. |
| Block and inline layout | Current | Block stacking, inline text measurement, line wrapping, whitespace normalization, margins, padding, borders, width, and height. |
| Flex layout | Partial | Rows, columns, reverse directions, wrapping, gaps, grow, shrink, basis, justify, and align basics; full flexbox parity is still out of scope. |
| CSS values and colors | Partial / 0.2 target | Pixel lengths are current; 0.2 tracks percent and calc() lengths for common box values plus named, hex, rgb(), rgba(), hsl(), hsla(), and transparent colors. |
| PDF painting | Partial | Text, borders, border colors, and simple backgrounds are current; 0.2 tracks local raster image painting and print page sizing. |
| Images | Partial / 0.2 target | Local image loading, intrinsic sizing, and PDF smoke coverage are planned for 0.2; remote images, SVG, animated formats, object-fit, and object-position are unsupported. |
| Visual regression | Current | Chromium reference PDF rendering with PNG comparison; generated artifacts are written to tmp/visual/. |
| Pagination and fragmentation | Unsupported | Page breaks, repeated headers/footers, and content overflow across pages are before-1.0 work. |
| Advanced layout | Unsupported | CSS Grid, positioning, floats, tables, and list markers are not implemented yet. |
| Advanced painting | Unsupported | Border radius, shadows, gradients, background images, filters, and transforms are not implemented yet. |
Example-Driven Roadmap
The next rendering milestones are anchored to realistic document families rather
than abstract CSS checklists. The comparison fixtures in tmp/pdf_compare/
currently show a browser/Chromium render next to SilkLayout output for each
target. They are temporary evaluation artifacts, but the document types below are
the product goals they represent.
| Goal document | Current fit | Feature work needed |
|---|---|---|
| Plain invoices and receipt-like statements | Closest near-term target. Simple text, spacing, borders, page sizing, and gray bands are mostly in range. | Table layout or robust table-like rows; reliable numeric column alignment; better font-weight handling; footer placement; tighter support for absolute/relative positioning used by headers and payment blocks. |
| Colorful invoices and branded receipts | Partially reachable when simplified, but decorative layout falls apart quickly. | Stable flex for document components; border radius; layered backgrounds; background images; gradients; better positioned panels; custom or mapped font weights; table row styling including alternating fills. |
| Government notices and simple pamphlets | Good medium-term target for one-page notices; multi-page publications remain limited. | Multi-column layout; pagination and fragmentation; repeated headers/footers; page counters; column rules; improved text sizing/leading parity; better page-margin and print CSS handling. |
| Posters and flyers | Useful stress target, but not visually faithful yet. | Absolute positioning; transforms/rotation; border radius and circles; dashed borders; SVG/vector image support; background images/textures; object fitting and image clipping; richer z-index/layering. |
| Brochures and park/map guides | Long-range target because these combine nearly every hard print feature. | Multi-page spreads; CSS Grid; floats; positioned overlays; clipping/masking; remote and local raster image scaling; SVG/vector paths; map/icon rendering; gradients and blend-like background effects; robust small-text layout. |
Cross-cutting engine work that serves all of these goals:
- Stabilize font resolution and weight/style mapping so common CSS such as
font-weight: boldnever crashes PDF rendering. - Make partial flexbox behavior predictable for document layout, then add regression fixtures for invoice headers, side panels, and totals blocks.
- Add a first-class table layout path before treating real invoices or receipts as supported.
- Add paged-media primitives: page breaks, content overflow across pages, repeated headers/footers, and page counters.
- Expand the painter beyond rectangular fills and straight borders: rounded corners, dashed borders, gradients, background images, and image clipping.
- Support SVG and remote images so real logos, badges, maps, QR codes, and brochure artwork can be rendered without pre-flattening.
- Keep browser-vs-SilkLayout visual comparison fixtures for each goal document and graduate them into the visual regression suite as features land.
Installation
Add the gem to your bundle once released:
gem "silk_layout"
For local development from this repository:
bundle install
Usage
require "silk_layout"
html = <<~HTML
<!doctype html>
<html>
<head>
<style>
body { font-family: Helvetica; margin: 0; }
.row {
display: flex;
gap: 16px;
padding: 16px;
border: 2px solid black;
}
.item {
width: 80px;
padding: 8px;
border: 1px solid blue;
background: lightblue;
}
</style>
</head>
<body>
<div class="row">
<div class="item">One</div>
<div class="item">Two</div>
</div>
</body>
</html>
HTML
SilkLayout.render_document(html, "out.pdf")
Documentation
The documentation site lives in docs/. It includes the project
goal, current support matrix, before-1.0 roadmap, and Chromium-vs-SilkLayout
screenshots from the visual regression suite.
Development
Run the full local gate:
bundle exec rake
Run tests only:
bundle exec rake test
Run visual regression tests:
BROWSER_PATH=/path/to/chrome bundle exec ruby -Ilib:test test/visual_test.rb
Run lint:
bundle exec standardrb
Run a single test file:
bundle exec ruby -Ilib:test test/layout/flex_layout_test.rb
Run a single visual fixture:
BROWSER_PATH=/path/to/chrome bundle exec ruby -Ilib:test test/visual_test.rb -n test_visual_flex_row_basic
Build and install the gem into a temporary GEM_HOME, then require it and render
a smoke PDF from the installed package:
bundle exec rake package:smoke
Visual regression tests require Chromium or Chrome plus PDF-to-PNG tooling such
as Poppler or ImageMagick. Generated visual artifacts are written to
tmp/visual/.
Releasing
SilkLayout releases use the checked-in release script:
DRY_RUN=1 script/release
script/release
The script must be run from a clean, up-to-date main branch after the release
PR is merged. It installs dependencies, runs the test/lint/package smoke gate,
publishes the gem through Bundler's release task, and creates a GitHub release
from the matching CHANGELOG.md section.
This gem is still pre-1.0. Before a public 1.0 release, the project should stabilize the supported CSS surface, add pagination, improve visual parity, and document compatibility promises.
Contributing
Contributions are welcome while the engine is young. Please read
CONTRIBUTING.md and open issues or PRs with focused examples
and, where possible, visual regression fixtures.
Security
Please report security issues privately using the process in
SECURITY.md.
License
SilkLayout is available under the MIT License. See LICENSE.