render-tag 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,7 +6,7 @@ Render HTML rich text onto canvas with the 2D API. No SVG, no `foreignObject`
6
6
 
7
7
  ## Why
8
8
 
9
- Browsers can render HTML into canvas via SVG `foreignObject`, but it's slow (~100ms) and inconsistent across browsers. `render-tag` parses your HTML, resolves styles via `getComputedStyle`, then lays out and draws everything with canvas 2D calls. It's **10-60x faster** than SVG-based approaches.
9
+ When you need rich text as part of a canvas design editors, image export, canvas-based apps the standard SVG `foreignObject` approach is slow. `render-tag` parses your HTML, resolves styles with a built-in CSS parser, then lays out and draws everything with pure canvas 2D calls. It's significantly faster than SVG-based approaches.
10
10
 
11
11
  By design, render-tag focuses on **rich text only** — paragraphs, headings, lists, tables, inline formatting. It is not designed for interactive elements (buttons, inputs, iframes) or complex HTML layouts. This focus is what makes it fast.
12
12
 
@@ -109,7 +109,7 @@ All-in-one: compute layout and draw in a single call.
109
109
  | `ctx` | `CanvasRenderingContext2D` | — | Existing context to draw onto (no resizing/scaling) |
110
110
  | `canvas` | `HTMLCanvasElement \| OffscreenCanvas` | created | Target canvas element (mutually exclusive with `ctx`) |
111
111
  | `pixelRatio` | `number` | `devicePixelRatio` | Device pixel ratio for sharp rendering |
112
- | `accuracy` | `'balanced' \| 'performance'` | `'balanced'` | `'balanced'` uses DOM probes for cross-browser line height accuracy. `'performance'` uses pure canvas API only. |
112
+ | `accuracy` | `'balanced' \| 'performance'` | `'performance'` | `'balanced'` uses DOM probes for cross-browser line height accuracy. `'performance'` uses pure canvas API only. |
113
113
 
114
114
  Returns `{ canvas, height, layoutRoot, lines }`.
115
115
 
@@ -124,7 +124,7 @@ Compute layout without rendering. Use when you need to measure content or render
124
124
  | `html` | `string` | *required* | HTML string (include `<style>` tags for CSS) |
125
125
  | `width` | `number` | *required* | Layout width in CSS pixels |
126
126
  | `height` | `number` | auto | Fixed height (auto-sized from content if omitted) |
127
- | `accuracy` | `'balanced' \| 'performance'` | `'balanced'` | Measurement accuracy mode |
127
+ | `accuracy` | `'balanced' \| 'performance'` | `'performance'` | Measurement accuracy mode |
128
128
 
129
129
  Returns `{ layoutRoot, height, lines }`.
130
130
 
@@ -176,11 +176,16 @@ drawLayout({ layout: result, width: 400, ctx: offscreenCtx });
176
176
  - `overflow-wrap: break-word`
177
177
  - Soft hyphens (`&shy;`)
178
178
 
179
- ## Cross-browser consistency
179
+ ## Recommended CSS reset
180
180
 
181
- The library targets Chrome as the primary browser. For consistent rendering across Chrome and Firefox, add these CSS rules to your input:
181
+ For best consistency between DOM and canvas rendering, add these CSS rules to your input HTML:
182
182
 
183
183
  ```css
184
+ /* Normalize monospace font size.
185
+ Chrome reduces <code>/<pre> font-size via a UA quirk that canvas can't replicate.
186
+ This makes DOM and canvas render code at the same size. */
187
+ code, pre, kbd, samp { font-size: inherit; }
188
+
184
189
  /* Suppress Firefox's ::marker extra line height (~1.5px per list item).
185
190
  render-tag draws list markers itself, so this loses nothing visually. */
186
191
  li::marker { content: none; font-size: 0; line-height: 0; }
@@ -192,29 +197,28 @@ li::marker { content: none; font-size: 0; line-height: 0; }
192
197
  .has-emoji { font-kerning: none; }
193
198
  ```
194
199
 
195
- With `accuracy: 'balanced'` (the default), the library uses hidden DOM probes to match Firefox's actual line box heights. With `accuracy: 'performance'`, the CSS above becomes especially important for Firefox consistency.
200
+ The default `accuracy: 'performance'` uses pure canvas API measurements with no DOM touches, producing consistent canvas output across browsers. Use `accuracy: 'balanced'` if you need each browser's canvas output to match its own native DOM rendering more closely (at the cost of cross-browser canvas consistency).
196
201
 
197
- ## How it works
202
+ ## Design decisions
198
203
 
199
- 1. **Parse** HTML with `DOMParser`
200
- 2. **Resolve styles** via hidden DOM + `getComputedStyle` (CSS cascade for free)
201
- 3. **Layout** with canvas `measureText` (block flow, inline wrapping, margin collapsing)
202
- 4. **Render** with canvas 2D API (`fillText`, `fillRect`, `strokeText`, etc.)
204
+ ### Chrome-first rendering
203
205
 
204
- Style resolution uses a hidden DOM element with `getComputedStyle` to get the full CSS cascade. Layout and rendering are done entirely with the canvas 2D API. Optional DOM probes (`accuracy: 'balanced'`) improve cross-browser accuracy for line heights and mixed-font wrapping.
206
+ Chrome is the primary target browser. When a rendering choice must favor one browser over another, Chrome wins. All development and CI testing defaults to Chromium.
205
207
 
206
- ## Development
208
+ ### Cross-browser consistency over per-browser accuracy
207
209
 
208
- ```bash
209
- npm install
210
- npx playwright install chromium
210
+ The library prioritizes producing **the same canvas output in every browser** over matching each browser's native DOM rendering pixel-for-pixel. If Chrome and Firefox render a `<p>` slightly differently in DOM, our canvas output should match Chrome's version in both browsers — not adapt to each browser's quirks.
211
211
 
212
- # Run visual comparison demo
213
- npm run dev
212
+ In other words: identical canvas output everywhere > perfect DOM fidelity per browser. Users expect the same visual result regardless of which browser their audience uses.
214
213
 
215
- # Run tests (60 cases, Chromium via Playwright)
216
- npm test
217
- ```
214
+ ## How it works
215
+
216
+ 1. **Parse** HTML with `DOMParser`
217
+ 2. **Resolve styles** via built-in CSS resolver (selector matching, cascade, inheritance — no DOM insertion)
218
+ 3. **Layout** with canvas `measureText` (block flow, inline wrapping, margin collapsing)
219
+ 4. **Render** with canvas 2D API (`fillText`, `fillRect`, `strokeText`, etc.)
220
+
221
+ Style resolution uses a built-in CSS parser and resolver that handles selectors, specificity, cascade, and inheritance without inserting HTML into the document. Layout and rendering are done entirely with the canvas 2D API.
218
222
 
219
223
  ## License
220
224
 
@@ -0,0 +1,10 @@
1
+ import type { StyledNode } from './types.js';
2
+ /**
3
+ * Resolve styles for a DOM tree without inserting into the document.
4
+ * Parses CSS rules, matches selectors, resolves cascade + inheritance.
5
+ */
6
+ export declare function resolveStylesFromCSS(fragment: DocumentFragment, css: string, containerWidth: number): {
7
+ tree: StyledNode;
8
+ cleanup: () => void;
9
+ };
10
+ //# sourceMappingURL=css-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"css-resolver.d.ts","sourceRoot":"","sources":["../src/css-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,UAAU,EAAE,MAAM,YAAY,CAAC;AAm4B5D;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,gBAAgB,EAC1B,GAAG,EAAE,MAAM,EACX,cAAc,EAAE,MAAM,GACrB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,CAiZ3C"}