# Hosted image generation

Create an image Block with any catalog model, settings and reference images, paid with StillMade credits.

Use `runtime: "capability"` with `operation: "image.generate"` for one visual
prompt (and optional reference images) to one generated PNG. Every image model
the app's own Canvas and Image Panels use is available: Nano Banana 2, 2 Lite and
Pro, GPT Image 2 and 1.5, Kling Image V3 and Seedream 4.5, with their aspect
ratios, resolutions and qualities (see
[generation models](/docs/reference/generation-models)). Users pay with their
StillMade credits at StillMade's own price, or with their OpenAI key for the
direct GPT Image 2 option. The host shows model, settings and the exact price
before any provider call. Imported packages never receive API keys or choose an
endpoint or a price.

### Complete package

The downloaded SDK includes `examples/generate-image.stillmade.json` and
`packages/block-sdk/image-generation-example.js` (export `imageGenerate`).

```json
{
  "manifest": {
    "schemaVersion": 1,
    "sdkVersion": "0.1.0",
    "id": "example.generate-image",
    "version": "1.0.0",
    "name": "Generate an image",
    "description": "Generate a square PNG from a short visual prompt using an approved host request.",
    "kind": "task",
    "runtime": "capability",
    "entry": "src/capability.json",
    "license": "MIT",
    "inputs": {
      "prompt": {
        "type": "text",
        "primary": true
      }
    },
    "outputs": {
      "image": {
        "type": "image",
        "primary": true
      }
    },
    "permissions": {
      "project": [],
      "capabilities": [
        "image.generate"
      ],
      "network": [],
      "filesystem": [],
      "secrets": []
    },
    "ui": [
      {
        "control": "text",
        "port": "prompt"
      }
    ]
  },
  "capability": {
    "schemaVersion": 1,
    "operation": "image.generate",
    "prompt": {
      "$input": "prompt"
    },
    "output": "image"
  },
  "tests": [
    {
      "name": "A simple forest illustration",
      "input": {
        "prompt": "A simple illustration of a quiet forest with clear dark outlines and soft green colors."
      },
      "expectations": {
        "image": {
          "kind": "image",
          "format": "png",
          "width": 1024,
          "height": 1024,
          "minBytes": 67,
          "maxBytes": 12000000
        }
      }
    }
  ]
}
```

### Inputs and controls

Declare exactly one primary input of type `text`, `script`, or `brief`, optionally
one `image` or `image[]` input of reference images, and one primary output of
type `image`. Script and brief values contain `schemaVersion:1`
and `text`; text ports receive a string. The resolved prompt must contain
1–32,000 characters and cannot be blank. Existing declared project context read
scopes can supply that input through the normal host resolver.

The descriptor contains `schemaVersion`, `operation`, `prompt` and `output`, and
optionally:

- `settings`: the Block's default `{model, aspectRatio, resolution, quality}`.
  Each value must be one the model accepts; axes a model has no knob for are
  `"default"`.
- `references`: `{"$input":"refs"}`, binding the declared `image`/`image[]`
  input. Up to 8 saved images; the model must edit from references (the Nano
  Banana family and GPT Image 2).
- `negativePrompt` (up to 2,000 characters) and `seed` (0–2147483647).

Declare exactly `capabilities:["image.generate"]`; network, filesystem and
secrets permissions stay empty. Payment, credentials and price are never
descriptor fields.

```json
"capability": {
  "schemaVersion": 1, "operation": "image.generate",
  "prompt": {"$input": "prompt"}, "references": {"$input": "refs"},
  "settings": {"model": "nano-banana-pro", "aspectRatio": "16:9", "resolution": "2K"},
  "negativePrompt": "text, watermark", "output": "image"
}
```

In StillMade, the run dialog preselects the Block's default model and settings;
the user can change them before running and sees the exact credit price. Every
review fixture and the separate sample is included in the displayed total. The
direct OpenAI option (fixed 1024 × 1024, your own key) takes text prompts only.
Reference images must be saved in the user's own library; anything else is
refused before any credit is spent.

### Output and tests

The output is an exact reference to a retained PNG:

```js
{
  kind: "image", assetId, versionId, url,
  mimeType: "image/png", width, height, bytes
}
```

The host bounds the provider response, decodes the actual PNG, JPEG or WebP,
stores one sRGB PNG under an immutable hash and measures its `width`, `height`
(up to 8192 a side and 40 megapixels) and `bytes` (up to 64 MiB); package code
cannot assert those measurements on its own. `assetId` identifies the execution's
image, `versionId` is its saved SHA-256, and `url` is a StillMade media URL.

Each fixture requires `expectations` for the declared output: `kind:"image"`,
`format:"png"`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `minBytes` and
`maxBytes` (ordered integers within the limits). Older fixtures that name the
fixed `width:1024, height:1024` square remain valid.
These checks verify a usable image contract. They cannot prove the picture
matches the meaning of the prompt; inspect the actual image before acceptance.

### Review, preview and project use

Upload the package to run schema, dependency, permissions and static checks.
Offline CLI validation and packaging can pass those checks but report that live
review is required; offline test/preview cannot call the provider or produce a
placeholder. In StillMade, review the cost, confirm generation, inspect every
fixture and sample, finish the review, then **Confirm Import**.

A project run has its own current prompt and quote. **Use this image** accepts
its reviewed output. Compatible image inputs can consume that result through
the host's existing image resolver; sandboxed pixel processing receives actual
decoded pixels rather than a guessed URL. Accepted current project results also
appear in the Editor's visual media inventory. Earlier placed images keep their
original source when the generating Block runs again.

A custom interface can use the existing `StillMade.run` flow. Host image
previews remain outside the isolated iframe, and guest code cannot supply
execution receipts or access the provider. No `generateImage`, provider-key or
arbitrary fetch API is added to the guest interface.

### Host integration and recovery

`prepareCapabilityInvocation` returns `{operation:"image.generate",prompt}` plus
`references`, `negativePrompt` and `seed` when declared. A credit selection is
`{payment:"credits",provider:"stillmade",model,aspectRatio,resolution,quality}`;
the direct key option stays `{provider:"openai",model:"gpt-image-2",size:"1024x1024",quality,payment}`.
`capabilityOutputs(package, imageReference)` maps the generated reference to the
named output. `validateGeneratedImageReference` and
`defaultCapabilityExpectations` enforce the declared shape and bounds.

A trusted executor may return `{outputs, metadata, mediaReceipts}`. The receipt
map is keyed by the output port; each receipt contains its `schemaVersion` (3 for catalog images), all
canonical image fields, plus `ownerId`, `runId`, `index`, `storageKey` and
`sha256`. SDK validation checks shape and equality to the output. The
authenticated host additionally binds owner/run/index and reads the saved bytes
again during review acceptance and completed-result recovery. The receipt is
host evidence, not a credential or a guest-authored permission grant.

Execution uses one exact provider request per invocation, without automatic
provider, payment or model fallback. An uncertain submission is not retried
automatically. Cancelling stops further work and acceptance; it cannot promise
that a remote provider stopped or that already-generated output was free.
Received output that fails storage or contract checks remains a charged request;
a definite provider rejection follows the existing refund path.

Automated checks use local image fixtures and mocked providers. They do not
claim a successful live provider image test. Each account must complete its
actual hosted review before importing a generated-image Block.

### Connected production runs with hosted Blocks

Inside a project, **Run connected steps** passes the actual previous result to
each next Block. Hosted text, speech and image Blocks use StillMade's existing
model and payment dialog for each call. Confirm its cost before execution; a
Block cannot choose approval or payment. Waiting for this choice does not consume
the local sandbox timeout. Cancelling stops downstream work and preserves already
completed results. Use **Use completed results** to adopt them into the project.

Saved hosted results are rechecked against the signed-in account's server run,
including the exact project, source, input, selection, quote and retained media.
This verification does not generate again. Standalone import reviews are not
production outputs. Unattended hosted automation is not enabled by this control.
