@orangecatai/adgen-canvas 0.0.30 → 0.0.32
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/dist/dev/{chunk-X6KPARLJ.js → chunk-OWDDSUUQ.js} +3 -3
- package/dist/dev/{chunk-2WAJTVZS.js → chunk-VL47Q2RH.js} +2 -2
- package/dist/dev/data/{image-HGVO7LLH.js → image-5Y3GORNT.js} +3 -3
- package/dist/dev/index.css +118 -1
- package/dist/dev/index.css.map +3 -3
- package/dist/dev/index.js +3633 -2579
- package/dist/dev/index.js.map +4 -4
- package/dist/dev/subset-shared.chunk.js +1 -1
- package/dist/dev/subset-worker.chunk.js +1 -1
- package/dist/prod/{chunk-SZMIDXG6.js → chunk-452N23ZE.js} +1 -1
- package/dist/prod/{chunk-GTYNSLQE.js → chunk-AQSA3HNR.js} +2 -2
- package/dist/prod/data/image-5D6ZUEOG.js +1 -0
- package/dist/prod/index.css +1 -1
- package/dist/prod/index.js +112 -94
- package/dist/prod/subset-shared.chunk.js +1 -1
- package/dist/prod/subset-worker.chunk.js +1 -1
- package/dist/types/excalidraw/components/AIChatPanel.d.ts +13 -3
- package/dist/types/excalidraw/components/App.d.ts +8 -0
- package/dist/types/excalidraw/components/ChipSourceMenu.d.ts +14 -0
- package/dist/types/excalidraw/components/ElementPickHighlight.d.ts +8 -0
- package/dist/types/excalidraw/components/ai-chat/agentLoop.d.ts +18 -1
- package/dist/types/excalidraw/components/ai-chat/canvasTools.d.ts +113 -9
- package/dist/types/excalidraw/components/ai-chat/reviewerAgent.d.ts +7 -1
- package/dist/types/excalidraw/components/auto-resize/autoResizeEngine.d.ts +6 -0
- package/dist/types/excalidraw/components/elementPicker.d.ts +33 -0
- package/dist/types/excalidraw/components/frameToolbarVariant.d.ts +14 -1
- package/dist/types/excalidraw/components/useCanvasFramePicker.d.ts +28 -0
- package/dist/types/excalidraw/types.d.ts +3 -2
- package/dist/types/excalidraw/utils/brandContextUtils.d.ts +16 -3
- package/dist/types/excalidraw/utils/imageApi.d.ts +41 -1
- package/dist/types/excalidraw/utils/videoFrameSource.d.ts +17 -0
- package/dist/types/excalidraw/utils/videoStitch.d.ts +7 -7
- package/package.json +1 -1
- package/dist/prod/data/image-B2RV64CG.js +0 -1
- /package/dist/dev/{chunk-X6KPARLJ.js.map → chunk-OWDDSUUQ.js.map} +0 -0
- /package/dist/dev/{chunk-2WAJTVZS.js.map → chunk-VL47Q2RH.js.map} +0 -0
- /package/dist/dev/data/{image-HGVO7LLH.js.map → image-5Y3GORNT.js.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a,b,c,d}from"./chunk-Z5NKEFVG.js";import"./chunk-
|
|
1
|
+
import{a,b,c,d}from"./chunk-Z5NKEFVG.js";import"./chunk-452N23ZE.js";import"./chunk-SRAX5OIU.js";export{a as Commands,b as subsetToBase64,c as subsetToBinary,d as toBase64};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as r,c as t}from"./chunk-Z5NKEFVG.js";import"./chunk-
|
|
1
|
+
import{a as r,c as t}from"./chunk-Z5NKEFVG.js";import"./chunk-452N23ZE.js";import"./chunk-SRAX5OIU.js";var s=import.meta.url?new URL(import.meta.url):void 0;typeof window>"u"&&typeof self<"u"&&(self.onmessage=async e=>{switch(e.data.command){case r.Subset:let a=await t(e.data.arrayBuffer,e.data.codePoints);self.postMessage(a,{transfer:[a]});break}});export{s as WorkerUrl};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { type ToolAction } from "./ai-chat/agentLoop";
|
|
2
|
+
import { type ToolAction, type FrameGenerationMeta } from "./ai-chat/agentLoop";
|
|
3
3
|
import "./AIChatPanel.scss";
|
|
4
4
|
import type { ReviewerFeedback } from "./ai-chat/reviewerAgent";
|
|
5
5
|
import type { ExcalidrawImperativeAPI } from "../types";
|
|
@@ -18,6 +18,16 @@ export type ChatMessage = {
|
|
|
18
18
|
}>;
|
|
19
19
|
/** Reviewer feedback attached to an assistant message after HTML ad generation */
|
|
20
20
|
reviewFeedback?: ReviewerFeedback;
|
|
21
|
+
/**
|
|
22
|
+
* Set on an assistant message that generated/regenerated an image for a
|
|
23
|
+
* frame. Persisted so that on reload / session switch,
|
|
24
|
+
* resetAndSeedFrameGenerationMemory can rebuild canvasTools' in-memory
|
|
25
|
+
* frame-continuity state (original prompt anchor, reference-image reuse,
|
|
26
|
+
* "frames generated in this conversation" list) from chat history — none
|
|
27
|
+
* of that survives a reload on its own since it lives in a JS module, not
|
|
28
|
+
* the DB. See FrameGenerationMeta in agentLoop.ts.
|
|
29
|
+
*/
|
|
30
|
+
generatedFrame?: FrameGenerationMeta;
|
|
21
31
|
};
|
|
22
32
|
export type ChatSession = {
|
|
23
33
|
id: string;
|
|
@@ -121,8 +131,8 @@ export type AIChatPanelProps = {
|
|
|
121
131
|
transcribeUrl?: string;
|
|
122
132
|
/**
|
|
123
133
|
* OpenRouter model ID used by the agent's generate_image tool.
|
|
124
|
-
* @default "
|
|
125
|
-
* @example "google/gemini-
|
|
134
|
+
* @default "openai/gpt-image-2"
|
|
135
|
+
* @example "google/gemini-3.1-flash-image-preview"
|
|
126
136
|
*/
|
|
127
137
|
agentImageModel?: string;
|
|
128
138
|
/**
|
|
@@ -11,6 +11,7 @@ import { LaserTrails } from "../laser-trails";
|
|
|
11
11
|
import { isOverScrollBars } from "../scene/scrollbars";
|
|
12
12
|
import { LassoTrail } from "../lasso";
|
|
13
13
|
import { EraserTrail } from "../eraser";
|
|
14
|
+
import { type ElementPickerState } from "./elementPicker";
|
|
14
15
|
import type { ExcalidrawElement, NonDeleted, ExcalidrawImageElement, NonDeletedExcalidrawElement, ExcalidrawFrameLikeElement, ExcalidrawIframeElement, ExcalidrawEmbeddableElement, Ordered, SceneElementsMap } from "@orangecatai/element/types";
|
|
15
16
|
import type { Mutable } from "@orangecatai/common/utility-types";
|
|
16
17
|
import type { ExportedElements } from "../data";
|
|
@@ -239,6 +240,13 @@ declare class App extends React.Component<AppProps, AppState> {
|
|
|
239
240
|
missingPointerEventCleanupEmitter: Emitter<[event: PointerEvent | null]>;
|
|
240
241
|
onRemoveEventListenersEmitter: Emitter<[]>;
|
|
241
242
|
constructor(props: AppProps);
|
|
243
|
+
/**
|
|
244
|
+
* Arms (or disarms) canvas element picking. While armed, the next canvas
|
|
245
|
+
* pointer-down resolves the element under the cursor instead of changing
|
|
246
|
+
* selection — see `handleCanvasPointerDown` and `elementPicker.ts` for why
|
|
247
|
+
* selection must not move.
|
|
248
|
+
*/
|
|
249
|
+
setElementPicker: (picker: ElementPickerState | null) => void;
|
|
242
250
|
updateEditorAtom: <Value, Args extends unknown[], Result>(atom: WritableAtom<Value, Args, Result>, ...args: Args) => Result;
|
|
243
251
|
private onWindowMessage;
|
|
244
252
|
private handleSkipBindMode;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import "./ChipSourceMenu.scss";
|
|
3
|
+
export declare const ChipSourceMenu: React.FC<{
|
|
4
|
+
onUpload: () => void;
|
|
5
|
+
onPickFromCanvas: () => void;
|
|
6
|
+
onClose: () => void;
|
|
7
|
+
/** Label for the canvas option — videos are not always eligible. */
|
|
8
|
+
pickLabel?: string;
|
|
9
|
+
}>;
|
|
10
|
+
/** Asks which frame of a picked video should fill the chip. */
|
|
11
|
+
export declare const VideoFrameChoiceMenu: React.FC<{
|
|
12
|
+
onChoose: (which: "first" | "last") => void;
|
|
13
|
+
onCancel: () => void;
|
|
14
|
+
}>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import "./ElementPickHighlight.scss";
|
|
3
|
+
import type { ExcalidrawElement } from "@orangecatai/element/types";
|
|
4
|
+
import type { AppState } from "../types";
|
|
5
|
+
export declare const ElementPickHighlight: React.FC<{
|
|
6
|
+
element: ExcalidrawElement | null;
|
|
7
|
+
appState: AppState;
|
|
8
|
+
}>;
|
|
@@ -56,9 +56,26 @@ export type AgentUpdate = {
|
|
|
56
56
|
message: string;
|
|
57
57
|
feedback: import("./reviewerAgent").ReviewerFeedback;
|
|
58
58
|
};
|
|
59
|
+
/**
|
|
60
|
+
* Metadata about a frame this turn generated an image for. The caller
|
|
61
|
+
* (AIChatPanel) attaches this to the persisted assistant ChatMessage so that
|
|
62
|
+
* on a later page load / session switch, canvasTools' in-memory
|
|
63
|
+
* frameGenerationMemory / chatCreatedFrames (which otherwise reset with the
|
|
64
|
+
* page) can be reconstructed from chat history via
|
|
65
|
+
* resetAndSeedFrameGenerationMemory — without this, "fix the previous image"
|
|
66
|
+
* only works within the same unreloaded tab, which defeats the point.
|
|
67
|
+
*/
|
|
68
|
+
export type FrameGenerationMeta = {
|
|
69
|
+
frameId: string;
|
|
70
|
+
prompt: string;
|
|
71
|
+
referenceImageIndex?: number;
|
|
72
|
+
userBrief: string;
|
|
73
|
+
};
|
|
59
74
|
export type AgentResult = {
|
|
60
75
|
reply: string;
|
|
61
76
|
toolActions: ToolAction[];
|
|
77
|
+
/** Set when this turn generated (or regenerated) an image for a frame. */
|
|
78
|
+
frameGeneration?: FrameGenerationMeta;
|
|
62
79
|
};
|
|
63
80
|
export type FileAttachment = {
|
|
64
81
|
name: string;
|
|
@@ -107,7 +124,7 @@ export declare function runAgentLoop(opts: {
|
|
|
107
124
|
* Maximum number of reviewer rounds per banner.
|
|
108
125
|
* After this many rounds the reviewer is skipped and the outer MAX_ITERATIONS
|
|
109
126
|
* cap handles loop termination.
|
|
110
|
-
* @default
|
|
127
|
+
* @default 1
|
|
111
128
|
*/
|
|
112
129
|
maxReviewRounds?: number;
|
|
113
130
|
}): Promise<AgentResult>;
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import type { ExcalidrawElement } from "@orangecatai/element/types";
|
|
2
2
|
import type { ExcalidrawImperativeAPI, BrandContext } from "../../types";
|
|
3
|
+
/**
|
|
4
|
+
* Image model the chat agent's `generate_image` tool falls back to when the host
|
|
5
|
+
* does not pass `agentImageModel`. Hosts should pass the prop — this only keeps
|
|
6
|
+
* the SDK usable standalone.
|
|
7
|
+
*/
|
|
8
|
+
export declare const DEFAULT_AGENT_IMAGE_MODEL = "openai/gpt-image-2";
|
|
3
9
|
/** The only video model the chat agent can drive. */
|
|
4
10
|
export declare const CHAT_VIDEO_MODEL = "google/veo-3.1-fast";
|
|
5
11
|
export declare const VIDEO_TOOLS: ({
|
|
@@ -12,11 +18,21 @@ export declare const VIDEO_TOOLS: ({
|
|
|
12
18
|
properties: {
|
|
13
19
|
first_frame_element_id: {
|
|
14
20
|
readonly type: "string";
|
|
15
|
-
readonly description: "ID of an existing IMAGE element already on the canvas to use as the video's opening frame (image-to-video). Use this to animate an image the user can see on the canvas.";
|
|
21
|
+
readonly description: "ID of an existing IMAGE or VIDEO element already on the canvas to use as the video's opening frame (image-to-video). Use this to animate an image the user can see on the canvas, or to continue from an existing clip. When it names a video, first_frame_which selects which frame of that clip is taken.";
|
|
22
|
+
};
|
|
23
|
+
first_frame_which: {
|
|
24
|
+
readonly type: "string";
|
|
25
|
+
readonly enum: readonly ["first", "last"];
|
|
26
|
+
readonly description: "Only meaningful when first_frame_element_id names a VIDEO. Which frame of that clip to use. Defaults to 'last', which is what continuing a clip needs.";
|
|
16
27
|
};
|
|
17
28
|
last_frame_element_id: {
|
|
18
29
|
readonly type: "string";
|
|
19
|
-
readonly description: "ID of an existing IMAGE element on the canvas to use as the video's closing frame. Optional.";
|
|
30
|
+
readonly description: "ID of an existing IMAGE or VIDEO element on the canvas to use as the video's closing frame. Optional.";
|
|
31
|
+
};
|
|
32
|
+
last_frame_which: {
|
|
33
|
+
readonly type: "string";
|
|
34
|
+
readonly enum: readonly ["first", "last"];
|
|
35
|
+
readonly description: "Only meaningful when last_frame_element_id names a VIDEO. Which frame of that clip to use. Defaults to 'last'.";
|
|
20
36
|
};
|
|
21
37
|
first_frame_attachment_index: {
|
|
22
38
|
readonly type: "number";
|
|
@@ -68,7 +84,12 @@ export declare const VIDEO_TOOLS: ({
|
|
|
68
84
|
};
|
|
69
85
|
first_frame_element_id: {
|
|
70
86
|
readonly type: "string";
|
|
71
|
-
readonly description: "ID of an existing IMAGE element already on the canvas to use as the video's opening frame (image-to-video). Use this to animate an image the user can see on the canvas.";
|
|
87
|
+
readonly description: "ID of an existing IMAGE or VIDEO element already on the canvas to use as the video's opening frame (image-to-video). Use this to animate an image the user can see on the canvas, or to continue from an existing clip. When it names a video, first_frame_which selects which frame of that clip is taken.";
|
|
88
|
+
};
|
|
89
|
+
first_frame_which: {
|
|
90
|
+
readonly type: "string";
|
|
91
|
+
readonly enum: readonly ["first", "last"];
|
|
92
|
+
readonly description: "Only meaningful when first_frame_element_id names a VIDEO. Which frame of that clip to use. Defaults to 'last', which is what continuing a clip needs.";
|
|
72
93
|
};
|
|
73
94
|
first_frame_attachment_index: {
|
|
74
95
|
readonly type: "number";
|
|
@@ -257,11 +278,21 @@ export declare const CANVAS_TOOLS: readonly [{
|
|
|
257
278
|
properties: {
|
|
258
279
|
first_frame_element_id: {
|
|
259
280
|
readonly type: "string";
|
|
260
|
-
readonly description: "ID of an existing IMAGE element already on the canvas to use as the video's opening frame (image-to-video). Use this to animate an image the user can see on the canvas.";
|
|
281
|
+
readonly description: "ID of an existing IMAGE or VIDEO element already on the canvas to use as the video's opening frame (image-to-video). Use this to animate an image the user can see on the canvas, or to continue from an existing clip. When it names a video, first_frame_which selects which frame of that clip is taken.";
|
|
282
|
+
};
|
|
283
|
+
first_frame_which: {
|
|
284
|
+
readonly type: "string";
|
|
285
|
+
readonly enum: readonly ["first", "last"];
|
|
286
|
+
readonly description: "Only meaningful when first_frame_element_id names a VIDEO. Which frame of that clip to use. Defaults to 'last', which is what continuing a clip needs.";
|
|
261
287
|
};
|
|
262
288
|
last_frame_element_id: {
|
|
263
289
|
readonly type: "string";
|
|
264
|
-
readonly description: "ID of an existing IMAGE element on the canvas to use as the video's closing frame. Optional.";
|
|
290
|
+
readonly description: "ID of an existing IMAGE or VIDEO element on the canvas to use as the video's closing frame. Optional.";
|
|
291
|
+
};
|
|
292
|
+
last_frame_which: {
|
|
293
|
+
readonly type: "string";
|
|
294
|
+
readonly enum: readonly ["first", "last"];
|
|
295
|
+
readonly description: "Only meaningful when last_frame_element_id names a VIDEO. Which frame of that clip to use. Defaults to 'last'.";
|
|
265
296
|
};
|
|
266
297
|
first_frame_attachment_index: {
|
|
267
298
|
readonly type: "number";
|
|
@@ -313,7 +344,12 @@ export declare const CANVAS_TOOLS: readonly [{
|
|
|
313
344
|
};
|
|
314
345
|
first_frame_element_id: {
|
|
315
346
|
readonly type: "string";
|
|
316
|
-
readonly description: "ID of an existing IMAGE element already on the canvas to use as the video's opening frame (image-to-video). Use this to animate an image the user can see on the canvas.";
|
|
347
|
+
readonly description: "ID of an existing IMAGE or VIDEO element already on the canvas to use as the video's opening frame (image-to-video). Use this to animate an image the user can see on the canvas, or to continue from an existing clip. When it names a video, first_frame_which selects which frame of that clip is taken.";
|
|
348
|
+
};
|
|
349
|
+
first_frame_which: {
|
|
350
|
+
readonly type: "string";
|
|
351
|
+
readonly enum: readonly ["first", "last"];
|
|
352
|
+
readonly description: "Only meaningful when first_frame_element_id names a VIDEO. Which frame of that clip to use. Defaults to 'last', which is what continuing a clip needs.";
|
|
317
353
|
};
|
|
318
354
|
first_frame_attachment_index: {
|
|
319
355
|
readonly type: "number";
|
|
@@ -435,11 +471,21 @@ export declare const BANNER_TOOLS: readonly [...({
|
|
|
435
471
|
properties: {
|
|
436
472
|
first_frame_element_id: {
|
|
437
473
|
readonly type: "string";
|
|
438
|
-
readonly description: "ID of an existing IMAGE element already on the canvas to use as the video's opening frame (image-to-video). Use this to animate an image the user can see on the canvas.";
|
|
474
|
+
readonly description: "ID of an existing IMAGE or VIDEO element already on the canvas to use as the video's opening frame (image-to-video). Use this to animate an image the user can see on the canvas, or to continue from an existing clip. When it names a video, first_frame_which selects which frame of that clip is taken.";
|
|
475
|
+
};
|
|
476
|
+
first_frame_which: {
|
|
477
|
+
readonly type: "string";
|
|
478
|
+
readonly enum: readonly ["first", "last"];
|
|
479
|
+
readonly description: "Only meaningful when first_frame_element_id names a VIDEO. Which frame of that clip to use. Defaults to 'last', which is what continuing a clip needs.";
|
|
439
480
|
};
|
|
440
481
|
last_frame_element_id: {
|
|
441
482
|
readonly type: "string";
|
|
442
|
-
readonly description: "ID of an existing IMAGE element on the canvas to use as the video's closing frame. Optional.";
|
|
483
|
+
readonly description: "ID of an existing IMAGE or VIDEO element on the canvas to use as the video's closing frame. Optional.";
|
|
484
|
+
};
|
|
485
|
+
last_frame_which: {
|
|
486
|
+
readonly type: "string";
|
|
487
|
+
readonly enum: readonly ["first", "last"];
|
|
488
|
+
readonly description: "Only meaningful when last_frame_element_id names a VIDEO. Which frame of that clip to use. Defaults to 'last'.";
|
|
443
489
|
};
|
|
444
490
|
first_frame_attachment_index: {
|
|
445
491
|
readonly type: "number";
|
|
@@ -491,7 +537,12 @@ export declare const BANNER_TOOLS: readonly [...({
|
|
|
491
537
|
};
|
|
492
538
|
first_frame_element_id: {
|
|
493
539
|
readonly type: "string";
|
|
494
|
-
readonly description: "ID of an existing IMAGE element already on the canvas to use as the video's opening frame (image-to-video). Use this to animate an image the user can see on the canvas.";
|
|
540
|
+
readonly description: "ID of an existing IMAGE or VIDEO element already on the canvas to use as the video's opening frame (image-to-video). Use this to animate an image the user can see on the canvas, or to continue from an existing clip. When it names a video, first_frame_which selects which frame of that clip is taken.";
|
|
541
|
+
};
|
|
542
|
+
first_frame_which: {
|
|
543
|
+
readonly type: "string";
|
|
544
|
+
readonly enum: readonly ["first", "last"];
|
|
545
|
+
readonly description: "Only meaningful when first_frame_element_id names a VIDEO. Which frame of that clip to use. Defaults to 'last', which is what continuing a clip needs.";
|
|
495
546
|
};
|
|
496
547
|
first_frame_attachment_index: {
|
|
497
548
|
readonly type: "number";
|
|
@@ -1011,6 +1062,18 @@ export type ToolExecutionContext = {
|
|
|
1011
1062
|
* failure mode for private Vercel Blob URLs.
|
|
1012
1063
|
*/
|
|
1013
1064
|
_templateJsonCache?: Map<string, string>;
|
|
1065
|
+
/**
|
|
1066
|
+
* The user's own first message, verbatim (not the LLM's paraphrase of it).
|
|
1067
|
+
* generate_image's `prompt` argument is always authored fresh by the chat
|
|
1068
|
+
* model — nothing forces it to preserve specific subject/scene/action
|
|
1069
|
+
* details the user actually typed (only on-image copy is instructed to be
|
|
1070
|
+
* verbatim). execGenerateImage appends this raw text to every image-gen
|
|
1071
|
+
* call for a frame as a fidelity backstop, so a model that quietly drops or
|
|
1072
|
+
* substitutes a described detail (e.g. "boy playing guitar" -> "boy
|
|
1073
|
+
* walking") doesn't silently ship — the image model sees the user's exact
|
|
1074
|
+
* words either way.
|
|
1075
|
+
*/
|
|
1076
|
+
originalUserBrief?: string;
|
|
1014
1077
|
};
|
|
1015
1078
|
export type ToolResult = {
|
|
1016
1079
|
success: boolean;
|
|
@@ -1019,3 +1082,44 @@ export type ToolResult = {
|
|
|
1019
1082
|
statusMessage: string;
|
|
1020
1083
|
};
|
|
1021
1084
|
export declare function executeCanvasTool(toolName: string, rawArgs: string, ctx: ToolExecutionContext): Promise<ToolResult>;
|
|
1085
|
+
/**
|
|
1086
|
+
* Renders `chatCreatedFrames` as a system-message string for injection into
|
|
1087
|
+
* the agent loop, or "" if this session hasn't generated anything yet (in
|
|
1088
|
+
* which case the caller should skip adding a message at all).
|
|
1089
|
+
*/
|
|
1090
|
+
export declare function getChatCreatedFramesContext(): string;
|
|
1091
|
+
/**
|
|
1092
|
+
* Rebuilds `frameGenerationMemory` and `chatCreatedFrames` from persisted
|
|
1093
|
+
* chat history (the assistant messages' `generatedFrame` metadata — see
|
|
1094
|
+
* `FrameGenerationMeta` in agentLoop.ts). Both are in-memory module state
|
|
1095
|
+
* that would otherwise be empty after a page reload or a chat-session
|
|
1096
|
+
* switch, silently breaking "fix the previous image" the moment the tab
|
|
1097
|
+
* isn't the one that generated it. Call this whenever chat history is
|
|
1098
|
+
* (re)loaded — on mount and on every session switch — BEFORE the next
|
|
1099
|
+
* message is sent.
|
|
1100
|
+
*
|
|
1101
|
+
* Always clears first: this also fixes the memory leaking across sessions —
|
|
1102
|
+
* without a reset, switching to a different chat would keep the previous
|
|
1103
|
+
* session's frames in the "generated in this conversation" list.
|
|
1104
|
+
*
|
|
1105
|
+
* Takes a loosely-typed array (not the SDK's `ChatMessage[]`) to avoid a
|
|
1106
|
+
* circular import — `AIChatPanel.tsx` imports FROM this file already.
|
|
1107
|
+
*/
|
|
1108
|
+
export declare function resetAndSeedFrameGenerationMemory(messages: Array<{
|
|
1109
|
+
generatedFrame?: {
|
|
1110
|
+
frameId: string;
|
|
1111
|
+
prompt: string;
|
|
1112
|
+
referenceImageIndex?: number;
|
|
1113
|
+
userBrief: string;
|
|
1114
|
+
};
|
|
1115
|
+
}>): void;
|
|
1116
|
+
/**
|
|
1117
|
+
* Fits a generated image to its frame, returning the size to place it at and
|
|
1118
|
+
* its offset from the frame's top-left corner.
|
|
1119
|
+
*/
|
|
1120
|
+
export declare function fitGeneratedImageToFrame(actualW: number, actualH: number, frameW: number, frameH: number): {
|
|
1121
|
+
width: number;
|
|
1122
|
+
height: number;
|
|
1123
|
+
offsetX: number;
|
|
1124
|
+
offsetY: number;
|
|
1125
|
+
};
|
|
@@ -62,7 +62,13 @@ export declare function runReviewerAgent(opts: {
|
|
|
62
62
|
width: number;
|
|
63
63
|
height: number;
|
|
64
64
|
};
|
|
65
|
-
/**
|
|
65
|
+
/**
|
|
66
|
+
* All of the user's text turns in the conversation, concatenated — not
|
|
67
|
+
* just the first message. The actual creative brief is often not
|
|
68
|
+
* userMessages[0] (e.g. "hi" -> clarifying questions -> the message that
|
|
69
|
+
* actually describes the ad), so anchoring to only the first message can
|
|
70
|
+
* silently drop the real brief.
|
|
71
|
+
*/
|
|
66
72
|
userBrief: string;
|
|
67
73
|
/**
|
|
68
74
|
* The original user-supplied reference image used to generate this frame
|
|
@@ -152,6 +152,12 @@ export declare function enforceMinProductBox({ x, y, width, height, targetW, tar
|
|
|
152
152
|
width: number;
|
|
153
153
|
height: number;
|
|
154
154
|
};
|
|
155
|
+
export declare function buildAutoResizeImagePrompt(srcW: number, srcH: number, tgtW: number, tgtH: number, aspectRatio: string, brandImages?: {
|
|
156
|
+
logo?: string;
|
|
157
|
+
fontPreview?: string;
|
|
158
|
+
fontUrl?: string;
|
|
159
|
+
name?: string;
|
|
160
|
+
}, sourceTextColors?: string[]): string;
|
|
155
161
|
export type PreCreatedFrameInfo = {
|
|
156
162
|
frameId: string;
|
|
157
163
|
x: number;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ExcalidrawElement } from "@orangecatai/element/types";
|
|
2
|
+
/** Which element types a given pick will accept. */
|
|
3
|
+
export type PickerAccept = "image" | "imageOrVideo";
|
|
4
|
+
export type ElementPickerState = {
|
|
5
|
+
accept: PickerAccept;
|
|
6
|
+
/** Fired with the picked element. The picker is disarmed first. */
|
|
7
|
+
onPick: (element: ExcalidrawElement) => void;
|
|
8
|
+
/** Fired on Esc, or when the arming component unmounts. */
|
|
9
|
+
onCancel: () => void;
|
|
10
|
+
/**
|
|
11
|
+
* Fired when the user clicks canvas that holds nothing pickable. The picker
|
|
12
|
+
* stays armed — a stray click should not force the user to re-arm.
|
|
13
|
+
*/
|
|
14
|
+
onMiss?: () => void;
|
|
15
|
+
/**
|
|
16
|
+
* Fired as the pointer moves with the element currently under it (or null).
|
|
17
|
+
* The arming component draws the highlight, so App never re-renders the
|
|
18
|
+
* editor on hover.
|
|
19
|
+
*/
|
|
20
|
+
onHover?: (element: ExcalidrawElement | null) => void;
|
|
21
|
+
};
|
|
22
|
+
export declare const elementPickerAtom: import("jotai/vanilla/atom").PrimitiveAtom<ElementPickerState | null> & {
|
|
23
|
+
init: ElementPickerState | null;
|
|
24
|
+
};
|
|
25
|
+
export declare const isPickable: (element: ExcalidrawElement, accept: PickerAccept) => boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Returns the topmost pickable element containing the given scene point, or
|
|
28
|
+
* null. Deliberately does its own hit test rather than reusing
|
|
29
|
+
* `App.getElementAtPosition`: that method is private, weighs z-index against
|
|
30
|
+
* selection and bound text, and considers every element type — whereas a pick
|
|
31
|
+
* only ever targets images and videos, both plain rectangles.
|
|
32
|
+
*/
|
|
33
|
+
export declare const pickElementAt: (elements: readonly ExcalidrawElement[], x: number, y: number, accept: PickerAccept) => ExcalidrawElement | null;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ElementsMapOrArray, ExcalidrawFrameLikeElement, ExcalidrawVideoElement } from "@orangecatai/element/types";
|
|
1
|
+
import type { ElementsMapOrArray, ExcalidrawElement, ExcalidrawFrameLikeElement, ExcalidrawVideoElement } from "@orangecatai/element/types";
|
|
2
2
|
export type FrameToolbarVariant = "frame" | "video";
|
|
3
3
|
export type FrameToolbarVariantResult = {
|
|
4
4
|
variant: FrameToolbarVariant;
|
|
@@ -21,3 +21,16 @@ export type FrameToolbarVariantResult = {
|
|
|
21
21
|
* Campaign on one would present an action that is guaranteed to fail.
|
|
22
22
|
*/
|
|
23
23
|
export declare const getFrameToolbarVariant: (frame: ExcalidrawFrameLikeElement, elements: ElementsMapOrArray) => FrameToolbarVariantResult | null;
|
|
24
|
+
/**
|
|
25
|
+
* Resolves the frame that Resize should act on when an *image* is selected.
|
|
26
|
+
*
|
|
27
|
+
* An ad frame is covered edge to edge by its generated image, so clicking the
|
|
28
|
+
* artwork selects that child image, not the frame — and the child shows
|
|
29
|
+
* `ImageEditToolbar`, which has no Resize. From the user's side the button
|
|
30
|
+
* simply vanishes depending on where they clicked. This lets the image toolbar
|
|
31
|
+
* offer the same Resize action, targeting the parent frame.
|
|
32
|
+
*
|
|
33
|
+
* Returns null unless the parent frame would itself show the full "frame"
|
|
34
|
+
* toolbar, so the child never surfaces an action the frame does not have.
|
|
35
|
+
*/
|
|
36
|
+
export declare const getResizeTargetFrame: (element: ExcalidrawElement, elements: readonly ExcalidrawElement[]) => ExcalidrawFrameLikeElement | null;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { PickerAccept } from "./elementPicker";
|
|
2
|
+
import type { VideoFrameChoice } from "../utils/videoFrameSource";
|
|
3
|
+
import type { AppClassProperties } from "../types";
|
|
4
|
+
import type { ExcalidrawElement, ExcalidrawVideoElement } from "@orangecatai/element/types";
|
|
5
|
+
/**
|
|
6
|
+
* `slot` is opaque to the hook — panels use it to route the resolved data URL
|
|
7
|
+
* back to the right chip ("first", "last", "reference", …).
|
|
8
|
+
*/
|
|
9
|
+
export type CanvasFramePicker = {
|
|
10
|
+
/** Slot currently awaiting a canvas click, or null. */
|
|
11
|
+
pickingSlot: string | null;
|
|
12
|
+
/** Video awaiting a first/last choice, or null. */
|
|
13
|
+
pendingVideo: {
|
|
14
|
+
slot: string;
|
|
15
|
+
element: ExcalidrawVideoElement;
|
|
16
|
+
} | null;
|
|
17
|
+
/** True while a video frame is being downloaded and decoded. */
|
|
18
|
+
isResolving: boolean;
|
|
19
|
+
error: string | null;
|
|
20
|
+
/** True when the last canvas click landed on nothing pickable. */
|
|
21
|
+
missed: boolean;
|
|
22
|
+
/** Element currently under the pointer while picking, for the highlight. */
|
|
23
|
+
hoveredElement: ExcalidrawElement | null;
|
|
24
|
+
begin: (slot: string, accept: PickerAccept) => void;
|
|
25
|
+
cancel: () => void;
|
|
26
|
+
chooseVideoFrame: (which: VideoFrameChoice) => void;
|
|
27
|
+
};
|
|
28
|
+
export declare const useCanvasFramePicker: (app: AppClassProperties, onResolved: (slot: string, dataUrl: string) => void) => CanvasFramePicker;
|
|
@@ -761,8 +761,8 @@ export interface ExcalidrawProps {
|
|
|
761
761
|
* background regeneration and the agent chat `generate_image` tool.
|
|
762
762
|
* Pass the same value here and to `AIChatPanel.agentImageModel` to keep
|
|
763
763
|
* both surfaces on the same model with a single configuration.
|
|
764
|
-
* @default "
|
|
765
|
-
* @example "google/gemini-
|
|
764
|
+
* @default "openai/gpt-image-2"
|
|
765
|
+
* @example "google/gemini-3.1-flash-image-preview"
|
|
766
766
|
*/
|
|
767
767
|
agentImageModel?: string;
|
|
768
768
|
/**
|
|
@@ -923,6 +923,7 @@ export type AppClassProperties = {
|
|
|
923
923
|
editorInterface: App["editorInterface"];
|
|
924
924
|
scene: App["scene"];
|
|
925
925
|
syncActionResult: App["syncActionResult"];
|
|
926
|
+
setElementPicker: App["setElementPicker"];
|
|
926
927
|
fonts: App["fonts"];
|
|
927
928
|
pasteFromClipboard: App["pasteFromClipboard"];
|
|
928
929
|
id: App["id"];
|
|
@@ -17,9 +17,16 @@ export declare function buildBrandContextMessage(ctx: BrandContext): string;
|
|
|
17
17
|
* block before the prompt. This function only appends the per-asset mandatory
|
|
18
18
|
* instructions that reference the visual attachments by position.
|
|
19
19
|
*/
|
|
20
|
-
export declare function buildImageGenSafePrompt(prompt: string, brandContext: BrandContext,
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
export declare function buildImageGenSafePrompt(prompt: string, brandContext: BrandContext, opts?: {
|
|
21
|
+
/**
|
|
22
|
+
* True when the user attached their own reference images. The brand logo
|
|
23
|
+
* and font specimens are then not attached at all (see imageApi), so the
|
|
24
|
+
* mandates that point at them — "embed the logo VERBATIM", "render ALL text
|
|
25
|
+
* in this exact typeface" — must go too: they would order the model to
|
|
26
|
+
* reproduce images it can no longer see, and they compete with the
|
|
27
|
+
* reference the user actually chose.
|
|
28
|
+
*/
|
|
29
|
+
hasUserReferences?: boolean;
|
|
23
30
|
}): string;
|
|
24
31
|
/**
|
|
25
32
|
* Augments a video prompt with brand direction reframed for motion.
|
|
@@ -41,4 +48,10 @@ export declare function buildImageGenSafePrompt(prompt: string, brandContext: Br
|
|
|
41
48
|
*/
|
|
42
49
|
export declare function buildVideoBrandPrompt(prompt: string, ctx: BrandContext, opts?: {
|
|
43
50
|
hasLogoReference?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* How many of the attached references the user supplied themselves. They
|
|
53
|
+
* are attached ahead of the brand logo, so this also fixes the logo's
|
|
54
|
+
* position in the numbered manifest below.
|
|
55
|
+
*/
|
|
56
|
+
userReferenceCount?: number;
|
|
44
57
|
}): string;
|
|
@@ -1,4 +1,27 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Hard cap on user-supplied reference images per generation. Providers differ on
|
|
3
|
+
* how many references they accept; six covers every realistic ad brief and keeps
|
|
4
|
+
* the request well inside the limits of the models we route to.
|
|
5
|
+
*/
|
|
6
|
+
export declare const MAX_USER_REFERENCE_IMAGES = 6;
|
|
7
|
+
/**
|
|
8
|
+
* Describes each attached reference image by its real 1-based position, and
|
|
9
|
+
* states the precedence rule between them.
|
|
10
|
+
*
|
|
11
|
+
* This exists because attachment order alone does not steer the model — it
|
|
12
|
+
* follows whichever image the prompt names. Previously only the brand assets
|
|
13
|
+
* were named ("the first reference image is the exact brand logo"), so a
|
|
14
|
+
* user-supplied reference sat in the array unmentioned and was ignored.
|
|
15
|
+
*
|
|
16
|
+
* When the user attaches anything, their references are the authority: the
|
|
17
|
+
* brand kit, stored logo, and reference ads are explicitly demoted so a
|
|
18
|
+
* contradiction resolves in the user's favour rather than the brand's.
|
|
19
|
+
*
|
|
20
|
+
* Returns "" when there is nothing worth numbering, so prompts that carry no
|
|
21
|
+
* attachments are left byte-identical to before.
|
|
22
|
+
*/
|
|
23
|
+
export declare function buildReferenceManifest(userReferenceCount: number, brandLabels: string[]): string;
|
|
24
|
+
export declare function callOpenRouterImageAPI(prompt: string, modelId: string, aspectRatio: string, imageSize: string | null, textOutput: boolean, imageGenUrl: string, referenceImageDataUrl?: string | string[], signal?: AbortSignal, brandImages?: {
|
|
2
25
|
logo?: string;
|
|
3
26
|
fontPreview?: string;
|
|
4
27
|
/** Optional second font preview (brand body typeface) shown as a reference. */
|
|
@@ -16,4 +39,21 @@ export declare function callOpenRouterImageAPI(prompt: string, modelId: string,
|
|
|
16
39
|
* prepended to the prompt so the model applies brand guidelines to the image.
|
|
17
40
|
*/
|
|
18
41
|
brandContextText?: string;
|
|
42
|
+
}, options?: {
|
|
43
|
+
/**
|
|
44
|
+
* How to treat `referenceImageDataUrl`.
|
|
45
|
+
*
|
|
46
|
+
* "user-priority" — the references came from the end user. They are
|
|
47
|
+
* attached FIRST, named individually in the reference manifest, and
|
|
48
|
+
* explicitly overrule the brand kit, stored logo, and brand reference ads
|
|
49
|
+
* on any contradiction. Used by the surfaces where the user picks the
|
|
50
|
+
* reference themselves: image generation, quick edit, and canvas chat.
|
|
51
|
+
*
|
|
52
|
+
* "legacy-positional" (default) — the reference is a pipeline input rather
|
|
53
|
+
* than a user choice (e.g. the auto-resize source ad), and the caller has
|
|
54
|
+
* already written its own numbered reference list into the prompt assuming
|
|
55
|
+
* brand assets come first. Preserves the original ordering and emits no
|
|
56
|
+
* manifest, so those callers are unaffected by this option.
|
|
57
|
+
*/
|
|
58
|
+
referenceMode?: "user-priority" | "legacy-positional";
|
|
19
59
|
}): Promise<string>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ExcalidrawVideoElement } from "@orangecatai/element/types";
|
|
2
|
+
export type VideoFrameChoice = "first" | "last";
|
|
3
|
+
/**
|
|
4
|
+
* Downloads the video bytes. Routes through the host's download proxy for the
|
|
5
|
+
* same reason playback does — presigned URLs expire on long-lived canvases —
|
|
6
|
+
* while `blob:` URLs are fetched directly (they resolve only in this tab, and
|
|
7
|
+
* the proxy could not reach them anyway).
|
|
8
|
+
*/
|
|
9
|
+
export declare const fetchVideoBlob: (videoUrl: string, videoDownloadProxyUrl?: string) => Promise<Blob>;
|
|
10
|
+
/**
|
|
11
|
+
* Resolves one frame of a canvas video element to a PNG/JPEG data URL.
|
|
12
|
+
*
|
|
13
|
+
* The first frame is already cached on the element as `thumbnailDataUrl`, so
|
|
14
|
+
* that case avoids the download entirely; only a last-frame pick (or a video
|
|
15
|
+
* whose thumbnail never materialised) pays for the fetch and decode.
|
|
16
|
+
*/
|
|
17
|
+
export declare const extractFrameFromVideoElement: (element: ExcalidrawVideoElement, which: VideoFrameChoice, videoDownloadProxyUrl?: string) => Promise<string>;
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
export type AudioPolicy = "first-only" | "none";
|
|
2
2
|
/**
|
|
3
|
-
* Decodes the final frame of a video
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* Uses `CanvasSink.getCanvas(Infinity)` rather than seeking a `<video>`
|
|
7
|
-
* element to `duration - epsilon`: a time-based seek can land on a keyframe
|
|
8
|
-
* boundary or a black tail frame depending on the encoder, which poisons the
|
|
9
|
-
* next segment's starting state.
|
|
3
|
+
* Decodes the final frame of a video, suitable as the next chain segment's
|
|
4
|
+
* `firstFrameDataUrl`.
|
|
10
5
|
*/
|
|
11
6
|
export declare function extractLastFrame(video: Blob): Promise<string>;
|
|
7
|
+
/**
|
|
8
|
+
* Decodes the opening frame of a video. Used when linking an existing canvas
|
|
9
|
+
* video into a generator panel's start/end frame chip.
|
|
10
|
+
*/
|
|
11
|
+
export declare function extractFirstFrame(video: Blob): Promise<string>;
|
|
12
12
|
/**
|
|
13
13
|
* Stream-copy concatenates segments produced by the same model at the same
|
|
14
14
|
* codec/resolution/fps into one MP4. No re-encode — packets are demuxed
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{S as a,T as b,U as c}from"../chunk-GTYNSLQE.js";import"../chunk-SZMIDXG6.js";import"../chunk-SRAX5OIU.js";export{c as decodePngMetadata,b as encodePngMetadata,a as getTEXtChunk};
|
|
File without changes
|
|
File without changes
|
|
File without changes
|