@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.
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +14 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/client/AgentPanel.tsx +1 -1
- package/corpus/core/src/client/rich-markdown-editor/useCollabReconcile.ts +11 -6
- package/corpus/core/src/client/use-action.ts +39 -2
- package/corpus/core/src/client/use-db-sync.ts +44 -18
- package/corpus/core/src/db/create-get-db.ts +32 -2
- package/corpus/core/src/server/framework-request-handler.ts +52 -4
- package/corpus/templates/assets/.agents/skills/asset-generation/SKILL.md +5 -0
- package/corpus/templates/assets/.agents/skills/logo-composite/SKILL.md +34 -6
- package/corpus/templates/assets/AGENTS.md +23 -4
- package/corpus/templates/assets/actions/_generation-preset-settings.ts +48 -0
- package/corpus/templates/assets/actions/_helpers.ts +8 -1
- package/corpus/templates/assets/actions/_preset-skeleton-validation.ts +64 -0
- package/corpus/templates/assets/actions/create-generation-preset.ts +11 -3
- package/corpus/templates/assets/actions/generate-image-batch.ts +7 -2
- package/corpus/templates/assets/actions/generate-image.ts +342 -25
- package/corpus/templates/assets/actions/get-library.ts +4 -3
- package/corpus/templates/assets/actions/navigate.ts +2 -1
- package/corpus/templates/assets/actions/refresh-generation-run.ts +5 -1
- package/corpus/templates/assets/actions/update-asset.ts +1 -0
- package/corpus/templates/assets/actions/update-generation-preset.ts +8 -1
- package/corpus/templates/assets/actions/view-screen.ts +8 -1
- package/corpus/templates/assets/app/components/generation/GenerationResults.tsx +9 -1
- package/corpus/templates/assets/app/hooks/use-image-model-menu.ts +1 -0
- package/corpus/templates/assets/app/hooks/use-navigation-state.ts +11 -0
- package/corpus/templates/assets/app/i18n/zh-TW.ts +64 -0
- package/corpus/templates/assets/app/i18n-data.ts +650 -0
- package/corpus/templates/assets/app/routes/asset.$id.tsx +2 -1
- package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +44 -33
- package/corpus/templates/assets/app/routes/brand-kits.$id_.presets.$presetId.tsx +1474 -0
- package/corpus/templates/assets/app/routes/library.tsx +43 -1
- package/corpus/templates/assets/server/lib/generation.ts +366 -44
- package/corpus/templates/assets/server/lib/image-processing.ts +252 -0
- package/corpus/templates/assets/server/lib/preset-skeleton.ts +137 -0
- package/corpus/templates/assets/shared/api.ts +47 -0
- package/corpus/templates/clips/app/components/library/library-layout.tsx +7 -2
- package/corpus/templates/clips/app/components/library/sort-menu.tsx +1 -1
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +114 -33
- package/corpus/templates/clips/app/routes/_app.library._index.tsx +27 -1
- package/corpus/templates/clips/app/routes/record.tsx +157 -68
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +5 -5
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +20 -3
- package/corpus/templates/clips/shared/finalize-recovery.ts +23 -3
- package/corpus/templates/content/AGENTS.md +52 -52
- package/corpus/templates/content/actions/_builder-cms-read-client.ts +188 -8
- package/corpus/templates/content/actions/_builder-docs-client.ts +41 -3
- package/corpus/templates/content/actions/_database-source-utils.ts +998 -160
- package/corpus/templates/content/actions/_database-utils.ts +44 -4
- package/corpus/templates/content/actions/_notion-action-utils.ts +6 -2
- package/corpus/templates/content/actions/add-content-database-source-field-property.ts +23 -1
- package/corpus/templates/content/actions/attach-content-database-source.ts +85 -12
- package/corpus/templates/content/actions/change-content-database-source-role.ts +9 -1
- package/corpus/templates/content/actions/delete-content-database.ts +1 -0
- package/corpus/templates/content/actions/get-document.ts +11 -2
- package/corpus/templates/content/actions/list-content-databases.ts +57 -9
- package/corpus/templates/content/actions/prepare-builder-source-review.ts +23 -6
- package/corpus/templates/content/actions/refresh-content-database-source.ts +26 -3
- package/corpus/templates/content/actions/restore-content-database.ts +1 -0
- package/corpus/templates/content/actions/update-document.ts +43 -0
- package/corpus/templates/content/app/components/editor/BuilderBodySyncingNotice.tsx +21 -0
- package/corpus/templates/content/app/components/editor/DocumentDatabase.tsx +0 -1
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +70 -28
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +69 -17
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +4 -4
- package/corpus/templates/content/app/components/editor/body-hydration.ts +112 -0
- package/corpus/templates/content/app/components/editor/builder-body-hydration-pump.ts +52 -0
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +9076 -2876
- package/corpus/templates/content/app/components/editor/database-sources/BuilderSourceReviewDialog.tsx +41 -1
- package/corpus/templates/content/app/components/editor/extensions/ImageBlock.tsx +36 -11
- package/corpus/templates/content/app/components/editor/previewDocumentSaveController.ts +21 -1
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +11 -1
- package/corpus/templates/content/app/components/sidebar/DocumentTreeItem.tsx +11 -8
- package/corpus/templates/content/app/global.css +41 -0
- package/corpus/templates/content/app/hooks/use-content-database.ts +346 -42
- package/corpus/templates/content/app/hooks/use-db-sync.ts +9 -0
- package/corpus/templates/content/app/hooks/use-documents.ts +47 -0
- package/corpus/templates/content/app/hooks/use-notion.ts +12 -10
- package/corpus/templates/content/app/i18n/zh-TW.ts +35 -0
- package/corpus/templates/content/app/i18n-data.ts +355 -0
- package/corpus/templates/content/app/root.tsx +22 -0
- package/corpus/templates/content/changelog/2026-07-01-builder-database-sources-keep-loading-rows-in-the-background.md +6 -0
- package/corpus/templates/content/changelog/2026-07-01-builder-source-attach-starts-with-usable-rows.md +6 -0
- package/corpus/templates/content/changelog/2026-07-01-builder-source-attachment-now-stays-connected-after-large.md +6 -0
- package/corpus/templates/content/changelog/2026-07-01-builder-source-refreshes-now-show-progress-for-large-docs-blog.md +6 -0
- package/corpus/templates/content/changelog/2026-07-01-database-pages-now-delete-to-trash-without-route-errors.md +6 -0
- package/corpus/templates/content/changelog/2026-07-02-builder-source-refreshes-recover-from-stalled-background-row.md +6 -0
- package/corpus/templates/content/changelog/2026-07-02-builder-sourced-rows-open-with-sync-protection.md +6 -0
- package/corpus/templates/content/changelog/2026-07-02-database-rows-and-pages-open-faster-from-recently-loaded-dat.md +6 -0
- package/corpus/templates/content/changelog/2026-07-02-preview-panels-close-reliably-narrow-sidebar-row-actions-sta.md +6 -0
- package/corpus/templates/content/changelog/2026-07-06-builder-sync-progress-no-longer-shows-continue.md +6 -0
- package/corpus/templates/content/shared/api.ts +13 -0
- package/corpus/templates/content/shared/builder-mdx.ts +16 -3
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +23 -13
- package/corpus/templates/design/.agents/skills/responsive-breakpoints/SKILL.md +98 -0
- package/corpus/templates/design/.agents/skills/shader-fills/SKILL.md +162 -0
- package/corpus/templates/design/AGENTS.md +9 -2
- package/corpus/templates/design/actions/add-breakpoint.ts +6 -3
- package/corpus/templates/design/actions/apply-a11y-fix.ts +57 -37
- package/corpus/templates/design/actions/apply-component-prop-edit.ts +41 -20
- package/corpus/templates/design/actions/apply-motion-edit.ts +251 -38
- package/corpus/templates/design/actions/apply-shader-fill.ts +90 -66
- package/corpus/templates/design/actions/apply-visual-edit.ts +282 -55
- package/corpus/templates/design/actions/create-component.ts +29 -60
- package/corpus/templates/design/actions/create-file.ts +9 -2
- package/corpus/templates/design/actions/duplicate-design.ts +31 -2
- package/corpus/templates/design/actions/edit-design.ts +36 -38
- package/corpus/templates/design/actions/generate-design-title.ts +87 -0
- package/corpus/templates/design/actions/generate-design.ts +53 -18
- package/corpus/templates/design/actions/generate-screens.ts +108 -4
- package/corpus/templates/design/actions/get-motion-timeline.ts +35 -7
- package/corpus/templates/design/actions/insert-asset.ts +34 -29
- package/corpus/templates/design/actions/insert-design-native-asset.ts +129 -32
- package/corpus/templates/design/actions/insert-figma-library-asset.ts +35 -30
- package/corpus/templates/design/actions/present-design-variants.ts +7 -2
- package/corpus/templates/design/actions/remove-motion-timeline.ts +31 -36
- package/corpus/templates/design/actions/update-file.ts +190 -75
- package/corpus/templates/design/app/components/design/BreakpointBar.tsx +403 -0
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +469 -222
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +708 -53
- package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +83 -3
- package/corpus/templates/design/app/components/design/EditPanel.tsx +1091 -6948
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +419 -85
- package/corpus/templates/design/app/components/design/MotionDock.tsx +1124 -103
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +2610 -1398
- package/corpus/templates/design/app/components/design/ReadOnlyDesignBanner.tsx +22 -0
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +2182 -235
- package/corpus/templates/design/app/components/design/bridge/motion-preview.bridge.ts +187 -11
- package/corpus/templates/design/app/components/design/bridge/shader-fill-preview.bridge.ts +376 -1
- package/corpus/templates/design/app/components/design/bridge/shader-runtime.bridge.ts +746 -0
- package/corpus/templates/design/app/components/design/canvas-primitive-style.ts +17 -0
- package/corpus/templates/design/app/components/design/code-workbench/SideBar.tsx +1 -1
- package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +1 -3
- package/corpus/templates/design/app/components/design/code-workbench/quickinput/QuickInput.tsx +1 -1
- package/corpus/templates/design/app/components/design/edit-panel/appearance-properties.tsx +518 -0
- package/corpus/templates/design/app/components/design/edit-panel/code-inspect-helpers.tsx +562 -0
- package/corpus/templates/design/app/components/design/edit-panel/component-section.tsx +763 -0
- package/corpus/templates/design/app/components/design/edit-panel/document-colors.ts +94 -0
- package/corpus/templates/design/app/components/design/edit-panel/effects-properties.tsx +780 -0
- package/corpus/templates/design/app/components/design/edit-panel/element-classification.ts +446 -0
- package/corpus/templates/design/app/components/design/edit-panel/element-identity.ts +79 -0
- package/corpus/templates/design/app/components/design/edit-panel/field-primitives.tsx +315 -0
- package/corpus/templates/design/app/components/design/edit-panel/fill-gradient-helpers.ts +344 -0
- package/corpus/templates/design/app/components/design/edit-panel/fill-properties.tsx +594 -0
- package/corpus/templates/design/app/components/design/edit-panel/frame-presets-panel.tsx +119 -0
- package/corpus/templates/design/app/components/design/edit-panel/inspector-controls.tsx +248 -0
- package/corpus/templates/design/app/components/design/edit-panel/interaction-state-helpers.ts +45 -0
- package/corpus/templates/design/app/components/design/edit-panel/layout-properties.tsx +693 -0
- package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +724 -0
- package/corpus/templates/design/app/components/design/edit-panel/position-helpers.ts +207 -0
- package/corpus/templates/design/app/components/design/edit-panel/position-layout-properties.tsx +628 -0
- package/corpus/templates/design/app/components/design/edit-panel/selection-helpers.ts +91 -0
- package/corpus/templates/design/app/components/design/edit-panel/stroke-properties.tsx +649 -0
- package/corpus/templates/design/app/components/design/edit-panel/style-change-types.ts +118 -0
- package/corpus/templates/design/app/components/design/edit-panel/style-options.ts +88 -0
- package/corpus/templates/design/app/components/design/edit-panel/transform-helpers.ts +100 -0
- package/corpus/templates/design/app/components/design/edit-panel/typography-helpers.ts +117 -0
- package/corpus/templates/design/app/components/design/edit-panel/typography-properties.tsx +501 -0
- package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +91 -40
- package/corpus/templates/design/app/components/design/inspector/BreakpointOverrideIndicator.tsx +82 -0
- package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +189 -87
- package/corpus/templates/design/app/components/design/inspector/GlslShaderPanel.tsx +1097 -0
- package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +44 -0
- package/corpus/templates/design/app/components/design/inspector/InteractionStatePanel.tsx +258 -0
- package/corpus/templates/design/app/components/design/inspector/MotionKeyframeDiamond.tsx +144 -0
- package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +99 -9
- package/corpus/templates/design/app/components/design/inspector/frame-size-presets.ts +116 -0
- package/corpus/templates/design/app/components/design/inspector/index.ts +26 -0
- package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +29 -0
- package/corpus/templates/design/app/components/design/multi-screen/alt-hover-measurement.ts +171 -0
- package/corpus/templates/design/app/components/design/multi-screen/board-surface-html.ts +220 -0
- package/corpus/templates/design/app/components/design/multi-screen/chrome-transitions.ts +35 -0
- package/corpus/templates/design/app/components/design/multi-screen/cross-screen-drop.ts +134 -0
- package/corpus/templates/design/app/components/design/multi-screen/culling.ts +185 -0
- package/corpus/templates/design/app/components/design/multi-screen/gradient-overlay-geometry.ts +120 -0
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +892 -0
- package/corpus/templates/design/app/components/design/multi-screen/vector-edit-geometry.ts +21 -0
- package/corpus/templates/design/app/components/design/types.ts +15 -0
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +109 -5
- package/corpus/templates/design/app/global.css +8 -8
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +259 -2
- package/corpus/templates/design/app/i18n/zh-TW.ts +163 -9
- package/corpus/templates/design/app/i18n-breakpoints.ts +205 -0
- package/corpus/templates/design/app/i18n-data.ts +1664 -152
- package/corpus/templates/design/app/i18n-motion.ts +563 -0
- package/corpus/templates/design/app/lib/design-import.ts +73 -0
- package/corpus/templates/design/app/pages/Index.tsx +41 -22
- package/corpus/templates/design/changelog/2026-06-29-design-inspector-controls-now-match-figmas-softer-dark-chrome.md +1 -1
- package/corpus/templates/design/changelog/2026-06-30-design-now-has-a-figma-style-left-rail-for-file-agent-assets.md +1 -1
- package/corpus/templates/design/changelog/2026-06-30-design-tools-now-use-a-quieter-figma-style-list-layout.md +1 -1
- package/corpus/templates/design/changelog/2026-06-30-multi-select-outlines-now-stay-consistent-across-all-screens.md +1 -1
- package/corpus/templates/design/changelog/2026-07-03-canvas-interactions-now-match-figma-rotation-aware-resizing-.md +1 -1
- package/corpus/templates/design/changelog/2026-07-03-layers-panel-matches-figma-top-layer-on-top-drag-with-auto-s.md +1 -1
- package/corpus/templates/design/changelog/2026-07-05-designs-get-ai-generated-names-from-your-prompt.md +6 -0
- package/corpus/templates/design/changelog/2026-07-05-local-code-screens-keep-their-connection-when-duplicated-and.md +6 -0
- package/corpus/templates/design/changelog/2026-07-05-press-a-to-draw-screens-on-the-canvas-inside-a-screen-it-dr.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-3d-rotation-and-perspective-controls-on-every-element.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-ai-generated-and-duplicated-screens-now-get-their-editor-sel.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-applying-shaders-and-fills-in-quick-succession-can-no-longer.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-breakpoint-frames-in-the-overview-now-support-click-to-selec.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-breakpoint-segments-in-the-inspector-now-show-a-device-icon-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-breakpoint-targeting-now-lives-in-one-compact-control-in-the.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-canvas-edits-can-no-longer-be-overwritten-by-stale-collabora.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-canvas-edits-inside-screens-save-reliably-again.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-cleaner-inspector-removed-the-ask-ai-box-from-the-design-tab.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-clicking-empty-canvas-space-now-deselects-an-element-inside-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-dragging-an-element-onto-a-rectangle-now-nests-it-inside-wit.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-dragging-screens-and-objects-on-the-canvas-is-now-much-smoot.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-drawing-a-shape-or-text-on-the-canvas-no-longer-flashes-away.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-dropping-an-element-between-two-others-inside-a-screen-now-s.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-duplicating-a-screen-now-places-the-copy-exactly-where-you-d.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-edit-gradients-directly-on-elements-inside-screens-scale-str.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-edits-from-collaborators-and-the-agent-now-update-the-canvas.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-a-bug-where-most-style-position-and-text-edits-briefly.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-a-confusing-raw-error-message-when-a-file-upload-fails.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-a-rare-case-where-an-edit-could-be-silently-overwritte.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-inserted-assets-sometimes-disappearing-reappearing-or-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-inspector-value-scrubbing-producing-erratic-numbers-an.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-padding-gap-and-min-max-size-scrubbing-not-updating-th.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-text-stroke-color-turning-black-and-glyphs-disappearin.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-the-collapsed-effects-and-stroke-inspector-sections-sh.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-the-new-design-dialog-closing-unexpectedly-when-using-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-the-typography-section-missing-when-selecting-text-nes.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-full-view-no-longer-flashes-back-to-the-overview-on-entry-no.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-keyframe-animation-timeline-per-property-keyframes-easing-cu.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-moving-restyling-and-scrubbing-values-on-elements-in-ai-gene.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-padding-and-corner-radius-value-scrubbing-now-snaps-to-whole.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-padding-handles-now-only-resize-on-the-handle-line-itself-sh.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-preview-and-edit-hover-focus-and-pressed-states-with-real-cs.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-promoting-an-element-to-a-component-now-works-correctly-for-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-reduced-url-history-churn-and-selection-overlay-flicker-whil.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-removed-the-decorative-dot-before-screen-names-in-the-overvi.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-responsive-breakpoints-edit-at-any-width-with-cascading-over.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-screen-labels-no-longer-turn-blue-when-you-hover-inside-the-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-scrolling-a-screen-with-an-element-selected-stays-smooth-on-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-selecting-multiple-elements-and-dragging-now-moves-the-whole.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-selection-borders-handles-and-value-readouts-now-stay-the-sa.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-selection-handles-and-editing-chrome-now-stay-a-constant-siz.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-shader-fills-and-effects-ai-authored-or-preset-glsl-shaders-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-text-drawn-on-the-canvas-now-defaults-to-white-and-inter-in-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-text-dropped-into-a-shape-now-stays-readable-instead-of-disa.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-the-add-tweak-controls-prompt-no-longer-jumps-to-the-corner-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-the-padding-value-readout-now-stays-visible-while-you-hover-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-the-selected-element-attachment-now-clears-from-the-chat-com.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-the-zoom-menu-is-more-compact-with-tight-rows-and-right-alig.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-undo-and-redo-no-longer-flash-the-screen-changes-now-apply-i.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-zoom-presets-like-zoom-to-50-now-stay-on-the-focused-screen-.md +6 -0
- package/corpus/templates/design/server/lib/import-design-files.ts +11 -2
- package/corpus/templates/design/server/source-workspace.ts +139 -59
- package/corpus/templates/design/shared/board-file.ts +11 -2
- package/corpus/templates/design/shared/breakpoint-media.ts +543 -0
- package/corpus/templates/design/shared/canvas-math.ts +354 -35
- package/corpus/templates/design/shared/code-layer.ts +277 -8
- package/corpus/templates/design/shared/design-state.ts +11 -4
- package/corpus/templates/design/shared/interaction-states.ts +548 -0
- package/corpus/templates/design/shared/motion-compiler.ts +186 -23
- package/corpus/templates/design/shared/motion-easing.ts +294 -0
- package/corpus/templates/design/shared/motion-timeline.ts +400 -34
- package/corpus/templates/design/shared/prompt-title.ts +95 -0
- package/corpus/templates/design/shared/responsive-classes.ts +448 -10
- package/corpus/templates/design/shared/screen-annotation.ts +46 -0
- package/corpus/templates/design/shared/shader-fills.ts +1009 -0
- package/corpus/templates/design/shared/shader-presets.ts +852 -4
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +15 -2
- package/corpus/templates/slides/app/components/editor/ImportButton.tsx +10 -1
- package/corpus/templates/slides/app/lib/upload-response.ts +71 -0
- package/dist/client/AgentPanel.js +1 -1
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.js +11 -6
- package/dist/client/rich-markdown-editor/useCollabReconcile.js.map +1 -1
- package/dist/client/use-action.d.ts +3 -0
- package/dist/client/use-action.d.ts.map +1 -1
- package/dist/client/use-action.js +34 -3
- package/dist/client/use-action.js.map +1 -1
- package/dist/client/use-db-sync.d.ts +4 -0
- package/dist/client/use-db-sync.d.ts.map +1 -1
- package/dist/client/use-db-sync.js +37 -18
- package/dist/client/use-db-sync.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/db/create-get-db.d.ts +25 -0
- package/dist/db/create-get-db.d.ts.map +1 -1
- package/dist/db/create-get-db.js +25 -2
- package/dist/db/create-get-db.js.map +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/framework-request-handler.d.ts.map +1 -1
- package/dist/server/framework-request-handler.js +37 -1
- package/dist/server/framework-request-handler.js.map +1 -1
- package/package.json +1 -1
- package/corpus/templates/design/app/components/design/inspector/InspectorAiActions.tsx +0 -153
- package/corpus/templates/design/app/hooks/useAgentEditRequest.ts +0 -133
- package/corpus/templates/design/app/pages/DesignEditor.tsx +0 -22924
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { inArray } from "drizzle-orm";
|
|
2
|
+
|
|
3
|
+
import { schema } from "../server/db/index.js";
|
|
4
|
+
|
|
5
|
+
export async function assertPresetSkeletonAssetsValid(input: {
|
|
6
|
+
db: any;
|
|
7
|
+
libraryId: string;
|
|
8
|
+
settings: unknown;
|
|
9
|
+
}) {
|
|
10
|
+
const spec =
|
|
11
|
+
input.settings && typeof input.settings === "object"
|
|
12
|
+
? (input.settings as { skeletonSpec?: unknown }).skeletonSpec
|
|
13
|
+
: null;
|
|
14
|
+
if (!spec || typeof spec !== "object") return;
|
|
15
|
+
const skeleton = spec as {
|
|
16
|
+
background?: { type?: unknown; assetId?: unknown };
|
|
17
|
+
mask?: { type?: unknown; assetId?: unknown };
|
|
18
|
+
};
|
|
19
|
+
const backgroundAssetId =
|
|
20
|
+
skeleton.background?.type === "asset" &&
|
|
21
|
+
typeof skeleton.background.assetId === "string"
|
|
22
|
+
? skeleton.background.assetId
|
|
23
|
+
: "";
|
|
24
|
+
const maskAssetId =
|
|
25
|
+
skeleton.mask?.type === "asset" && typeof skeleton.mask.assetId === "string"
|
|
26
|
+
? skeleton.mask.assetId
|
|
27
|
+
: "";
|
|
28
|
+
if (!backgroundAssetId || !maskAssetId) return;
|
|
29
|
+
|
|
30
|
+
const rows = await input.db
|
|
31
|
+
.select({
|
|
32
|
+
id: schema.assets.id,
|
|
33
|
+
libraryId: schema.assets.libraryId,
|
|
34
|
+
width: schema.assets.width,
|
|
35
|
+
height: schema.assets.height,
|
|
36
|
+
})
|
|
37
|
+
.from(schema.assets)
|
|
38
|
+
.where(inArray(schema.assets.id, [backgroundAssetId, maskAssetId]));
|
|
39
|
+
const background = rows.find((asset: any) => asset.id === backgroundAssetId);
|
|
40
|
+
const mask = rows.find((asset: any) => asset.id === maskAssetId);
|
|
41
|
+
if (
|
|
42
|
+
!background ||
|
|
43
|
+
!mask ||
|
|
44
|
+
background.libraryId !== input.libraryId ||
|
|
45
|
+
mask.libraryId !== input.libraryId
|
|
46
|
+
) {
|
|
47
|
+
throw new Error(
|
|
48
|
+
"Skeleton image and mask must belong to this asset library.",
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
if (
|
|
52
|
+
typeof background.width !== "number" ||
|
|
53
|
+
typeof background.height !== "number" ||
|
|
54
|
+
typeof mask.width !== "number" ||
|
|
55
|
+
typeof mask.height !== "number"
|
|
56
|
+
) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (background.width !== mask.width || background.height !== mask.height) {
|
|
60
|
+
throw new Error(
|
|
61
|
+
"Skeleton inpainting mask must be the same pixel size as the background plate.",
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -13,7 +13,9 @@ import {
|
|
|
13
13
|
IMAGE_MODELS,
|
|
14
14
|
IMAGE_SIZES,
|
|
15
15
|
} from "../shared/api.js";
|
|
16
|
+
import { generationPresetSettingsSchema } from "./_generation-preset-settings.js";
|
|
16
17
|
import { serializeGenerationPreset } from "./_helpers.js";
|
|
18
|
+
import { assertPresetSkeletonAssetsValid } from "./_preset-skeleton-validation.js";
|
|
17
19
|
|
|
18
20
|
export default defineAction({
|
|
19
21
|
description:
|
|
@@ -38,13 +40,14 @@ export default defineAction({
|
|
|
38
40
|
.describe(
|
|
39
41
|
"When true, images generated with this preset composite the library's canonical logo (no-op if the library has no canonical logo).",
|
|
40
42
|
),
|
|
41
|
-
settings:
|
|
43
|
+
settings: generationPresetSettingsSchema.optional(),
|
|
42
44
|
sortOrder: z.coerce.number().optional(),
|
|
43
45
|
}),
|
|
44
46
|
run: async (args) => {
|
|
47
|
+
const db = getDb();
|
|
45
48
|
await assertAccess("asset-library", args.libraryId, "editor");
|
|
46
49
|
if (args.collectionId) {
|
|
47
|
-
const [collection] = await
|
|
50
|
+
const [collection] = await db
|
|
48
51
|
.select()
|
|
49
52
|
.from(schema.assetCollections)
|
|
50
53
|
.where(eq(schema.assetCollections.id, args.collectionId))
|
|
@@ -53,6 +56,11 @@ export default defineAction({
|
|
|
53
56
|
throw new Error("Collection does not belong to this asset library.");
|
|
54
57
|
}
|
|
55
58
|
}
|
|
59
|
+
await assertPresetSkeletonAssetsValid({
|
|
60
|
+
db,
|
|
61
|
+
libraryId: args.libraryId,
|
|
62
|
+
settings: args.settings,
|
|
63
|
+
});
|
|
56
64
|
const now = nowIso();
|
|
57
65
|
const row = {
|
|
58
66
|
id: nanoid(),
|
|
@@ -78,7 +86,7 @@ export default defineAction({
|
|
|
78
86
|
createdAt: now,
|
|
79
87
|
updatedAt: now,
|
|
80
88
|
};
|
|
81
|
-
await
|
|
89
|
+
await db.insert(schema.assetGenerationPresets).values(row);
|
|
82
90
|
return serializeGenerationPreset(row);
|
|
83
91
|
},
|
|
84
92
|
});
|
|
@@ -62,7 +62,7 @@ export default defineAction({
|
|
|
62
62
|
.enum(ASPECT_RATIOS)
|
|
63
63
|
.optional()
|
|
64
64
|
.describe(
|
|
65
|
-
"Slot aspect ratio. When a presetId is set, omit this — the preset's aspect ratio is used unless the user explicitly asks for a different ratio for this slot.",
|
|
65
|
+
"Slot aspect ratio. When a presetId is set, omit this — the preset's aspect ratio is used unless the user explicitly asks for a different ratio for this slot. Note: gpt-image-2 supports only 1:1, 2:3, and 3:2; use a Gemini model for other ratios.",
|
|
66
66
|
),
|
|
67
67
|
imageSize: z.enum(IMAGE_SIZES).optional(),
|
|
68
68
|
categories: z.array(z.enum(IMAGE_CATEGORIES)).optional(),
|
|
@@ -82,7 +82,12 @@ export default defineAction({
|
|
|
82
82
|
.describe(
|
|
83
83
|
"Internal UI state scope for live candidate slots. Usually omitted; embedded picker UIs pass a browser-tab scope.",
|
|
84
84
|
),
|
|
85
|
-
model: z
|
|
85
|
+
model: z
|
|
86
|
+
.enum(IMAGE_MODELS)
|
|
87
|
+
.optional()
|
|
88
|
+
.describe(
|
|
89
|
+
"Image model applied to every slot. Omit to use the user's picker default. Gemini models accept any aspectRatio; gpt-image-2 supports ONLY 1:1, 2:3, and 3:2, so don't select it when any slot needs a different ratio — use a Gemini model instead.",
|
|
90
|
+
),
|
|
86
91
|
tier: z.enum(IMAGE_QUALITY_TIERS).optional(),
|
|
87
92
|
intent: z.enum(GENERATION_INTENTS).default("generate"),
|
|
88
93
|
styleStrength: z.enum(STYLE_STRENGTHS).default("balanced"),
|
|
@@ -23,9 +23,20 @@ import {
|
|
|
23
23
|
isImageGenerationSetupError,
|
|
24
24
|
resolveImageModelForRequest,
|
|
25
25
|
selectReferences,
|
|
26
|
+
type ReferenceForGeneration,
|
|
26
27
|
} from "../server/lib/generation.js";
|
|
27
|
-
import {
|
|
28
|
+
import {
|
|
29
|
+
applyPresetSkeleton,
|
|
30
|
+
compositeLogo,
|
|
31
|
+
maskFromManualMaskAlpha,
|
|
32
|
+
maskFromPlateAlpha,
|
|
33
|
+
} from "../server/lib/image-processing.js";
|
|
28
34
|
import { nowIso, parseJson, stringifyJson } from "../server/lib/json.js";
|
|
35
|
+
import {
|
|
36
|
+
clampCutoutAspectRatio,
|
|
37
|
+
normalizePresetSkeletonSpec,
|
|
38
|
+
skeletonUsesCanonicalLogo,
|
|
39
|
+
} from "../server/lib/preset-skeleton.js";
|
|
29
40
|
import { getObject } from "../server/lib/storage.js";
|
|
30
41
|
import {
|
|
31
42
|
ASPECT_RATIOS,
|
|
@@ -35,8 +46,11 @@ import {
|
|
|
35
46
|
IMAGE_QUALITY_TIERS,
|
|
36
47
|
IMAGE_SIZES,
|
|
37
48
|
STYLE_STRENGTHS,
|
|
49
|
+
supportedAspectRatiosForModel,
|
|
50
|
+
type AspectRatio,
|
|
38
51
|
type ImageCategory,
|
|
39
52
|
type ImageQualityTier,
|
|
53
|
+
type PresetSkeletonSpec,
|
|
40
54
|
type StyleBrief,
|
|
41
55
|
} from "../shared/api.js";
|
|
42
56
|
import {
|
|
@@ -84,7 +98,7 @@ export default defineAction({
|
|
|
84
98
|
.enum(ASPECT_RATIOS)
|
|
85
99
|
.optional()
|
|
86
100
|
.describe(
|
|
87
|
-
"Image aspect ratio. When a presetId is set, omit this — the preset's aspect ratio is used. Pass a value only when there is no preset, or when the user explicitly asks for a ratio different from the preset's.",
|
|
101
|
+
"Image aspect ratio. When a presetId is set, omit this — the preset's aspect ratio is used. Pass a value only when there is no preset, or when the user explicitly asks for a ratio different from the preset's. Note: OpenAI image models support only 1:1, 2:3, and 3:2; gpt-image-1 is used for transparent cutout skeleton subjects, while other ratios (16:9, 9:16, 4:5, 21:9, …) require a Gemini model.",
|
|
88
102
|
),
|
|
89
103
|
imageSize: z
|
|
90
104
|
.enum(IMAGE_SIZES)
|
|
@@ -92,7 +106,12 @@ export default defineAction({
|
|
|
92
106
|
.describe(
|
|
93
107
|
"Output resolution tier. When a presetId is set, omit this — the preset's size is used unless the user explicitly requests a different one.",
|
|
94
108
|
),
|
|
95
|
-
model: z
|
|
109
|
+
model: z
|
|
110
|
+
.enum(IMAGE_MODELS)
|
|
111
|
+
.optional()
|
|
112
|
+
.describe(
|
|
113
|
+
"Image model. Omit to use the user's picker default. Gemini models accept any aspectRatio; gpt-image-2 is the normal opaque OpenAI default, while gpt-image-1 is reserved for transparent cutout skeletons. OpenAI image models support ONLY 1:1, 2:3, and 3:2 — do not pair them with other ratios, choose a Gemini model (e.g. gemini-3-pro-image) for those instead.",
|
|
114
|
+
),
|
|
96
115
|
tier: z.enum(IMAGE_QUALITY_TIERS).optional(),
|
|
97
116
|
intent: z.enum(GENERATION_INTENTS).default("generate"),
|
|
98
117
|
styleStrength: z.enum(STYLE_STRENGTHS).default("balanced"),
|
|
@@ -256,25 +275,32 @@ export default defineAction({
|
|
|
256
275
|
...parseJson<StyleBrief>(library.styleBrief, {}),
|
|
257
276
|
...parseJson<StyleBrief>(collection?.styleBrief, {}),
|
|
258
277
|
};
|
|
259
|
-
const
|
|
278
|
+
const presetSettings = parseJson<{
|
|
279
|
+
tier?: ImageQualityTier;
|
|
280
|
+
includeLogo?: boolean;
|
|
281
|
+
skeletonSpec?: unknown;
|
|
282
|
+
}>(preset?.settings, {});
|
|
283
|
+
const skeletonSpec = normalizePresetSkeletonSpec(
|
|
284
|
+
presetSettings.skeletonSpec,
|
|
285
|
+
);
|
|
286
|
+
const isSkeletonCutout = skeletonSpec?.contentMode === "cutout";
|
|
287
|
+
const outputAspectRatio = (args.aspectRatio ??
|
|
260
288
|
preset?.aspectRatio ??
|
|
261
289
|
collection?.defaultAspectRatio ??
|
|
262
|
-
"16:9") as
|
|
290
|
+
"16:9") as AspectRatio;
|
|
263
291
|
const resolvedImageSize = (args.imageSize ??
|
|
264
292
|
preset?.imageSize ??
|
|
265
293
|
collection?.defaultImageSize ??
|
|
266
294
|
"2K") as (typeof IMAGE_SIZES)[number];
|
|
267
|
-
const presetSettings = parseJson<{
|
|
268
|
-
tier?: ImageQualityTier;
|
|
269
|
-
includeLogo?: boolean;
|
|
270
|
-
}>(preset?.settings, {});
|
|
271
295
|
const resolvedTier = args.tier ?? presetSettings.tier;
|
|
272
|
-
const
|
|
296
|
+
const requestedIncludeLogo =
|
|
273
297
|
args.includeLogo ?? presetSettings.includeLogo ?? false;
|
|
298
|
+
const resolvedIncludeLogo =
|
|
299
|
+
requestedIncludeLogo && !skeletonUsesCanonicalLogo(skeletonSpec);
|
|
274
300
|
const category = (args.categories?.[0] ??
|
|
275
301
|
preset?.category ??
|
|
276
302
|
collection?.category) as ImageCategory | undefined;
|
|
277
|
-
const
|
|
303
|
+
const selectedModel = resolveImageModelForRequest({
|
|
278
304
|
explicitModel: args.model,
|
|
279
305
|
imageModelDefault,
|
|
280
306
|
explicitTier: args.tier,
|
|
@@ -283,9 +309,65 @@ export default defineAction({
|
|
|
283
309
|
presetModel: preset?.model as (typeof IMAGE_MODELS)[number] | undefined,
|
|
284
310
|
embeddedText: args.embeddedText,
|
|
285
311
|
}) as (typeof IMAGE_MODELS)[number];
|
|
312
|
+
if (
|
|
313
|
+
isSkeletonCutout &&
|
|
314
|
+
args.model &&
|
|
315
|
+
args.model !== "gpt-image-1" &&
|
|
316
|
+
args.model !== "gpt-image-2"
|
|
317
|
+
) {
|
|
318
|
+
throw new Error(
|
|
319
|
+
"Cutout skeleton presets require gpt-image-1 for transparent output or gpt-image-2 for mask inpainting. Remove the explicit model override or choose one of those models.",
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
const resolvedModel = (
|
|
323
|
+
isSkeletonCutout && selectedModel !== "gpt-image-2"
|
|
324
|
+
? "gpt-image-1"
|
|
325
|
+
: selectedModel
|
|
326
|
+
) as (typeof IMAGE_MODELS)[number];
|
|
327
|
+
if (isSkeletonCutout && selectedModel !== resolvedModel) {
|
|
328
|
+
logSkeletonGeneration("model_overridden", {
|
|
329
|
+
presetId: preset?.id,
|
|
330
|
+
selectedModel,
|
|
331
|
+
model: resolvedModel,
|
|
332
|
+
});
|
|
333
|
+
}
|
|
286
334
|
const resolvedCategories =
|
|
287
335
|
args.categories ??
|
|
288
336
|
(preset?.category ? ([preset.category] as any) : undefined);
|
|
337
|
+
const skeletonReferenceExclusionIds =
|
|
338
|
+
skeletonCompositeAssetIds(skeletonSpec);
|
|
339
|
+
const skeletonAssets = skeletonSpec
|
|
340
|
+
? await loadSkeletonAssets({
|
|
341
|
+
spec: skeletonSpec,
|
|
342
|
+
libraryId: args.libraryId,
|
|
343
|
+
canonicalLogoAssetId: library.canonicalLogoAssetId,
|
|
344
|
+
appendCanonicalLogo:
|
|
345
|
+
resolvedIncludeLogo &&
|
|
346
|
+
!(isSkeletonCutout && resolvedModel === "gpt-image-2"),
|
|
347
|
+
})
|
|
348
|
+
: null;
|
|
349
|
+
const useSkeletonInpaint =
|
|
350
|
+
isSkeletonCutout &&
|
|
351
|
+
Boolean(skeletonAssets?.backgroundAsset) &&
|
|
352
|
+
resolvedModel === "gpt-image-2";
|
|
353
|
+
const resolvedAspectRatio =
|
|
354
|
+
isSkeletonCutout && !useSkeletonInpaint
|
|
355
|
+
? clampCutoutAspectRatio({
|
|
356
|
+
aspectRatio: outputAspectRatio,
|
|
357
|
+
supported: supportedAspectRatiosForModel("gpt-image-1"),
|
|
358
|
+
})
|
|
359
|
+
: outputAspectRatio;
|
|
360
|
+
if (
|
|
361
|
+
isSkeletonCutout &&
|
|
362
|
+
!useSkeletonInpaint &&
|
|
363
|
+
outputAspectRatio !== resolvedAspectRatio
|
|
364
|
+
) {
|
|
365
|
+
logSkeletonGeneration("aspect_ratio_clamped", {
|
|
366
|
+
presetId: preset?.id,
|
|
367
|
+
outputAspectRatio,
|
|
368
|
+
subjectAspectRatio: resolvedAspectRatio,
|
|
369
|
+
});
|
|
370
|
+
}
|
|
289
371
|
const promptForRun = applyPromptTemplate(
|
|
290
372
|
preset?.promptTemplate,
|
|
291
373
|
args.prompt,
|
|
@@ -302,21 +384,37 @@ export default defineAction({
|
|
|
302
384
|
.filter(Boolean)
|
|
303
385
|
.join("\n")
|
|
304
386
|
: "";
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
intent: args.intent,
|
|
313
|
-
limit:
|
|
387
|
+
let references: ReferenceForGeneration[];
|
|
388
|
+
if (useSkeletonInpaint) {
|
|
389
|
+
references = await inpaintReferencesForSkeleton(skeletonAssets);
|
|
390
|
+
} else {
|
|
391
|
+
const backgroundPlateReference =
|
|
392
|
+
backgroundPlateReferenceForSkeleton(skeletonAssets);
|
|
393
|
+
const baseReferenceLimit =
|
|
314
394
|
args.intent !== "restyle" &&
|
|
315
395
|
preset?.referencePolicy === "explicit" &&
|
|
316
396
|
!args.referenceAssetIds?.length
|
|
317
397
|
? 0
|
|
318
|
-
: DEFAULT_GENERATION_REFERENCE_LIMIT
|
|
319
|
-
|
|
398
|
+
: DEFAULT_GENERATION_REFERENCE_LIMIT;
|
|
399
|
+
const referenceLimit =
|
|
400
|
+
backgroundPlateReference && baseReferenceLimit > 0
|
|
401
|
+
? baseReferenceLimit + 1
|
|
402
|
+
: baseReferenceLimit;
|
|
403
|
+
references = await selectReferences({
|
|
404
|
+
libraryId: args.libraryId,
|
|
405
|
+
collectionId: resolvedCollectionId,
|
|
406
|
+
categories: resolvedCategories,
|
|
407
|
+
referenceAssetIds: args.referenceAssetIds,
|
|
408
|
+
excludeAssetIds: skeletonReferenceExclusionIds,
|
|
409
|
+
sourceAssetId: args.sourceAssetId,
|
|
410
|
+
subjectAssetId: args.subjectAssetId,
|
|
411
|
+
intent: args.intent,
|
|
412
|
+
limit: referenceLimit,
|
|
413
|
+
});
|
|
414
|
+
if (backgroundPlateReference) {
|
|
415
|
+
references.unshift(backgroundPlateReference);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
320
418
|
const compiledPrompt = compilePrompt({
|
|
321
419
|
libraryTitle: library.title,
|
|
322
420
|
styleBrief,
|
|
@@ -328,6 +426,13 @@ export default defineAction({
|
|
|
328
426
|
textPlacement: args.textPlacement,
|
|
329
427
|
referenceCount: references.length,
|
|
330
428
|
includeLogo: resolvedIncludeLogo,
|
|
429
|
+
skeletonContentMode: skeletonSpec?.contentMode ?? null,
|
|
430
|
+
hasBackgroundPlate: Boolean(
|
|
431
|
+
isSkeletonCutout &&
|
|
432
|
+
!useSkeletonInpaint &&
|
|
433
|
+
skeletonAssets?.backgroundAsset,
|
|
434
|
+
),
|
|
435
|
+
skeletonInpaint: useSkeletonInpaint,
|
|
331
436
|
aspectRatio: resolvedAspectRatio,
|
|
332
437
|
imageSize: resolvedImageSize,
|
|
333
438
|
category,
|
|
@@ -371,6 +476,10 @@ export default defineAction({
|
|
|
371
476
|
imageSize: resolvedImageSize,
|
|
372
477
|
groundingMode: args.groundingMode,
|
|
373
478
|
includeLogo: resolvedIncludeLogo,
|
|
479
|
+
requestedIncludeLogo,
|
|
480
|
+
skeletonSpec: skeletonSpec ?? null,
|
|
481
|
+
outputAspectRatio,
|
|
482
|
+
subjectAspectRatio: resolvedAspectRatio,
|
|
374
483
|
categories: resolvedCategories ?? [],
|
|
375
484
|
collectionId: resolvedCollectionId ?? null,
|
|
376
485
|
presetId: preset?.id ?? null,
|
|
@@ -394,6 +503,10 @@ export default defineAction({
|
|
|
394
503
|
styleStrength: args.styleStrength,
|
|
395
504
|
tier: resolvedTier,
|
|
396
505
|
includeLogo: resolvedIncludeLogo,
|
|
506
|
+
requestedIncludeLogo,
|
|
507
|
+
skeletonSpec: skeletonSpec ?? null,
|
|
508
|
+
outputAspectRatio,
|
|
509
|
+
subjectAspectRatio: resolvedAspectRatio,
|
|
397
510
|
categories: resolvedCategories ?? [],
|
|
398
511
|
presetId: preset?.id,
|
|
399
512
|
sessionId: session?.id,
|
|
@@ -409,7 +522,7 @@ export default defineAction({
|
|
|
409
522
|
prompt: args.prompt,
|
|
410
523
|
compiledPrompt,
|
|
411
524
|
model: resolvedModel,
|
|
412
|
-
aspectRatio:
|
|
525
|
+
aspectRatio: outputAspectRatio,
|
|
413
526
|
imageSize: resolvedImageSize,
|
|
414
527
|
groundingMode: args.groundingMode,
|
|
415
528
|
referenceAssetIds: stringifyJson(references.map((ref) => ref.id)),
|
|
@@ -455,8 +568,13 @@ export default defineAction({
|
|
|
455
568
|
compiledPrompt,
|
|
456
569
|
references,
|
|
457
570
|
model: resolvedModel,
|
|
571
|
+
mode: useSkeletonInpaint ? "edit" : undefined,
|
|
458
572
|
aspectRatio: resolvedAspectRatio,
|
|
459
573
|
imageSize: resolvedImageSize,
|
|
574
|
+
background:
|
|
575
|
+
isSkeletonCutout && !useSkeletonInpaint
|
|
576
|
+
? "transparent"
|
|
577
|
+
: undefined,
|
|
460
578
|
groundingMode: args.groundingMode,
|
|
461
579
|
intent: args.intent,
|
|
462
580
|
styleStrength: args.styleStrength,
|
|
@@ -470,7 +588,17 @@ export default defineAction({
|
|
|
470
588
|
await deleteAppState("image-generation-setup").catch(() => {});
|
|
471
589
|
let image = generated.image;
|
|
472
590
|
let mimeType = generated.mimeType;
|
|
473
|
-
if (
|
|
591
|
+
if (skeletonAssets && !useSkeletonInpaint) {
|
|
592
|
+
image = await applyPresetSkeleton({
|
|
593
|
+
subject: image,
|
|
594
|
+
spec: skeletonAssets.spec,
|
|
595
|
+
canvasAspectRatio: outputAspectRatio,
|
|
596
|
+
backgroundAsset: skeletonAssets.backgroundAsset,
|
|
597
|
+
canonicalLogo: skeletonAssets.canonicalLogo,
|
|
598
|
+
foregroundAssets: skeletonAssets.foregroundAssets,
|
|
599
|
+
});
|
|
600
|
+
mimeType = "image/png";
|
|
601
|
+
} else if (resolvedIncludeLogo && library.canonicalLogoAssetId) {
|
|
474
602
|
const [logo] = await db
|
|
475
603
|
.select()
|
|
476
604
|
.from(schema.assets)
|
|
@@ -534,7 +662,7 @@ export default defineAction({
|
|
|
534
662
|
status: "candidate",
|
|
535
663
|
prompt: args.prompt,
|
|
536
664
|
model: generated.model,
|
|
537
|
-
aspectRatio:
|
|
665
|
+
aspectRatio: outputAspectRatio,
|
|
538
666
|
imageSize: resolvedImageSize,
|
|
539
667
|
generationRunId: runId,
|
|
540
668
|
metadata: {
|
|
@@ -547,6 +675,10 @@ export default defineAction({
|
|
|
547
675
|
styleStrength: args.styleStrength,
|
|
548
676
|
tier: resolvedTier,
|
|
549
677
|
includeLogo: resolvedIncludeLogo,
|
|
678
|
+
requestedIncludeLogo,
|
|
679
|
+
skeletonSpec: skeletonSpec ?? null,
|
|
680
|
+
outputAspectRatio,
|
|
681
|
+
subjectAspectRatio: resolvedAspectRatio,
|
|
550
682
|
presetId: preset?.id,
|
|
551
683
|
sessionId: session?.id,
|
|
552
684
|
generated: true,
|
|
@@ -592,6 +724,10 @@ export default defineAction({
|
|
|
592
724
|
styleStrength: args.styleStrength,
|
|
593
725
|
tier: resolvedTier,
|
|
594
726
|
includeLogo: resolvedIncludeLogo,
|
|
727
|
+
requestedIncludeLogo,
|
|
728
|
+
skeletonSpec: skeletonSpec ?? null,
|
|
729
|
+
outputAspectRatio,
|
|
730
|
+
subjectAspectRatio: resolvedAspectRatio,
|
|
595
731
|
categories: resolvedCategories ?? [],
|
|
596
732
|
referenceSelection,
|
|
597
733
|
settingsUsed,
|
|
@@ -667,3 +803,184 @@ export default defineAction({
|
|
|
667
803
|
}
|
|
668
804
|
},
|
|
669
805
|
});
|
|
806
|
+
|
|
807
|
+
function skeletonCompositeAssetIds(
|
|
808
|
+
spec: PresetSkeletonSpec | null,
|
|
809
|
+
): string[] | undefined {
|
|
810
|
+
if (!spec) return undefined;
|
|
811
|
+
const ids = new Set<string>();
|
|
812
|
+
if (spec.background.type === "asset") ids.add(spec.background.assetId);
|
|
813
|
+
if (spec.mask?.type === "asset") ids.add(spec.mask.assetId);
|
|
814
|
+
for (const layer of spec.foreground ?? []) {
|
|
815
|
+
if (layer.source !== "canonicalLogo") ids.add(layer.source.assetId);
|
|
816
|
+
}
|
|
817
|
+
return ids.size ? [...ids] : undefined;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
function backgroundPlateReferenceForSkeleton(
|
|
821
|
+
skeletonAssets: LoadedSkeletonAssets | null,
|
|
822
|
+
): ReferenceForGeneration | null {
|
|
823
|
+
if (
|
|
824
|
+
!skeletonAssets?.backgroundAsset ||
|
|
825
|
+
!skeletonAssets.backgroundAssetId ||
|
|
826
|
+
!skeletonAssets.backgroundMimeType
|
|
827
|
+
) {
|
|
828
|
+
return null;
|
|
829
|
+
}
|
|
830
|
+
return {
|
|
831
|
+
id: skeletonAssets.backgroundAssetId,
|
|
832
|
+
role: "background_reference",
|
|
833
|
+
category: "skeleton",
|
|
834
|
+
mimeType: skeletonAssets.backgroundMimeType,
|
|
835
|
+
data: skeletonAssets.backgroundAsset.toString("base64"),
|
|
836
|
+
selectionReason: "explicit",
|
|
837
|
+
};
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
async function inpaintReferencesForSkeleton(
|
|
841
|
+
skeletonAssets: LoadedSkeletonAssets | null,
|
|
842
|
+
): Promise<ReferenceForGeneration[]> {
|
|
843
|
+
if (
|
|
844
|
+
!skeletonAssets?.backgroundAsset ||
|
|
845
|
+
!skeletonAssets.backgroundAssetId ||
|
|
846
|
+
!skeletonAssets.backgroundMimeType
|
|
847
|
+
) {
|
|
848
|
+
throw new Error("Skeleton inpainting requires a background plate image.");
|
|
849
|
+
}
|
|
850
|
+
const mask = skeletonAssets.maskAsset
|
|
851
|
+
? await maskFromManualMaskAlpha({
|
|
852
|
+
mask: skeletonAssets.maskAsset,
|
|
853
|
+
plate: skeletonAssets.backgroundAsset,
|
|
854
|
+
})
|
|
855
|
+
: await maskFromPlateAlpha(skeletonAssets.backgroundAsset);
|
|
856
|
+
return [
|
|
857
|
+
{
|
|
858
|
+
id: skeletonAssets.backgroundAssetId,
|
|
859
|
+
role: "edit_target",
|
|
860
|
+
category: "skeleton",
|
|
861
|
+
mimeType: skeletonAssets.backgroundMimeType,
|
|
862
|
+
data: skeletonAssets.backgroundAsset.toString("base64"),
|
|
863
|
+
selectionReason: "explicit",
|
|
864
|
+
},
|
|
865
|
+
{
|
|
866
|
+
id:
|
|
867
|
+
skeletonAssets.maskAssetId ??
|
|
868
|
+
`${skeletonAssets.backgroundAssetId}:mask`,
|
|
869
|
+
role: "mask",
|
|
870
|
+
category: "skeleton",
|
|
871
|
+
mimeType: "image/png",
|
|
872
|
+
data: mask.toString("base64"),
|
|
873
|
+
selectionReason: "explicit",
|
|
874
|
+
},
|
|
875
|
+
];
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
type LoadedSkeletonAssets = {
|
|
879
|
+
spec: PresetSkeletonSpec;
|
|
880
|
+
backgroundAssetId?: string;
|
|
881
|
+
backgroundMimeType?: string;
|
|
882
|
+
backgroundAsset?: Buffer;
|
|
883
|
+
maskAssetId?: string;
|
|
884
|
+
maskAsset?: Buffer;
|
|
885
|
+
canonicalLogo?: Buffer;
|
|
886
|
+
foregroundAssets: Record<string, Buffer>;
|
|
887
|
+
};
|
|
888
|
+
|
|
889
|
+
async function loadSkeletonAssets(input: {
|
|
890
|
+
spec: PresetSkeletonSpec;
|
|
891
|
+
libraryId: string;
|
|
892
|
+
canonicalLogoAssetId?: string | null;
|
|
893
|
+
appendCanonicalLogo: boolean;
|
|
894
|
+
}): Promise<LoadedSkeletonAssets> {
|
|
895
|
+
const db = getDb();
|
|
896
|
+
const spec = appendCanonicalLogoToSkeleton(
|
|
897
|
+
input.spec,
|
|
898
|
+
input.appendCanonicalLogo,
|
|
899
|
+
);
|
|
900
|
+
const assetIds = new Set<string>();
|
|
901
|
+
if (spec.background.type === "asset") assetIds.add(spec.background.assetId);
|
|
902
|
+
if (spec.mask?.type === "asset") assetIds.add(spec.mask.assetId);
|
|
903
|
+
for (const layer of spec.foreground ?? []) {
|
|
904
|
+
if (layer.source !== "canonicalLogo") assetIds.add(layer.source.assetId);
|
|
905
|
+
}
|
|
906
|
+
if (input.canonicalLogoAssetId) assetIds.add(input.canonicalLogoAssetId);
|
|
907
|
+
|
|
908
|
+
const buffers = new Map<string, Buffer>();
|
|
909
|
+
const mimeTypes = new Map<string, string>();
|
|
910
|
+
for (const assetId of assetIds) {
|
|
911
|
+
const [asset] = await db
|
|
912
|
+
.select()
|
|
913
|
+
.from(schema.assets)
|
|
914
|
+
.where(eq(schema.assets.id, assetId))
|
|
915
|
+
.limit(1);
|
|
916
|
+
if (!asset) {
|
|
917
|
+
if (assetId === input.canonicalLogoAssetId) continue;
|
|
918
|
+
throw new Error("Skeleton asset not found.");
|
|
919
|
+
}
|
|
920
|
+
if (asset.libraryId !== input.libraryId) {
|
|
921
|
+
throw new Error("Skeleton assets must belong to the selected brand kit.");
|
|
922
|
+
}
|
|
923
|
+
if (!asset.mimeType.startsWith("image/")) {
|
|
924
|
+
throw new Error("Skeleton assets must be images.");
|
|
925
|
+
}
|
|
926
|
+
buffers.set(assetId, await getObject(asset.objectKey));
|
|
927
|
+
mimeTypes.set(assetId, asset.mimeType);
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
const foregroundAssets: Record<string, Buffer> = {};
|
|
931
|
+
for (const layer of spec.foreground ?? []) {
|
|
932
|
+
if (layer.source !== "canonicalLogo") {
|
|
933
|
+
const buffer = buffers.get(layer.source.assetId);
|
|
934
|
+
if (buffer) foregroundAssets[layer.source.assetId] = buffer;
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
return {
|
|
939
|
+
spec,
|
|
940
|
+
backgroundAssetId:
|
|
941
|
+
spec.background.type === "asset" ? spec.background.assetId : undefined,
|
|
942
|
+
backgroundMimeType:
|
|
943
|
+
spec.background.type === "asset"
|
|
944
|
+
? mimeTypes.get(spec.background.assetId)
|
|
945
|
+
: undefined,
|
|
946
|
+
backgroundAsset:
|
|
947
|
+
spec.background.type === "asset"
|
|
948
|
+
? buffers.get(spec.background.assetId)
|
|
949
|
+
: undefined,
|
|
950
|
+
maskAssetId: spec.mask?.type === "asset" ? spec.mask.assetId : undefined,
|
|
951
|
+
maskAsset:
|
|
952
|
+
spec.mask?.type === "asset" ? buffers.get(spec.mask.assetId) : undefined,
|
|
953
|
+
canonicalLogo: input.canonicalLogoAssetId
|
|
954
|
+
? buffers.get(input.canonicalLogoAssetId)
|
|
955
|
+
: undefined,
|
|
956
|
+
foregroundAssets,
|
|
957
|
+
};
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
function appendCanonicalLogoToSkeleton(
|
|
961
|
+
spec: PresetSkeletonSpec,
|
|
962
|
+
appendCanonicalLogo: boolean,
|
|
963
|
+
): PresetSkeletonSpec {
|
|
964
|
+
if (!appendCanonicalLogo || skeletonUsesCanonicalLogo(spec)) return spec;
|
|
965
|
+
return {
|
|
966
|
+
...spec,
|
|
967
|
+
foreground: [
|
|
968
|
+
...(spec.foreground ?? []),
|
|
969
|
+
{ source: "canonicalLogo", x: 0.805, y: 0.06, w: 0.16 },
|
|
970
|
+
],
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
function logSkeletonGeneration(
|
|
975
|
+
event: string,
|
|
976
|
+
fields: Record<string, unknown>,
|
|
977
|
+
): void {
|
|
978
|
+
if (process.env.NODE_ENV === "test") return;
|
|
979
|
+
const detail = Object.entries(fields)
|
|
980
|
+
.filter(([, value]) => value !== undefined)
|
|
981
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
982
|
+
.join(" ");
|
|
983
|
+
console.info(
|
|
984
|
+
`[assets] preset-skeleton ${event}${detail ? ` ${detail}` : ""}`,
|
|
985
|
+
);
|
|
986
|
+
}
|
|
@@ -4,7 +4,7 @@ import { z } from "zod";
|
|
|
4
4
|
|
|
5
5
|
import { getDb, schema } from "../server/db/index.js";
|
|
6
6
|
import {
|
|
7
|
-
|
|
7
|
+
requireLibraryAccess,
|
|
8
8
|
serializeAssets,
|
|
9
9
|
serializeGenerationRun,
|
|
10
10
|
serializeLibrary,
|
|
@@ -19,7 +19,8 @@ export default defineAction({
|
|
|
19
19
|
http: { method: "GET" },
|
|
20
20
|
readOnly: true,
|
|
21
21
|
run: async ({ id }, ctx) => {
|
|
22
|
-
const
|
|
22
|
+
const access = await requireLibraryAccess(id, ctx);
|
|
23
|
+
const library = access.resource;
|
|
23
24
|
const db = getDb();
|
|
24
25
|
const [collections, folders, assets, runs] = await Promise.all([
|
|
25
26
|
db
|
|
@@ -42,7 +43,7 @@ export default defineAction({
|
|
|
42
43
|
.orderBy(desc(schema.assetGenerationRuns.createdAt)),
|
|
43
44
|
]);
|
|
44
45
|
return {
|
|
45
|
-
library: serializeLibrary(library),
|
|
46
|
+
library: serializeLibrary({ ...library, accessRole: access.role }),
|
|
46
47
|
collections,
|
|
47
48
|
folders,
|
|
48
49
|
assets: serializeAssets(assets),
|
|
@@ -4,7 +4,7 @@ import { z } from "zod";
|
|
|
4
4
|
|
|
5
5
|
export default defineAction({
|
|
6
6
|
description:
|
|
7
|
-
"Navigate the Assets UI. Views (internal keys, with the surface they open): create, picker (the embedded image Library picker), libraries (the unified Library workspace), library (a single Brand Kit inside Library), asset, generation-session, generation-run, extensions, audit, settings. Use threadId to open a specific create/chat thread; use libraryId, assetId, sessionId, runId, or extensionId where appropriate.",
|
|
7
|
+
"Navigate the Assets UI. Views (internal keys, with the surface they open): create, picker (the embedded image Library picker), libraries (the unified Library workspace), library (a single Brand Kit inside Library), preset (a generation preset editor), asset, generation-session, generation-run, extensions, audit, settings. Use threadId to open a specific create/chat thread; use libraryId, presetId, assetId, sessionId, runId, or extensionId where appropriate.",
|
|
8
8
|
schema: z.object({
|
|
9
9
|
view: z
|
|
10
10
|
.enum([
|
|
@@ -12,6 +12,7 @@ export default defineAction({
|
|
|
12
12
|
"picker",
|
|
13
13
|
"libraries",
|
|
14
14
|
"library",
|
|
15
|
+
"preset",
|
|
15
16
|
"asset",
|
|
16
17
|
"image",
|
|
17
18
|
"generation-session",
|