Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6612,6 +6612,71 @@ export declare interface IRedoService {
redo(options?: IUndoOperationOptions): Promise<IUndoRedoResult>;
canRedo(options?: IUndoOperationOptions): boolean;
}
export declare interface IReferenceImageCancelOptions {
interactionId: number;
}
export declare interface IReferenceImageCommitOptions {
interactionId?: number;
patch: IReferenceImageParameters;
}
export declare interface IReferenceImageConfigItem {
path: string;
x: number;
y: number;
scaleX: number;
scaleY: number;
opacity: number;
}
export declare interface IReferenceImageError {
stage: 'config' | 'file' | 'decode';
message: string;
}
export declare interface IReferenceImageItem extends IReferenceImageConfigItem {
missing: boolean;
}
export declare interface IReferenceImageParameters {
x?: number;
y?: number;
scaleX?: number;
scaleY?: number;
opacity?: number;
}
export declare interface IReferenceImagePathOptions {
path: string;
}
export declare interface IReferenceImagePreviewOptions {
interactionId: number;
patch: IReferenceImageParameters;
}
export declare interface IReferenceImageService extends IServiceEvents {
getState(): Promise<IReferenceImageState>;
addAndSelect(options: IReferenceImagePathOptions): Promise<IReferenceImageState>;
remove(options: IReferenceImagePathOptions): Promise<IReferenceImageState>;
select(options: IReferenceImagePathOptions): Promise<IReferenceImageState>;
clearBinding(): Promise<IReferenceImageState>;
setVisible(options: IReferenceImageVisibilityOptions): Promise<IReferenceImageState>;
refresh(): Promise<IReferenceImageState>;
previewParameters(options: IReferenceImagePreviewOptions): Promise<IReferenceImageState>;
commitParameters(options: IReferenceImageCommitOptions): Promise<IReferenceImageState>;
cancelPreview(options: IReferenceImageCancelOptions): Promise<IReferenceImageState>;
}
export declare interface IReferenceImageState {
images: IReferenceImageItem[];
current: {
sceneUuid: string | null;
imagePath: string | null;
image: IReferenceImageItem | null;
};
desiredVisible: boolean;
effectiveVisible: boolean;
visibilityReason: ReferenceImageVisibilityReason;
is2D: boolean;
hasOpenEditor: boolean;
error: IReferenceImageError | null;
}
export declare interface IReferenceImageVisibilityOptions {
desiredVisible: boolean;
}
export declare interface IReloadOptions {
urlOrUUID?: string;
preserveUndoHistory?: boolean;
Expand Down Expand Up @@ -6756,6 +6821,7 @@ export declare interface IServiceManager {
SceneView: ISceneViewService;
Preview: IPreviewService;
UI: IUIService;
ReferenceImage: IReferenceImageService;
}
export declare interface ISetParentParams {
paths: string[];
Expand Down Expand Up @@ -7090,6 +7156,7 @@ export declare enum PrefabState {
PrefabInstance = 2,
PrefabLostAsset = 3
}
export declare type ReferenceImageVisibilityReason = 'visible' | 'disabled' | 'no-editor' | 'not-2d' | 'unbound' | 'missing' | 'load-error';
export declare enum ReloadResult {
SUCCESS = 0,
FAILED = 1,
Expand Down
53 changes: 53 additions & 0 deletions src/api/scene/reference-image-schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/** Runtime schemas for the public AI/MCP reference-image operations. */
import { z } from 'zod';

export const SchemaReferenceImageParameters = z.object({
x: z.number().finite().optional().describe('Horizontal offset in 2D scene world units'),
y: z.number().finite().optional().describe('Vertical offset in 2D scene world units'),
scaleX: z.number().finite().optional().describe('Horizontal scale factor'),
scaleY: z.number().finite().optional().describe('Vertical scale factor'),
opacity: z.number().min(0).max(100).optional().describe('Opacity percentage from 0 to 100'),
}).refine((value) => Object.keys(value).length > 0, {
message: 'At least one reference image parameter is required.',
}).describe('Reference image parameters');

export const SchemaReferenceImagePath = z.object({
path: z.string().min(1).describe('Absolute local PNG, JPG, or JPEG file path'),
}).describe('Reference image file');

export const SchemaReferenceImageVisibility = z.object({
desiredVisible: z.boolean().describe('Whether the user wants reference images visible in supported editors'),
}).describe('Reference image visibility preference');

const SchemaReferenceImageItem = z.object({
path: z.string(),
x: z.number(),
y: z.number(),
scaleX: z.number(),
scaleY: z.number(),
opacity: z.number().min(0).max(100),
missing: z.boolean(),
});

export const SchemaReferenceImageState = z.object({
images: z.array(SchemaReferenceImageItem),
current: z.object({
sceneUuid: z.string().nullable(),
imagePath: z.string().nullable(),
image: SchemaReferenceImageItem.nullable(),
}),
desiredVisible: z.boolean(),
effectiveVisible: z.boolean(),
visibilityReason: z.enum(['visible', 'disabled', 'no-editor', 'not-2d', 'unbound', 'missing', 'load-error']),
is2D: z.boolean(),
hasOpenEditor: z.boolean(),
error: z.object({
stage: z.enum(['config', 'file', 'decode']),
message: z.string(),
}).nullable(),
}).describe('Current editor reference-image state');

export type TReferenceImageParameters = z.infer<typeof SchemaReferenceImageParameters>;
export type TReferenceImagePath = z.infer<typeof SchemaReferenceImagePath>;
export type TReferenceImageVisibility = z.infer<typeof SchemaReferenceImageVisibility>;
export type TReferenceImageState = z.infer<typeof SchemaReferenceImageState>;
89 changes: 89 additions & 0 deletions src/api/scene/reference-image.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/** Public AI/MCP facade for formal reference-image operations. */
import { COMMON_STATUS, CommonResultType } from '../base/schema-base';
import { description, param, result, title, tool } from '../decorator/decorator';
import { Scene } from '../../core/scene';
import {
SchemaReferenceImageParameters,
SchemaReferenceImagePath,
SchemaReferenceImageState,
SchemaReferenceImageVisibility,
TReferenceImageParameters,
TReferenceImagePath,
TReferenceImageState,
TReferenceImageVisibility,
} from './reference-image-schema';

/** Formal, semantic MCP operations. Ephemeral preview APIs remain scene-Webview only. */
export class ReferenceImageApi {
@tool('reference-image-query')
@title('Query reference image state')
@description('Get the current reference-image library, current binding, parameters and effective visibility.')
@result(SchemaReferenceImageState)
async query(): Promise<CommonResultType<TReferenceImageState>> {
return this.execute(() => Scene.ReferenceImage.getState());
}

@tool('reference-image-add')
@title('Add and select reference image')
@description('Validate a local PNG, JPG, or JPEG, add it to the local library, and bind it to the current scene or prefab.')
@result(SchemaReferenceImageState)
async add(@param(SchemaReferenceImagePath) options: TReferenceImagePath): Promise<CommonResultType<TReferenceImageState>> {
return this.execute(() => Scene.ReferenceImage.addAndSelect(options));
}

@tool('reference-image-delete')
@title('Delete reference image')
@description('Remove a reference image record and all scene bindings. The original local file is not deleted.')
@result(SchemaReferenceImageState)
async delete(@param(SchemaReferenceImagePath) options: TReferenceImagePath): Promise<CommonResultType<TReferenceImageState>> {
return this.execute(() => Scene.ReferenceImage.remove(options));
}

@tool('reference-image-select')
@title('Select reference image')
@description('Bind an existing reference image to the current scene or prefab.')
@result(SchemaReferenceImageState)
async select(@param(SchemaReferenceImagePath) options: TReferenceImagePath): Promise<CommonResultType<TReferenceImageState>> {
return this.execute(() => Scene.ReferenceImage.select(options));
}

@tool('reference-image-clear-binding')
@title('Clear current reference image binding')
@description('Unbind the reference image from the current scene or prefab while preserving the local library and other bindings.')
@result(SchemaReferenceImageState)
async clearBinding(): Promise<CommonResultType<TReferenceImageState>> {
return this.execute(() => Scene.ReferenceImage.clearBinding());
}

@tool('reference-image-set-visible')
@title('Set reference image visibility')
@description('Set the persisted desired visibility. Reference images remain hidden while the editor is not in 2D mode.')
@result(SchemaReferenceImageState)
async setVisible(@param(SchemaReferenceImageVisibility) options: TReferenceImageVisibility): Promise<CommonResultType<TReferenceImageState>> {
return this.execute(() => Scene.ReferenceImage.setVisible(options));
}

@tool('reference-image-refresh')
@title('Refresh current reference image')
@description('Reload the current reference image from its original local path.')
@result(SchemaReferenceImageState)
async refresh(): Promise<CommonResultType<TReferenceImageState>> {
return this.execute(() => Scene.ReferenceImage.refresh());
}

@tool('reference-image-set-parameters')
@title('Set reference image parameters')
@description('Persist finite position or scale values and opacity from 0 to 100 for the image bound to the current scene or prefab.')
@result(SchemaReferenceImageState)
async setParameters(@param(SchemaReferenceImageParameters) patch: TReferenceImageParameters): Promise<CommonResultType<TReferenceImageState>> {
return this.execute(() => Scene.ReferenceImage.commitParameters({ patch }));
}

private async execute(operation: () => Promise<TReferenceImageState>): Promise<CommonResultType<TReferenceImageState>> {
try {
return { code: COMMON_STATUS.SUCCESS, data: await operation() };
} catch (error) {
return { code: COMMON_STATUS.FAIL, reason: error instanceof Error ? error.message : String(error) };
}
}
}
3 changes: 3 additions & 0 deletions src/api/scene/scene.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,20 @@ import { Scene, TSceneTemplateType } from '../../core/scene';
import { ComponentApi } from './component';
import { NodeApi } from './node';
import { PrefabApi } from './prefab';
import { ReferenceImageApi } from './reference-image';
import { options } from '../../core/builder/platforms/android/i18n/en';

export class SceneApi {
public component: ComponentApi;
public node: NodeApi;
public prefab: PrefabApi;
public referenceImage: ReferenceImageApi;

constructor() {
this.component = new ComponentApi();
this.node = new NodeApi();
this.prefab = new PrefabApi();
this.referenceImage = new ReferenceImageApi();
}

@tool('scene-query-current')
Expand Down
1 change: 1 addition & 0 deletions src/core/scene/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ export * from './scene-view';
export * from './preview';
export * from './ui';
export * from './message';
export * from './reference-image';
2 changes: 2 additions & 0 deletions src/core/scene/common/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type { ICameraEvents } from './camera';
import type { ISceneViewEvents } from './scene-view';
import type { IUndoEvents } from './undo';
import type { IAnimationEvents } from './animation';
import type { IReferenceImageEvents } from './reference-image';

/**
* messageManager 不在已有接口中的补充事件
Expand All @@ -35,4 +36,5 @@ export interface IMessageManagerEvents extends
ISceneViewEvents,
IUndoEvents,
IAnimationEvents,
IReferenceImageEvents,
ISceneEvents {}
Loading
Loading