Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 65 additions & 9 deletions .codebuddy/skills/pagx/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ description: >-
post) to a PAGX file, and edits existing PAGX files. Use when the user asks to
create a PAGX from a visual description, convert HTML to PAGX, modify/update an
existing PAGX, run pagx CLI commands (render, verify, format, layout, bounds,
font info/embed, import, resolve, export to SVG/HTML/PPTX, or export to HTML for
browser preview), or look up PAGX element attributes and syntax.
font info/embed, import, resolve, export to SVG/HTML/PPTX, preview in browser,
or look up PAGX element attributes and syntax).
---

# PAGX Skill
Expand Down Expand Up @@ -34,7 +34,7 @@ relevant reference:
| `references/guide.md` | Spec rules, techniques, common pitfalls | Read before editing |
| `references/patterns.md` | Structural patterns for UI components, layouts, tables, charts, decorative effects | Read before editing |
| `references/attributes.md` | Attribute defaults, enumerations, required attributes | As needed |
| `references/cli.md` | CLI commands — `render`, `verify`, `format`, `layout`, `bounds`, `font info`, `font embed`, `import`, `resolve`, `export` (SVG, HTML, PPTX) | As needed |
| `references/cli.md` | CLI commands — `render`, `verify`, `format`, `layout`, `bounds`, `font info`, `font embed`, `import`, `resolve`, `export` (SVG, HTML, PPTX), `preview` (live browser) | As needed |
| `references/authoring-html.md` | How to write HTML that converts cleanly to PAGX, plus design tips | Read before writing HTML (HTML → PAGX) |
| `references/pipeline.md` | Full HTML→PAGX converter usage, setup, fonts/images, URL input, troubleshooting | As needed (HTML → PAGX) |
| `spec/html_subset.md` | Authoritative HTML/CSS subset the importer accepts — every allowed tag/property and its PAGX mapping, diagnostics, auto-normalization passes | Debugging conversion warnings or edge cases |
Expand Down Expand Up @@ -70,7 +70,12 @@ higher detail when visually inspecting screenshots. Output files are written to
working directory: `input.png` (screenshot), `input.layout.xml` (computed bounds). With
`--id`, outputs are `input.{id}.png` and `input.{id}.layout.xml`. Always run `pagx verify`
from the same directory as the `.pagx` file. See `references/cli.md` for verify options and
all other CLI commands (`render`, `format`, `layout`, `bounds`, `font`, `import`, `export`).
all other CLI commands (`render`, `format`, `layout`, `bounds`, `font`, `import`, `export`,
`preview`).

`pagx preview` starts a live browser preview with hot reload — use it to show the user the
finished design interactively (see [Live browser preview](#live-browser-preview)). It runs as
a background daemon and prints a URL; stop it with `pagx preview stop` when done.

---

Expand Down Expand Up @@ -177,6 +182,11 @@ Keep final `input.png` for reference (do not commit). If further edits are made
this step, re-run the full verify to regenerate it. Delete `input.layout.xml` and any
scoped `{id}` artifacts produced during the fix.

**Live browser preview (optional)**: to let the user see the edited design interactively,
run `pagx preview input.pagx` and open the printed URL in the IDE's built-in browser. The
preview hot-reloads on save, so any later touch-ups refresh the open tab automatically. Stop
the background daemon with `pagx preview stop` when done.

---

## HTML to PAGX Workflow
Expand Down Expand Up @@ -280,7 +290,8 @@ needed. `pagx render` then writes the preview PNG:

```bash
pagx import --input <name>.html --output <name>.pagx # snapshot + import + resolve
pagx render <name>.pagx -o <name>.png # preview; add --scale 2 for a crisp image
pagx render <name>.pagx -o <name>.png # preview PNG; add --scale 2 for a crisp image
pagx preview <name>.pagx # live browser preview (background daemon, non-blocking)
```

- Output: `<name>.pagx` (the result) and `<name>.png` (the preview render).
Expand All @@ -306,7 +317,8 @@ triggers the one-time browser download). `pagx import` snapshots, imports, **and

```bash
pagx import --input <name>.html --output <name>.pagx
pagx render <name>.pagx -o <name>.png # preview; add --scale 2 for a crisp image
pagx render <name>.pagx -o <name>.png # preview PNG; add --scale 2 for a crisp image
pagx preview <name>.pagx # live browser preview (background daemon, non-blocking)
```

A public URL works the same way (`--input https://… --output <name>.pagx`). Note: this path does not
Expand All @@ -317,19 +329,63 @@ machine, or embed it explicitly with `pagx font embed --file <font>`. See `refer
See `references/pipeline.md` for advanced options (URL inputs, image storage modes, custom viewport
via `snapshot.js`, and a manual step-by-step path for debugging).

**Open the live preview in the IDE browser (REQUIRED, do not skip).** `pagx preview` prints a URL
line like `pagx preview: http://127.0.0.1:<port>/...` to stdout. Parse that URL and open it with
the IDE's built-in browser tool (e.g. `preview_url`) so the user sees the real, interactive
design — not just the static PNG. The PNG from `pagx render` is for your own QA comparison only;
the live browser preview is what you show the user. The preview daemon watches the `.pagx`, so
later re-imports (Step 4) reload the open tab automatically — do not restart it each time.

### Step 4: Review and iterate

1. Open `<name>.png` and compare it against the user's intent. Show it to the user.
1. The live browser preview is already open from Step 3 — compare it (and the `<name>.png` QA
screenshot) against the user's intent.
2. If something is wrong, **edit the `<name>.html`** (not the PAGX) and re-run Step 3. The HTML is
the source of truth; treat the `.pagx` as a build artifact.
the source of truth; treat the `.pagx` as a build artifact. The preview tab reloads on its own
— do not restart `pagx preview`.
3. Common fixes:
- Text in the wrong font → ensure the Google Fonts `<link>` is present; if the typeface is still
wrong, install that font on the machine or embed it with `pagx font embed --file <font>`.
- Content clipped or off-canvas → match `--viewport-width`/`--viewport-height` to the `body` size.
- An element missing from the PNG → it was hidden, an unsupported widget, or a tainted
`<canvas>`; see `references/authoring-html.md` §What to avoid and `references/pipeline.md`.
4. When the preview matches the intent, deliver `<name>.pagx` to the user and briefly describe what
it contains. Do not commit generated `.png` / `.subset.html` files.
it contains. Stop the background preview daemon with `pagx preview stop`. Do not commit
generated `.png` / `.subset.html` files.

For deeper polish of the resulting PAGX (precise spacing, constraints, animation-ready structure),
switch to the [Update Workflow](#update-workflow), which edits the `.pagx` directly.

---

## Live browser preview

`pagx preview <file>.pagx` starts a local HTTP server that renders the PAGX in a browser tab and
watches the file for hot reload. Use it to show the user the finished design interactively;
use `pagx render` / `pagx verify` for pixel-level QA screenshots (the sub-agent reviewer reads
PNG files, not a live tab).

```bash
pagx preview input.pagx # background daemon, prints URL, returns prompt
pagx preview stop # stop the daemon when done
```

- **Non-blocking.** The default spawns a detached background daemon, prints
`pagx preview: http://127.0.0.1:<port>/...` to stdout, and returns the shell prompt — it does
not hang the session. In non-TTY / agent contexts no system browser is auto-opened; open the
printed URL in the IDE's built-in browser instead (e.g. the `preview_url` tool).
- **Hot reload.** Saving the `.pagx` (or re-running `pagx import` in the HTML→PAGX workflow)
refreshes every open tab automatically — start the preview once, then iterate and watch it
update.
- **Session reuse.** Running `pagx preview` again reuses the running daemon for a new file;
each file gets its own session, cleaned up independently when its tab closes.
- **Always clean up.** The daemon stays up until stopped. Run `pagx preview stop` when the user
is done previewing to free the port and process.

See `references/cli.md` §pagx preview for all options (`--port`, `--json`, `--foreground`, etc.).

**Tip**: when creating internal task lists, keep the PNG-screenshot step and the live-browser-preview
step as separate items with their real actions — "generate preview PNG via `pagx render`" (QA
screenshot for visual comparison) vs "launch `pagx preview` and open the URL in the IDE browser"
(interactive preview for the user). Do not collapse them into a single "preview" item, or the
live browser preview gets misnamed as a PNG export.
51 changes: 51 additions & 0 deletions .codebuddy/skills/pagx/references/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ and `pagx <command> --help` for per-command usage.
- [pagx import](#pagx-import) — convert SVG/HTML to PAGX
- [pagx resolve](#pagx-resolve) — expand inline `<svg>` and `import` attributes
- [pagx export](#pagx-export) — export PAGX to SVG/HTML/PPTX
- [pagx preview](#pagx-preview) — live browser preview with hot reload

---

Expand Down Expand Up @@ -497,3 +498,53 @@ pagx export --input icon.pagx --output out.html # PAGX to HTML
| `--svg-no-xml-declaration` | Omit the `<?xml ...?>` declaration |
| `--ppt-no-bake-unsupported` | Disable the default baking of layers that use features OOXML cannot represent natively — masks, scrollRect clipping, blend modes outside of `Normal`/`Multiply`/`Screen`/`Darken`/`Lighten`, wide-gamut color, and `BackgroundBlurStyle`. By default the exporter bakes these layers into PNG patches so the slide matches the tgfx renderer (for unsupported blend modes and `BackgroundBlurStyle` the backdrop beneath the layer is baked into the PNG too, so the blend/frosted-glass composites against the real scene, at the cost of turning native content under the patch into pixels). Pass this flag to silently drop those features and emit the layer as editable shapes instead (mask ignored, scrollRect dropped, blend falls back to `Normal`, wide-gamut clamped to sRGB). Tiled image patterns are always baked regardless of this flag, and features with no vector fallback (TextPath, ColorMatrix, conic/diamond gradient, shear transform) always bake regardless of this flag |

---

## pagx preview

Launch a live, interactive browser preview of a PAGX file with hot reload. Unlike `pagx render`
(a one-shot PNG screenshot for QA), `pagx preview` starts a local HTTP server that renders the
PAGX in a browser tab and watches the file — saving the `.pagx` (or the source HTML in the
HTML→PAGX workflow) reloads the open tab automatically. Use it to let the user see and interact
with the finished design; use `pagx render` for pixel-level QA comparisons.

```bash
pagx preview input.pagx # background daemon, prints URL, returns prompt
pagx preview --json input.pagx # single-line JSON {url,pid,logFile,reused} on stdout
pagx preview --foreground input.pagx # run in foreground (Ctrl+C to stop)
pagx preview --port 8080 input.pagx # pick a specific port (default: random free port)
pagx preview stop # stop the background daemon
pagx preview --log # print the daemon log file
```

| Option / Subcommand | Description |
|---------------------|-------------|
| `<file>` | PAGX file to preview (required unless using `--mcp`, `stop`, or `--log`) |
| `--port <n>` | Port to bind (default: 0 = auto-pick a free port) |
| `--host <addr>` | Bind address (default: `127.0.0.1`) |
| `--fonts <dir>` | Extra font directory for the preview renderer |
| `--json` | Emit a single-line JSON record on stdout (`{url,pid,logFile,reused}`); implies `--no-open` |
| `--no-open` | Do not auto-open a system browser (default in non-TTY / agent contexts) |
| `--foreground` | Run the server in the foreground instead of a detached daemon |
| `--mcp` | Run as a stdio MCP server for AI assistants (not for interactive preview) |
| `stop` | Stop the running background daemon |
| `--log` | Print the daemon log file path and contents |

### Behavior

- **Default = background daemon.** `pagx preview input.pagx` spawns a detached server process,
prints `pagx preview: http://127.0.0.1:<port>/...` to stdout, and **returns the shell prompt**
(it does not block). The server keeps running in the background so repeated invocations reuse
it instead of starting a new one.
- **Browser auto-open.** In a real TTY the default opens the system browser; in non-TTY contexts
(piped stdout, IDE agents, CI) it does not — the URL is printed only. Pass `--no-open` to force
it off, or open the printed URL manually / via the IDE's browser preview tool.
- **Hot reload.** The server watches the `.pagx` file; any save triggers a `reload` SSE event
that refreshes every open tab. Editing the source HTML in the HTML→PAGX workflow and re-running
`pagx import` will also reload the preview automatically.
- **Session reuse.** A second `pagx preview another.pagx` reuses the already-running daemon,
opens a new session for the new file, and prints its URL. Each file gets its own session and
is cleaned up independently when its tab disconnects.
- **Lifecycle.** The daemon stays up until explicitly stopped with `pagx preview stop` or the
machine reboots. Always run `pagx preview stop` when done to free the port and process.

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ cli/npm/bin/win32
cli/npm/node_modules
cli/npm/package-lock.json
cli/npm/*.tgz
cli/npm/preview

# PAGX verify artifacts
*.layout.xml
Expand Down
43 changes: 43 additions & 0 deletions cli/npm/bin/pagx.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,49 @@ if (!process.env.PAGX_HTML_SNAPSHOT_BIN) {
}
}

// Intercept the preview sub-command and delegate to pagx-preview (a Node.js-based
// HTTP server + MCP service). The preview module lives under preview/ at the package
// root so it can be bundled and published alongside the native binary.
if (process.argv[2] === 'preview') {
const previewEntry = path.join(__dirname, '..', 'preview', 'src', 'cli.js');
if (!fs.existsSync(previewEntry)) {
console.error('pagx: preview command not available. Preview module not found.');
process.exit(1);
}
const { spawn } = require('child_process');
// Use process.execPath (the Node binary currently running this wrapper) rather than the string
// 'node': under nvm/Volta/asdf, on Windows without node on PATH, or when launched from a packaged
// runtime, a bare 'node' may not resolve. process.execPath is always the correct interpreter.
const child = spawn(process.execPath, [previewEntry, ...process.argv.slice(3)], { stdio: 'inherit' });
child.on('error', (err) => {
console.error('pagx: failed to start preview: ' + err.message);
process.exit(1);
});
child.on('exit', (code) => process.exit(code != null ? code : 1));
return;
}

// Inject the preview sub-command into the native binary's --help output. The native binary is
// unaware of preview (it lives in the Node.js wrapper), so we run its help, then splice a preview
// line under the "Commands:" header. Any future native command changes flow through untouched;
// only the preview line is maintained here.
if ((process.argv[2] === '--help' || process.argv[2] === '-h') && process.argv.length === 3) {
const { spawnSync } = require('child_process');
const result = spawnSync(binPath, ['--help'], { encoding: 'utf8' });
const lines = result.stdout.split('\n');
const output = lines
.map((line) => {
if (line.trim() === 'Commands:') {
return line + '\n preview Preview a PAGX file in the browser with live reload';
}
return line;
})
.join('\n');
process.stdout.write(output);
if (result.stderr) process.stderr.write(result.stderr);
process.exit(result.status || 0);
}

try {
execFileSync(binPath, process.argv.slice(2), { stdio: "inherit" });
} catch (e) {
Expand Down
Loading
Loading