Commit graph

165 commits

Author SHA1 Message Date
Danila Poyarkov 005f1bcdfa
Merge branch 'master' into polish-pr-455 2026-08-05 17:03:52 +03:00
Danila Poyarkov 3353c747af fix(ai): preserve valid design assignment
- Reject removing the active Design profile when no tools-capable fallback exists

- Cover text-only fallback handling
2026-08-05 17:03:37 +03:00
Danila Poyarkov 7a3a8bf53f refactor(chat): polish model profile switching
- Centralize design-profile eligibility for the selector, role assignment, fallback, and tests
- Keep built-in provider model selection intact while switching saved custom profiles
- Add localized accessible labeling and constrain long profile names
2026-08-05 15:44:27 +03:00
Danila Poyarkov 79aa6ba5dd refactor(app): move storage workspace navigation into File menu
- Replace the full-width editor header action with a shared browser and native menu command
- Localize the destination and cover menu schema and browser navigation
2026-08-03 17:42:39 +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
rcoenen ff31f90de9
fix(ai): opt into Anthropic direct browser access (#438)
Anthropic omits Access-Control-Allow-Origin unless the caller sends
anthropic-dangerous-direct-browser-access, so the web build failed with an
opaque "Could not reach this endpoint from the browser" for the anthropic
provider. @ai-sdk/anthropic does not send the header and neither did our
adapter.

Send it from the browser only. The desktop build routes through tauriFetch
and is not subject to CORS, so it does not need to advertise browser access.

Fixes #436

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 20:22:45 +03:00
Danila Poyarkov cb2c4aa3d3 fix(vector): edit vectors from opened files
- Resolve the active graph at action time and map edit geometry through full world transforms
- Regenerate live path fills and discard stale imported stroke outlines after edits
- Preserve fill and stroke geometry through resize previews, undo, and redo
- Cover graph replacement, nested transforms, edit history, resizing, and CanvasKit output

Co-authored-by: Rob Coenen <753704+rcoenen@users.noreply.github.com>
2026-07-28 12:30:21 +03:00
tae.virus 679ee9f98f
feat(export): add editable PPTX export (#416)
- Export text and basic shapes as editable PowerPoint elements
- Rasterize unsupported geometry, effects, masks, and clipped content for fidelity
- Support app and CLI exports across multiple pages

Co-authored-by: TKman <102001532+greekr4@users.noreply.github.com>
2026-07-28 10:12:41 +03:00
Danila Poyarkov 1415640718 refactor(core): centralize Base64 encoding
- Add portable byte and Unicode Base64 helpers backed by js-base64

- Replace manual binary-string, Buffer, and unsupported typed-array conversions

- Cover binary, Unicode, URL-safe, malformed, and large inputs
2026-07-28 08:27:22 +03:00
Danila Poyarkov a7a44e90b2 fix(settings): remember browser credentials by default
- Default fresh browser sessions to encrypted credential persistence with an explicit session-only opt-out

- Keep API-key links left-aligned, legible, and limited to their text click target

- Update credential guidance and browser coverage
2026-07-27 19:21:19 +03:00
Danila Poyarkov 858e6451de fix(storage): parse S3 responses as XML
- Replace regex-based list and error parsing with xmldom

- Decode entities through the parser and support namespaced pagination responses

- Treat malformed listing documents as empty pages
2026-07-27 19:04:50 +03:00
Danila Poyarkov a6940bcab8 feat(app): convert image layers to vectors
- Add secure Recraft and fal.ai clients with centralized credentials and Media settings

- Replace image rectangles with editable vector frames in one undoable operation

- Bound desktop proxy responses, timeouts, and redirects for provider downloads

- Cover provider parsing, placement, settings, context-menu visibility, and undo

Co-authored-by: Rob Coenen <753704+rcoenen@users.noreply.github.com>
2026-07-27 16:22:05 +03:00
Danila Poyarkov 49b2d49e40 fix(storage): preserve durable sync work
- Resume persisted outbox jobs at startup without dropping writes when credentials are unavailable

- Serialize IndexedDB revisions and guard sync completion against concurrent saves

- Reconcile tombstones without reviving deleted documents and bound S3 metadata requests

- Require explicit CORS configuration instead of overwriting bucket rules during connection tests

- Keep ACP agents exclusive to the Design role and normalize invalid model limits
2026-07-26 23:43:38 +03:00
Danila Poyarkov e56727c22c feat(ai): configure reusable model profiles
- Separate provider connections, model profiles, capabilities, and role assignments

- Replace role-specific forms with a reusable model library and assignment table

- Resolve credentials lazily per connection and preserve existing Design settings

- Route Design chat through the assigned profile while exposing Review, Fast, and Vision runtimes
2026-07-26 22:53:45 +03:00
Danila Poyarkov a22d1edf8b refactor(ui): unify full-area placeholders
- Add one themed placeholder primitive for page, panel, dialog, and setup states

- Vertically center chat, code, assets, variables, and storage placeholders

- Let Vue replace the static boot splash instead of mutating global DOM from views
2026-07-26 17:02:29 +03:00
Danila Poyarkov c45e5e5cef refactor(app): share document source access types
- Reuse one named source-state contract across save and source actions

- Keep storage bindings and local source identity typed without duplicated shapes
2026-07-26 15:09:26 +03:00
Danila Poyarkov ca80b0e787 feat(app): add storage workspace
- List local and remote documents from an explicit storage workspace route

- Open remote .fig documents into deduplicated storage-bound editor tabs

- Create locally durable documents only after storage configuration is complete

- Cover unconfigured guidance and mocked S3 document opening end to end

Co-authored-by: Rob Coenen <753704+rcoenen@users.noreply.github.com>
2026-07-26 15:06:01 +03:00
Danila Poyarkov b4a82239a3 feat(app): persist storage-bound documents locally first
- Track remote storage bindings without replacing local file identity

- Route saves and autosaves through the durable local cache before enqueueing uploads

- Clear storage bindings on Save As and cover ordering and identity behavior

Co-authored-by: Rob Coenen <753704+rcoenen@users.noreply.github.com>
2026-07-26 14:46:38 +03:00
Danila Poyarkov f31341d488 feat(app): add background storage sync engine
- Drain local outbox jobs through the active registered storage adapter

- Preserve revision guards, retry backoff, tombstones, progress, and offline recovery

- Resolve the active adapter and credentials for each queued operation

Co-authored-by: Rob Coenen <753704+rcoenen@users.noreply.github.com>
2026-07-26 14:40:36 +03:00
Danila Poyarkov bac1b79a6b feat(app): add storage integration settings
- Add schema-driven S3 preferences and status-only credential controls to unified Settings

- Keep storage preferences persistent while secrets remain in the selected credential backend

- Include storage credentials when browser persistence changes and test session behavior

Co-authored-by: Rob Coenen <753704+rcoenen@users.noreply.github.com>
2026-07-26 14:39:24 +03:00
Danila Poyarkov 56a3b77ac5 feat(app): add local-first storage substrate
- Recover the IndexedDB and in-memory document cache behind the storage domain

- Add persistent outbox supersession, cache eviction, import validation, and naming helpers

- Keep the substrate provider-neutral and cover its pure behavior

Co-authored-by: Rob Coenen <753704+rcoenen@users.noreply.github.com>
2026-07-26 14:30:39 +03:00
Danila Poyarkov d315547f2b feat(app): register S3-compatible storage
- Adapt the contributed S3 client behind the neutral storage provider contract

- Resolve access credentials lazily for each storage operation

- Preserve namespace isolation, CORS setup, pagination, progress, and metadata fallbacks

Co-authored-by: Rob Coenen <753704+rcoenen@users.noreply.github.com>
2026-07-26 14:26:44 +03:00
Danila Poyarkov a4a8eab46e feat(app): add storage provider registry
- Define backend-neutral document storage and provider schema contracts

- Keep provider preferences separate from credential references

- Resolve declared secrets lazily through the shared credential service
2026-07-26 14:21:11 +03:00
Danila Poyarkov 266f85a73c feat(app): unify integration settings
- Open one Settings dialog for AI providers, agents, and media credentials

- Resolve secrets only when requests start and keep settings on status-only credential APIs

- Make browser persistence explicit and default fresh web sessions to memory

- Move provider controls into the settings domain and cover setup, reload, and clearing
2026-07-26 14:07:48 +03:00
Danila Poyarkov 4c5cd0a678 refactor(ai): register direct model providers
- Move provider-specific model construction behind typed adapters

- Keep OpenAI- and Anthropic-compatible configuration reusable

- Verify every direct provider is registered while ACP agents stay separate
2026-07-26 14:07:35 +03:00
Danila Poyarkov 95a920197e feat(app): add cross-platform credential storage
- Store desktop secrets in native OS credential services through a narrow Tauri bridge

- Provide session-only and encrypted remembered browser stores with explicit switching

- Migrate legacy plaintext keys only after verified writes and cover failure recovery
2026-07-26 14:07:26 +03:00
Danila Poyarkov 5b2334ba2d
fix(acp): launch Windows command shims (#425)
- Route npm-installed ACP and MCP launchers through cmd on Windows
- Preserve inherited agent environment and current MCP transport settings
- Cover Windows process resolution and document the user-facing fix

Co-authored-by: Damián Briones <insertnickname1@gmail.com>
2026-07-26 08:47:20 +03:00
Danila Poyarkov 57eb59769d
feat(components): match Figma asset browsing (#424)
* feat(components): match Figma asset browsing

- Add thumbnail grid and list views grouped by source page
- Support component drag insertion and main-component navigation
- Keep asset previews working across document pages
- Cover views, context actions, and drag-to-canvas behavior

* fix(components): remove redundant Assets heading

* fix(components): render crisp asset thumbnails

- Render preview images at twice their display dimensions
- Preserve the existing grid and list thumbnail sizes

* fix(render): exclude ancestors from selection exports

- Reparent selected export roots directly under the extracted page
- Preserve absolute positions without drawing ancestor backgrounds
- Cover transparent selection export around nested components

* fix(components): address Assets panel review

- Handle thumbnail export failures without stale previews
- Share page lookup and thumbnail sizing across asset views
- Make list actions keyboard accessible and honor requested export pages
2026-07-26 01:18:27 +03:00
Danila Poyarkov f6e446a789
fix(app): reuse tabs for repeated file opens (#423)
- Match documents by desktop path or File System Access handle
- Share concurrent duplicate loads while allowing unrelated files to load in parallel
- Publish source identity only after successful opens and saves

Co-authored-by: Joseph Cumines <joeycumines@gmail.com>
2026-07-26 00:22:36 +03:00
Luca Candela 18899ff13c
feat(editor): add Figma-style frame presets (#418)
Add frame preset creation and resizing with constraint-aware layout, undo/redo, toolbar flyouts, localization, documentation, and regression coverage.
2026-07-26 00:05:57 +03:00
Danila Poyarkov 2b32a8c7d3 feat(mcp): add local transport discovery
- Prefer private Unix sockets with TCP fallback for local MCP clients

- Unify HTTP and WebSocket lifecycle, authentication, and cleanup

- Discover transport details from an owner-only runtime file
2026-07-25 21:29:03 +03:00
Danila Poyarkov bc73b15f0c revert(demo): restore the visual-features showcase demo
Roll back the Pulse music-app demo to the prior standalone showcase
(Components / App Preview / Effects) which cleanly demonstrates gradients,
drop/inner shadows, blend modes, masks, and corner smoothing. Also removed the
Pulse JSX showcase file and restored the matching demo test.
2026-07-24 15:29:43 +03:00
Danila Poyarkov 3cfc86371d feat(design-jsx): masks, inline <svg> vectors, and instance overrides
Fill the three biggest gaps that blocked authoring real designs in JSX:

- mask prop on any node: <Ellipse mask> / mask="luminance" / mask="vector"
  sets isMask + maskType so sibling content clips (Figma's mask model)
- <svg> element rendering inline SVG markup into vector nodes, reusing the
  iconify path pipeline (extractPaths + parseSVGPath + scalePathInfos)
- Instance overrides: <Instance of="X" overrides={{ 'childName:prop': v }} />
  applies child overrides by name and records them so component sync keeps them

Adds gap tests and the shared scalePathInfos/finishIconRender helpers to
avoid duplicating the iconify pipeline.
2026-07-21 11:40:13 +03:00
Danila Poyarkov 8561d73eaf fix(demo): restore showcase validation
- Replace nested tone branches with a typed color map

- Cover the rebuilt component library and analytics demo
2026-07-21 02:32:03 +03:00
Danila Poyarkov 56f99cbc47 feat(demo): correct stat badge tones via recorded fill overrides
Apply success/accent/danger tones to the stat badges after layout with the
label fill recorded as an override, so component sync preserves them.
Badges now read +14% green, +8% blue, -3% red.
2026-07-21 02:13:22 +03:00
Danila Poyarkov bc2beeea22 feat(demo): tighten component library with captions
Shrink the library section to fit its content and label each component so
the library-to-app relationship reads clearly.
2026-07-21 01:55:11 +03:00
Danila Poyarkov 3597c9382c feat(demo): rebuild as cohesive product showcase
Replace the grab-bag demo (3 disconnected feature boxes) with a real product
screen that teaches the OpenPencil workflow by example:

- Component Library: Button (primary/secondary), Badge, Avatar, Nav item,
  Toggle as actual COMPONENTs
- App — Analytics: a modern dashboard assembled from INSTANCEs of those
  components, laid out with real auto-layout (sidebar, stat row, chart,
  callout), themed via bound semantic variables
- Single restrained palette (one accent + surfaces/text/semantic tones)
- Instance text set with recorded overrides so component sync keeps labels

Editing a variable re-themes the screen; resizing frames demonstrates live
auto-layout reflow.
2026-07-21 01:48:15 +03:00
Danila Poyarkov 00d80f3bdc fix(automation): keep expected bridge closures quiet
- Reconnect after normal closures without reporting them as browser errors
2026-07-20 22:40:43 +03:00
Danila Poyarkov adffdd791c fix(automation): reconnect after bridge closure
- Retry normal WebSocket closures unless disconnect was intentional
2026-07-20 22:19:27 +03:00
Danila Poyarkov cff46fbc50 fix(app): restore release validation coverage
- Keep the development MCP bridge alive until Vite shuts down
- Ignore empty host-font responses and cover current browser font policy
- Update interaction selectors, menu labels, resize accounting, and reviewed UI snapshots
2026-07-20 16:26:07 +03:00
Danila Poyarkov 708152e33f fix(canvas): rulers follow the active theme
Rulers stayed dark in light theme because the canvas ruler theme was only
pushed to the editor store at theme-apply time, before any editor existed,
and the renderer fell back to a hardcoded dark color.

- Push the ruler theme to the active editor whenever it registers or the
  theme changes, via a reactive active-store ref (keeps the no-browser-
  globals-in-core boundary intact)
- Refresh the light ruler palette for proper contrast on the light canvas
2026-07-18 08:12:58 +03:00
Danila Poyarkov 33d6a1efd1 fix(app): align property item subcontrols
- Keep Fill and Effects settings inside their shared content rails\n- Use panel spacing tokens instead of ad-hoc offsets\n- Preserve selection when Escape dismisses overlays\n- Label the Font settings trigger for assistive technology
2026-07-18 05:44:52 +03:00
Danila Poyarkov 429a7e5ae2 fix(app): polish variable dialog states
- Restore the empty collection call to action\n- Fill the table width and prevent variable type hint clipping\n- Let dialogs and popup menus handle Escape before editor shortcuts
2026-07-18 05:25:40 +03:00
Danila Poyarkov e0d8efb2a4
Merge pull request #411 from open-pencil/figma-paste-images
fix(clipboard): fetch pasted Figma images on desktop
2026-07-18 05:04:49 +03:00
Danila Poyarkov c2812ba136 fix(tauri): preserve request and abort semantics
- Serialize bodies from the normalized Request, including Request inputs\n- Consume late transport failures after an already-aborted signal\n- Handle pre-aborted clipboard test requests
2026-07-18 05:02:51 +03:00
Danila Poyarkov a3127e716b refactor(tauri): share HTTP abort handling
- Make the desktop HTTP adapter honor standard AbortSignal cancellation
- Use AbortSignal.timeout directly for Figma batch and image requests
- Cover resolved, pre-aborted, and in-flight abort behavior
2026-07-18 04:40:15 +03:00
Danila Poyarkov 798a3c2b2c fix(editor): harden opacity shortcuts
- Match numeric keypad input by generated key so NumLock-off navigation remains available
- Coalesce buffered opacity updates into one undo interaction
- Add end-to-end coverage for digit composition, modifiers, and undo
2026-07-18 04:22:38 +03:00
Danila Poyarkov b08e199c85 fix(clipboard): finalize paste before image fetch
- Complete placement and undo registration before awaiting image hydration
- Bound Figma image requests with timeouts and use shared Tauri detection
- Localize missing-image notifications and cover stalled requests
2026-07-18 04:22:38 +03:00
sadkodev d58cf0b9e9
test(keyboard): add unit tests for opacity buffer logic
Extract opacityFromBuffer as a pure function in core/editor and test
it directly. Covers Figma semantics: 0→100%, 5→50%, 28→28%, 00→0%,
100→100%, clamp at 100%, NaN guard. Refactor the keyboard handler to
reuse the shared function instead of inlining the buffer math.
2026-07-17 15:00:10 -04:00
sadkodev 1ca1cbc896
refactor(keyboard): deduplicate opacity binding handler
Collapse the duplicated Digit/Numpad opacity bindings into a single
OPACITY_CODES array with one shared run handler. Digit value is
extracted via code.slice(-1), which works for both Digit0-9 and
Numpad0-9.
2026-07-17 14:49:00 -04:00