* fix(docker): support multi-platform builds and fix monorepo paths
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* perf(renderer): cache pre-rasterized paragraph images to avoid per-frame glyph rasterization (#76)
* fix(canvas): stabilize frame label size during zoom
Draw frame labels in screen-space after the viewport transform
restore, converting scene coords manually. Previously fontSize=12/zoom
fed into Math.ceil caused integer-boundary jumps that made labels
flicker during zoom. Also skip shadow rendering while actively
zooming for smoother performance.
* perf(renderer): cache pre-rasterized paragraph images to avoid per-frame glyph rasterization
- Add paraImageCache (SkImage, 128 MB LRU limit) keyed on the same key as paraCache
- Use drawImageRect instead of drawParagraph on cache hit, skipping per-frame glyph shaping and rasterization
- Fall back to direct drawParagraph only when off-screen surface creation (MakeSurface) fails
- Extract _dpr getter to deduplicate device-pixel-ratio resolution logic across draw paths
- Evict oldest entries when cache exceeds byte limit; delete SkImage on eviction and dispose()
* feat(cli): introduce OpenPencil CLI for terminal control of the design tool
- Added a new CLI application under `apps/cli` to manage OpenPencil from the terminal.
- Implemented commands for app control (`start`, `stop`, `status`), document operations (`open`, `save`, `get`, `selection`), and design manipulation (`design`, `import`).
- Enhanced documentation with usage instructions and platform support details.
- Updated build scripts to include CLI compilation and publishing processes.
- Introduced a new GitHub Actions workflow for publishing the CLI to npm.
- Updated existing workflows to integrate CLI build steps and ensure proper versioning across packages.
* docs: update README files to include CLI tool details and multi-platform code export
- Added CLI section to README files in multiple languages, detailing commands for terminal control of the design tool.
- Included instructions for global installation and usage examples for the CLI.
- Expanded documentation on multi-platform code export capabilities from a single `.op` file to various frameworks.
- Updated CLAUDE.md to reference the new CLI documentation and its integration with the design tool.
* chore(bun.lock): update package dependencies to specific versions
- Removed workspace references for several packages in the bun.lock file.
- Updated dependencies for `@zseven-w/pen-core`, `@zseven-w/pen-types`, `@zseven-w/pen-codegen`, `@zseven-w/pen-figma`, and `@zseven-w/pen-renderer` to version `0.5.1-beta.1`.
- Ensured consistency in dependency management across the project.
* fix(docker): add missing CLI package.json to build context
The Dockerfile was missing COPY for apps/cli/package.json, causing
bun install --frozen-lockfile to fail because the CLI workspace
dependency could not be resolved.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add unpublish script and enhance CLI publish workflow
- Introduced a new `unpublish` script to manage unpublishing of all @zseven-w packages from npm, with options for specific versions, all versions, or deprecation.
- Updated the GitHub Actions workflow to check if a version is already published before proceeding with the publish step, ensuring better error handling and preventing conflicts.
- Removed the fallback for npm publish commands to fail fast on errors, improving the reliability of the publishing process.
* chore(bun.lock): update package versions and configuration
- Bumped the configVersion from 0 to 1 in bun.lock.
- Updated several package dependencies to their latest versions, including:
- @anthropic-ai/claude-agent-sdk to 0.2.81
- @babel/helpers to 7.29.2
- @babel/parser to 7.29.2
- @babel/runtime to 7.29.2
- @csstools/color-helpers to 6.0.2
- @csstools/css-color-parser to 4.0.2
- Ensured consistency in dependency management across the project.
* docs: restore Feishu group QR code in Chinese README
* chore: update dependencies and add workspace references
- Added "h3" package with version "^2.0.1-rc.18" to bun.lock, package.json, and apps/web/package.json.
- Updated dependencies in multiple packages to use "workspace:*" for better management and consistency across the project.
- Ensured all relevant packages are aligned with the latest workspace structure.
* chore: update package versions in bun.lock and package.json
- Updated several @tanstack packages to their latest versions, including:
- @tanstack/react-devtools to 0.10.0
- @tanstack/react-router to 1.168.1
- @tanstack/react-router-devtools to 1.166.11
- @tanstack/react-router-ssr-query to 1.166.10
- @tanstack/react-start to 1.167.2
- @tanstack/router-plugin to 1.167.1
- Bumped @tanstack/devtools-vite to 0.6.0 in devDependencies.
- Mocked 'paper' module in security tests to prevent crashes in jsdom environment.
* chore: update CLI and MCP compile scripts to include package aliases
- Enhanced the `mcp:compile` and `cli:compile` scripts in `package.json` and `apps/cli/package.json` to include additional package aliases for better module resolution.
- This change improves the build process by ensuring that the correct paths are used for various dependencies.
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: leinaldo <60176594+leinaldo@users.noreply.github.com>
Co-authored-by: Fini <fini.yang@gmail.com>
* fix(docker): support multi-platform builds and fix monorepo paths
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* perf(renderer): cache pre-rasterized paragraph images to avoid per-frame glyph rasterization (#76)
* fix(canvas): stabilize frame label size during zoom
Draw frame labels in screen-space after the viewport transform
restore, converting scene coords manually. Previously fontSize=12/zoom
fed into Math.ceil caused integer-boundary jumps that made labels
flicker during zoom. Also skip shadow rendering while actively
zooming for smoother performance.
* perf(renderer): cache pre-rasterized paragraph images to avoid per-frame glyph rasterization
- Add paraImageCache (SkImage, 128 MB LRU limit) keyed on the same key as paraCache
- Use drawImageRect instead of drawParagraph on cache hit, skipping per-frame glyph shaping and rasterization
- Fall back to direct drawParagraph only when off-screen surface creation (MakeSurface) fails
- Extract _dpr getter to deduplicate device-pixel-ratio resolution logic across draw paths
- Evict oldest entries when cache exceeds byte limit; delete SkImage on eviction and dispose()
* feat(cli): introduce OpenPencil CLI for terminal control of the design tool
- Added a new CLI application under `apps/cli` to manage OpenPencil from the terminal.
- Implemented commands for app control (`start`, `stop`, `status`), document operations (`open`, `save`, `get`, `selection`), and design manipulation (`design`, `import`).
- Enhanced documentation with usage instructions and platform support details.
- Updated build scripts to include CLI compilation and publishing processes.
- Introduced a new GitHub Actions workflow for publishing the CLI to npm.
- Updated existing workflows to integrate CLI build steps and ensure proper versioning across packages.
* docs: update README files to include CLI tool details and multi-platform code export
- Added CLI section to README files in multiple languages, detailing commands for terminal control of the design tool.
- Included instructions for global installation and usage examples for the CLI.
- Expanded documentation on multi-platform code export capabilities from a single `.op` file to various frameworks.
- Updated CLAUDE.md to reference the new CLI documentation and its integration with the design tool.
* chore(bun.lock): update package dependencies to specific versions
- Removed workspace references for several packages in the bun.lock file.
- Updated dependencies for `@zseven-w/pen-core`, `@zseven-w/pen-types`, `@zseven-w/pen-codegen`, `@zseven-w/pen-figma`, and `@zseven-w/pen-renderer` to version `0.5.1-beta.1`.
- Ensured consistency in dependency management across the project.
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: leinaldo <60176594+leinaldo@users.noreply.github.com>
* docs: add image search & generation design spec and implementation plan
- Spec: dual-source image search (Openverse + Wikimedia), multi-provider image generation
- Plan: 16 tasks covering types, server endpoints, settings UI, property panel, auto-search pipeline, MCP integration
* feat(types): add image service types and imagePrompt to ImageNode
* feat(server): add image service API key validation endpoint
Adds POST /api/ai/image-service-test that validates credentials for
openverse (client_credentials), openai/custom (Bearer + /v1/models),
gemini (API key + v1beta/models), and replicate (Bearer + /v1/models).
* feat(server): add multi-provider image generation endpoint
* feat(server): add dual-source image search endpoint (Openverse + Wikimedia)
POST /api/ai/image-search searches freely-licensed images via Openverse
with automatic fallback to Wikimedia Commons on 429 rate-limit responses.
Supports optional OAuth credentials for authenticated Openverse requests.
* feat(store): add imageSearchStatuses to canvas store for runtime status tracking
* feat(store): add image generation config and Openverse OAuth to agent settings
* feat(editor): add Images tab to agent settings dialog
Adds Popover primitive, ImagesPage component with Image Search (Openverse OAuth, test) and Image Generation (provider select, API key, model, base URL) sections, and wires them into the settings dialog sidebar.
* feat(panels): add image search popover with Openverse/Wikimedia results grid
* feat(panels): add image generate popover with multi-provider support
* feat(panels): add Search and Generate buttons to image property section
* feat(ai): update prompts to use imagePrompt instead of src for image nodes
* feat(ai): add auto-search pipeline with Openverse/Wikimedia fallback
* feat(ai): trigger auto image search after design generation completes
* feat(mcp): implement G() operation for image search in batch design DSL
Adds the G(parent, mode, prompt) operation to batch_design DSL that creates
an image node and optionally fetches a real image URL via the image-search
API when mode is "search". Converts executeLine to async to support the
network call.
* feat(mcp): auto-fill images after design refinement in layered pipeline
* feat(ai): split imageSearchQuery and imagePrompt for search vs generation
- ImageNode now has both imageSearchQuery (short keywords for search)
and imagePrompt (long description for AI image generation)
- AI prompts instruct LLM to generate both fields
- Search pipeline and popovers use imageSearchQuery
- Generate popover uses imagePrompt
- Server-side simplifySearchQuery kept as fallback for manual input
* fix(ai): hook auto image search into orchestrator completion path
The primary generation path uses executeOrchestration -> insertStreamingNode,
not applyNodesToCanvas/animateNodesToCanvas. Added scanAndFillImages call
to orchestrator.ts after all sub-agents complete. Added debug logging.
Removed plan/spec docs from git.
* style(editor): remove provider names from image search ready status
* fix(panels): clean up image gen error display and settings UI
- Parse API error response to show concise message instead of raw JSON
- Limit error text to 2 lines with line-clamp
- Fix image gen test button sending wrong service name
- Inline Image Search ready indicator with section header
- Remove debug logging from image search pipeline
* style(panels): allow up to 4 lines for image gen error message
* fix: avoid 1-frame delay when resizing canvas (#60)
rAF callbacks run before ResizeObserver in the same frame.
Scheduling render in ResizeObserver via rAF defers it to the next frame.
Invoke render() synchronously to leverage ResizeObserver's pre-paint timing
and ensure immediate visual update.
* feat(electron): implement desktop application structure and auto-updater
- Introduced a new Electron desktop application with a structured directory for apps and packages.
- Added auto-updater functionality to manage application updates seamlessly.
- Created a comprehensive menu system for the desktop app.
- Implemented logging capabilities for better debugging and error tracking.
- Configured build settings for various platforms (macOS, Windows, Linux) using electron-builder.
- Established TypeScript configurations for both the desktop and web applications.
- Integrated Vite for the web application with support for React and Tailwind CSS.
- Added icons and assets for the desktop application.
* chore: update package versions to 0.5.0 across all package.json files and add pre-commit hook for version synchronization
- Bumped version to 0.5.0 in package.json files for the main project, desktop app, web app, and all packages.
- Introduced a pre-commit hook to automatically sync version numbers from branch names to all package.json files.
* chore: update package versions to 0.5.0 and refactor Skia components
- Bumped version to 0.5.0 in bun.lock and all relevant package.json files.
- Refactored Skia components to utilize shared functionality from @zseven-w/pen-renderer, including image loading, hit testing, and path utilities.
- Removed redundant code and improved modularity by re-exporting necessary functions and classes from the renderer package.
* fix(panels): handle string fill values in icon nodes (#61)
AI-generated icon/path nodes may have fill stored as a raw string
instead of a PenFill[] array, causing "Cannot use 'in' operator"
crash when selecting the node in the property panel.
* chore: update documentation and project structure for monorepo organization
- Added a new version bump command to synchronize all package.json files.
- Updated the project structure to reflect a monorepo setup with organized workspaces for apps and packages.
- Enhanced README files in multiple languages to include the new structure and commands.
- Adjusted image paths in documentation to point to the correct locations for the desktop application.
* feat(ai): incremental image search and improved image generation prompts
- Refactor image search from batch post-generation to incremental queue:
enqueueImageForSearch() triggers as each image node is inserted during
streaming, so images appear progressively instead of all at once after
generation completes. scanAndFillImages() remains as a final sweep.
- Update imagePrompt guidance to avoid "transparent background" and
similar phrases that many models cannot reliably produce.
- Pass node width/height from image panel to generation endpoint for
aspect-ratio-aware output (Gemini aspect ratio mapping, OpenAI size
selection, Replicate dimensions).
* feat(ai): multi-profile image generation config and cleaner error messages
- Support multiple image generation profiles with active selection;
first configured profile becomes default. Old single-config migrated
automatically on hydrate.
- Fix Gemini aspect ratio: move to generationConfig.imageConfig per API spec.
- Extract clean error messages from provider JSON responses (Gemini
error.message, OpenAI error.message, Replicate detail) instead of
returning raw JSON text.
- Remove destructive client-side regex that mangled error display.
* feat(design-md): integrate design system panel and functionality
- Added a new DesignMdPanel component for managing design system specifications.
- Implemented functionality to toggle the design system panel in the editor layout and toolbar.
- Introduced new commands for importing, exporting, and auto-generating design.md content.
- Updated AI chat handlers to utilize design.md data for enhanced design generation.
- Enhanced localization support for design system features across multiple languages.
* perf(canvas): skip draw calls for nodes outside the viewport (#64)
Add viewport culling in render() to avoid issuing CanvasKit draw calls
for off-screen nodes. A 64px screen-space buffer is kept around the
viewport edges so nearby nodes are pre-rendered, preventing pop-in
during fast panning.
* feat(utils): enhance Windows process spawning for CLI scripts
- Updated the buildSpawnClaudeCodeProcess function to handle .cmd and .ps1 scripts appropriately.
- Implemented PowerShell invocation for .ps1 files and ensured safe defaults for .cmd and .exe files.
- Improved handling of command execution to avoid limitations of cmd.exe.
* feat(ai): add support for Gemini CLI integration
- Extended the AI provider options to include 'gemini' across various components and APIs.
- Implemented functions for generating, validating, and connecting to the Gemini CLI.
- Added Gemini-specific error handling and model fetching logic.
- Updated UI components to display Gemini as a selectable provider with appropriate icons and labels.
- Enhanced localization support for Gemini-related features in multiple languages.
* feat(editor): warn before closing with unsaved changes
Intercept window/tab close when isDirty is true:
- Electron: native dialog with Save / Don't Save / Cancel
- Web: beforeunload handler + confirm on New/Open actions
- i18n: close-confirm strings for all 15 locales
* feat(ipc): extract IPC handlers to a dedicated module
- Moved IPC dialog handling and updater functions from main.ts to ipc-handlers.ts for better organization and maintainability.
- Implemented file open/save dialogs, theme setting, and preferences management through IPC.
- Enhanced updater functionality with state management and auto-update settings.
- Improved code structure by separating concerns, making it easier to manage IPC-related logic.
* feat(docs): update CLAUDE documentation and add new files for desktop and web apps
- Enhanced CLAUDE.md with detailed module documentation references for `packages/` and `apps/`.
- Updated `pen-core` description to include clone utilities in `pen-core`.
- Added new documentation files for the desktop and web applications, outlining their structure, components, and functionalities.
- Included IPC handler details in the desktop app documentation for better clarity on file dialogs and theme synchronization.
* feat(docker): add Gemini CLI support and update documentation
- Introduced a new Docker build stage for the Gemini CLI, allowing users to install and run it.
- Updated the Dockerfile to include the installation of the Gemini CLI alongside existing CLI tools.
- Enhanced README files in multiple languages to document the new `openpencil-gemini` image variant.
- Added Gemini CLI connection instructions to the main README for better user guidance.
* feat(docs): add Gemini CLI connection instructions to multiple language READMEs
- Updated README files in German, Spanish, French, Hindi, Indonesian, Japanese, Korean, Portuguese, Russian, Thai, Turkish, Vietnamese, and both Traditional and Simplified Chinese to include connection instructions for the Gemini CLI.
- Enhanced documentation to improve user guidance for connecting the Gemini CLI in agent settings.
* perf(renderer): replace count-based text cache limits with memory-based eviction (#66)
previous limits (PARA_CACHE_MAX=200, TEXT_CACHE_MAX=300) were too small
for scenes with many nodes, causing constant cache churn and paragraph
rebuilds every frame, which dropped FPS significantly during canvas pan.
- switch to byte-budget limits (64 MB paragraphs, 256 MB bitmaps)
- bitmap size measured exactly as cw*ch*4; paragraph WASM heap estimated
as content.length*64+4096
- eviction uses Map insertion order (FIFO) instead of a separate string[]
array, replacing O(n) array.shift() with O(1) Map.entries().next()
- evict before insert so the budget check includes the incoming entry
---------
Co-authored-by: Fini <fini.yang@gmail.com>
Co-authored-by: leinaldo <60176594+leinaldo@users.noreply.github.com>
* feat(docker): add Docker support with multi-stage build and CI workflow
- Introduced a `.dockerignore` file to exclude unnecessary files from the Docker context.
- Added a `Dockerfile` for multi-stage builds, optimizing the application for production with a slim runtime.
- Created a GitHub Actions workflow (`docker.yml`) to automate the building and pushing of Docker images on version tag pushes.
- Enhanced the `connect-agent.ts` and `install-agent.ts` files to improve OpenCode binary resolution and installation commands.
- Updated the canvas components to support new polygon shape and related functionalities, including UI adjustments for shape tools and appearance settings.
This update significantly enhances the deployment process and expands the application's capabilities with Docker integration.
* feat(docker): enhance Dockerfile with multi-stage builds and CLI variants
- Updated the Dockerfile to include multiple image variants for different CLI tools, including Claude, Codex, OpenCode, and Copilot, alongside the base web app.
- Improved the build process by separating the build stage and production stage, optimizing the final image size.
- Added environment variables and commands for each variant to ensure proper execution in production.
- Enhanced the README files in multiple languages to document the new Docker deployment options and usage instructions.
This update significantly expands the Docker deployment capabilities, allowing users to choose the appropriate image variant based on their needs.
* fix(ai): add icon name aliases and fix multi-path SVG concatenation
Add 55+ common icon name aliases (burger→hamburger, sushi→fish, etc.)
to both client icon-resolver and server icon API for robust AI-generated
icon resolution. Register Lucide's own aliases for broader coverage.
Fix SVG path concatenation bug where joining multiple <path> d-values
caused incorrect rendering — a standalone <path> treats initial lowercase
"m" as absolute, but after concatenation it becomes relative to the
previous sub-path endpoint. Now ensures each sub-path starts with
absolute "M".
Add tryAsyncIconFontResolution for icon_font nodes that miss local
lookup — fetches from server API, caches result, and triggers canvas
re-render.
* fix(canvas): preserve badge/overlay absolute positioning in auto-layout
Add isBadgeOverlayNode() detector for badge, indicator, notification-dot,
and overlay nodes. These nodes now retain their x/y coordinates instead
of being stripped by layout sanitization.
Update computeLayoutPositions to exclude badge nodes from the layout flow
— they keep absolute positioning and render on top (prepended for correct
z-order in reverse iteration).
* fix(ai): prevent duplicate canvas objects and fix emoji-to-icon pipeline
Streaming path: add ensureUniqueNodeIds before inserting nodes to prevent
ID collisions across multiple AI generations. Track newly inserted IDs
so subsequent streaming nodes don't collide either.
Canvas sync: deduplicate Fabric objects sharing the same penNodeId —
keep only the one tracked in objMap, remove stale duplicates.
Badge nodes: use shared isBadgeOverlayNode() for z-order insertion
and skip x/y stripping in layout parents.
Fix emoji-to-icon pipeline: re-run applyIconPathResolution after
applyNoEmojiIconHeuristic converts emoji text nodes to path nodes,
so the icon resolver can match by name (e.g. "Pizza Emoji Path" → pizza).
* fix(canvas): add async icon resolution fallback for icon_font nodes
When lookupIconByName fails locally, queue tryAsyncIconFontResolution
to fetch from server API. Cache result in ICON_PATH_MAP and trigger
canvas re-render via store update. Store iconFontName and iconStyle
on Fabric object for sync tracking.
* fix(ai): strengthen emoji ban in prompts and improve orchestrator defaults
Update all AI prompts to explicitly ban emoji characters with concrete
examples and redirect to icon_font nodes instead of the previously
incorrect "path nodes" guidance.
Add z-order rule to orchestrator prompt: overlay elements must come
before content they overlap.
Add padding support to OrchestratorPlan rootFrame type. Default mobile
root frame gap to 16 for consistent spacing.
* feat(electron): add publisher name to Windows build configuration
Updated the `electron-builder.yml` to include a publisher name for Windows builds, enhancing the identification of the application during installation. Additionally, revised the README files across multiple languages to reflect the new project description and features, emphasizing OpenPencil as the world's first AI-native open-source vector design tool with concurrent agent teams and design-as-code capabilities.
---------
Co-authored-by: Fini <fini.yang@gmail.com>
* feat(mcp): enhance document management and design tools
- Updated `openDocument` to always re-fetch the live canvas, ensuring user edits are captured.
- Introduced new tools: `get_design_prompt` for retrieving design guidelines and `batch_design` for executing multiple design operations using a DSL.
- Improved `handleInsertNode` and `handleUpdateNode` to include validation for node data and return the final node state after operations.
- Enhanced design prompt with detailed PenNode schema and layout rules for better AI-generated designs.
- Added validation functions to ensure node data integrity during CRUD operations.
- Updated `handleOpenDocument` to provide context-aware design prompts based on document content.
* feat(electron): enhance build configuration and auto-update functionality
- Updated `electron-builder.yml` to include artifact naming conventions for Windows and Linux builds.
- Enhanced NSIS installer settings to create desktop and start menu shortcuts.
- Improved path handling for GUI applications on Windows to ensure proper environment variable inheritance.
- Refactored auto-update logic in `main.ts` to streamline update checks and improve error handling.
- Added new IPC handlers for managing pending file paths and improved file handling during application startup.
- Updated `use-electron-menu` hook to handle additional menu structures and improve document loading logic.
* chore: bump version to 0.3.1 and update project description
- Updated version in package.json to 0.3.1.
- Enhanced project description to highlight OpenPencil as the world's first open-source AI-native vector design tool featuring concurrent Agent Teams and Design-as-Code capabilities.
- Refactored auto-updater to utilize constants for GitHub repository details, improving maintainability.
- Introduced a new constants file to centralize shared values for the Electron application, enhancing code clarity and reducing duplication.
- Updated various components to use new constants for port file handling and window dimensions, ensuring consistency across the application.
* feat(ai): clarify mobile design guidelines and mockup usage
- Updated design guidelines to emphasize that "mobile" requests should generate actual mobile-sized screens (375x812) instead of desktop mockups.
- Added critical notes regarding the use of phone mockups, specifying they should only be used for marketing showcases and not for functional mobile screens.
- Enhanced clarity on sizing and layout rules for mobile and web designs to ensure consistent application of design principles.
* fix(canvas): improve text centering, layout inference, and Pencil format rendering
- Resolve fit-content parent dimensions in computeLayoutPositions instead of
using 0 (which caused negative available space and broken child positioning)
- Reduce text width estimation minimum from 20px to 1px to fix centering of
narrow single-character text in fixed-size centered frames
- Add inferLayout() to detect padding-only frames as layout containers, so
padding offsets are applied to children (fixes badge text ignoring padding)
- Use Fabric's fontSize * 1.13 for single-line text height in centering
calculations instead of fontSize * lineHeight
- Add fontWeight propagation to text width/height estimation functions
- Refine defaultLineHeight() tiers for better Pencil format compatibility
- Support Pencil's singular `effect` property alongside `effects` array
- Handle plain color strings in fill/stroke resolution for Pencil format
- Add directional stroke rendering as synthetic border rectangles
- Add icon_font node type rendering via lookupIconByName
- Fix z-order reconciliation to use fresh canvas object map after text recreation
- Fix canvas initialization race: defer reference tracking until canvas is ready
- Resolve $variable references with circular reference guards
* feat(types): add icon_font node type with panel and store support
- Add IconFontNode type to pen.ts for icon_font nodes storing iconFontName
- Extend property panel and icon section to recognize icon_font nodes
- Add icon_font type icon in layer panel
- Support icon_font in document tree utilities
* feat(ai): improve design generation accuracy and validation
- Add pre-validation pass to fix text with explicit pixel height to fit_content
- Enhance validation tree dump with textGrowth and lineHeight fields
- Update orchestrator prompts with structural patterns from Pencil analysis
- Simplify role-resolver defaults to match Pencil conventions
- Only force textGrowth=fixed-width on text >15 chars in streaming insertion
* feat(ai): optimize generation pipeline and fix streaming layout
- Disable LLM validation layer (pre-validation heuristics still run)
- Remove visual-ref pipeline (3 fewer LLM calls per generation)
- Compress sub-agent prompt and design principles (~70% smaller)
- Remove width>480 guards so mobile gets root frame height expansion
- Add gap field to orchestrator rootFrame format and guidance
- Default icon_font nodes to lucide family in generation heuristics
* feat(ai): load full Lucide icon set and default icon_font to lucide
- Load all 1,729 Lucide icons as primary set (replaces 286 hand-picked)
- Keep Feather as fallback for unmatched names
- Default iconFontFamily to 'lucide' during .pen file normalization
* feat(codegen): add icon_font support to all 8 code generators
Output Lucide icon references instead of 'Unknown node' comments.
React/RN use component syntax, HTML/Vue/Svelte use data-lucide,
Flutter/SwiftUI/Compose use framework-native icon APIs.
* feat(panels): replace product card quick action with food app homepage
* feat(electron): implement preferences management and app storage abstraction
- Introduced a new preferences management system in Electron, replacing localStorage with a JSON-based preferences file.
- Added IPC handlers for getting, setting, and removing preferences, ensuring data persistence across sessions.
- Created an app storage utility to provide a consistent API for accessing preferences in both Electron and web environments.
- Updated various components and stores to utilize the new app storage system for improved data handling and synchronization.
- Enhanced the initialization process to load preferences at startup, ensuring a seamless user experience.
* fix(electron): update desktop entry configuration for OpenPencil
- Enhanced the desktop entry in electron-builder.yml to include detailed application metadata.
- Added fields for Name, Exec, Terminal, Type, Icon, Categories, and MimeType to improve application integration on Linux systems.
* fix(electron): prevent automatic publishing during build
- Updated the Electron app build command to include the `--publish never` flag, ensuring that builds do not automatically publish to the repository.
* refactor(electron): remove GitHub publish configuration from electron-builder.yml
- Deleted the publish section to prevent automatic publishing during builds, aligning with recent changes to the build process.
---------
Co-authored-by: Fini <fini.yang@gmail.com>
* chore(electron): update mac build scripts for improved artifact handling
- Modified the `electron:build:mac-arm64` script to rename the generated YAML file for better clarity.
- Adjusted the `electron:build:mac-both` script to run builds sequentially without file renaming logic, ensuring consistent output.
* chore(electron): enable notarization for macOS builds and update build workflow secrets
- Added notarization support in `electron-builder.yml` for enhanced security.
- Updated GitHub Actions workflow to include necessary Apple credentials for notarization.
* chore(electron): add additional secrets for macOS notarization in build workflow
- Included CSC_LINK and CSC_KEY_PASSWORD in the GitHub Actions workflow to support code signing for macOS builds.
* feat(types): add ImageFitMode type and objectFit to ImageNode
Support fill/fit/crop/tile image scaling modes, matching Figma's
image fill behavior. Default is 'fill' (cover) for backward compat.
* feat(canvas): render images per fill mode with native crop
Add computeImageTransform helper supporting fill/fit/crop/tile modes.
Fill/crop uses FabricImage native cropX/cropY instead of clipPath to
avoid conflict with parent frame clipping. Tile mode creates a Rect
with Pattern fill. Detect mode changes via __needsRecreation flag for
object recreation when switching between tile and non-tile modes.
* feat(panels): add image fit mode dropdown to property panel
New ImageSection component with Fill/Fit/Crop/Tile dropdown for
image nodes. Wired into PropertyPanel between icon and appearance
sections.
* feat(figma): preserve image scale mode from Figma import
Map Figma imageScaleMode (FIT/FILL/TILE) to objectFit property on
imported ImageNodes so fill mode is preserved across import.
* fix(canvas): fix zoom-to-fit bounds inflated by clipped children
computeDocBounds was recursing into frame children, inflating the
bounding box beyond visible frame bounds. Now only recurses into
groups. Also use double-RAF in Figma import for reliable timing.
* feat(figma): implement Figma clipboard paste functionality
- Added a new hook, useFigmaPaste, to handle pasting Figma clipboard data into the canvas.
- Integrated clipboard data extraction and processing to convert Figma nodes into PenNodes.
- Enhanced keyboard shortcuts to attempt reading Figma data from the system clipboard as a fallback.
- Introduced utility functions for decoding and processing Figma clipboard HTML data.
- Updated editor layout to utilize the new Figma paste functionality.
* feat(figma): implement Figma clipboard support for pasting nodes
- Added a new hook, `useFigmaPaste`, to handle Figma clipboard data extraction and processing.
- Integrated Figma clipboard support into the editor layout and keyboard shortcuts for seamless pasting.
- Updated README to reflect changes in file format from `.pen` to `.op`.
- Refactored AI service methods to route to appropriate provider SDK based on the `provider` field, enhancing flexibility in AI interactions.
* fix(figma): preserve imported node order and disable openpencil auto layout
Prevent imported/generated nodes from being prepended in auto-layout containers, which could reverse visual order during progressive insertion.
Hide the unfinished OpenPencil auto-layout path from the import dialog to avoid selecting a mode that is not ready yet.
* fix(ai): enforce explicit provider and model routing
Pass selected provider and model through design generation, orchestration, sub-agent, and validation flows.
Disable provider/model fallback and remove model retry-without-selection behavior so requests fail fast instead of silently routing to Claude.
* chore(package): bump version to 0.1.1
---------
Co-authored-by: Fini <fini.yang@gmail.com>
* feat(editor): implement Figma import functionality
- Added a new FigmaImportDialog component for importing .fig files.
- Integrated file processing and conversion logic to handle Figma files.
- Enhanced the editor layout to include a button for opening the Figma import dialog.
- Introduced page tabs for better navigation between document pages.
- Updated various components to utilize active page children for rendering and interactions.
- Added new dependencies: fzstd and kiwi-schema for improved functionality.
* fix(ai): harden Claude agent env variable resolution
- Filter empty strings and object values from settings.json env
- Validate ANTHROPIC_CUSTOM_HEADERS is valid JSON before passing
- Remove incorrect ANTHROPIC_CUSTOM_HEADERS auto-generation from auth token
* refactor(ai): remove silent fallback logic, surface errors in AI panel
- Remove direct-stream fallback in generateDesign, delegate to orchestrator
- Remove orchestrator planner fallback plan (buildFallbackPlanFromPrompt)
- Remove sub-agent retry logic, minimal mode retry, and placeholder insertion
- Throw on sub-agent error instead of silently degrading
- Call updateLastMessage in catch block so errors display immediately
- Clean up unused imports, functions, and console.log/warn statements
* fix(ai): add 30s API connect timeout for faster error detection
- Set maxRetries: 0 on Anthropic SDK to prevent retry delays on 429
- Add AbortController-based 30s timeout for initial API connection
- If the provider doesn't respond within 30s, abort and send SSE error
- Refactor streamViaAnthropicSDK with shared send() helper
* fix(editor): improve Figma import visual fidelity
- Extract image files from .fig ZIP archive and resolve by SHA-1 hash
- Map Figma textCase property (UPPER/LOWER/TITLE) to text content
- Convert ellipse nodes with image fills to image nodes
- Decode Figma vector paths and match icons via Lucide icon registry
- Fix z-order: move background rectangles behind content layers
- Set clipContent=true for Figma frames (default clip behavior)
- Unwrap single-artboard pages to use artboard as root frame
* fix(canvas): preserve clipPath during async image load and invalidate cache
- Copy clipPath from placeholder rect to FabricImage in onload callback
- Set obj.dirty=true after applying/removing clipPath so Fabric.js
re-renders with the updated clip region instead of using stale cache
* fix(ai): use page-aware empty frame detection and place new designs as siblings
- Fix isCanvasOnlyEmptyFrame() to use getActivePageChildren() instead of
document.children which is empty after page migration
- When canvas is empty, replace default frame (existing behavior restored)
- When canvas has content, add generated frame as top-level sibling
positioned to the right with 100px gap
- Track generationRootFrameId so height adjustment targets correct frame
- Add WIDTH SELECTION rule: app screens use 375x812 mobile dimensions
- Include selected node dimensions in AI context string
* feat(electron): implement application menu with native actions
- Added a native application menu for macOS and Windows, including File, Edit, View, and Window menus.
- Integrated menu actions for creating, opening, saving files, and editing operations like undo/redo.
- Enhanced the editor layout to handle Electron menu actions through a custom hook.
- Updated icon components in the toolbar and top bar for consistent styling.
- Refactored padding and layout components for improved structure and readability.
* fix(canvas): use page-aware children for selection depth resolution
getSelectableNodeIds() used doc.children which is empty under the
pages architecture. Switch to getActivePageChildren() so canvas
selection correctly syncs to the layers panel.
* fix(panels): adjust property panel sections for image nodes
Hide fill/stroke sections (not applicable to images) and show
corner radius section for image elements.
* feat(canvas): implement image corner radius via clipPath
FabricImage does not support rx/ry natively. Use a rounded-rect
clipPath instead, with objectCaching disabled to ensure immediate
re-render on radius changes.
* fix(canvas): use page-aware forcePageResync for canvas re-sync
The old pattern { ...doc, children: [...doc.children] } only touched
root-level children which are empty under pages architecture. Extract
forcePageResync() into canvas-sync-utils and replace all 7 occurrences
across canvas-object-modified, drag-into-layout, and layout-reorder.
* fix(canvas): preserve image corner radius clipPath during drag
Three issues caused corner radius loss on image drag:
1. Scale baking in object:modified changed FabricImage width from
natural to display dimensions, creating a clipPath size mismatch.
Exclude images from scale baking (like paths/polygons).
2. object:moving unconditionally cleared all clipPaths to avoid stale
frame clipping. Now only clears absolutePositioned (frame) clips,
preserving object-level clips like image corner radius.
3. Post-drag re-sync overwrote the corner radius clipPath with the
parent frame clip. Now skips frame clip when the object already
has its own non-absolutePositioned clipPath.
* feat(ai): enhance chat functionality with image attachments support
- Added support for image attachments in chat messages, allowing users to send images alongside text.
- Implemented temporary file handling for attachments, ensuring they are accessible to the AI processing.
- Updated chat message structure to include attachments, and modified the prompt building logic to reference these images.
- Enhanced the chat panel UI to allow users to select and preview images before sending.
- Introduced a new state management for pending attachments in the AI store.
- Refactored related components to accommodate the new attachment feature, improving user experience and interaction.
* feat(multi-page): introduce multi-page architecture and enhance agent settings UI
- Added multi-page architecture to the document structure, allowing for page CRUD actions such as add, remove, rename, reorder, and duplicate.
- Implemented `activePageId` state management in the canvas store for better page handling.
- Enhanced the top bar with an `AgentStatusButton` to display connected AI providers and their statuses.
- Updated the agent settings dialog to improve the UI for managing AI integrations, including better layout and connection indicators.
- Refactored related components for improved usability and visual consistency.
* docs(README): add contributors section with dynamic contributor image
* feat(ai): improve chat streaming and error handling
- Added functionality to hide the checklist when streaming stops with no completed items.
- Implemented abort controller management to handle user-initiated stops during chat generation.
- Enhanced error handling to prevent displaying errors for user-initiated stops while preserving partial content.
- Updated orchestration and design generation functions to support abort signals, improving responsiveness during streaming.
* fix(canvas): align z-order with layer panel convention (top = front)
Establish consistent z-order: children[0] = top of layer panel = frontmost
on canvas. This matches the standard design tool convention (Figma, Sketch).
- Reverse flattenNodes iteration so children[0] is added last to canvas
- Add z-order reconciliation via moveObjectTo after each sync pass
- Figma import: sort children descending so front items are at children[0]
- addNode defaults to prepend (index 0) so new items appear at top
- duplicateNode inserts clone above original (at idx instead of idx+1)
- drag-reparent inserts at index 0 (frontmost) instead of childCount
- Async image loading preserves z-order via insertAt instead of add
- Add FigmaImportLayoutMode toggle (preserve vs openpencil auto-layout)
* chore: resolve .gitignore merge conflict
* fix(canvas): clamp corner radius to half the element height
* chore: update version to 0.1.0 and modify mac artifact naming in electron-builder configuration
* chore: update build-electron workflow to include write permissions for contents
---------
Co-authored-by: Fini <fini.yang@gmail.com>
* feat(editor): add github releases auto update flow
Enable desktop auto-update checks and install prompt so packaged apps can update from published GitHub Releases.
* fix(canvas): keep frame labels aligned during zoom
Draw labels in viewport space with zoom-aware positioning so frame titles stay anchored while panning and zooming.
* fix(ai): disable chat interactions when no models connected
Prevent sending and shortcut actions when provider models are unavailable, and show a concise model picker hint to avoid false-available UI states.
* docs: refresh readme community and demo section
Embed the product demo video inline, add a styled Discord community entry, and update media assets for clearer README presentation.
* chore: update nitro external dependency settings
Align SSR bundling with current runtime usage by removing the unnecessary @opencode-ai external entries.
* feat(electron): enhance macOS build process and update auto-updater
- Added a new build script for macOS that allows building for both arm64 and x64 architectures.
- Updated GitHub Actions workflow to support separate build arguments for macOS arm64 and x64.
- Implemented a custom GitHub update provider for macOS to handle versioning based on architecture.
- Introduced a new icon for the electron app and removed the old logo image.
---------
Co-authored-by: Fini <fini.yang@gmail.com>
* feat(canvas,panels): multi-selection drag, shift-key selection, and chat pipeline UI
- Preserve multi-selection when clicking a selected object without Shift,
enabling drag-move of the whole set
- Set selectionKey to shiftKey so only Shift+click toggles multi-select
- Refactor chat-message step rendering: extract step blocks with regex,
add pipeline checklist progress UI, separate step display from markdown
- Adjust AI chat panel selection count display and layout
* feat(opencode): integrate OpenCode SDK for enhanced AI interactions
- Add support for OpenCode as a new AI provider, allowing users to connect to a local OpenCode server.
- Implement new API endpoints for generating and streaming chat responses via OpenCode.
- Update UI components to include OpenCode in provider selection and display.
- Introduce OpenCode logo and enhance the agent settings dialog to manage OpenCode connections.
- Refactor existing chat and generation logic to accommodate provider-specific routing.
- Include type definitions for OpenCode SDK to ensure type safety and improve developer experience.
* feat(electron): integrate Electron framework for desktop application support
- Add Electron configuration and main process setup for building a desktop application.
- Implement IPC communication for file operations (open, save) between the renderer and main processes.
- Create a preload script to expose Electron APIs to the renderer.
- Update package.json to include Electron and related dependencies.
- Enhance the build process with electron-builder for packaging the application.
- Introduce a new electron-builder.yml configuration file for build settings.
- Modify Vite configuration to support Electron-specific builds.
- Update UI components to accommodate Electron's window management and drag regions.
* fix(canvas): multi-selection drag reparenting and infinite recursion guard
- Add re-entry guard to object:modified handler to prevent infinite
recursion caused by discardActiveObject() firing object:modified
via _finalizeCurrentTransform
- Extend drag-into detection to non-layout root frames (rootFrameBounds)
in addition to layout containers (layoutContainerBounds)
- Add checkReparentIntoFrame() fallback for root-level objects dragged
into frames, handling both layout and non-layout targets
- Redirect _currentTransform to ActiveSelection in mouse:down so the
whole group moves/scales/rotates together
- Support same-container reorder in commitDragIntoMulti
- Fix guide-utils getEdges() for center-origin ActiveSelection objects
- Track selection descendants for visual drag-follow during multi-drag
- Show position coordinates during multi-selection drag in dimension label
* feat(store,canvas): add reusable component and instance system
add makeReusable/detachComponent store methods, RefNode resolution in
canvas sync with component/instance selection borders, virtual child ID
handling in selection context, purple/instance-colored frame labels,
and collision avoidance when duplicating nodes
* feat(panels): add component/instance UI to layer and property panels
layer panel shows diamond icon and purple/#9281f7 styling for
components/instances with context menu actions; property panel resolves
RefNode display, routes instance overrides, adds header with go-to and
detach buttons, and supports inline name editing on click
* feat(canvas): match hover outline to selection style for components and instances
hover outlines now use purple solid for reusable components and #9281f7
dashed for instances, consistent with their selection border styling
* fix(editor): save directly without dialog for previously opened files
prioritize fileName check over File System Access API so opened files
save via download without showing a file picker; also add Cmd+Alt+K
shortcut for creating reusable components
* refactor(canvas): remove dimension label overlay
remove the blue dimension/position label that appeared on selection,
drag, and scale interactions
* feat(export): add export section for raster image export functionality
- Introduce a new ExportSection component to facilitate exporting layers as raster images in various formats (PNG, JPEG, WEBP) with adjustable scale options.
- Integrate the ExportSection into the PropertyPanel for easy access during design editing.
- Enhance export utility functions to support exporting layers and managing descendant nodes.
* feat(assets): add new icon files for application branding
- Introduce new icon files in various formats (ICNS, ICO, PNG) for application branding.
- Add logo image for the Electron interface to enhance visual identity.
- Update canvas selection logic to allow programmatic selection from the layer panel.
* feat(electron): enhance Electron app integration and CI/CD workflows
- Add new commands for Electron development, compilation, and building processes in CLAUDE.md.
- Update README.md to reflect the availability of the application as both a web and desktop app.
- Introduce a FixedChecklist component in the AI chat panel for better user interaction with generated tasks.
- Implement CI/CD workflows for automated testing and Electron builds in GitHub Actions.
- Refactor design generator prompts to support element-by-element streaming for improved performance.
* feat(ai): enhance chat functionality and orchestration capabilities
- Introduce context optimization to manage chat history size and prevent unbounded growth.
- Implement complexity assessment for design prompts to determine orchestration needs.
- Add orchestrator functionality for parallel design generation, improving performance and responsiveness.
- Update chat message parsing to include explicit status handling for orchestrator steps.
- Refactor design generator to support orchestration and streamline context building.
* refactor(ai): streamline orchestration and remove complexity classifier
- Remove the complexity classifier as its functionality is no longer needed.
- Update design generator to always route through the orchestrator, simplifying the logic.
- Enhance error handling during orchestration to ensure fallback to direct generation is clear.
- Introduce a new sub-agent prompt for improved output formatting and clarity in design generation.
* feat(ai): refine orchestrator prompt and timeout settings
- Update the ORCHESTRATOR_PROMPT to allow for more granular task division, specifying 4-15 atomic sections.
- Enhance the JSON output structure by adding new subtasks for the hero section.
- Adjust ORCHESTRATOR_TIMEOUTS to extend hard and no-text timeout values for improved orchestration performance.
* feat(docs): update CLAUDE.md and README.md for new features and improvements
- Expand the Fabric.js integration section in CLAUDE.md to include new files and functionalities.
- Highlight new features such as double-click frame entry, advanced drag-and-drop capabilities, and per-layer export options in README.md.
- Add context optimization and multi-provider support for AI in README.md.
- Update the project structure descriptions for clarity and completeness.
* refactor(config): update Vite configuration import for Vitest compatibility
* chore(ci): update GitHub Actions workflow to trigger on main branch pushes
* feat(uikit): introduce UIKit browser and component management features
- Add a new ComponentBrowserPanel for browsing and managing UI components.
- Implement ComponentBrowserGrid and ComponentBrowserCard for displaying components.
- Integrate UIKit store for managing component kits, search queries, and active categories.
- Enhance editor layout to support toggling the UIKit browser with keyboard shortcuts.
- Include import/export functionality for UIKit components.
* feat(types): add clipContent to ContainerProps
Allow frames to explicitly clip overflowing children, essential for
cards with cornerRadius + image children.
* feat(canvas): wire letterSpacing, textGrowth and clipContent to Fabric.js
- Convert letterSpacing (px) to Fabric charSpacing (1/1000 em) in
factory and sync
- Select IText vs Textbox based on textGrowth mode, restore canvas
selection after text object recreation
- Add multi-line text height estimation with CJK character support
- Honor clipContent flag in clipping logic
* feat(panels): split text Layout and Typography into separate sections
- Add readOnly prop to NumberInput for non-editable dimension display
- Extract text Layout section (dimensions, fill/hug, resizing toggles)
into text-layout-section.tsx
- Enhance Typography section with line height, letter spacing, vertical
alignment controls
- Reorder property panel: Size → Layout → Appearance → Fill → Stroke →
Typography → Effects
- Add hideWH prop to SizeSection to avoid duplicate W/H inputs
* feat(panels): rewrite layout-section with full Flex Layout panel
- 3x3 alignment grid with context-aware behavior per layout direction
- Gap section with numeric/space-between/space-around radio modes
- Multi-mode padding: single, 2-axis (V/H), 4-individual (T/R/B/L)
with gear popover
- Dimensions (W/H) and sizing checkboxes (fill/hug/clip) integrated
into layout panel
* feat(panels): improve layer panel with auto-collapse and scroll-to-selection
- Collapse all layers by default, auto-collapse newly added nodes
- Auto-expand ancestor layers when a child is selected on canvas
- Scroll selected layer item into view after expansion
* fix(panels): improve AI chat panel overflow and color picker styling
- Fix chat panel overflow with proper flex layout and min-h-0
- Cap checklist height with scrollable overflow
- Adjust color picker input sizing
* feat(codegen): add textGrowth, textAlignVertical and clipContent to code generation
- textGrowth: auto → whitespace-nowrap, fixed-width-height → overflow-hidden
- textAlignVertical: middle/bottom → vertical-align CSS
- clipContent: true → overflow-hidden on containers
* feat(ai): integrate text typography properties into design prompts
- Add textGrowth, lineHeight, letterSpacing, textAlignVertical, fontStyle
to PEN_NODE_SCHEMA and sub-agent prompt
- Add typography scale guidelines with lineHeight/letterSpacing defaults
- Update examples with lineHeight, clipContent, fill_container usage
- Add phone placeholder and clipContent rules
* feat(ai): enhance streaming service with runtime config and thinking modes
- Extract timeout constants to ai-runtime-config.ts
- Add thinking mode control (adaptive/disabled/enabled) to stream options
- Add StyleGuide interface for orchestrator visual consistency
- Add ping timeout and first-text timeout options
* feat(ai): improve design generator with typography defaults and phone placeholder
- Set default lineHeight on text nodes (1.2 for headings, 1.5 for body)
- Expand phone/mockup placeholder detection with shape-based fallback
- Flatten nested phone-shaped frames in post-streaming tree fixes
- Increase CJK character width estimation and button padding buffer
* feat(ai): enhance orchestrator with style guide and prompt optimizer
- Pass style guide from orchestrator plan to sub-agent prompts
- Add orchestrator-prompt-optimizer for context-aware prompt tuning
- Improve parallel sub-task generation and error recovery
* feat(ai): add thinking mode and Codex provider support to server API
- Support thinkingMode/effort params in chat and generate endpoints
- Add Codex (OpenAI) provider streaming via codex-client utility
- Forward thinking config to both Anthropic SDK and Agent SDK paths
* feat(mcp): implement OpenPencil file format and MCP server integration
- Introduce support for .op file format alongside .pen
- Add MCP server functionality for document management and tool operations
- Implement batch processing tools for design and variable management
- Enhance save and open dialogs to accommodate new file format
- Update dependencies and scripts for MCP server compilation and execution
* feat(build): update electron build configuration and resource handling
- Add mcp-server.cjs to extraResources in electron-builder.yml for production packaging
- Modify package.json build script to include MCP server compilation
- Enhance main.ts to set ELECTRON_RESOURCES_PATH for resource access
- Update mcp-install.ts to resolve MCP server path from resources in production
---------
Co-authored-by: Fini <fini.yang@gmail.com>
- Add new commands for Electron development, compilation, and building processes in CLAUDE.md.
- Update README.md to reflect the availability of the application as both a web and desktop app.
- Introduce a FixedChecklist component in the AI chat panel for better user interaction with generated tasks.
- Implement CI/CD workflows for automated testing and Electron builds in GitHub Actions.
- Refactor design generator prompts to support element-by-element streaming for improved performance.