Assets & caching

Before a render, the SDK uploads your scene's files (its assets). Each file is identified by a hash of its content, so a file that has not changed is never uploaded twice.

You do not call anything for this. render(), renderVideo() and bake() upload what is missing and skip the rest.

First render    Uploaded: 148 MB
Camera moves    Uploaded: 2 KB
Texture change  Uploaded: 6 MB

Show upload progress

await bakery3.render({
  onUpload: ({ cached, uploaded, bytesUploaded, bytesTotal }) => {
    setStatus(`${uploaded} uploading, ${cached} already cached`);
    setProgress(bytesTotal ? bytesUploaded / bytesTotal : 1);
  },
});
// onUpload receives:
// { cached: 3, uploaded: 1, bytesUploaded: 6291456, bytesTotal: 6291456 }

cached and uploaded count files. When nothing has changed, bytesTotal is 0.

What causes a new upload

The scene is exported to a .glb on every render. If the export is different from last time, it is uploaded again. Moving a mesh, hiding a variant or swapping a material all change it.

Moving only the camera does not. The camera is sent with the render request, not inside the .glb, so an orbit uploads almost nothing.

What gets uploaded

KindWhat it is
sceneThe exported .glb: geometry, materials, hierarchy, embedded textures.
textureTextures used by a node material, which the .glb does not carry.
hdriAn environment map of your own. A preset one is not uploaded.
geometryStandalone geometry.
animationPer-frame motion for a video.
iesAn IES light profile.

When an upload fails

The SDK tries each file three times. If it still fails, the render throws AssetUploadIncomplete:

Bakery3Error: Could not upload scene.glb (148.2 MB): 403 Forbidden

Why: The presigned upload URL was rejected. These expire, and they
     are signed over an exact set of headers.
Fix: Retry the render. If it keeps failing, check for a service
     worker or proxy that rewrites request headers.

Files go straight from the browser to storage on a signed URL. If the error keeps coming back, the usual cause is a service worker or a corporate proxy that adds, drops or rewrites a request header.

The same render twice comes from the cache

If you ask for a render that was already made in the same project (same scene, camera, size and quality), you get the existing image back. It is not rendered again, and it costs nothing. This works for as long as the first image is stored, which is the project's retention: 30 days by default.

When we update the renderer, the cache starts fresh, because the image could come out different.

Stop a retry from rendering twice

Pass an idempotencyKey. A second call with the same key returns the first render instead of starting a new one, so your own retry button cannot charge twice.

await bakery3.render({ idempotencyKey: `sku-${sku}-hero-v3` });

See Render image for more.

Delete your uploaded files

Delete one file by its hash, or every file in the project. Call it from your server, because it needs your secret key.

import { Bakery3Server } from '@oeave/bakery3/node';

const bakery3 = new Bakery3Server(process.env.BAKERY3_SECRET_KEY!);

await bakery3.assets.delete('sha256:9f2b…');
// { hash: 'sha256:9f2b…', deleted: true }

await bakery3.assets.deleteAll();
// { deleted: 240 }

Delete uploaded files on a project in Settings deletes every file too, and the REST API has a route for each. The next render uploads what it needs again. A render still waiting in the queue for a file you deleted can fail, and a failed render costs nothing.

Privacy and retention

Results are private by default and served from signed URLs that expire. Your files are kept under your own project. A file no render has used for the project's retention window (never less than two days) is deleted on its own. See Limits for the numbers.