Resource readers and file tools
Find page resource readers, import/export tools, and resource attachment operations.
Choose the layer you need
These interfaces run in trusted local pages with the bridge. Basic resource and externalFiles APIs are injected by the host. resourceIO, image readers, and DOM interception need additional helper scripts. File interaction has defaults even without an explicit Python window policy; explicit declarations constrain types and budgets, while screenshot pasting must be enabled separately. Page filters cannot loosen host policy.
| Item | Usage and limitations |
|---|---|
| Basic resource API | Resource references, byte transport, and low-level pick/save transactions. |
| resourceIO | Combines import classification, file picking, and saving into common operations. |
| DOM and interception scripts | Connect buttons, file inputs, download links, or components to the same resource operations. |
For loading order, see Page markers and script loading.
References, bytes, and attachments
export interface WebUIResourceRef {
resourceId: string;
kind: string;
mime: string;
byteLength: number;
revision: number;
[extra: string]: WebUIJSONValue;
}export interface WebUIResourceInfoResult {
resourceRef: WebUIResourceRef;
}export interface WebUIResourceUrlResult {
resourceRef: WebUIResourceRef;
url: string;
expiresAtUnix: number;
}export type WebUIResourceUploadBody = Blob | ArrayBuffer | ArrayBufferView;export interface WebUIResourceUploadOptions extends WebUIRequestOptions {
mime?: string;
}export interface WebUIResourceUploadResult {
uploadUrl: string;
resourceId: string;
expiresAtUnix: number;
byteLength: number;
mime: string;
}export interface WebUIActionWithResourceInput {
resource: WebUIResourceUploadBody;
mime?: string;
params?: Record<string, WebUIJSONValue>;
}| Item | Usage and limitations |
|---|---|
| resource.info(resourceId, options?) | Returns an object containing resourceRef, not the reference itself or file content. |
| resource.url(ref, options?) | Returns a temporary URL, expiry, and reference for displayable resources such as images. Do not store it as a permanent address. |
| resource.arrayBuffer(ref, options?) | Reads bytes. Interpret RGBA floating-point pixels, HDR, and mesh data according to their actual formats. |
| resource.upload(bytes, options?) | Uploads a Blob, ArrayBuffer, or view and returns upload information including resourceId. Does not automatically write to Blender. |
| action.callWithResource(name, input, options?) | Uploads an attachment and invokes an action. Put application arguments in params; the framework adds resourceId for the Python handler. |
Attachments are scoped resources. Do not mix in references from another add-on. Renew expired URLs from valid references; republish if the reference itself expired. Python resource reference explains reading and consuming uploads.
Image and HDR reading helpers
export interface NexusResourceKitMethods {
loadImage(resourceRef: WebUIResourceRef, options?: WebUIRequestOptions): Promise<NexusResourceImageResult>;
loadImageBitmap(
resourceRef: WebUIResourceRef,
options?: WebUIRequestOptions,
): Promise<NexusResourceImageBitmapResult>;
loadHDRBytes(resourceRef: WebUIResourceRef, options?: WebUIRequestOptions): Promise<NexusResourceHDRBytesResult>;
}export interface NexusResourceImageResult {
image: HTMLImageElement;
ref: WebUIResourceRef;
meta: NexusResourceMeta;
}export interface NexusResourceImageBitmapResult {
bitmap: ImageBitmap;
ref: WebUIResourceRef;
meta: NexusResourceMeta;
}export interface NexusResourceHDRBytesResult {
buffer: ArrayBuffer;
ref: WebUIResourceRef;
meta: NexusResourceMeta;
}After loading kit, loadImage returns image/ref/meta, loadImageBitmap returns bitmap/ref/meta, and loadHDRBytes returns buffer/ref/meta. Check meta.format, dimensions, and color information. HDR bytes still need an appropriate parser. Close ImageBitmap objects you own and remove unused display references.
High-level picking, import, and saving
export interface NexusResourceIO {
onImport(handler: NexusImportEventCallback): Promise<NexusResourceIOSubscriptionHandle>;
/** Fires only when the delivered event has at least one file. */
onFiles(handler: NexusImportEventCallback): Promise<NexusResourceIOSubscriptionHandle>;
/** Fires only when the delivered event has at least one image. */
onImages(handler: NexusImportEventCallback): Promise<NexusResourceIOSubscriptionHandle>;
/** Fires only when the delivered event has at least one text item. */
onText(handler: NexusImportEventCallback): Promise<NexusResourceIOSubscriptionHandle>;
/** Resolves null (not an error) when the user cancels the native dialog. */
pickFiles(options?: NexusPickOptions): Promise<NexusImportEvent | null>;
pickImages(options?: NexusPickOptions): Promise<NexusImportEvent | null>;
importDirectory(options?: NexusPickOptions): Promise<NexusImportEvent | null>;
pickSaveDirectory(options?: NexusPickOptions): Promise<WebUICancelledOutcome | { destinationRef: WebUIDestinationRef }>;
saveFile(bytes: WebUIResourceUploadBody, options?: NexusSaveOptions): Promise<NexusSaveResult>;
saveFiles(items: readonly NexusSaveFilesItem[], options?: NexusSaveOptions): Promise<NexusSaveResult[]>;
saveText(text: string, options?: NexusSaveOptions): Promise<NexusSaveResult>;
saveJSON(value: WebUIJSONValue, options?: NexusSaveOptions): Promise<NexusSaveResult>;
saveCanvas(canvas: HTMLCanvasElement, options?: NexusSaveOptions): Promise<NexusSaveResult>;
callActionWithResource(
actionName: string,
options: WebUIActionWithResourceInput & { requestOptions?: WebUIRequestOptions },
): Promise<WebUIJSONValue>;
/** Rejects with code 'unsupported_feature' unless nexus-resource-dom.js was also loaded. */
registerAdapter(adapter: NexusResourceAdapter): Promise<NexusResourceAdapterHandle>;
/** Rejects with code 'unsupported_feature' unless nexus-resource-dom.js was also loaded. */
enableDOM(options?: NexusEnableDOMOptions): Promise<boolean>;
dispose(): void;
}export interface NexusPickOptions extends WebUIRequestOptions {
/** Extensions ("['.png']"), mime types ("image/png"), or "image/*"; narrows the native dialog filter only. */
accept?: string | readonly string[];
initialPath?: string;
}export type NexusImportEventMeta = WebUIEventMeta | {
name: 'nexus.external_files.import';
subscriptionId: null;
dropped: false;
};export interface NexusSaveOptions extends WebUIRequestOptions {
name?: string;
mime?: string;
accept?: string | readonly string[];
initialPath?: string;
onConflict?: WebUISaveConflictPolicy;
}export interface NexusSaveFilesItem {
bytes: WebUIResourceUploadBody;
mime?: string;
name?: string;
onConflict?: WebUISaveConflictPolicy;
}export interface NexusSaveResult {
ok: boolean;
/** True when the user dismissed the save-target dialog; the other fields are then all null/default. */
cancelled: boolean;
fileName: string | null;
byteLength: number | null;
code: string | null;
message: string;
}| Item | Usage and limitations |
|---|---|
| onImport / onFiles / onImages / onText | Asynchronously returns a listener handle. onImport receives the complete result; the other three callbacks run when files, images, or texts are nonempty. files may include resources that failed decoding and does not prove usable content. Completing a pick also notifies the listeners, with meta.subscriptionId set to null. |
| pickFiles / pickImages / importDirectory | Returns a classified import event; cancelling the native picker returns null. pickSaveDirectory instead returns {cancelled:true} on cancellation. |
| saveFile / saveText / saveJSON / saveCanvas | Returns a save result. Check cancelled first, then ok. Type filters do not replace format or permission checks. |
| saveFiles | Normal submission returns per-item results. Cancelling selection returns only one cancelled result, so array length need not match input. Upload and other steps may reject directly. Catch exceptions, then inspect each save result. |
| callActionWithResource | Combines attachment upload and action calls. Accepts resource, mime, and params; validate application results according to the action contract. |
| registerAdapter / enableDOM | Requires the DOM extension; rejects with unsupported_feature if absent. |
| dispose | Releases this helper instance's listeners and DOM interception, not subscriptions owned by other components. |
async function saveSettings(settings) {
const webui = window.acquireNexusWebUI();
await webui.ready();
const result = await webui.resourceIO.saveJSON(settings, {name: "settings.json"});
if (result.cancelled) return "已取消";
if (!result.ok) throw new Error(result.message || result.code || "保存失败");
return "已保存:" + result.fileName;
}Load io → dom → kit as described in the marker guide. settings must be JSON data. Catch and display errors in the user-triggered handler; do not automatically repeat saves.
Import events and coordinates
export interface NexusImportEvent {
importId: string | null;
/** Derived by the kit (defaults to importId); the host never sends one. */
traceId: string;
source: WebUIExternalFileSource;
/** Shorthand for placement.fallbackPoint. */
point: NexusImportPoint;
placement: NexusImportPlacement;
/** Raw wire items, unclassified. */
files: WebUIExternalFileItem[];
/** Successfully decoded images in their relative order from files. */
images: NexusImportedImage[];
/** Successfully decoded text in its relative order from files. */
texts: NexusImportedText[];
binaries: NexusImportedBinary[];
rejected: WebUIExternalFileRejectedItem[];
/** Nearest ancestor with [data-nexus-import] (or a bare <canvas>) at `point`; computed by the kit, never sent by the host. */
targetElement: Element | null;
/** The untouched (already-sanitized) wire payload this event was built from. */
raw: WebUIJSONValue;
}export interface NexusImportPlacement {
coordinateSpace: 'css';
clientPoint: NexusImportPoint | null;
viewportCenter: NexusImportPoint;
/** Always usable: clientPoint when valid and in-bounds, otherwise viewportCenter. */
fallbackPoint: NexusImportPoint;
fallbackReason: NexusPlacementFallbackReason;
}export interface NexusImportedBinary {
item: WebUIExternalFileItem;
ref: WebUIResourceRef;
}export interface WebUIExternalFilesImportEvent {
importId: string;
source: WebUIExternalFileSource;
clientPoint: WebUIExternalFilePoint | null;
files: WebUIExternalFileItem[];
rejected: WebUIExternalFileRejectedItem[];
}High-level events contain images, texts, binaries, and rejected. Raw events contain files/rejected and transport information. point uses CSS page coordinates, not Blender coordinates. fallbackPoint uses the viewport center when missing or out of bounds. Binary classification means a reference exists, not that bytes were read. Read during the import lease and retain needed content yourself; references are not permanent file paths.
Low-level transactions and cancellation
export interface WebUIResourceOperationEnvelope<TResult> {
operationId: string;
result: TResult;
}export interface WebUIDestinationRef {
destinationId: string;
kind: 'file' | 'directory';
}export interface WebUISaveCommitItem {
destinationId: string;
resourceId: string;
suggestedName?: string;
onConflict?: WebUISaveConflictPolicy;
}export interface WebUISaveCommitOutcome {
ok: boolean;
code: string | null;
fileName: string | null;
byteLength: number | null;
message: string;
}export interface WebUIImportReceiptRecord {
importId: string;
traceId: string;
receipt: WebUIImportReceiptKind;
itemIds: readonly string[];
ok: boolean;
message?: string | null;
error?: string | null;
}| Item | Usage and limitations |
|---|---|
| pickFiles / importDirectory | Returns operationId and result; result is a raw import event or cancellation result. |
| pickSaveTarget / pickSaveDirectory | Returns a temporary destination reference or cancellation, not a real disk path. |
| commitSaveResource / commitSaveResources | Commits with destinationId and uploaded resourceId. Check ok/code for each item. |
| cancelOperation(operationId) | Requests cancellation of an operation. The locally pending original operation rejects with cancelled. A cancellation receipt does not prove application completion. |
| reportImport(records) | Reports loaded/failed/released import consumption status. Actual enum values are resource_loaded, failed, and released. |
The confirm conflict policy currently behaves like error and returns name_conflict; it does not display a host confirmation dialog. After user choice, retry with overwrite or rename. Do not treat a timeout as cancellation or blindly repeat writes.
Completion and troubleshooting
High-level listener release/unsubscribe methods are asynchronous; await or handle failures on unmount. Adapter registration returns a synchronous unregister method. Do not consume the same event through both low- and high-level APIs. See Adapter lifecycle, Import tutorial, Export tutorial.