Export

Register the export lifecycle hook, and the platform will invoke your generator to retrieve the resulting file whenever the user clicks "Export" or "Open in Studio." The return value is always { filename, blob }, and any file format is supported (images, SVG, 3D models, PDF, etc.).

User clicks Export
Triggered by the export button you placed
export hook fires
Your app returns (filename, blob)
Platform takes over
Saves to disk · Open in Studio · zips multi-file exports

Placing the Export Button

You place the export button yourself, inside your app—add an element with the data-atomm-export-button attribute anywhere on the page, and the SDK will render it in place as a platform-controlled Export dropdown (Download / Open in Studio + credit indicator). Clicks are always routed through the platform:

<div data-atomm-export-button></div>
  • Position and outer layout are entirely up to you (e.g., position: fixed to pin it to a corner); you can place multiple instances on one page, each hydrating independently.
  • The button renders inside a Shadow DOM for style isolation; theming is done exclusively through the documented --atomm-export-* CSS variables (set them on the element itself or any ancestor—they're automatically inherited by the button):
[data-atomm-export-button] {
  --atomm-export-bg: #d32f2f; /* Button background color */
  --atomm-export-radius: 0; /* Border radius */
  --atomm-export-width: 200px; /* Width: px, or 100% to fill the container */
  --atomm-export-height: 40px; /* Height */
}
VariableDefaultControls
--atomm-export-bg / -bg-hover / -bg-active#070b10 / #252c36 / #1c2129Button background for the default / hover / active states
--atomm-export-color#fffButton text color
--atomm-export-widthauto (fits content)Button width (px, or 100% to fill the container; min 24px)
--atomm-export-height32pxButton height (px or 100%; min 24px)
--atomm-export-radius8pxBorder radius
--atomm-export-font / -font-sizeInter, system-ui, sans-serif / 14pxFont family / font size
--atomm-export-menu-bg / -menu-color / -menu-hover-bg#fff / #111 / #f4f4f5Dropdown menu colors
--atomm-export-menu-radius / -menu-shadow8px / 0 4px 16px rgba(16,24,40,.12)Menu border radius / shadow
--atomm-export-z1000Dropdown overlay z-index

Only the --atomm-export-* variables listed above are supported customization points; internal button class names may change at any time, so don't rely on them.

Default appearance
Export 6
CSS variable reskin (black background, sharp corners)
Export 6
The export button only works inside the atomm environment (not a bug)

The export button—and its Download / Open in Studio / credit indicator—is driven by the atomm platform, and only works when your generator runs inside the atomm environment: the live platform, or the dev tool's local preview (?local=).

If you open your generator standalone, outside atomm (e.g. opening the HTML directly), the button may still render, but clicking it won't produce a file and no billing status will show—this is by design, not a bug. Always verify export via local preview or the live platform.

Free-Use Count / Credit Indicator on the Button

The button automatically displays the current billing status (pushed by the platform—no action needed on your part):

StateDisplayMeaning
Free window30s countdownA short grace period granted after a successful export; exports within this window are free
Free countFree 3/3Remaining / total free exports
Credit costCredit icon + numberCredits consumed per export once free uses are exhausted

In local debugging (?local=), clicking export never actually deducts credits; refreshing the page resets it.

Registering the export Hook

atomm.lifecycle.on('export', async () => {
  // No arguments are passed when triggered; the handler reads the current generation result itself and produces a Blob
  const blob = await exportCurrentResultAsBlob()
  if (!blob) {
    throw new Error('请先生成作品后再下载')
  }

  return {
    filename: 'my-generator.glb', // Must include an extension; this determines the downloaded filename and the asset type used by Open in Studio
    blob, // A Blob of any format; MIME type comes from blob.type
  }
})

Return Value Fields

FieldTypeDescription
filenamestringThe downloaded filename; must include an extension (e.g., design.glb) and must not contain path separators / \
blobBlobFile content of any format; each file must be ≤ 100MB; MIME type comes from blob.type, falling back to the filename extension when empty

Multi-File Export (Optional)

The handler can also return an array of files, and the platform will bundle them into a single zip download:

atomm.lifecycle.on('export', async () => [
  { filename: 'model.glb', blob: glbBlob },
  { filename: 'preview.png', blob: pngBlob },
])
RuleDescription
zip filenameDerived from the base name of the first file in the array (model.glbmodel.zip)
Duplicate namesAutomatically deduplicated to name (1).ext
Size limitThe combined size of all files must be ≤ 100MB; exceeding this fails the entire export
Array of length 1Downloads the file directly, without wrapping it in a zip
Open in StudioSupports multiple files—all returned files are handed to Studio to open, with no format restriction; formats Studio doesn't support are flagged by Studio itself. Multi-file import requires xTool Studio 1.8+; single-file export remains compatible with older versions

Single files still use { filename, blob }; use an array for multiple files. If any item in the returned array is invalid (not a Blob, filename missing an extension, etc.), the entire result is considered invalid.

Getting a Blob

Almost any export source can be converted to a Blob in a single line:

What you haveConvert to Blob
Canvas (2D drawing)canvas.toBlob(cb, 'image/png')
SVG string / text / JSONnew Blob([str], { type: 'image/svg+xml' })
ArrayBuffer / 3D mesh (glb/stl, etc.)new Blob([buffer], { type: 'model/gltf-binary' })
Existing data URL / remote URLawait (await fetch(x)).blob()
File from <input type=file>Use it directly (a File is already a Blob)
The return value is always { filename, blob }

Export data is always carried as a Blob, so any format is supported — a Blob preserves the binary content of any file type.

filename must include an extension and must not contain path separators; if a file exceeds 100MB or the return value isn't a valid { filename, blob }, the platform treats it as invalid, the export fails, and the user is notified.

Open in Studio's format support is determined by Studio

Downloads support saving any format to disk. "Open in Studio" hands the file off to xTool Studio to open—the platform makes no assumptions about format, and Studio itself will flag any format it doesn't support.

Not registering the hook will cause review rejection

The export button is available to every generator (it appears as soon as you add data-atomm-export-button to your app). If a user clicks export and you haven't registered the export hook, the platform receives "the app provides no download method"—and your submission will be rejected in review as a result. Any generator that supports export must register this hook; you can test it locally by clicking "Export" in the preview to confirm a file is produced correctly.

Esc
Search all docs · to navigate · to open