@agent-native/core 0.90.1 → 0.90.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (295) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +14 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/client/AgentPanel.tsx +1 -1
  5. package/corpus/core/src/client/rich-markdown-editor/useCollabReconcile.ts +11 -6
  6. package/corpus/core/src/client/use-action.ts +39 -2
  7. package/corpus/core/src/client/use-db-sync.ts +44 -18
  8. package/corpus/core/src/db/create-get-db.ts +32 -2
  9. package/corpus/core/src/server/framework-request-handler.ts +52 -4
  10. package/corpus/templates/assets/.agents/skills/asset-generation/SKILL.md +5 -0
  11. package/corpus/templates/assets/.agents/skills/logo-composite/SKILL.md +34 -6
  12. package/corpus/templates/assets/AGENTS.md +23 -4
  13. package/corpus/templates/assets/actions/_generation-preset-settings.ts +48 -0
  14. package/corpus/templates/assets/actions/_helpers.ts +8 -1
  15. package/corpus/templates/assets/actions/_preset-skeleton-validation.ts +64 -0
  16. package/corpus/templates/assets/actions/create-generation-preset.ts +11 -3
  17. package/corpus/templates/assets/actions/generate-image-batch.ts +7 -2
  18. package/corpus/templates/assets/actions/generate-image.ts +342 -25
  19. package/corpus/templates/assets/actions/get-library.ts +4 -3
  20. package/corpus/templates/assets/actions/navigate.ts +2 -1
  21. package/corpus/templates/assets/actions/refresh-generation-run.ts +5 -1
  22. package/corpus/templates/assets/actions/update-asset.ts +1 -0
  23. package/corpus/templates/assets/actions/update-generation-preset.ts +8 -1
  24. package/corpus/templates/assets/actions/view-screen.ts +8 -1
  25. package/corpus/templates/assets/app/components/generation/GenerationResults.tsx +9 -1
  26. package/corpus/templates/assets/app/hooks/use-image-model-menu.ts +1 -0
  27. package/corpus/templates/assets/app/hooks/use-navigation-state.ts +11 -0
  28. package/corpus/templates/assets/app/i18n/zh-TW.ts +64 -0
  29. package/corpus/templates/assets/app/i18n-data.ts +650 -0
  30. package/corpus/templates/assets/app/routes/asset.$id.tsx +2 -1
  31. package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +44 -33
  32. package/corpus/templates/assets/app/routes/brand-kits.$id_.presets.$presetId.tsx +1474 -0
  33. package/corpus/templates/assets/app/routes/library.tsx +43 -1
  34. package/corpus/templates/assets/server/lib/generation.ts +366 -44
  35. package/corpus/templates/assets/server/lib/image-processing.ts +252 -0
  36. package/corpus/templates/assets/server/lib/preset-skeleton.ts +137 -0
  37. package/corpus/templates/assets/shared/api.ts +47 -0
  38. package/corpus/templates/clips/app/components/library/library-layout.tsx +7 -2
  39. package/corpus/templates/clips/app/components/library/sort-menu.tsx +1 -1
  40. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +114 -33
  41. package/corpus/templates/clips/app/routes/_app.library._index.tsx +27 -1
  42. package/corpus/templates/clips/app/routes/record.tsx +157 -68
  43. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +5 -5
  44. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +20 -3
  45. package/corpus/templates/clips/shared/finalize-recovery.ts +23 -3
  46. package/corpus/templates/content/AGENTS.md +52 -52
  47. package/corpus/templates/content/actions/_builder-cms-read-client.ts +188 -8
  48. package/corpus/templates/content/actions/_builder-docs-client.ts +41 -3
  49. package/corpus/templates/content/actions/_database-source-utils.ts +998 -160
  50. package/corpus/templates/content/actions/_database-utils.ts +44 -4
  51. package/corpus/templates/content/actions/_notion-action-utils.ts +6 -2
  52. package/corpus/templates/content/actions/add-content-database-source-field-property.ts +23 -1
  53. package/corpus/templates/content/actions/attach-content-database-source.ts +85 -12
  54. package/corpus/templates/content/actions/change-content-database-source-role.ts +9 -1
  55. package/corpus/templates/content/actions/delete-content-database.ts +1 -0
  56. package/corpus/templates/content/actions/get-document.ts +11 -2
  57. package/corpus/templates/content/actions/list-content-databases.ts +57 -9
  58. package/corpus/templates/content/actions/prepare-builder-source-review.ts +23 -6
  59. package/corpus/templates/content/actions/refresh-content-database-source.ts +26 -3
  60. package/corpus/templates/content/actions/restore-content-database.ts +1 -0
  61. package/corpus/templates/content/actions/update-document.ts +43 -0
  62. package/corpus/templates/content/app/components/editor/BuilderBodySyncingNotice.tsx +21 -0
  63. package/corpus/templates/content/app/components/editor/DocumentDatabase.tsx +0 -1
  64. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +70 -28
  65. package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +69 -17
  66. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +4 -4
  67. package/corpus/templates/content/app/components/editor/body-hydration.ts +112 -0
  68. package/corpus/templates/content/app/components/editor/builder-body-hydration-pump.ts +52 -0
  69. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +9076 -2876
  70. package/corpus/templates/content/app/components/editor/database-sources/BuilderSourceReviewDialog.tsx +41 -1
  71. package/corpus/templates/content/app/components/editor/extensions/ImageBlock.tsx +36 -11
  72. package/corpus/templates/content/app/components/editor/previewDocumentSaveController.ts +21 -1
  73. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +11 -1
  74. package/corpus/templates/content/app/components/sidebar/DocumentTreeItem.tsx +11 -8
  75. package/corpus/templates/content/app/global.css +41 -0
  76. package/corpus/templates/content/app/hooks/use-content-database.ts +346 -42
  77. package/corpus/templates/content/app/hooks/use-db-sync.ts +9 -0
  78. package/corpus/templates/content/app/hooks/use-documents.ts +47 -0
  79. package/corpus/templates/content/app/hooks/use-notion.ts +12 -10
  80. package/corpus/templates/content/app/i18n/zh-TW.ts +35 -0
  81. package/corpus/templates/content/app/i18n-data.ts +355 -0
  82. package/corpus/templates/content/app/root.tsx +22 -0
  83. package/corpus/templates/content/changelog/2026-07-01-builder-database-sources-keep-loading-rows-in-the-background.md +6 -0
  84. package/corpus/templates/content/changelog/2026-07-01-builder-source-attach-starts-with-usable-rows.md +6 -0
  85. package/corpus/templates/content/changelog/2026-07-01-builder-source-attachment-now-stays-connected-after-large.md +6 -0
  86. package/corpus/templates/content/changelog/2026-07-01-builder-source-refreshes-now-show-progress-for-large-docs-blog.md +6 -0
  87. package/corpus/templates/content/changelog/2026-07-01-database-pages-now-delete-to-trash-without-route-errors.md +6 -0
  88. package/corpus/templates/content/changelog/2026-07-02-builder-source-refreshes-recover-from-stalled-background-row.md +6 -0
  89. package/corpus/templates/content/changelog/2026-07-02-builder-sourced-rows-open-with-sync-protection.md +6 -0
  90. package/corpus/templates/content/changelog/2026-07-02-database-rows-and-pages-open-faster-from-recently-loaded-dat.md +6 -0
  91. package/corpus/templates/content/changelog/2026-07-02-preview-panels-close-reliably-narrow-sidebar-row-actions-sta.md +6 -0
  92. package/corpus/templates/content/changelog/2026-07-06-builder-sync-progress-no-longer-shows-continue.md +6 -0
  93. package/corpus/templates/content/shared/api.ts +13 -0
  94. package/corpus/templates/content/shared/builder-mdx.ts +16 -3
  95. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +23 -13
  96. package/corpus/templates/design/.agents/skills/responsive-breakpoints/SKILL.md +98 -0
  97. package/corpus/templates/design/.agents/skills/shader-fills/SKILL.md +162 -0
  98. package/corpus/templates/design/AGENTS.md +9 -2
  99. package/corpus/templates/design/actions/add-breakpoint.ts +6 -3
  100. package/corpus/templates/design/actions/apply-a11y-fix.ts +57 -37
  101. package/corpus/templates/design/actions/apply-component-prop-edit.ts +41 -20
  102. package/corpus/templates/design/actions/apply-motion-edit.ts +251 -38
  103. package/corpus/templates/design/actions/apply-shader-fill.ts +90 -66
  104. package/corpus/templates/design/actions/apply-visual-edit.ts +282 -55
  105. package/corpus/templates/design/actions/create-component.ts +29 -60
  106. package/corpus/templates/design/actions/create-file.ts +9 -2
  107. package/corpus/templates/design/actions/duplicate-design.ts +31 -2
  108. package/corpus/templates/design/actions/edit-design.ts +36 -38
  109. package/corpus/templates/design/actions/generate-design-title.ts +87 -0
  110. package/corpus/templates/design/actions/generate-design.ts +53 -18
  111. package/corpus/templates/design/actions/generate-screens.ts +108 -4
  112. package/corpus/templates/design/actions/get-motion-timeline.ts +35 -7
  113. package/corpus/templates/design/actions/insert-asset.ts +34 -29
  114. package/corpus/templates/design/actions/insert-design-native-asset.ts +129 -32
  115. package/corpus/templates/design/actions/insert-figma-library-asset.ts +35 -30
  116. package/corpus/templates/design/actions/present-design-variants.ts +7 -2
  117. package/corpus/templates/design/actions/remove-motion-timeline.ts +31 -36
  118. package/corpus/templates/design/actions/update-file.ts +190 -75
  119. package/corpus/templates/design/app/components/design/BreakpointBar.tsx +403 -0
  120. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +469 -222
  121. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +708 -53
  122. package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +83 -3
  123. package/corpus/templates/design/app/components/design/EditPanel.tsx +1091 -6948
  124. package/corpus/templates/design/app/components/design/LayersPanel.tsx +419 -85
  125. package/corpus/templates/design/app/components/design/MotionDock.tsx +1124 -103
  126. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +2610 -1398
  127. package/corpus/templates/design/app/components/design/ReadOnlyDesignBanner.tsx +22 -0
  128. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +2182 -235
  129. package/corpus/templates/design/app/components/design/bridge/motion-preview.bridge.ts +187 -11
  130. package/corpus/templates/design/app/components/design/bridge/shader-fill-preview.bridge.ts +376 -1
  131. package/corpus/templates/design/app/components/design/bridge/shader-runtime.bridge.ts +746 -0
  132. package/corpus/templates/design/app/components/design/canvas-primitive-style.ts +17 -0
  133. package/corpus/templates/design/app/components/design/code-workbench/SideBar.tsx +1 -1
  134. package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +1 -3
  135. package/corpus/templates/design/app/components/design/code-workbench/quickinput/QuickInput.tsx +1 -1
  136. package/corpus/templates/design/app/components/design/edit-panel/appearance-properties.tsx +518 -0
  137. package/corpus/templates/design/app/components/design/edit-panel/code-inspect-helpers.tsx +562 -0
  138. package/corpus/templates/design/app/components/design/edit-panel/component-section.tsx +763 -0
  139. package/corpus/templates/design/app/components/design/edit-panel/document-colors.ts +94 -0
  140. package/corpus/templates/design/app/components/design/edit-panel/effects-properties.tsx +780 -0
  141. package/corpus/templates/design/app/components/design/edit-panel/element-classification.ts +446 -0
  142. package/corpus/templates/design/app/components/design/edit-panel/element-identity.ts +79 -0
  143. package/corpus/templates/design/app/components/design/edit-panel/field-primitives.tsx +315 -0
  144. package/corpus/templates/design/app/components/design/edit-panel/fill-gradient-helpers.ts +344 -0
  145. package/corpus/templates/design/app/components/design/edit-panel/fill-properties.tsx +594 -0
  146. package/corpus/templates/design/app/components/design/edit-panel/frame-presets-panel.tsx +119 -0
  147. package/corpus/templates/design/app/components/design/edit-panel/inspector-controls.tsx +248 -0
  148. package/corpus/templates/design/app/components/design/edit-panel/interaction-state-helpers.ts +45 -0
  149. package/corpus/templates/design/app/components/design/edit-panel/layout-properties.tsx +693 -0
  150. package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +724 -0
  151. package/corpus/templates/design/app/components/design/edit-panel/position-helpers.ts +207 -0
  152. package/corpus/templates/design/app/components/design/edit-panel/position-layout-properties.tsx +628 -0
  153. package/corpus/templates/design/app/components/design/edit-panel/selection-helpers.ts +91 -0
  154. package/corpus/templates/design/app/components/design/edit-panel/stroke-properties.tsx +649 -0
  155. package/corpus/templates/design/app/components/design/edit-panel/style-change-types.ts +118 -0
  156. package/corpus/templates/design/app/components/design/edit-panel/style-options.ts +88 -0
  157. package/corpus/templates/design/app/components/design/edit-panel/transform-helpers.ts +100 -0
  158. package/corpus/templates/design/app/components/design/edit-panel/typography-helpers.ts +117 -0
  159. package/corpus/templates/design/app/components/design/edit-panel/typography-properties.tsx +501 -0
  160. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +91 -40
  161. package/corpus/templates/design/app/components/design/inspector/BreakpointOverrideIndicator.tsx +82 -0
  162. package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +189 -87
  163. package/corpus/templates/design/app/components/design/inspector/GlslShaderPanel.tsx +1097 -0
  164. package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +44 -0
  165. package/corpus/templates/design/app/components/design/inspector/InteractionStatePanel.tsx +258 -0
  166. package/corpus/templates/design/app/components/design/inspector/MotionKeyframeDiamond.tsx +144 -0
  167. package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +99 -9
  168. package/corpus/templates/design/app/components/design/inspector/frame-size-presets.ts +116 -0
  169. package/corpus/templates/design/app/components/design/inspector/index.ts +26 -0
  170. package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +29 -0
  171. package/corpus/templates/design/app/components/design/multi-screen/alt-hover-measurement.ts +171 -0
  172. package/corpus/templates/design/app/components/design/multi-screen/board-surface-html.ts +220 -0
  173. package/corpus/templates/design/app/components/design/multi-screen/chrome-transitions.ts +35 -0
  174. package/corpus/templates/design/app/components/design/multi-screen/cross-screen-drop.ts +134 -0
  175. package/corpus/templates/design/app/components/design/multi-screen/culling.ts +185 -0
  176. package/corpus/templates/design/app/components/design/multi-screen/gradient-overlay-geometry.ts +120 -0
  177. package/corpus/templates/design/app/components/design/multi-screen/types.ts +892 -0
  178. package/corpus/templates/design/app/components/design/multi-screen/vector-edit-geometry.ts +21 -0
  179. package/corpus/templates/design/app/components/design/types.ts +15 -0
  180. package/corpus/templates/design/app/components/editor/PromptDialog.tsx +109 -5
  181. package/corpus/templates/design/app/global.css +8 -8
  182. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +259 -2
  183. package/corpus/templates/design/app/i18n/zh-TW.ts +163 -9
  184. package/corpus/templates/design/app/i18n-breakpoints.ts +205 -0
  185. package/corpus/templates/design/app/i18n-data.ts +1664 -152
  186. package/corpus/templates/design/app/i18n-motion.ts +563 -0
  187. package/corpus/templates/design/app/lib/design-import.ts +73 -0
  188. package/corpus/templates/design/app/pages/Index.tsx +41 -22
  189. package/corpus/templates/design/changelog/2026-06-29-design-inspector-controls-now-match-figmas-softer-dark-chrome.md +1 -1
  190. package/corpus/templates/design/changelog/2026-06-30-design-now-has-a-figma-style-left-rail-for-file-agent-assets.md +1 -1
  191. package/corpus/templates/design/changelog/2026-06-30-design-tools-now-use-a-quieter-figma-style-list-layout.md +1 -1
  192. package/corpus/templates/design/changelog/2026-06-30-multi-select-outlines-now-stay-consistent-across-all-screens.md +1 -1
  193. package/corpus/templates/design/changelog/2026-07-03-canvas-interactions-now-match-figma-rotation-aware-resizing-.md +1 -1
  194. package/corpus/templates/design/changelog/2026-07-03-layers-panel-matches-figma-top-layer-on-top-drag-with-auto-s.md +1 -1
  195. package/corpus/templates/design/changelog/2026-07-05-designs-get-ai-generated-names-from-your-prompt.md +6 -0
  196. package/corpus/templates/design/changelog/2026-07-05-local-code-screens-keep-their-connection-when-duplicated-and.md +6 -0
  197. package/corpus/templates/design/changelog/2026-07-05-press-a-to-draw-screens-on-the-canvas-inside-a-screen-it-dr.md +6 -0
  198. package/corpus/templates/design/changelog/2026-07-06-3d-rotation-and-perspective-controls-on-every-element.md +6 -0
  199. package/corpus/templates/design/changelog/2026-07-06-ai-generated-and-duplicated-screens-now-get-their-editor-sel.md +6 -0
  200. package/corpus/templates/design/changelog/2026-07-06-applying-shaders-and-fills-in-quick-succession-can-no-longer.md +6 -0
  201. package/corpus/templates/design/changelog/2026-07-06-breakpoint-frames-in-the-overview-now-support-click-to-selec.md +6 -0
  202. package/corpus/templates/design/changelog/2026-07-06-breakpoint-segments-in-the-inspector-now-show-a-device-icon-.md +6 -0
  203. package/corpus/templates/design/changelog/2026-07-06-breakpoint-targeting-now-lives-in-one-compact-control-in-the.md +6 -0
  204. package/corpus/templates/design/changelog/2026-07-06-canvas-edits-can-no-longer-be-overwritten-by-stale-collabora.md +6 -0
  205. package/corpus/templates/design/changelog/2026-07-06-canvas-edits-inside-screens-save-reliably-again.md +6 -0
  206. package/corpus/templates/design/changelog/2026-07-06-cleaner-inspector-removed-the-ask-ai-box-from-the-design-tab.md +6 -0
  207. package/corpus/templates/design/changelog/2026-07-06-clicking-empty-canvas-space-now-deselects-an-element-inside-.md +6 -0
  208. package/corpus/templates/design/changelog/2026-07-06-dragging-an-element-onto-a-rectangle-now-nests-it-inside-wit.md +6 -0
  209. package/corpus/templates/design/changelog/2026-07-06-dragging-screens-and-objects-on-the-canvas-is-now-much-smoot.md +6 -0
  210. package/corpus/templates/design/changelog/2026-07-06-drawing-a-shape-or-text-on-the-canvas-no-longer-flashes-away.md +6 -0
  211. package/corpus/templates/design/changelog/2026-07-06-dropping-an-element-between-two-others-inside-a-screen-now-s.md +6 -0
  212. package/corpus/templates/design/changelog/2026-07-06-duplicating-a-screen-now-places-the-copy-exactly-where-you-d.md +6 -0
  213. package/corpus/templates/design/changelog/2026-07-06-edit-gradients-directly-on-elements-inside-screens-scale-str.md +6 -0
  214. package/corpus/templates/design/changelog/2026-07-06-edits-from-collaborators-and-the-agent-now-update-the-canvas.md +6 -0
  215. package/corpus/templates/design/changelog/2026-07-06-fixed-a-bug-where-most-style-position-and-text-edits-briefly.md +6 -0
  216. package/corpus/templates/design/changelog/2026-07-06-fixed-a-confusing-raw-error-message-when-a-file-upload-fails.md +6 -0
  217. package/corpus/templates/design/changelog/2026-07-06-fixed-a-rare-case-where-an-edit-could-be-silently-overwritte.md +6 -0
  218. package/corpus/templates/design/changelog/2026-07-06-fixed-inserted-assets-sometimes-disappearing-reappearing-or-.md +6 -0
  219. package/corpus/templates/design/changelog/2026-07-06-fixed-inspector-value-scrubbing-producing-erratic-numbers-an.md +6 -0
  220. package/corpus/templates/design/changelog/2026-07-06-fixed-padding-gap-and-min-max-size-scrubbing-not-updating-th.md +6 -0
  221. package/corpus/templates/design/changelog/2026-07-06-fixed-text-stroke-color-turning-black-and-glyphs-disappearin.md +6 -0
  222. package/corpus/templates/design/changelog/2026-07-06-fixed-the-collapsed-effects-and-stroke-inspector-sections-sh.md +6 -0
  223. package/corpus/templates/design/changelog/2026-07-06-fixed-the-new-design-dialog-closing-unexpectedly-when-using-.md +6 -0
  224. package/corpus/templates/design/changelog/2026-07-06-fixed-the-typography-section-missing-when-selecting-text-nes.md +6 -0
  225. package/corpus/templates/design/changelog/2026-07-06-full-view-no-longer-flashes-back-to-the-overview-on-entry-no.md +6 -0
  226. package/corpus/templates/design/changelog/2026-07-06-keyframe-animation-timeline-per-property-keyframes-easing-cu.md +6 -0
  227. package/corpus/templates/design/changelog/2026-07-06-moving-restyling-and-scrubbing-values-on-elements-in-ai-gene.md +6 -0
  228. package/corpus/templates/design/changelog/2026-07-06-padding-and-corner-radius-value-scrubbing-now-snaps-to-whole.md +6 -0
  229. package/corpus/templates/design/changelog/2026-07-06-padding-handles-now-only-resize-on-the-handle-line-itself-sh.md +6 -0
  230. package/corpus/templates/design/changelog/2026-07-06-preview-and-edit-hover-focus-and-pressed-states-with-real-cs.md +6 -0
  231. package/corpus/templates/design/changelog/2026-07-06-promoting-an-element-to-a-component-now-works-correctly-for-.md +6 -0
  232. package/corpus/templates/design/changelog/2026-07-06-reduced-url-history-churn-and-selection-overlay-flicker-whil.md +6 -0
  233. package/corpus/templates/design/changelog/2026-07-06-removed-the-decorative-dot-before-screen-names-in-the-overvi.md +6 -0
  234. package/corpus/templates/design/changelog/2026-07-06-responsive-breakpoints-edit-at-any-width-with-cascading-over.md +6 -0
  235. package/corpus/templates/design/changelog/2026-07-06-screen-labels-no-longer-turn-blue-when-you-hover-inside-the-.md +6 -0
  236. package/corpus/templates/design/changelog/2026-07-06-scrolling-a-screen-with-an-element-selected-stays-smooth-on-.md +6 -0
  237. package/corpus/templates/design/changelog/2026-07-06-selecting-multiple-elements-and-dragging-now-moves-the-whole.md +6 -0
  238. package/corpus/templates/design/changelog/2026-07-06-selection-borders-handles-and-value-readouts-now-stay-the-sa.md +6 -0
  239. package/corpus/templates/design/changelog/2026-07-06-selection-handles-and-editing-chrome-now-stay-a-constant-siz.md +6 -0
  240. package/corpus/templates/design/changelog/2026-07-06-shader-fills-and-effects-ai-authored-or-preset-glsl-shaders-.md +6 -0
  241. package/corpus/templates/design/changelog/2026-07-06-text-drawn-on-the-canvas-now-defaults-to-white-and-inter-in-.md +6 -0
  242. package/corpus/templates/design/changelog/2026-07-06-text-dropped-into-a-shape-now-stays-readable-instead-of-disa.md +6 -0
  243. package/corpus/templates/design/changelog/2026-07-06-the-add-tweak-controls-prompt-no-longer-jumps-to-the-corner-.md +6 -0
  244. package/corpus/templates/design/changelog/2026-07-06-the-padding-value-readout-now-stays-visible-while-you-hover-.md +6 -0
  245. package/corpus/templates/design/changelog/2026-07-06-the-selected-element-attachment-now-clears-from-the-chat-com.md +6 -0
  246. package/corpus/templates/design/changelog/2026-07-06-the-zoom-menu-is-more-compact-with-tight-rows-and-right-alig.md +6 -0
  247. package/corpus/templates/design/changelog/2026-07-06-undo-and-redo-no-longer-flash-the-screen-changes-now-apply-i.md +6 -0
  248. package/corpus/templates/design/changelog/2026-07-06-zoom-presets-like-zoom-to-50-now-stay-on-the-focused-screen-.md +6 -0
  249. package/corpus/templates/design/server/lib/import-design-files.ts +11 -2
  250. package/corpus/templates/design/server/source-workspace.ts +139 -59
  251. package/corpus/templates/design/shared/board-file.ts +11 -2
  252. package/corpus/templates/design/shared/breakpoint-media.ts +543 -0
  253. package/corpus/templates/design/shared/canvas-math.ts +354 -35
  254. package/corpus/templates/design/shared/code-layer.ts +277 -8
  255. package/corpus/templates/design/shared/design-state.ts +11 -4
  256. package/corpus/templates/design/shared/interaction-states.ts +548 -0
  257. package/corpus/templates/design/shared/motion-compiler.ts +186 -23
  258. package/corpus/templates/design/shared/motion-easing.ts +294 -0
  259. package/corpus/templates/design/shared/motion-timeline.ts +400 -34
  260. package/corpus/templates/design/shared/prompt-title.ts +95 -0
  261. package/corpus/templates/design/shared/responsive-classes.ts +448 -10
  262. package/corpus/templates/design/shared/screen-annotation.ts +46 -0
  263. package/corpus/templates/design/shared/shader-fills.ts +1009 -0
  264. package/corpus/templates/design/shared/shader-presets.ts +852 -4
  265. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +15 -2
  266. package/corpus/templates/slides/app/components/editor/ImportButton.tsx +10 -1
  267. package/corpus/templates/slides/app/lib/upload-response.ts +71 -0
  268. package/dist/client/AgentPanel.js +1 -1
  269. package/dist/client/AgentPanel.js.map +1 -1
  270. package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts.map +1 -1
  271. package/dist/client/rich-markdown-editor/useCollabReconcile.js +11 -6
  272. package/dist/client/rich-markdown-editor/useCollabReconcile.js.map +1 -1
  273. package/dist/client/use-action.d.ts +3 -0
  274. package/dist/client/use-action.d.ts.map +1 -1
  275. package/dist/client/use-action.js +34 -3
  276. package/dist/client/use-action.js.map +1 -1
  277. package/dist/client/use-db-sync.d.ts +4 -0
  278. package/dist/client/use-db-sync.d.ts.map +1 -1
  279. package/dist/client/use-db-sync.js +37 -18
  280. package/dist/client/use-db-sync.js.map +1 -1
  281. package/dist/collab/routes.d.ts +1 -1
  282. package/dist/collab/struct-routes.d.ts +1 -1
  283. package/dist/db/create-get-db.d.ts +25 -0
  284. package/dist/db/create-get-db.d.ts.map +1 -1
  285. package/dist/db/create-get-db.js +25 -2
  286. package/dist/db/create-get-db.js.map +1 -1
  287. package/dist/observability/routes.d.ts +3 -3
  288. package/dist/secrets/routes.d.ts +9 -9
  289. package/dist/server/framework-request-handler.d.ts.map +1 -1
  290. package/dist/server/framework-request-handler.js +37 -1
  291. package/dist/server/framework-request-handler.js.map +1 -1
  292. package/package.json +1 -1
  293. package/corpus/templates/design/app/components/design/inspector/InspectorAiActions.tsx +0 -153
  294. package/corpus/templates/design/app/hooks/useAgentEditRequest.ts +0 -133
  295. package/corpus/templates/design/app/pages/DesignEditor.tsx +0 -22924
@@ -1,5 +1,12 @@
1
1
  import sharp from "sharp";
2
2
 
3
+ import type {
4
+ AspectRatio,
5
+ PresetSkeletonForegroundLayer,
6
+ PresetSkeletonSpec,
7
+ } from "../../shared/api.js";
8
+ import { aspectRatioValue } from "./preset-skeleton.js";
9
+
3
10
  export async function imageInfo(buffer: Buffer): Promise<{
4
11
  width: number | null;
5
12
  height: number | null;
@@ -81,6 +88,251 @@ export async function compositeLogo(input: {
81
88
  .toBuffer();
82
89
  }
83
90
 
91
+ export async function renderBackground(input: {
92
+ spec: PresetSkeletonSpec;
93
+ size: { width: number; height: number };
94
+ backgroundAsset?: Buffer;
95
+ }): Promise<Buffer> {
96
+ const { width, height } = input.size;
97
+ if (!input.backgroundAsset) {
98
+ throw new Error("Preset skeleton background image is missing.");
99
+ }
100
+ return sharp(input.backgroundAsset, { failOn: "none" })
101
+ .rotate()
102
+ .resize({ width, height, fit: "cover" })
103
+ .png()
104
+ .toBuffer();
105
+ }
106
+
107
+ export async function maskFromPlateAlpha(plate: Buffer): Promise<Buffer> {
108
+ return maskFromAlphaChannel({
109
+ image: plate,
110
+ transparentError:
111
+ "gpt-image-2 skeleton inpainting requires a background plate with transparent areas.",
112
+ });
113
+ }
114
+
115
+ export async function maskFromManualMaskAlpha(input: {
116
+ mask: Buffer;
117
+ plate: Buffer;
118
+ }): Promise<Buffer> {
119
+ const plateMeta = await sharp(input.plate, { failOn: "none" }).metadata();
120
+ return maskFromAlphaChannel({
121
+ image: input.mask,
122
+ expectedSize: {
123
+ width: plateMeta.width ?? 0,
124
+ height: plateMeta.height ?? 0,
125
+ },
126
+ sizeError:
127
+ "Skeleton inpainting mask must be the same pixel size as the background plate.",
128
+ transparentError:
129
+ "Skeleton inpainting mask requires transparent areas to mark where the subject may be painted.",
130
+ });
131
+ }
132
+
133
+ async function maskFromAlphaChannel(input: {
134
+ image: Buffer;
135
+ expectedSize?: { width: number; height: number };
136
+ sizeError?: string;
137
+ transparentError: string;
138
+ }): Promise<Buffer> {
139
+ const { data, info } = await sharp(input.image, { failOn: "none" })
140
+ .ensureAlpha()
141
+ .raw()
142
+ .toBuffer({ resolveWithObject: true });
143
+ if (
144
+ input.expectedSize &&
145
+ (info.width !== input.expectedSize.width ||
146
+ info.height !== input.expectedSize.height)
147
+ ) {
148
+ throw new Error(input.sizeError ?? "Mask image dimensions are invalid.");
149
+ }
150
+ const mask = Buffer.alloc(info.width * info.height * 4);
151
+ let hasTransparentPixels = false;
152
+ for (let source = 0, target = 0; source < data.length; source += 4) {
153
+ const alpha = data[source + 3];
154
+ if (alpha < 255) hasTransparentPixels = true;
155
+ mask[target++] = 255;
156
+ mask[target++] = 255;
157
+ mask[target++] = 255;
158
+ mask[target++] = alpha;
159
+ }
160
+ if (!hasTransparentPixels) {
161
+ throw new Error(input.transparentError);
162
+ }
163
+ return sharp(mask, {
164
+ raw: {
165
+ width: info.width,
166
+ height: info.height,
167
+ channels: 4,
168
+ },
169
+ })
170
+ .png()
171
+ .toBuffer();
172
+ }
173
+
174
+ export async function applyPresetSkeleton(input: {
175
+ subject: Buffer;
176
+ spec: PresetSkeletonSpec;
177
+ canvasSize?: { width: number; height: number };
178
+ canvasAspectRatio?: AspectRatio;
179
+ backgroundAsset?: Buffer;
180
+ canonicalLogo?: Buffer;
181
+ foregroundAssets?: Record<string, Buffer>;
182
+ }): Promise<Buffer> {
183
+ const subjectBase = sharp(input.subject, { failOn: "none" }).rotate();
184
+ const subjectMeta = await subjectBase.metadata();
185
+ const size =
186
+ input.canvasSize ??
187
+ canvasSizeFromAspectRatio({
188
+ aspectRatio: input.canvasAspectRatio,
189
+ baseWidth: subjectMeta.width ?? 1024,
190
+ baseHeight: subjectMeta.height ?? 1024,
191
+ });
192
+ const background = await renderBackground({
193
+ spec: input.spec,
194
+ size,
195
+ backgroundAsset: input.backgroundAsset,
196
+ });
197
+ const region = normalizeContentRegion(input.spec.contentRegion);
198
+ const subjectBox = {
199
+ left: Math.round(size.width * region.x),
200
+ top: Math.round(size.height * region.y),
201
+ width: Math.max(1, Math.round(size.width * region.w)),
202
+ height: Math.max(1, Math.round(size.height * region.h)),
203
+ };
204
+ const resizedSubject = await subjectBase
205
+ .resize({
206
+ width: subjectBox.width,
207
+ height: subjectBox.height,
208
+ fit: input.spec.contentMode === "cutout" ? "contain" : "cover",
209
+ background: { r: 0, g: 0, b: 0, alpha: 0 },
210
+ })
211
+ .png()
212
+ .toBuffer();
213
+ const composites: sharp.OverlayOptions[] = [];
214
+ if (input.spec.contentMode === "cutout" && input.spec.dropShadow) {
215
+ composites.push({
216
+ input: contactShadowSvg(size, subjectBox),
217
+ top: 0,
218
+ left: 0,
219
+ });
220
+ }
221
+ composites.push({
222
+ input: resizedSubject,
223
+ top: subjectBox.top,
224
+ left: subjectBox.left,
225
+ });
226
+ composites.push(
227
+ ...(await foregroundCompositeLayers({
228
+ layers: input.spec.foreground ?? [],
229
+ canvasSize: size,
230
+ canonicalLogo: input.canonicalLogo,
231
+ foregroundAssets: input.foregroundAssets ?? {},
232
+ })),
233
+ );
234
+ return sharp(background, { failOn: "none" })
235
+ .composite(composites)
236
+ .png()
237
+ .toBuffer();
238
+ }
239
+
240
+ export function canvasSizeFromAspectRatio(input: {
241
+ aspectRatio?: AspectRatio;
242
+ baseWidth: number;
243
+ baseHeight: number;
244
+ }): { width: number; height: number } {
245
+ const baseWidth = Math.max(1, input.baseWidth);
246
+ const baseHeight = Math.max(1, input.baseHeight);
247
+ if (!input.aspectRatio) return { width: baseWidth, height: baseHeight };
248
+ const requested = aspectRatioValue(input.aspectRatio);
249
+ const current = baseWidth / baseHeight;
250
+ if (Math.abs(requested - current) < 0.01) {
251
+ return { width: baseWidth, height: baseHeight };
252
+ }
253
+ if (requested > current) {
254
+ return {
255
+ width: Math.max(1, Math.round(baseHeight * requested)),
256
+ height: baseHeight,
257
+ };
258
+ }
259
+ return {
260
+ width: baseWidth,
261
+ height: Math.max(1, Math.round(baseWidth / requested)),
262
+ };
263
+ }
264
+
265
+ function normalizeContentRegion(region: PresetSkeletonSpec["contentRegion"]): {
266
+ x: number;
267
+ y: number;
268
+ w: number;
269
+ h: number;
270
+ } {
271
+ if (!region) return { x: 0, y: 0, w: 1, h: 1 };
272
+ const x = clamp(region.x, 0, 1);
273
+ const y = clamp(region.y, 0, 1);
274
+ return {
275
+ x,
276
+ y,
277
+ w: clamp(region.w, 0.02, 1 - x),
278
+ h: clamp(region.h, 0.02, 1 - y),
279
+ };
280
+ }
281
+
282
+ async function foregroundCompositeLayers(input: {
283
+ layers: PresetSkeletonForegroundLayer[];
284
+ canvasSize: { width: number; height: number };
285
+ canonicalLogo?: Buffer;
286
+ foregroundAssets: Record<string, Buffer>;
287
+ }): Promise<sharp.OverlayOptions[]> {
288
+ const overlays: sharp.OverlayOptions[] = [];
289
+ for (const layer of input.layers) {
290
+ const source =
291
+ layer.source === "canonicalLogo"
292
+ ? input.canonicalLogo
293
+ : input.foregroundAssets[layer.source.assetId];
294
+ if (!source) continue;
295
+ const targetWidth = Math.max(
296
+ 1,
297
+ Math.round(input.canvasSize.width * clamp(layer.w, 0.02, 1)),
298
+ );
299
+ const buffer = await sharp(source, { failOn: "none" })
300
+ .rotate()
301
+ .resize({ width: targetWidth, fit: "inside", withoutEnlargement: true })
302
+ .png()
303
+ .toBuffer();
304
+ overlays.push({
305
+ input: buffer,
306
+ left: Math.round(input.canvasSize.width * clamp(layer.x, 0, 1)),
307
+ top: Math.round(input.canvasSize.height * clamp(layer.y, 0, 1)),
308
+ });
309
+ }
310
+ return overlays;
311
+ }
312
+
313
+ function contactShadowSvg(
314
+ canvasSize: { width: number; height: number },
315
+ subjectBox: { left: number; top: number; width: number; height: number },
316
+ ): Buffer {
317
+ const cx = subjectBox.left + subjectBox.width / 2;
318
+ const cy = subjectBox.top + subjectBox.height * 0.86;
319
+ const rx = Math.max(12, subjectBox.width * 0.28);
320
+ const ry = Math.max(6, subjectBox.height * 0.045);
321
+ const blur = Math.max(
322
+ 6,
323
+ Math.min(canvasSize.width, canvasSize.height) * 0.018,
324
+ );
325
+ return Buffer.from(`<svg width="${canvasSize.width}" height="${canvasSize.height}" viewBox="0 0 ${canvasSize.width} ${canvasSize.height}" xmlns="http://www.w3.org/2000/svg">
326
+ <defs><filter id="shadow"><feGaussianBlur stdDeviation="${blur}"/></filter></defs>
327
+ <ellipse cx="${cx}" cy="${cy}" rx="${rx}" ry="${ry}" fill="#000000" opacity="0.24" filter="url(#shadow)"/>
328
+ </svg>`);
329
+ }
330
+
331
+ function clamp(value: number, min: number, max: number): number {
332
+ if (!Number.isFinite(value)) return min;
333
+ return Math.max(min, Math.min(max, value));
334
+ }
335
+
84
336
  export function hasRasterImageSignature(
85
337
  mimeType: string,
86
338
  data: Uint8Array,
@@ -0,0 +1,137 @@
1
+ import type {
2
+ AspectRatio,
3
+ PresetSkeletonForegroundLayer,
4
+ PresetSkeletonSpec,
5
+ } from "../../shared/api.js";
6
+
7
+ export function normalizePresetSkeletonSpec(
8
+ value: unknown,
9
+ ): PresetSkeletonSpec | null {
10
+ if (!value || typeof value !== "object") return null;
11
+ const raw = value as Record<string, unknown>;
12
+ const background = normalizeBackground(raw.background);
13
+ if (!background) return null;
14
+ const mask = normalizeMask(raw.mask);
15
+ const contentMode =
16
+ raw.contentMode === "fill" || raw.contentMode === "cutout"
17
+ ? raw.contentMode
18
+ : "fill";
19
+ const contentRegion = normalizeRegion(raw.contentRegion);
20
+ const foreground = Array.isArray(raw.foreground)
21
+ ? raw.foreground
22
+ .map(normalizeForegroundLayer)
23
+ .filter((layer): layer is PresetSkeletonForegroundLayer =>
24
+ Boolean(layer),
25
+ )
26
+ .slice(0, 8)
27
+ : undefined;
28
+ return {
29
+ background,
30
+ ...(mask ? { mask } : {}),
31
+ contentMode,
32
+ ...(contentRegion ? { contentRegion } : {}),
33
+ ...(raw.dropShadow === true ? { dropShadow: true } : {}),
34
+ ...(foreground?.length ? { foreground } : {}),
35
+ };
36
+ }
37
+
38
+ function normalizeMask(value: unknown): PresetSkeletonSpec["mask"] | null {
39
+ if (!value || typeof value !== "object") return null;
40
+ const record = value as Record<string, unknown>;
41
+ if (record.type === "asset" && typeof record.assetId === "string") {
42
+ const assetId = record.assetId.trim();
43
+ return assetId ? { type: "asset", assetId } : null;
44
+ }
45
+ return null;
46
+ }
47
+
48
+ export function skeletonUsesCanonicalLogo(
49
+ spec: PresetSkeletonSpec | null | undefined,
50
+ ): boolean {
51
+ return Boolean(
52
+ spec?.foreground?.some((layer) => layer.source === "canonicalLogo"),
53
+ );
54
+ }
55
+
56
+ export function clampCutoutAspectRatio(input: {
57
+ aspectRatio: AspectRatio;
58
+ supported: readonly AspectRatio[];
59
+ }): AspectRatio {
60
+ if (input.supported.includes(input.aspectRatio)) return input.aspectRatio;
61
+ const requested = aspectRatioValue(input.aspectRatio);
62
+ return [...input.supported].sort(
63
+ (left, right) =>
64
+ Math.abs(aspectRatioValue(left) - requested) -
65
+ Math.abs(aspectRatioValue(right) - requested),
66
+ )[0];
67
+ }
68
+
69
+ export function aspectRatioValue(aspectRatio: AspectRatio | string): number {
70
+ const [w, h] = String(aspectRatio)
71
+ .split(":")
72
+ .map((part) => Number(part));
73
+ return Number.isFinite(w) && Number.isFinite(h) && h > 0 ? w / h : 1;
74
+ }
75
+
76
+ function normalizeBackground(
77
+ value: unknown,
78
+ ): PresetSkeletonSpec["background"] | null {
79
+ if (!value || typeof value !== "object") return null;
80
+ const record = value as Record<string, unknown>;
81
+ if (record.type === "asset" && typeof record.assetId === "string") {
82
+ const assetId = record.assetId.trim();
83
+ return assetId ? { type: "asset", assetId } : null;
84
+ }
85
+ return null;
86
+ }
87
+
88
+ function normalizeForegroundLayer(
89
+ value: unknown,
90
+ ): PresetSkeletonForegroundLayer | null {
91
+ if (!value || typeof value !== "object") return null;
92
+ const raw = value as Record<string, unknown>;
93
+ let source: PresetSkeletonForegroundLayer["source"] | null = null;
94
+ if (raw.source === "canonicalLogo") {
95
+ source = "canonicalLogo";
96
+ } else if (
97
+ raw.source &&
98
+ typeof raw.source === "object" &&
99
+ typeof (raw.source as Record<string, unknown>).assetId === "string"
100
+ ) {
101
+ source = { assetId: (raw.source as { assetId: string }).assetId };
102
+ }
103
+ if (!source) return null;
104
+ return {
105
+ source,
106
+ x: clampNumber(raw.x, 0, 1, 0.78),
107
+ y: clampNumber(raw.y, 0, 1, 0.06),
108
+ w: clampNumber(raw.w, 0.02, 1, 0.16),
109
+ };
110
+ }
111
+
112
+ function normalizeRegion(value: unknown) {
113
+ if (!value || typeof value !== "object") return null;
114
+ const raw = value as Record<string, unknown>;
115
+ return {
116
+ x: clampNumber(raw.x, 0, 1, 0),
117
+ y: clampNumber(raw.y, 0, 1, 0),
118
+ w: clampNumber(raw.w, 0.02, 1, 1),
119
+ h: clampNumber(raw.h, 0.02, 1, 1),
120
+ };
121
+ }
122
+
123
+ function clampNumber(
124
+ value: unknown,
125
+ min: number,
126
+ max: number,
127
+ fallback: number,
128
+ ): number {
129
+ const numberValue =
130
+ typeof value === "number"
131
+ ? value
132
+ : typeof value === "string"
133
+ ? Number(value)
134
+ : Number.NaN;
135
+ if (!Number.isFinite(numberValue)) return fallback;
136
+ return Math.min(max, Math.max(min, numberValue));
137
+ }
@@ -8,6 +8,7 @@ export const IMAGE_CATEGORIES = [
8
8
  "social",
9
9
  "campaign",
10
10
  "style-only",
11
+ "skeleton",
11
12
  "other",
12
13
  ] as const;
13
14
 
@@ -38,8 +39,29 @@ export const IMAGE_MODELS = [
38
39
  "gemini-3.1-flash-image-preview",
39
40
  "gemini-3-pro-image-preview",
40
41
  "gemini-2.5-flash-image",
42
+ "gpt-image-1",
43
+ "gpt-image-2",
41
44
  ] as const;
42
45
 
46
+ // Per-model aspect-ratio constraints. Mirrors the image service catalog's
47
+ // `supportedAspectRatios` (see the ai-services image-generation catalog). Models
48
+ // omitted here accept the full ASPECT_RATIOS set. GPT image models map each
49
+ // aspect ratio to a fixed OpenAI resolution and support only these three; other
50
+ // ratios are rejected upstream with `unsupported_aspect_ratio`. Keep this in
51
+ // sync with the catalog until the picker sources it dynamically from `/discover`.
52
+ export const MODEL_ASPECT_RATIOS: Partial<
53
+ Record<ImageModel, readonly AspectRatio[]>
54
+ > = {
55
+ "gpt-image-1": ["1:1", "2:3", "3:2"],
56
+ "gpt-image-2": ["1:1", "2:3", "3:2"],
57
+ };
58
+
59
+ export function supportedAspectRatiosForModel(
60
+ model: ImageModel,
61
+ ): readonly AspectRatio[] {
62
+ return MODEL_ASPECT_RATIOS[model] ?? ASPECT_RATIOS;
63
+ }
64
+
43
65
  export const GENERATION_INTENTS = ["generate", "restyle", "edit"] as const;
44
66
 
45
67
  export const STYLE_STRENGTHS = ["subtle", "balanced", "strong"] as const;
@@ -79,6 +101,7 @@ export type ImageRole =
79
101
  | "product_reference"
80
102
  | "diagram_reference"
81
103
  | "video_reference"
104
+ | "background_reference"
82
105
  | "subject_reference"
83
106
  | "edit_target"
84
107
  | "generated";
@@ -120,6 +143,29 @@ export interface StyleBrief {
120
143
  doNot?: string[];
121
144
  }
122
145
 
146
+ export type PresetSkeletonBackground = { type: "asset"; assetId: string };
147
+ export type PresetSkeletonMask = { type: "asset"; assetId: string };
148
+
149
+ export type PresetSkeletonForegroundSource =
150
+ | "canonicalLogo"
151
+ | { assetId: string };
152
+
153
+ export interface PresetSkeletonForegroundLayer {
154
+ source: PresetSkeletonForegroundSource;
155
+ x: number;
156
+ y: number;
157
+ w: number;
158
+ }
159
+
160
+ export interface PresetSkeletonSpec {
161
+ background: PresetSkeletonBackground;
162
+ mask?: PresetSkeletonMask;
163
+ contentMode: "cutout" | "fill";
164
+ contentRegion?: { x: number; y: number; w: number; h: number };
165
+ dropShadow?: boolean;
166
+ foreground?: PresetSkeletonForegroundLayer[];
167
+ }
168
+
123
169
  export interface ImageLibrarySummary {
124
170
  id: string;
125
171
  title: string;
@@ -130,6 +176,7 @@ export interface ImageLibrarySummary {
130
176
  canonicalLogoAssetId?: string | null;
131
177
  coverAssetId?: string | null;
132
178
  visibility?: string;
179
+ accessRole?: "owner" | "admin" | "editor" | "viewer";
133
180
  archivedAt?: string | null;
134
181
  createdAt?: string;
135
182
  updatedAt?: string;
@@ -361,7 +361,8 @@ export function LibraryLayout({ children }: LibraryLayoutProps) {
361
361
  <>
362
362
  <div className="px-3 py-3">
363
363
  <Button
364
- className="w-full gap-1.5 bg-primary text-primary-foreground shadow-sm hover:bg-primary/90"
364
+ className="w-full gap-1.5"
365
+ variant="outline"
365
366
  size="sm"
366
367
  asChild
367
368
  >
@@ -563,7 +564,11 @@ export function LibraryLayout({ children }: LibraryLayoutProps) {
563
564
  {t("navigation.desktopBody")}
564
565
  </span>
565
566
  </div>
566
- <CaptureInstallButton size="sm" className="shrink-0">
567
+ <CaptureInstallButton
568
+ variant="outline"
569
+ size="sm"
570
+ className="shrink-0"
571
+ >
567
572
  Download
568
573
  </CaptureInstallButton>
569
574
  <Tooltip>
@@ -25,7 +25,7 @@ export function SortMenu({ value, onChange }: SortMenuProps) {
25
25
  return (
26
26
  <DropdownMenu>
27
27
  <DropdownMenuTrigger asChild>
28
- <Button variant="outline" size="sm" className="gap-1.5 h-8">
28
+ <Button variant="outline" size="sm" className="gap-1.5 h-9">
29
29
  <IconArrowsSort className="h-3.5 w-3.5" />
30
30
  <span className="text-xs">{LABELS[value]}</span>
31
31
  </Button>