kittyhtml 0.2.1 → 0.3.0

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
@@ -2,7 +2,7 @@
2
2
 
3
3
  Render HTML to an image and display it inline in a graphics-capable terminal (Kitty, WezTerm, Ghostty, iTerm2).
4
4
 
5
- This is **not** a headless browser. It's a thin CLI that pipes HTML through [DropFlow](https://github.com/chearon/dropflow) (a real CSS layout engine, no JS/no Chromium) to a PNG, then emits the Kitty graphics protocol or iTerm2 inline-image protocol on stdout.
5
+ This is **not** a headless browser. It's a thin CLI that pipes HTML through [Blitz](https://github.com/DioxusLabs/blitz) a Rust HTML/CSS engine (Stylo + Taffy + Parley + Vello) to a PNG, then emits the Kitty graphics protocol or iTerm2 inline-image protocol on stdout. Headless CPU rasterization, no GPU required.
6
6
 
7
7
  Built for AI agents that have something nice to show you — a styled report, a small table, a card — without taking over your screen with a browser.
8
8
 
@@ -18,7 +18,7 @@ Or one-shot, no install:
18
18
  npx kittyhtml --demo
19
19
  ```
20
20
 
21
- Requires Node 20+. Pulls in [`@napi-rs/canvas`](https://www.npmjs.com/package/@napi-rs/canvas) (prebuilt native binary, no compile step) and `dropflow`. Two deps total, ~90 KB tarball.
21
+ Requires Node 20+. The native renderer ships as a prebuilt N-API binary per platform (macOS arm64, Linux x64). No Rust toolchain required at install time.
22
22
 
23
23
  ## Use
24
24
 
@@ -49,32 +49,13 @@ const png = await renderHtml('<h1>hello</h1>', { width: 400, scale: 2 });
49
49
  process.stdout.write(encode(png, 'kitty'));
50
50
  ```
51
51
 
52
- ## Releasing
53
-
54
- Releases publish via GitHub Actions using npm trusted publishing (OIDC, no long-lived token). To cut a release:
55
-
56
- ```sh
57
- npm version patch # or minor / major — bumps package.json and tags
58
- git push --follow-tags
59
- ```
60
-
61
- The `Publish to npm` workflow fires on the `v*` tag, exchanges a GitHub OIDC token with npm for a one-shot publish token, and publishes with `--provenance` so each release carries a Sigstore attestation linking it back to the source commit.
62
-
63
- ## CSS caveats
64
-
65
- DropFlow implements a serious subset of CSS but isn't a browser. Things to know when writing HTML for it (as of DropFlow 0.6.x):
52
+ ## CSS
66
53
 
67
- - Use the longhand `background-color`, not the `background` shorthand.
68
- - `max-width` / `min-width` aren't supported yet — use `width`.
69
- - `list-style` markers don't render; use `&bull;` or numbers inline.
70
- - `border-radius`, `box-shadow`, `transform`, and `position: absolute/fixed` aren't supported yet.
71
- - Body background doesn't propagate to the canvas — set the background on a wrapper element, or pass `--background <css>` to fill the canvas.
72
-
73
- See the [DropFlow README](https://github.com/chearon/dropflow#supported-css-rules) for the full support matrix.
54
+ Blitz implements a serious subset of CSS — flexbox, grid, `border-radius`, `box-shadow`, web fonts, `<img>` tags, `background:` shorthand, `max-width`, native `<ul>` bullets, the things you'd expect. It's pre-alpha for general embedding but works well for our render-once use case. The full status matrix is at [the Blitz repo](https://github.com/DioxusLabs/blitz).
74
55
 
75
56
  ## Fonts
76
57
 
77
- `Noto Sans` (regular, bold, italic, bold-italic) and `Noto Sans Mono` (regular, bold) ship inside the package as latin-subset TTFs (~160 KB total). No CDN fetch on first run; works offline. Reference them in HTML with `font-family: 'Noto Sans', sans-serif` and `font-family: 'Noto Sans Mono', monospace`.
58
+ `Noto Sans` (regular, bold, italic, bold-italic) and `Noto Sans Mono` (regular, bold) are baked into the native binary as latin-subset TTFs. No system font dependency; renders identically across macOS and Linux. Reference them in HTML with `font-family: 'Noto Sans', sans-serif` and `font-family: 'Noto Sans Mono', monospace`.
78
59
 
79
60
  ## Claude Code skill
80
61
 
@@ -85,7 +66,7 @@ mkdir -p ~/.claude/skills
85
66
  cp -r "$(npm root -g)/kittyhtml/skill/kittyhtml" ~/.claude/skills/
86
67
  ```
87
68
 
88
- Then in any Claude Code session: *"give me this report as kittyhtml"* — the agent will generate DropFlow-compatible HTML and pipe it through this CLI. The skill is narrow on purpose; it only triggers on those keywords.
69
+ Then in any Claude Code session: *"give me this report as kittyhtml"* — the agent will generate HTML and pipe it through this CLI. The skill is narrow on purpose; it only triggers on those keywords.
89
70
 
90
71
  ## How agents should use it
91
72
 
@@ -96,3 +77,14 @@ echo "$HTML" | kittyhtml --width 700 --scale 2
96
77
  ```
97
78
 
98
79
  The image is one frame in the scrollback — no popups, no new windows.
80
+
81
+ ## Releasing
82
+
83
+ Releases publish via GitHub Actions using npm trusted publishing (OIDC, no long-lived token). The native binary is cross-compiled per platform and published as `@kittyhtml/native-*` packages, then the umbrella `kittyhtml` package selects the right one at install time.
84
+
85
+ ```sh
86
+ npm version patch # or minor / major — bumps package.json and tags
87
+ git push --follow-tags
88
+ ```
89
+
90
+ The `Publish to npm` workflow fires on the `v*` tag, builds the native binaries on the matrix, and publishes everything with `--provenance`.
@@ -0,0 +1,44 @@
1
+ // Platform-specific loader for the kittyhtml native renderer.
2
+ // Selects the right prebuilt .node file based on process.platform and process.arch.
3
+ //
4
+ // When packaged for npm, the .node files live in platform-specific subpackages
5
+ // (npm/darwin-arm64, npm/linux-x64-gnu, etc.) and are resolved via optionalDependencies.
6
+ // During local development, the build sits next to this file.
7
+
8
+ const { existsSync } = require('node:fs');
9
+ const { join } = require('node:path');
10
+
11
+ const platform = process.platform;
12
+ const arch = process.arch;
13
+ const libc = (() => {
14
+ if (platform !== 'linux') return '';
15
+ // Best-effort: assume gnu unless musl is hinted. CI builds will use named
16
+ // subpackages so this guess only matters during local dev on Linux.
17
+ try {
18
+ const { familySync, GLIBC, MUSL } = require('detect-libc');
19
+ const fam = familySync();
20
+ return fam === MUSL ? '-musl' : '-gnu';
21
+ } catch {
22
+ return '-gnu';
23
+ }
24
+ })();
25
+
26
+ const target = `${platform}-${arch}${libc}`;
27
+ const localBinary = join(__dirname, `kittyhtml-native.${target}.node`);
28
+
29
+ let mod;
30
+ if (existsSync(localBinary)) {
31
+ mod = require(localBinary);
32
+ } else {
33
+ try {
34
+ mod = require(`kittyhtml-${target}`);
35
+ } catch (err) {
36
+ throw new Error(
37
+ `kittyhtml: no prebuilt native binary for ${target}. ` +
38
+ `Tried ${localBinary} and the kittyhtml-${target} package. ` +
39
+ `If you're on an unsupported platform, please file an issue.`,
40
+ );
41
+ }
42
+ }
43
+
44
+ module.exports = mod;
@@ -1,35 +1,48 @@
1
1
  <!DOCTYPE html>
2
2
  <html>
3
- <body style="font-family: 'Noto Sans', sans-serif; margin: 0; padding: 0; background-color: #f4f4f5; color: #18181b;">
4
- <div style="background-color: #f4f4f5; padding: 32px 0;">
5
- <div style="width: 720px; margin: 0 auto;">
3
+ <body style="font-family: 'Noto Sans', sans-serif; margin: 0; padding: 0; background: #f4f4f5; color: #18181b;">
4
+ <div style="max-width: 720px; margin: 0 auto; padding: 32px 24px;">
6
5
 
7
- <div style="background-color: #ffffff; border: 1px solid #e4e4e7; padding: 28px 32px;">
8
- <div style="font-size: 11px; color: #71717a; font-weight: 700;">KITTYHTML &middot; DEMO</div>
9
- <div style="font-size: 26px; font-weight: 700; padding-top: 6px;">HTML, in your terminal.</div>
10
- <div style="font-size: 14px; color: #52525b; padding-top: 4px;">Rendered by DropFlow, displayed via the Kitty graphics protocol.</div>
6
+ <div style="background: #ffffff; border-radius: 16px; box-shadow: 0 1px 3px rgba(0,0,0,0.06); padding: 32px;">
7
+ <div style="font-size: 11px; color: #71717a; font-weight: 700; letter-spacing: 1.2px;">KITTYHTML &middot; v0.3</div>
8
+ <h1 style="font-size: 28px; margin: 6px 0 4px; font-weight: 700;">HTML, in your terminal.</h1>
9
+ <p style="margin: 0; font-size: 14px; color: #52525b;">Rendered by Blitz, displayed via the Kitty graphics protocol.</p>
11
10
 
12
- <div style="padding-top: 18px; font-size: 14px; line-height: 1.6;">
13
- No Chromium, no headless browser. Just CSS layout to a PNG, base64-streamed into your terminal as one inline image. Useful when an AI agent has something to show you that reads better as a page than as plain text.
14
- </div>
11
+ <p style="font-size: 14px; line-height: 1.6; margin: 20px 0 0;">
12
+ No Chromium, no headless browser. Just a Rust + Vello renderer producing a PNG, base64-streamed into your terminal as one inline image. Useful when an AI agent has something to show you that reads better as a page than as plain text.
13
+ </p>
14
+
15
+ <h2 style="font-size: 15px; margin: 24px 0 8px;">What this is good for</h2>
16
+ <ul style="font-size: 14px; line-height: 1.7; margin: 0; padding-left: 22px;">
17
+ <li>Inline reports, tables, and summaries from agents.</li>
18
+ <li>Quick previews of email or marketing copy.</li>
19
+ <li>Lightweight diagrams that compose better in HTML than ASCII.</li>
20
+ </ul>
15
21
 
16
- <div style="font-size: 14px; font-weight: 700; padding-top: 22px; padding-bottom: 6px;">What this is good for</div>
17
- <div style="font-size: 14px; line-height: 1.7; padding-left: 4px;">
18
- <div>&bull;&nbsp;&nbsp;Inline reports, tables, and summaries from agents.</div>
19
- <div>&bull;&nbsp;&nbsp;Quick previews of email or marketing copy.</div>
20
- <div>&bull;&nbsp;&nbsp;Lightweight diagrams that compose better in HTML than in ASCII.</div>
22
+ <div style="display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 10px; margin-top: 22px;">
23
+ <div style="background: #dbeafe; border-radius: 8px; padding: 12px 14px; font-size: 13px;">
24
+ <div style="font-weight: 700; font-size: 11px; color: #1e40af; letter-spacing: 0.8px;">FLEXBOX</div>
25
+ <div style="margin-top: 2px;">supported</div>
26
+ </div>
27
+ <div style="background: #fef3c7; border-radius: 8px; padding: 12px 14px; font-size: 13px;">
28
+ <div style="font-weight: 700; font-size: 11px; color: #92400e; letter-spacing: 0.8px;">GRID</div>
29
+ <div style="margin-top: 2px;">supported</div>
30
+ </div>
31
+ <div style="background: #d1fae5; border-radius: 8px; padding: 12px 14px; font-size: 13px;">
32
+ <div style="font-weight: 700; font-size: 11px; color: #065f46; letter-spacing: 0.8px;">RADIUS</div>
33
+ <div style="margin-top: 2px;">supported</div>
34
+ </div>
21
35
  </div>
22
36
 
23
- <div style="margin-top: 20px; background-color: #18181b; color: #e4e4e7; padding: 14px 16px; font-family: 'Noto Sans Mono', monospace; font-size: 13px;">
37
+ <div style="margin-top: 22px; background: #18181b; color: #e4e4e7; padding: 14px 18px; border-radius: 10px; font-family: 'Noto Sans Mono', monospace; font-size: 13px;">
24
38
  $ echo '&lt;h1&gt;hi&lt;/h1&gt;' | kittyhtml
25
39
  </div>
26
40
 
27
- <div style="font-size: 12px; color: #71717a; padding-top: 18px;">
41
+ <p style="font-size: 12px; color: #71717a; margin: 18px 0 0;">
28
42
  Tip: try <span style="font-family: 'Noto Sans Mono', monospace; color: #18181b;">--scale 2</span> for sharper text on high-DPI displays.
29
- </div>
43
+ </p>
30
44
  </div>
31
45
 
32
46
  </div>
33
- </div>
34
47
  </body>
35
48
  </html>
Binary file
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "kittyhtml",
3
- "version": "0.2.1",
4
- "description": "Render HTML to an image and display it inline in Kitty/iTerm2-capable terminals. No browser — CSS layout via DropFlow.",
3
+ "version": "0.3.0",
4
+ "description": "Render HTML to an image and display it inline in Kitty/iTerm2-capable terminals. No browser — Rust + Blitz layout, headless CPU rasterization.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "kittyhtml": "./src/cli.js"
@@ -14,20 +14,24 @@
14
14
  },
15
15
  "files": [
16
16
  "src",
17
- "assets/fonts",
17
+ "crates/renderer/index.cjs",
18
18
  "skill",
19
19
  "examples/demo.html",
20
- "README.md"
20
+ "examples/demo.png",
21
+ "README.md",
22
+ "LICENSE"
21
23
  ],
22
24
  "engines": {
23
25
  "node": ">=20"
24
26
  },
25
- "scripts": {
26
- "demo": "node src/cli.js --demo"
27
+ "optionalDependencies": {
28
+ "kittyhtml-darwin-arm64": "0.3.0",
29
+ "kittyhtml-darwin-x64": "0.3.0",
30
+ "kittyhtml-linux-x64-gnu": "0.3.0"
27
31
  },
28
- "dependencies": {
29
- "@napi-rs/canvas": "^1.0.0",
30
- "dropflow": "^0.6.1"
32
+ "scripts": {
33
+ "demo": "node src/cli.js --demo",
34
+ "build": "napi build --release --platform --manifest-path crates/renderer/Cargo.toml --package-json-path package.json --output-dir crates/renderer"
31
35
  },
32
36
  "keywords": [
33
37
  "kitty",
@@ -37,7 +41,8 @@
37
41
  "html",
38
42
  "css",
39
43
  "render",
40
- "dropflow",
44
+ "blitz",
45
+ "vello",
41
46
  "image",
42
47
  "cli",
43
48
  "ai-agent",
@@ -52,5 +57,16 @@
52
57
  "bugs": {
53
58
  "url": "https://github.com/kkukshtel/kittyhtml/issues"
54
59
  },
55
- "homepage": "https://github.com/kkukshtel/kittyhtml#readme"
60
+ "homepage": "https://github.com/kkukshtel/kittyhtml#readme",
61
+ "devDependencies": {
62
+ "@napi-rs/cli": "^3.6.2"
63
+ },
64
+ "napi": {
65
+ "binaryName": "kittyhtml-native",
66
+ "targets": [
67
+ "x86_64-apple-darwin",
68
+ "aarch64-apple-darwin",
69
+ "x86_64-unknown-linux-gnu"
70
+ ]
71
+ }
56
72
  }
@@ -9,9 +9,9 @@ The user has asked for output as **kittyhtml** or **khtml** — they want the re
9
9
 
10
10
  ## What to do
11
11
 
12
- 1. **Verify the tool is installed**: `command -v kittyhtml` (one-time check per session). If missing, tell the user to run `npm install -g kittyhtml` and stop.
12
+ 1. **Verify the tool is installed**: `command -v kittyhtml`. If missing, tell the user `npm install -g kittyhtml` and stop.
13
13
 
14
- 2. **Generate HTML** that represents the content the user asked about — a styled page, card, table, summary, or whatever fits the request. Keep it focused; the rendered image should fit on one screen.
14
+ 2. **Generate HTML** that represents the content the user asked about — a styled page, card, table, summary. Keep it focused; the rendered image should fit on one screen.
15
15
 
16
16
  3. **Pipe it through the CLI**:
17
17
  ```sh
@@ -21,33 +21,52 @@ The user has asked for output as **kittyhtml** or **khtml** — they want the re
21
21
  HTML
22
22
  ```
23
23
 
24
- Use `--scale 2` for crisp text on retina/HiDPI. Use `--width 600`–`800` for content that should feel "page-sized." Use a smaller width (`--width 400`) for compact card-like output.
24
+ Use `--scale 2` for crisp text on retina/HiDPI. Pick width based on shape:
25
+ - `--width 700`–`800` for full pages and reports
26
+ - `--width 500` for cards and summaries
27
+ - `--width 400` for compact, just-a-snippet output
25
28
 
26
29
  4. After piping, write a one-line confirmation (e.g. "Rendered above."). The image is the deliverable; don't restate its contents in text.
27
30
 
28
- ## CSS rules DropFlow subset
31
+ ## CSS — what works
29
32
 
30
- DropFlow is a real CSS layout engine but it's not a browser. Stick to this subset:
33
+ kittyhtml v0.3+ uses Blitz (Stylo + Taffy + Parley + Vello). Most modern CSS works:
31
34
 
32
- - **Use `background-color`, NOT the `background` shorthand.** The shorthand is silently dropped.
33
- - **Use `width: Npx`, NOT `max-width`.** `max-width` / `min-width` aren't implemented.
34
- - **No `list-style` markers.** Don't use `<ul><li>` and expect bullets. Use `<div>&bull;&nbsp;&nbsp;item</div>` or numbered prefixes.
35
- - **No `border-radius`, `box-shadow`, `transform`, `position: absolute/fixed`.** Square corners only. Use `border: 1px solid #color;` for definition.
36
- - **`<body>` background does NOT propagate to the canvas.** Wrap content in an outer `<div style="background-color: #fff; padding: ...">` to fill the image.
37
- - **Only inline `style` attributes work** — no `<style>` blocks, no classes.
38
- - **Fonts available**: `Noto Sans` (default), `Noto Sans Mono` for code.
35
+ - Flexbox (`display: flex`, `flex: 1`, `gap`, etc.)
36
+ - CSS Grid (`display: grid`, `grid-template-columns`, etc.)
37
+ - `border-radius`, `box-shadow`, `opacity`
38
+ - `max-width`, `min-width`, `width`, `height`
39
+ - `background:` shorthand (no need for `background-color` longhand)
40
+ - Native `<ul>` / `<ol>` bullets
41
+ - `<img>` tags (with absolute URLs; HTTPS works)
42
+ - `position: relative` / `absolute`
43
+ - Web fonts via `@font-face`
44
+
45
+ Inline styles only — no `<style>` blocks, no `class` selectors are honored.
46
+
47
+ ## Fonts
48
+
49
+ Two are baked in and reliable:
50
+ - `'Noto Sans'` (regular, bold, italic, bold-italic)
51
+ - `'Noto Sans Mono'` for code
52
+
53
+ Use them as the canonical `font-family`:
54
+ ```css
55
+ font-family: 'Noto Sans', sans-serif;
56
+ font-family: 'Noto Sans Mono', monospace;
57
+ ```
58
+
59
+ Other fonts will fall back to system defaults or fail to render predictably.
39
60
 
40
61
  ## Template that's known to render well
41
62
 
42
63
  ```html
43
64
  <!DOCTYPE html>
44
65
  <html>
45
- <body style="font-family: 'Noto Sans', sans-serif; margin: 0; padding: 0; color: #18181b;">
46
- <div style="background-color: #f4f4f5; padding: 24px 0;">
47
- <div style="width: 640px; margin: 0 auto;">
48
- <div style="background-color: #ffffff; border: 1px solid #e4e4e7; padding: 24px 28px;">
49
- <!-- content here -->
50
- </div>
66
+ <body style="font-family: 'Noto Sans', sans-serif; margin: 0; padding: 0; background: #f4f4f5; color: #18181b;">
67
+ <div style="max-width: 720px; margin: 0 auto; padding: 32px 24px;">
68
+ <div style="background: #fff; border-radius: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.06); padding: 28px 32px;">
69
+ <!-- content here -->
51
70
  </div>
52
71
  </div>
53
72
  </body>
package/src/render.js CHANGED
@@ -1,77 +1,30 @@
1
- import * as flow from 'dropflow';
2
- import parse from 'dropflow/parse.js';
3
- import { createCanvas, GlobalFonts, loadImage } from '@napi-rs/canvas';
4
-
5
- const FONTS_DIR = new URL('../assets/fonts/', import.meta.url);
6
- const BUNDLED_FONTS = [
7
- 'NotoSans-Regular.ttf',
8
- 'NotoSans-Bold.ttf',
9
- 'NotoSans-Italic.ttf',
10
- 'NotoSans-BoldItalic.ttf',
11
- 'NotoSansMono-Regular.ttf',
12
- 'NotoSansMono-Bold.ttf',
13
- ];
14
-
15
- let envReady = false;
16
- function ensureEnv() {
17
- if (envReady) return;
18
-
19
- // Tell DropFlow how to register a font and decode an image into the
20
- // @napi-rs/canvas backend (default wiring in environment-node.js targets the
21
- // legacy `canvas` package).
22
- flow.environment.registerFont = face => {
23
- const key = GlobalFonts.register(face.getBuffer(), face.uniqueFamily);
24
- if (key) return () => GlobalFonts.remove(key);
25
- };
26
- flow.environment.createDecodedImage = async image => {
27
- return await loadImage(Buffer.from(image.buffer));
28
- };
29
-
30
- for (const file of BUNDLED_FONTS) {
31
- flow.fonts.add(flow.createFaceFromTablesSync(new URL(file, FONTS_DIR)));
32
- }
33
-
34
- envReady = true;
1
+ import { createRequire } from 'node:module';
2
+
3
+ const require = createRequire(import.meta.url);
4
+ // Loaded lazily so importing this module doesn't pay the .node init cost
5
+ // until someone actually renders.
6
+ let _native = null;
7
+ function native() {
8
+ if (_native == null) _native = require('../crates/renderer/index.cjs');
9
+ return _native;
35
10
  }
36
11
 
37
12
  /**
38
- * Render an HTML string to a PNG buffer using DropFlow.
13
+ * Render an HTML string to a PNG buffer via Blitz + Vello-CPU.
39
14
  *
40
15
  * @param {string} html
41
16
  * @param {object} [opts]
42
17
  * @param {number} [opts.width=800] Viewport width in CSS px before scaling.
43
18
  * @param {number|null} [opts.height] Fixed canvas height; if null, auto-fit to content.
44
19
  * @param {number} [opts.scale=1] Pixel ratio (2 = retina-sharp).
45
- * @param {string|null} [opts.background] Optional canvas background fill (CSS color).
46
20
  * @returns {Promise<Buffer>} PNG image bytes.
47
21
  */
48
22
  export async function renderHtml(html, opts = {}) {
49
- const { width = 800, height = null, scale = 1, background = null } = opts;
50
- ensureEnv();
51
-
52
- const root = parse(html);
53
- await flow.load(root);
54
-
55
- const pxWidth = Math.max(1, Math.round(width * scale));
56
- const layout = flow.generate(root);
57
-
58
- let pxHeight;
59
- if (height != null) {
60
- pxHeight = Math.max(1, Math.round(height * scale));
61
- flow.layout(layout, pxWidth, pxHeight);
62
- } else {
63
- flow.layout(layout, pxWidth, 1_000_000);
64
- const measured = layout.getBorderArea().height;
65
- pxHeight = Math.max(1, Math.ceil(measured));
66
- flow.layout(layout, pxWidth, pxHeight);
67
- }
68
-
69
- const canvas = createCanvas(pxWidth, pxHeight);
70
- const ctx = canvas.getContext('2d');
71
- if (background) {
72
- ctx.fillStyle = background;
73
- ctx.fillRect(0, 0, pxWidth, pxHeight);
74
- }
75
- flow.paintToCanvas(layout, ctx);
76
- return await canvas.encode('png');
23
+ const { width = 800, height = null, scale = 1 } = opts;
24
+ const nativeOpts = {
25
+ width: Math.max(1, Math.round(width)),
26
+ scale: Math.max(0.01, scale),
27
+ };
28
+ if (height != null) nativeOpts.height = Math.max(1, Math.round(height));
29
+ return await native().renderHtml(html, nativeOpts);
77
30
  }
Binary file
Binary file
Binary file
Binary file