Commit graph

50 commits

Author SHA1 Message Date
Danila Poyarkov 6a05e30f15
fix(design-jsx): say what gradient helpers expect when stops are not an array (#881)
* fix(design-jsx): say what gradient helpers expect when stops are not an array

An AI agent called linearGradient with something other than an array of stops, and render failed with 'stops.map is not a function', which does not tell it how to fix the call. The helpers now validate their stops with Valibot and name the expected form, and the authoring reference shows the signature.

* fix(design-jsx): describe stops that cannot be shown as JSON

Review follow-up. JSON.stringify throws on a bigint or a circular object, so such a call failed with that error instead of the gradient's expected form.

* fix(design-jsx): word gradient stop errors from the Valibot issue

Review follow-up. The message now names the helper as a call, as the paint helper option warnings do, and ends with Valibot's description of what was wrong, which already says what it received without serializing the value. A stop that is neither [color, position] nor { color, position } names both forms and its index.
2026-10-04 18:28:44 +00:00
Danila Poyarkov 01e58a3ad0
feat: write variables as a CSS token stylesheet (#856)
* feat: write variables as a CSS token stylesheet

Copy a collection as CSS custom properties or a Tailwind v4 theme from the variables dialog, print it with openpencil tokens, and rebuild design_to_tokens on the same generator. Default modes go in :root or @theme, other modes override under their condition, and aliases are declared again in each mode scope so they follow it.

* fix: give modes that slug alike their own selector and variant

Two modes in one collection whose names reduce to the same slug, such as Dark and dark!, shared one default selector and Tailwind variant, so the later mode silently overrode the earlier one. Slugs are now numbered in mode order, as variable names already are.
2026-10-04 18:15:52 +00:00
Danila Poyarkov b52d7e2651
feat: control documents, history, settings, and tools from the CLI and MCP (#871)
* fix(app): record MCP and CLI structural edits as undo steps

The automation bridge ran non-atomic tools, render, and eval without an
undo entry, so Edit > Undo could not revert layers an MCP client or the
CLI created, deleted, or rearranged. Snapshot the page around these
edits as the AI chat does, and skip the entry when nothing changed so
read-only scripts leave the history alone.

* feat(app): activate documents, undo, redo, and change settings over automation

Add activate_document, undo, redo, get_settings, and update_settings to
the app's automation bridge. Settings cover appearance, snapping, canvas
rendering, recovery, and chat preferences, validated with Valibot and
applied through their owning stores; credentials, models, MCP
connections, storage, and tool access stay out of reach.

* feat(mcp): expose document activation, history, and settings tools

* feat(cli): manage documents, history, settings, and tools in the running app

Turn documents into a command group (list, open, new, save, close,
activate), add undo, redo, and settings get/set, and add tool
list/describe/call so every MCP tool runs from the shell, against the
running app or headlessly on a file.

* docs: document app control from the CLI and MCP

* fix: never prompt in the app from automation closes and saves

close_file opened the app's Save changes dialog, which an agent cannot
answer: the call timed out and the dialog stayed open. It now fails on
unsaved changes unless the caller passes unsaved "save" or "discard"
(CLI --save or --discard). save_file and new_document no longer open a
Save dialog for a document that was never saved, report a failed save
as an error, and leave the document untouched when the path is refused.

* docs: describe non-interactive close and save

* fix: address review findings in app automation

Keep a document's source when a save to a new path fails, report
vector-edit undo and redo no-ops as unapplied, echo only the applied
patch from update_settings so writing cannot read settings, reject
tool call --write/--output without a file, and stop settings get from
following inherited keys.

* fix(app): record render undo on the page that receives the layers

A render into a parent on another page was snapshotted against the
target page, so undo left the new layers in place. Snapshot the page
that contains the parent instead, and document that eval edits made
after switching pages stay outside the undo step.

* feat(app): limit automation undo to its own steps and expose design check settings

The undo history is shared with the person in the editor, so an agent's
undo could revert the user's last edit. Automation undo and redo now act
only on steps made through the bridge, and only while they are newest;
otherwise they fail and leave the history alone. Vector edit mode's
session history is off limits entirely. Settings automation also covers
the design check preferences that landed on master.
2026-10-04 16:02:36 +00:00
Danila Poyarkov 3f594fdc3a
feat: add visual diff and patch apply tools and openpencil diff (#810)
* feat(core): add visual diff and patch apply tools

diff_visual renders two nodes at one scale through the existing raster export, compares them with pixelmatch, and returns the diff PNG with the changed ratio and region in source-node coordinates. It takes export_image's scale and maxEdge inputs. FigmaAPI gains a CanvasKit-backed raster codec and a pageId export option, so the app and headless CLI decode pixels and render nodes off the current page.

diff_apply applies diff_create and diff_show patches through the Figma API, validates every node before changing any, and supports dryRun and force. diff_show now simulates changes on a detached copy with the same property code. One serializer and parser back all three. diffDocuments compares two documents page by page by name path.

Image tool results now reach models as media with their metadata as text, for any tool rather than export_image alone. diff_create, diff_jsx, and diff_visual join the default AI tool set, and the diff tools are no longer hidden from WebMCP.

* feat(cli): add diff commands and agent diff guidance

openpencil diff create, jsx, show, apply, and visual run the Core diff tools on a file or the running app; apply writes back with --write or --output like eval. diff files compares two documents page by page and exits 1 when they differ.

The chat prompt asks the agent to edit in place and to verify risky edits against a reference copy with diff_jsx, diff_create, and diff_visual. The skill, CLI reference, MCP tool table, and a new Comparing Designs page document the commands and tools.

* feat(core): diff and patch node trees as JSX attributes

diff_create, diff_show, diff_apply, and diffDocuments used a hand-rolled
`key: value` property format that covered about fifteen properties,
matched children by name path, and could not see moves.

Nodes are now projected to the attributes the JSX export prints, and
jsondiffpatch matches children (by ID or by name path) and detects
moves. Patches list `-`/`+` attribute lines per node plus moved, added,
and removed children. diff_apply checks every hunk first, applies
attribute changes through the renderer's prop handling, and changes only
the fields an attribute moves, so IDs, instance links, and other state
survive. diff_show takes JSX attributes instead of a JSON props object.

design-jsx gains sceneNodeAttributes, parseJSXAttributes, and
jsxNodeFields for this, and the export round-trip property table is
shared so every case is also diffed and applied. `diff files` loads its
documents in order so node IDs, and so its patches, are deterministic.

* fix(core): keep diff_apply atomic and diff files honest about differences

- Added nodes render before anything else changes; if one fails, for
  example on a missing component, the rendered ones are deleted and
  nothing else is committed.
- A hunk with an attribute the renderer ignores fails instead of
  reporting "unchanged".
- diffDocuments reports `changed` from page statuses, and a page only
  one document has gets its status but no patch, since patches do not
  add or remove pages. diff files uses it, so an added empty page no
  longer reads as a match.
- diff files rejects a --page neither document has and a --depth that
  is not a non-negative integer, exiting 2; diff_create's depth is
  validated the same way.
2026-10-03 21:00:13 +04:00
Danila Poyarkov 67dbd7156f
feat(design-jsx): export every property the renderer accepts (#814)
* feat(design-jsx): export every property the renderer accepts

JSX export wrote only part of a layer: one solid fill, one stroke
without its alignment, shadows as repeated attributes, background blurs
as layer blurs, and nothing for hidden children, constraints, size
limits, absolute positioning, vertical text alignment, masks, or
variable bindings. Rendering an export lost those properties, and JSX
diffs could not see changes to them.

The export now writes them, using paint and effect helper calls when a
shorthand cannot express a value exactly, and leaves out values the
renderer would infer, so ordinary output stays as it was. Prop values
can now hold objects, arrays, and helper calls, printed through
@open-pencil/codegen's builders, which gain a call expression. The
language gains `visible`, `locked`, `constraints` (Figma's constraints
object with lowercase values, as `blendMode` uses), `italic`,
`strokes`, `strokeWeights`, `strokeCap`, and `strokeJoin`, and now
applies `strokeAlign`, `strokeDash`, and the size limits, which it
accepted but ignored. Per-corner radii are written even when the
uniform radius is 0. A round-trip test renders each case's export and
checks the fields and that exporting again changes nothing.

* docs(fig): name the saved-glyph fixture by its repository path

The observation note linked the fixture with a relative path climbing four directories. Other notes name fixtures by their repository path, which reads the same from anywhere.

* fix(design-jsx): export the node-level dash pattern

A node's own dashPattern was not written, so a node dashed at node level
came back solid and the DOM/CSS export chose a solid border. It now
round-trips as a separate dashPattern prop; strokeDash stays the
stroke-local dash.
2026-10-03 15:40:21 +04:00
Marc Went 8c72b62da0
feat(cli): export Storybook stories beside many documents (#761)
* feat(cli): export Storybook stories beside many documents

Accept several documents, or a quoted glob such as 'src/**/*.pen', and add --beside to write each document's stories, design images, and manifest into the document's own folder, next to the component's code. Documents export one after another, since documents in one folder share its manifest; a failed document is reported and the rest still export. --watch covers every matched document through one queue. Several documents need --beside or --output, and --page takes a single document.

Refs #727

* fix(cli): resolve Storybook export documents by existence, not glob syntax

Deciding between a path and a pattern by looking for glob characters missed
extglobs, so 'src/+(a|b).pen' was opened as a literal filename, and it flagged
an escaped star, so a file genuinely named that way went to the matcher. The
character list also could not agree with Node's matcher: is-glob rejects a
bare '?', picomatch accepts a parenthesised directory name.

An existing path is now that file, and everything else goes to glob(), which
matches a plain path to itself and expands every pattern it supports.

---------

Co-authored-by: Danila Poyarkov <dev@dannote.net>
2026-09-30 22:05:51 +04:00
Danila Poyarkov 8404cee664
refactor(design-jsx): extract design JSX into its own package (#793)
* refactor(design-jsx): extract design JSX into its own package

Design JSX elements, helpers, schema, reference, and JSX export only need
the scene graph, yet lived in Core, so every consumer of the authoring API
pulled in the renderer, layout, and file formats.

@open-pencil/design-jsx now owns them and depends only on scene-graph. The
renderer takes icon lookup, SVG conversion, vector creation, and layout as
DesignJSXServices; Core binds its own and exports the bound renderJSX and
renderTree from @open-pencil/core/design-jsx.

* feat(design-jsx): export the JSX runtime for TSX authoring

The package already had a JSX runtime, but nothing exported it, so design
trees could only be written as function calls or JSX strings. Export
`./jsx-runtime` and `./jsx-dev-runtime` so `jsxImportSource` works, and make
`Fragment` produce the same empty-type node as `<>` in `renderJSX` strings.

* fix(design-jsx): render fragments nested in other elements

A fragment builds a node with an empty type, which only renderJSX expanded, and only at the root. Nested fragments and fragments passed to renderTree failed with 'Unknown element: <>'. Inline fragment children when trees are built, and share root expansion between renderTree and renderJSX.
2026-09-30 20:55:27 +04:00
mrhard9090 4faf20bab8
fix(design-jsx): warn about unsupported paint and effect helper options (#762)
* fix(design-jsx): accept blur in effect helpers and warn about unknown options

dropShadow({ blur: 12 }) silently used the default radius, although the shadow shorthand and the blur prop both call that value the blur, and any misspelled option was dropped without a word. The shadow and blur helpers now take blur as the radius, and renderJSX reports any other option they ignore, next to the existing unsupported-prop warnings.

Fixes #736

* refactor(design-jsx): check options for every paint and effect helper

The option check covered only effect helpers, and its key lists repeated
the option types by hand, so a new option could turn into a false
warning. One wrapper in `design-jsx/helpers.ts` now checks every paint
and effect helper that evaluated JSX can call, with key lists typed
against their option interfaces. Only plain objects are checked, and
repeated warnings are collapsed once. The authoring reference documents
the `blur` alias and the warnings.

* docs(design-jsx): scope helper option warnings to rendered JSX

* fix(design-jsx): name effect radius as Figma does and hint at it for blur

Accepting both `radius` and `blur` gave effect helpers two names for one
value, and when both were set `blur` was dropped without a warning.
Figma's effects only have `radius`, so the helpers take `radius` alone
and `blur` now warns with a pointer to it. The default radius is named
once instead of repeated.

---------

Co-authored-by: Danila Poyarkov <dev@dannote.net>
2026-09-30 09:59:45 +04:00
Marc Went 802091b051
feat: export components as Storybook stories (#751)
* feat(cli): export components as Storybook stories

Add `openpencil export -f storybook`, which writes one CSF3 `.stories.ts`
file per component set or component. Each variant becomes a story and the
variant properties become select controls, so the story renders the matching
variant; an unknown combination throws instead of showing another variant.

Stories embed the existing inline-style HTML projection, so consumers need no
OpenPencil runtime. `--framework react|vue|html` only changes the render
wrapper and the Meta/StoryObj import. When the document sits under the current
directory, stories carry an `openpencil://` design link for
@storybook/addon-designs.

Refs #727

* fix(pen): size auto-width text from its content on import

Text without a width in an auto-layout parent was imported 10000px wide, a placeholder the app's text measurer replaces. Headless layout keeps stored sizes, so CLI HTML and Storybook exports stretched hugging frames to over 10000px. Import the width as 0 so the importer's existing text-length estimate applies, and headless layout estimates the rest.

* feat(app): follow layer links to other pages

openpencil:// and web ?node= links only searched the current page, so a Storybook story linking to a component on another page reported it missing. When the current page has no match, load the other pages without showing them and switch to the first that carries the name.

* feat(cli): add design images and watch mode to Storybook export

Each story now links to its own variant when the layer name is unique, and carries a 2x PNG of the variant for @storybook/addon-designs, imported so Vite bundles it. --watch re-exports on every save. Re-exports replace the stories a previous export of the same document generated, including those of deleted components, and refuse to overwrite hand-written stories or another document's.

Refs #727

* fix(cli): reference Storybook design images without ambient PNG types

Import design images with new URL(..., import.meta.url) instead of an import declaration, so consumers need no vite/client types to typecheck the stories. Document that exports should run from the same directory.

* fix(app): search other pages for a link without cancelling page switches

The cross-page layer search prepared each page with preparePage, which advances the page-switch generation, so a page switch the user had in progress could be dropped, and every searched page paid for fonts and layout. Add loadPageNodes, which populates a page's layers through the same worker path without touching the switch generation, and report a failed search as an error instead of a missing layer.

* fix(pen): never import width-less text zero wide

Text without a width now imports at width 0 and relies on the importer's text-length estimate, which skipped single-glyph text. Estimate zero-width text of any length.

* fix(cli): harden Storybook export ownership, titles, and links

- A --page export replaces only its own stories, and names files as a full export does, so it cannot delete or overwrite other pages' stories.
- Same-named components on a page get distinct titles, so Storybook story ids do not collide.
- Read the generated header through CRLF line endings, and refuse a source containing a line break, which would end the header comment and start code.
- Link a story only to a layer name no other layer carries.
- Document the --page default for Storybook export.

Refs #727

* fix(app): let a page switch overtake a link's layer search

A link search that loads other pages could resume after the user started switching pages and move them to the matching page. Expose pageSwitchCount, which advances whenever a page switch starts, and abandon the search when it changes. An overtaken search reports neither a match nor a missing layer.

* fix(pen): estimate only omitted text widths

Estimate a width-less text node's width when it is imported, instead of estimating every zero-width text node afterwards, so an explicit width of 0 is kept.

* fix(cli): track Storybook story ownership by document path and page

- Identify the document by its path relative to the output directory rather than a basename or cwd-relative path, so same-named documents do not share stories and the export no longer depends on the working directory.
- Record the page in each story's header; a --page export replaces all of that page's stories and asks for a full export when renumbered file names land on another page's.
- Check every target, including design images, before removing anything, and refuse to overwrite files this export does not own.
- Quote the header fields as JSON with U+2028/U+2029 escaped, so any path stays inside the comment, instead of refusing line breaks.
- Deduplicate titles by Storybook id, which ignores case and punctuation.

Refs #727

* fix(app): focus a searched page only after its switch committed

A page switch the user starts while the link search's own switch is pending can keep that switch from committing. Check that the search's switch was the only one and landed on its page before focusing; otherwise report the search as superseded.

* fix(pen): keep empty text without a width at zero

* fix(cli): remove only the design images a Storybook export generated

Replacing a story removed its whole .design folder, including files someone else put there. Read the images each owned story references, remove just those, and remove a .design folder only once it is empty.

Refs #727

* test(app): cover a page switch still pending during a link search

The previous test committed the overtaking switch, so the page check alone caught it. Advance the switch count without committing, so the test fails without the count check.

* fix(cli): stage Storybook exports and refuse linked design folders

- Write every file to a staging folder inside the output before removing the previous export, then move them into place, so a failed write no longer leaves the export half replaced.
- Refuse a .design path that is not a real folder, such as a symbolic link, before removing or writing images through it, so an export cannot reach outside the output directory.

Refs #727

* refactor(dom-css): print Storybook stories from a parsed template

Story modules were assembled from string fragments, so quoting and
layout were an implicit contract: the CLI found design images with a
regex that only matched double-quoted `new URL("…")` paths.

A story module is now one TypeScript template, parsed once with acorn
and its TypeScript plugin. Data is filled into `$placeholder` nodes and
the module is printed with esrap, which owns quoting and escaping. The
CLI reads referenced design images back through `storyImagePaths()`
instead of matching text. Tests import generated modules and assert
values rather than formatting.

* refactor(storybook): track generated files in a manifest

The export recovered which files it owned by parsing its own output: a
header regex over JSON-quoted strings, line-separator escaping, CRLF
handling, an AST walk for design images, and a path regex in the CLI.

A `.openpencil-stories.json` manifest now records the document and page
behind each generated file. The CLI validates it with Valibot, including
that every listed path stays inside the output folder, and the story
header is a plain note. Story ids use a copy of Storybook's `sanitize`,
tested against the installed Storybook; the previous rule treated `A§B`
and `A-B` as the same story. Export names use es-toolkit's `pascalCase`.

The CLI export command moves into `commands/export/`, dom-css splits
grouping and naming out of the Storybook exporter, and the CLI takes the
framework list from dom-css.

* fix(pen): keep explicit narrow text widths

A post-import pass widened every multi-character text narrower than two
font sizes, including widths the `.pen` file set on purpose, such as
`width: 0`. Omitted widths are now estimated when the text node is
created, so the pass only overrode explicit widths and is removed.

---------

Co-authored-by: Danila Poyarkov <dev@dannote.net>
2026-09-30 03:16:47 +04:00
Danila Poyarkov 7a37f14327
refactor!: register HTML and Tailwind JSX as IO formats (#774)
* refactor!: register HTML and Tailwind JSX as IO formats

HTML and Tailwind JSX went around the IO registry: the CLI appended
`html` to its format list and had its own HTML and Tailwind export paths,
so the app's export options offered neither.

Core now registers `html` and `tailwind-jsx` adapters built on a new
browser-safe `@open-pencil/dom-css/export` entry. Export results can
carry assets written next to the main file, which covers standalone HTML
with external images and fonts, and the CLI writes every format the same
way. The CSS object model and Node file access load only when an export
needs them, so the app bundle stays free of the headless CSS runtime.

BREAKING CHANGE: `sceneNodesToTailwindJSX` and `designDocumentToTailwindJSX`
moved from `@open-pencil/dom-css/browser` to `@open-pencil/dom-css/export`.

* refactor(core): share export support and fixed-size options across IO formats

Five adapters export every target and six have no scale or quality
options; the new HTML and Tailwind JSX adapters repeated those blocks
again. Both are now named once and shared.

* fix(core): keep HTML asset paths relative for Windows output paths

The CLI passed the absolute output path as the export file name, and the
HTML adapter only split it on `/`, so on Windows the page referenced
absolute `C:\...\card.assets` paths and assets were written to a doubled
location. The CLI now passes the file name, and the adapter accepts
either separator.
2026-09-26 11:54:16 +04:00
Danila Poyarkov 9bc353587f
refactor!: generate Tailwind JSX through dom-css (#763)
* refactor!: generate Tailwind JSX through dom-css

Core kept its own SceneGraph → Tailwind mapper next to the one dom-css
uses for Tailwind HTML, and the two drifted: HTML export turned grid
frames into flex columns and dropped rotation, inner shadows, blur, and
flex grow, while Tailwind JSX had them.

Tailwind JSX is now printed by dom-css from the same CSS projection as
HTML export, with esrap building the JSX and string literals carrying
text or attributes that JSX would otherwise reinterpret. The projection
gains grid layout and placement, rotation, every shadow, layer and
background blur, flex grow, right-to-left direction, and sections, and
writes opaque colors as hex so Tailwind can match its palette.

BREAKING CHANGE: `sceneNodeToJSX` and `selectionToJSX` in
`@open-pencil/core` no longer accept a format, and `JSXFormat` and
`JSXExportOptions` are removed. Use `sceneNodesToTailwindJSX` from
`@open-pencil/dom-css` or `@open-pencil/dom-css/browser`.

* fix(dom-css): keep backslashes and line breaks in Tailwind JSX attributes

JSX attribute strings keep backslashes literally, but the printer
escapes backslashes and line breaks in string literals, so a layer
named `a\b` came back as `a\\b`. Such values are now written as
expression containers, like values containing quotes or `&`.
2026-09-26 10:50:28 +04:00
Danila Poyarkov e50df9ffda test: cover and document inherited instance dimensions 2026-09-14 00:24:52 +03:00
Danila Poyarkov b4f119a01b Merge branch 'native-authoring' into jsx-component-properties
# Conflicts:
#	packages/core/src/design-jsx/reference/authoring.md
#	packages/docs/reference/design-authoring.md
#	skills/open-pencil/references/design-authoring.md
2026-09-13 20:55:05 +03:00
Danila Poyarkov 8189c08e0b docs: clarify scalar modes and instance sizing guidance 2026-09-13 20:54:27 +03:00
Danila Poyarkov becc4f7432 feat: author scoped component properties in Design JSX 2026-09-13 19:27:06 +03:00
Danila Poyarkov 863b1e6c6a refactor: share design authoring guidance across agents 2026-09-13 19:08:27 +03:00
Danila Poyarkov 3ccc1d634f docs(fig): clarify existing round-trip fidelity limits 2026-09-13 15:32:57 +03:00
Victor Wads 6da2f2654b
fix(fig): use Cover pages for thumbnails 2026-08-18 03:43:38 -03:00
rcoenen be272dc4dc
feat(fig): support text on path 2026-08-17 12:00:01 +03:00
Danila Poyarkov d67415c793
docs: explain component library workflows (#520)
Documents component libraries and localized workflows added by #512.
2026-08-14 20:39:47 +03:00
Danila Poyarkov 3ef554ab2d docs: reorganize documentation and improve integrity
- Replace the ambiguous Guide section with explicit overview, reference, and development routes while preserving legacy URLs with redirects
- Route missing localized content to maintained canonical pages and emit SEO alternates only for real translations
- Add parser-backed documentation integrity checks and make the optimized local build the default while retaining a complete production build
2026-08-13 14:19:12 +03:00
Danila Poyarkov de8578c435
feat(app): expand Figma menu and selection parity (#459)
- Add Figma-style object, component, selection, view, settings, and browser Move to Page actions
- Add undoable z-order, transformed distribution, inverse selection, and single/bulk rename behavior
- Keep browser and native menus, shortcuts, generated schema, localization, and documentation aligned
2026-08-03 00:23:05 +03:00
Danila Poyarkov 23645d5a2d feat(editor): add component property controls
- Model typed component definitions, references, assignments, and preferred swap values

- Add SDK-owned variant, text, boolean, and nested instance-swap controls with mixed-selection undo

- Preserve assignments across variant changes and component synchronization

- Round-trip component property metadata through .fig import and export
2026-07-17 21:59:49 +03:00
Danila Poyarkov c96f87bf9b feat(editor): add shared style bindings
- Model imported fill, stroke, text, effect, and grid style definitions and references

- Add SDK and app selectors with mixed-selection batching, detach-on-edit, and undo restoration

- Preserve style definitions through .fig export and extracted subgraphs

- Document the shared-style composable and update compatibility coverage
2026-07-17 20:28:22 +03:00
Danila Poyarkov 7ac3ee035d fix(dom-css): compile standalone HTML exports 2026-07-04 19:37:58 +03:00
Danila Poyarkov b22a751f27 Revert "feat(cli): bundle standalone HTML exports"
This reverts commit 8330dda410.
2026-07-04 18:18:32 +03:00
Danila Poyarkov 8330dda410 feat(cli): bundle standalone HTML exports 2026-07-04 18:08:42 +03:00
Danila Poyarkov 3df6cc9bcd feat(cli): add standalone HTML export mode 2026-07-04 14:54:58 +03:00
Danila Poyarkov 8b1c452cc3 refactor(cli): replace DOM command with import and HTML export 2026-07-04 13:34:24 +03:00
Danila Poyarkov 60bb484ee4 refactor(ui): remove test-id prop APIs
- Forward data-test-id attrs through rendered controls instead of exposing test-id props
- Move shell chrome components into the Shell namespace
- Remove internal planning docs from published VitePress docs
- Add guardrails and contributor guidance for test hooks and component placement
2026-07-01 09:05:27 +03:00
Danila Poyarkov 1eb227ed02 feat(dom-css): harden package boundaries 2026-06-30 10:51:37 +03:00
Danila Poyarkov 346d13c405 feat(dom-css): map image aspect styles 2026-06-30 10:51:37 +03:00
Danila Poyarkov 49fefcd3a0 docs(dom-css): add mapping reference 2026-06-30 10:51:37 +03:00
Danila Poyarkov 3638fc11ba feat(cli): import DOM/CSS documents 2026-06-30 10:48:13 +03:00
Danila Poyarkov 883782846f docs(cli): use released openpencil command 2026-05-29 15:56:52 +03:00
Danila Poyarkov 540b706349 docs: document Figma compatibility 2026-05-22 19:31:06 +03:00
Danila Poyarkov b750d1f3dc docs: generate llms files
- Generate llms.txt and llms-full.txt from VitePress content loader

- Advertise the agent-readable docs through alternate links
2026-05-22 16:03:04 +03:00
Danila Poyarkov 890fb4f6d5 Update README and docs for new formats and SDK 2026-03-28 15:42:21 +03:00
Danila Poyarkov fe755fbb85 Release v0.9.0 2026-03-09 17:43:11 +03:00
Danila Poyarkov 16033c4c56 Revert mermaid plugin (crashes VitePress dev), use tables instead
vitepress-plugin-mermaid patches vitepress's client app entry,
which breaks ESM module resolution and renders all pages blank.
Replace mermaid diagrams with offset/content tables and pipeline
code blocks that render correctly.
2026-03-08 14:33:56 +03:00
Danila Poyarkov d91e6a36d9 Fix code formatting across all docs
- Wrap all enum values in backticks (FRAME, SOLID, ROUND, etc.)
- Fix single-backtick code blocks → triple backticks in node-types, scene-graph
- Replace ASCII diagrams with mermaid in file-format
- Delete stale mcp-tools.md and eval-command.md from all locales
- Update dead links: /reference/mcp-tools → /programmable/mcp-server,
  /eval-command → /programmable/cli/scripting
2026-03-08 13:53:33 +03:00
Danila Poyarkov 96b9b7733b Add CLI reference page with all commands and parameters 2026-03-08 13:42:10 +03:00
Danila Poyarkov 0109d33846 Add AI agent skill to README and docs
- README: new 'AI Agent Skill' section with install command
- MCP tools reference: skill section, fix tool count 78→90,
  add 10 missing tools (export_image, export_svg, flatten_nodes,
  list_fonts, page_bounds, set_layout_child, set_text_properties,
  viewport_get, viewport_set, viewport_zoom_to_fit)
- Features page: mention skill with install command
- All 6 locales updated
2026-03-08 01:08:28 +03:00
Anton A S 940d0de5b6 Sync docs with v0.7.0 and unreleased features
- Update comparison tables: 78 tools (was 75), SVG export no longer a Penpot advantage,
  renderer LOC updated to ~3,200 after split into 10 files
- Update figma-comparison: Rename layers ✅, SVG export ✅, +Copy/Paste as, +Tailwind export,
  +Stroke align, +per-side stroke weights; coverage 88/152 → 94/158
- Add What's Next roadmap to architecture.md: AI providers, figma-use tool set,
  CI tooling, prototyping, CSS Grid, PDF export, .fig fidelity
- Update user-guide: SVG in export format table, Copy/Paste as submenu,
  stroke align + per-side weights, layer inline rename, mobile drawer, Code tab format toggle
- Fix keyboard shortcuts: ⌘N/⌘T/⌘W ✅, ⌘\ ✅, add ⇧⌘C ✅
- Expand MCP tools reference from ~25 to all 78 tools in full category tables
- Add Homebrew tap install to Getting Started
- Add new features.md sections: SVG export, Copy/Paste as, stroke align, mobile/PWA,
  Tailwind JSX export, Google Fonts fallback, auto-save toggle, Homebrew tap,
  layer rename, renderer profiler
- Full locale sync for DE, ES, FR, IT, PL: all 7 files updated in each locale
2026-03-07 19:25:41 +03:00
Anton A S 8a486d5307 Sync docs with v0.5.0–v0.6.0: full locale translations, 75 tools
- Update tool count from 29 to 75 across all docs and locales
- Expand all locale pages (de/es/fr/it/pl) to full translations
- Add missing German sections: Advanced Rendering, Z-Order, ScrubInput,
  CI/CD, JSX Renderer, Code Panel, full figma-comparison matrix
- Write complete figma-comparison (152-row matrix) for all locales
- Expand comparison, features, tech-stack, contributing for es/fr/it/pl
- Fix garbled text in locale mcp-tools reference pages
- Architecture diagrams use '75+ tools' to avoid staleness
2026-03-04 18:12:01 +03:00
Peter 31d614a272
fix(mcp): harden HTTP transport defaults (#26) 2026-03-03 17:19:08 +03:00
Danila Poyarkov f4b45d4f13 Replace "fig-kiwi" format name with "Kiwi binary" in docs
fig-kiwi is the magic header string in .fig files, not a format name.
The format is Kiwi binary — used for both .fig files and clipboard.
2026-03-02 15:31:25 +03:00
Danila Poyarkov d93bcab0b6 Add install instructions for @open-pencil/mcp 2026-03-02 14:28:56 +03:00
Danila Poyarkov 4ad90d4819 Add MCP server package with stdio and HTTP transports
29 tools: open_file, save_file, new_document + all 26 from @open-pencil/core.
Stdio for MCP clients (Claude Code, Cursor), HTTP (Hono + Streamable HTTP
with sessions) for scripts, browser extensions, CI.
Runs on both Bun and Node.js (via tsx).
2026-03-02 14:20:49 +03:00
Danila Poyarkov 96d8ab5789 Move docs to packages/docs, add Cloudflare Pages deploy
- Move docs/ → packages/docs/ as @open-pencil/docs workspace package
- Add screenshot.png as hero image on landing page
- Add GitHub Actions workflow for Cloudflare Pages deploy (openpencil.dev)
- Remove vitepress from root devDependencies
- Root docs:* scripts delegate via bun --filter
2026-03-01 15:16:16 +03:00