Guides

Generator selection

Pick a generator and see what it costs.

Choosing the generator is the largest cost and capability decision in a PixelKiln manifest. The figures here were measured against a live PixelLab account; ENDPOINTS.md contains the detailed experiments.

Quick choice

You needGeneratorMeasured costCandidates/output
Standalone prop or icon with arbitrary dimensionsmap (default)1 generation1
Exact fixed palettepixflux, or imagePro for a larger or non-square canvas1 generation (imagePro: 10–25)1 inline image (imagePro: 1–64 by size)
Candidate variety, richer rendering, future rotation/animation1dir10–25 generations4–64 by size
Ground tiles or connectable structural setstiles10–25 generationsvariations or complete set
Two-terrain Wang tileset for elevation (grass to water, floor to cliff), or a sidescroller platform setterrainPro 15 at 32px and sidescroller 3, Pro 25 at 64px, standard 3 (all measured; standard plans at 4)16 or 25 tiles
Platform tileset for a sidescroller (stone body, grass top)terrain, terrainOrientation: "sidescroller"3 generations16 tiles
A single elevation tile — a raised mesa, a cliff blockisometricTile1 generation1
Larger or non-square scene or background, up to 792 wide and 688 tallimagePro10–25 generations by canvas1–64 by size
Controlled pose/expression sequence in ComfyUIframes0 free provider unitsone atomic ordered set
Animated GIF or spritesheet from Retro Diffusionanimation$0.07–$0.25 per animation (published price)1 GIF or PNG sheet
A character facing 4 or 8 directions, its poses, and its animationscharacter1 per base (standard), 10–25 per pose or portrait, 1 per template loop (2–4 as skeleton-v3), 20 per outfit (measured once)one set of directions, one ordered loop, or one portrait
A prop, creature, or vehicle with rotations, states, or loops but no character rigobjectProabout 6 per base at 64px (unmeasured)one set of directions, or one ordered loop
UI chrome — panels, buttons, health bars, toolbarsuiAsset20 generations (measured once, at 256x192)1 composited image
One UI element from a description, 16px and up, optionally guided by a concept imageuiElement10–25 generations (unmeasured)1 image
A styled still on the Pro Flash model, or the south sprite a Pro Flash character will rotateimageProFlash5–9 generations (PixelLab's provisional quote)1 image
An animated effect (spell, hit, explosion, aura), on its own or around a spritevfxfree from presets and parts; 1–28 when described to PixelLab's artist (lite measured at 1; plans at twice the quote)one ordered frame set

Start with map unless a required capability points elsewhere. Twenty-five map re-rolls cost the same as one 64×64 1dir call.

terrain and imagePro have no section below: their fields and limits are in the PixelLab skill reference, including Pro's border controls, sidescroller sets, and connecting sets that share a terrain (an asset's connect), and a terrain set's export shape is in Tiles. Retro Diffusion animation styles are in Set up Retro Diffusion.

map

map calls PixelLab's map-object endpoint. It is purpose-built for isolated props, badges, and icons, supports arbitrary width/height, and costs a flat one generation at every supported size.

Use it when:

  • one result per prompt is acceptable;
  • prompt prose can carry the style;
  • exact palette conformance and reference-image transfer are not required.

It does not accept style images or a forced palette. On a measured 1-bit restyle, switching from reference-anchored generation to map changed median palette distance from 6.6 to 41.9; cheap output is not cheap when unusable.

The API describes map objects as transparent, but both 256px isolated-object attempts in the environment provider benchmark were opaque. map has no noBackground control in PixelKiln. Check alpha before assuming the file can be placed directly over a map.

Drawing into a scene

A map asset can declare a scene: an existing picture of the place the object belongs in (a floor, a room, a level). PixelLab draws the object into that scene and in its style, which is the one way to match a specific map's look without a style image. The price is still one generation.

"barrel": {
  "prompt": "a small wooden barrel",
  "width": 64, "height": 64,
  "scene": { "image": "maps/tavern-floor.png", "placement": { "oval": 0.3 } }
}
  • scene.image is a manifest-relative PNG. It can be another asset's output; until that file exists, plan shows this asset as blocked. Its bytes are part of the spec's identity, so a redrawn scene makes the object stale.
  • scene.placement is where the object goes: { "oval": f } or { "rectangle": f }, a region PixelLab generates covering f (0.05–0.95) of the scene, or { "mask": "path.png" }, a PNG the size of the scene, white where the object goes and black for context. The default is { "oval": 0.3 }, PixelLab's own.
  • PixelLab only. Other providers refuse scene when the manifest is resolved.

Unverified until a real call is billed: whether the scene has to match the object's width/height or can be a larger picture; where an oval or a rectangle sits, since the API takes no position (presumably centered); and whether the result is the object alone or the object composited into the scene. Check the first result before drawing a batch.

1dir

1dir is the single-facing sibling of PixelLab's rotatable/animated object pipeline. It is square and priced by canvas area:

Pixel areaCost
≤102420
≤204825
larger40

Candidate count is also size-derived and does not reduce price:

Square sizeCandidates
≤4264
≤8516
≤1704
>1701

Use 1dir when candidate comparison, rendering detail, rotations, or animation justify the price. Style reference images are its strongest consistency tool. The largest reference determines output size, so references should already be at the target resolution. Keep style references separate from live assets: editing a reference intentionally invalidates every spec using it.

Candidate scoring is deterministic RGB palette-distance arithmetic. No LLM selects the artwork; the local contact sheet exists for human judgment.

Batch: several distinct objects for one call's cost

1dir's own candidate mechanic (the table above) normally returns several variations of one prompt to choose from. PixelLab's /create-1-direction-object also accepts item_descriptions: instead of N variations of one thing, N different described things, for the exact same canvas-tiered price — a loot table's worth of icons for the cost of one call.

One asset is the batch leader (an ordinary 1dir asset; its own prompt is implicitly slot 0), and its siblings claim the remaining slots:

{
  "assets": {
    "chest": { "prompt": "a treasure chest" },
    "potion": { "prompt": "a health potion", "batch": { "of": "chest", "index": 1 } },
    "key": { "prompt": "a rusty key", "batch": { "of": "chest", "index": 2 } }
  }
}

index is 1-based, unique, and contiguous among siblings (the leader is implicitly 0); the total (1 + members) cannot exceed the size's own candidate count from the table above (16 at ≤85px, for example). Every member must share the leader's exact canvas size — they are one API call, one size.

Only the leader spends. Its estimate() prices the whole call, same as a standalone 1dir asset of that size; every member reports zero cost, so --budget never double-counts one call across N lock entries. Submitting fans the leader's one job out to every member's own lock entry directly — members never call the provider a second time.

Every sibling's identity depends on the whole group. The spec hash includes the full ordered list of descriptions, not just an asset's own prompt, so changing any one member's text — or adding or removing a member — marks every sibling stale together. This isn't a choice pixelkiln made: PixelLab has no endpoint to add one more item to an already-submitted batch, so a batch's membership needs deciding before it's generated. Growing an existing batch later means declaring a new one, not editing the old.

Review works exactly like any other 1dir asset, once per sibling: each lands in pixelkiln pick independently (all sharing the same, real candidate set), and picking a different index for each is what actually turns N generated frames into N separate, kept assets. A member's row starts already scrolled to, and marked DECLARED, at its own declared index — a hint from the confirmed slot order below, not a forced choice; any candidate in the set can still be picked for any sibling.

Confirmed live against a Tier 2 account: a 32px, 3-item batch (a chest leader plus a potion and a key member) billed exactly 20 generations — the ordinary 1dir floor tier, unaffected by item_descriptions — and item_descriptions[0] does own candidate slot 0: frame 0 came back as the chest, frame 1 as the potion, frame 2 as the key, in exactly the declared order. The remaining candidates (61 of 64, at this size) are the model's ordinary per-slot variety, not repeats of any one description — free bonus material, not additional declared items. Only confirmed at this one size; whether the cost table's higher tiers hold unchanged is still unconfirmed.

pixflux

pixflux costs one generation, returns inline without polling, and supports a hard palette constraint:

"gameboy": {
  "generator": "pixflux",
  "palette": ["#0f380f", "#306230", "#8bac0f", "#9bbc0f"],
  "outDir": "art/gameboy"
}

A palette prompt is a request; pixflux's swatch is a constraint. Measured two- and four-color outputs contained exactly the supplied colors.

Trade-offs:

  • rendering is flatter than 1dir;
  • style reference images are unavailable;
  • the same color_image payload does not work on map;
  • inline results are temporarily cached between submit and fetch;
  • noBackground defaults to true in PixelKiln, which is correct for sprites but wrong for scenes and banners.

Set noBackground: false for full-bleed artwork. Prompt prose cannot undo a post-generation background-removal step.

tiles

tiles calls the tile-pro endpoint and understands tile geometry and connectable output sets.

"ground": {
  "generator": "tiles",
  "tileSize": 32,
  "tileType": "isometric",
  "tileView": "low top-down",
  "outlineMode": "segmentation",
  "outDir": "assets/tiles/src"
}

Independent variations enter the normal review-and-pick flow. A tileFeature instead creates a structural set in provider order:

FeatureMeaning
roads18-configuration connected path/road set.
tileset16-tile Wang-corner terrain transition.
buildingFloor/wall/doorway/pillar/stair construction kit.

Describe a tileset asset as the transition, "fairway grass to rough meadow", rather than one terrain. Every returned member is required, so PixelKiln records numerical roles such as tile-00 rather than treating them as choices.

Important constraints:

  • Style mode copies geometry from styleImages and ignores tileType and tileView. It is useful when new independent tiles must match an existing ground plane.
  • tileFeature and styleImages cannot be combined; PixelLab rejects it and the manifest catches it before spending.
  • Use outlineMode: "segmentation" for continuous ground. The provider default outlines every tile, which produces dark seams when repeated.
  • Six-edge and unknown adjacency families remain lossless in generic export but are rejected by engine exporters that cannot map them safely.

See tiles and engine exports.

frames

frames currently belongs to ComfyUI. It repeats one committed still-image workflow while varying one explicit per-asset binding, such as an ordered set of pose PNGs. It is not video diffusion. The whole sequence stays one planned, reviewed, downloaded, refined, and approved asset; partial sets never become packaging input.

Keep a fixed seed for identity, or opt into a deterministic seedStep. Use a quality profile so every frame shares one palette and must agree on detected native grid step and phase. The review page animates the sequence, shows the ordered strip, and lets the reviewer pause playback. It starts paused when the system requests reduced motion and stops while it is offscreen. After approval, pack emits the sprite sheet and stable asset/frame-XX atlas ids. See Set up ComfyUI.

character

character is PixelLab's character family as managed assets: a base drawn facing 4 or 8 directions (from a prompt, or from your own south-facing sprite with reference), states (a pose or a text-edited outfit) that PixelLab applies to every direction of an existing character, animations, one loop of one character in one direction, portraits, a bust made from the south sprite, and outfit transfers, an existing loop's frames re-clothed from a reference image instead of text. A state, animation, portrait, or outfit depends on its parent the way a revision does: the parent must be downloaded and current before the child can be submitted, and regenerating the parent makes the child stale.

AssetPixelLab callCost
base, mode: standardcreate-character-with-4/8-directions1
base, mode: v3create-character-v31 + ceil(size² × 8 / 65536): 2 at 64px, 3 at 128px; from a reference, the rotations alone on its canvas: 1 at 64px
base, mode: procreate-character-pro10–25 by canvas
base, mode: pro-flashcreate-character-pro-flashimage tier (5 to 96px, 6 to 208px, 9 above) + ceil(size² × 8 / 65536): 6 at 64px, 8 at 128px, 17 at 256px; rotations only from a reference
statecreate-character-state10–25 by canvas
animation with a templateanimate-character1
animation from text (v3)animate-characterceil(size² × frames / 65536): 1 at 64px, 2 at 128px
animation, mode: proanimate-character10–25 by canvas
portraitportrait-character-pro10–25 by size (16px billed exactly 20 live, before the October 2026 cut)
outfittransfer-outfit-v220 (a 2-frame, 92×92 job billed exactly this live; not yet measured at other frame counts or canvases)

The 20–40 tiers are PixelLab's; the tier is resolved from the canvas when the job runs and reserved against the floor, so plan reports the tier the canvas lands in. plan prices a 64px state at 40 (the 1dir tier for that many pixels); one live 64px state in September 2026 moved the balance by about 22, so the estimate reads high, which is the safe side for a budget. poll now reads what a job like this actually billed and records it alongside the estimate as billed; pixelkiln history, plan --json, and the gallery show both when they differ, though gen's wave budget still spends against the (safe-high) estimate. Every direction of a base or state is one file (<asset>-south.png, ...); an animation's frames are <asset>-frame-00.png onwards, with the resting pose as frame 0 unless keepFirstFrame is off. enforcePalette snaps all of them. Since each direction of a loop is its own generation, declare the east-facing loop as a mirror of the west one (and each diagonal as a mirror of the other) and PixelKiln flips it locally for nothing; see Mirrors. pack --format godot writes each base direction as a still and each animation as a looping set. The gallery labels a state or loop with its parent ("state of bot", "loop of bot.dented, east"), links parent and children in the record, and counts the family in the style header ("3 characters, 4 states, 6 loops"). See Characters.

objectPro

objectPro wraps PixelLab's /create-object-pro-flash — the same base → state → animation family as character, for PixelLab's separate, skeleton-free "object" entity. Use it for a prop, creature, or vehicle that needs a pose (state) or a directional loop (animation) but has no humanoid/quadruped rig to fit: a floating rune, a treasure chest, a turret, anything character's template concept does not describe.

It reuses character's own authoring shapes — asset.state/asset.animation are the identical fields, and a mirror flips an animation's direction the same way. Everything character's templates/proportions/skeleton bring is simply absent: no mode, template, proportions, isometric, concept, or styleCharacter — /create-object-pro-flash is the only base-creation path, and setting animation.template/subject/outline/shading/detail on an objectPro animation is rejected at resolve time rather than silently ignored, since none of them reach the API for an object.

  • objectDirections (1 or 8, default 8, style-level) is the rotation count — a real choice character does not offer (character pro-flash is always 8). A 1-direction object's animation.direction must be south; anything else is rejected, since the endpoint 400s if directions is even sent for a 1-direction object.
  • reference (asset-level, base only) rotates the author's own south-facing sprite instead of drawing from the prompt, same as character's reference — but only ever reads the south image, since one frame is all /create-object-pro-flash takes.
  • A style image anchors the look the same way character pro-flash's does, including styleTraits (which of the image's palette/outline/detail/shading to carry over).
  • Regenerating an already-animated direction is simpler than character's: the object endpoint has its own replace_existing flag, so PixelKiln always passes it rather than fetching the object first to find and delete a prior take (character's own workaround for not having one).
  • pixelkiln gallery --edit shows an objectPro family the same way it shows a cast — states under their base, loops with their direction — and a base or state's drawer offers "+ New state" and "+ New animation", restricted to the fields above (no template/subject, since neither applies). See Working with a cast.

Cost is not independently measured. objectProCost() assumes /create-object-pro-flash/its state/its animation price identically to character's own measured pro-flash formula (proFlashCharacterCost), since the request bodies are near-identical minus template_id — treat it as a working assumption, not a confirmed number, until checked against a live account.

Adoption (pixelkiln adopt) has not been extended for objectPro's own <object id>#<animation group id> remote-id scheme yet, unlike character's dedicated adoption path — a base may already be adoptable through the generic object-matching pixelkiln already does for 1dir/map, since a pro-flash object shares that same /objects identity space, but this is untested.

isometricTile

isometricTile wraps PixelLab's /create-isometric-tile — a different endpoint from both tiles (which also has its own isometric tileType for full connectable Wang/road/building sets) and terrain (/create-tileset, confirmed square-only, no isometric option at all). This one generates a single standalone isometric tile, no candidates, no connectable set.

Use it when a per-tile height/elevation primitive is what's needed — a raised mesa, a cliff block, a standalone rock outcrop — rather than a connected ground set.

  • isometricTileShape controls vertical thickness: "thin tile" (~15% of canvas height), "thick tile" (~25%), or "block" (~50%, the API default). This is a more direct elevation control than anything in tiles or terrain.
  • isometricTileSize is the API's own tile grid size, 16 or 32 (default 16) — a separate concept from size, the generation canvas (16–64px; the endpoint's own guidance is that sizes above 24px "often produce better quality results").
  • outline defaults to "lineless" on this endpoint specifically, unlike tiles-pro's "outline" default — its own valid values are "single color outline", "selective outline", or "lineless".

Cost: 1 generation flat, measured. PixelLab's own OpenAPI response schema example shows { type: "usd", usd: 0.02 }, which reads as billing in real dollars — but a real call against a live subscription account billed exactly 1 generation instead (usage: { type: "generations", generations: 1 }), and costUnit here is "generations" like every other generator. Only one size/tile-shape combination (32px canvas, "block") has actually been measured; the endpoint's own docs give no size-tiering formula the way 1dir/tiles do, so this assumes flat pricing across the 16–64px range rather than guessing a tier.

Style images, init_image/init_image_strength (image-to-image), and color_image (native forced-palette) are not modeled yet — PixelKiln's own palette/enforcePalette post-processing works generically on the downloaded tile regardless, if a closed palette is what's actually needed.

uiAsset

uiAsset wraps PixelLab's /create-ui-asset — panels, buttons, health bars, and other UI chrome, composited as one flat image. It is non-square capable like imagePro: width/height default to 256×256 but can be set per asset, subject to the endpoint's own aspect-gated size tiers (square up to 512×512, 16:9 up to 688×384, 9:16 up to 384×688, 4:3 up to 600×448, 3:4 up to 448×600; pixelkiln refuses anything under 192 or over 688 per side and leaves the exact aspect ceiling to the API).

Two asset-level fields, usable together or alone:

  • pieces: an array of exact shape regions (rounded_rect, circle, or polygon, each with a unique id and optional label) positioned on a virtual 0–512 coordinate canvas, independent of the actual output size.
  • elements: named, auto-positioned scaffolds — button, icon_button, toolbar, tab, panel, window, health_bar, avatar, triangle, pentagon, hexagon, octagon.

Omit both for a plain full-canvas panel from the prompt alone. A style-level uiColorPalette string (e.g. "brown and gold") is a free-text prompt hint sent as color_palette — a different, PixelLab-side concept from PixelKiln's own hex-array palette/enforcePalette (local quantization), which still applies to the downloaded image afterward if an exact palette is needed.

No cropping, no nine-slice, no states. GET /ui-assets/{id} returns one composited image with no per-piece sub-image or bounding-box data, confirmed absent from the response schema regardless of how many pieces/elements were requested — despite pieces' own precise coordinates, PixelLab does not hand back a way to split them out again. A themed variant of an existing panel (an empty vs. full health bar, say) needs no new mechanism: it is a plain revision (image-to-image) of the base panel, which already carries this for every other generator.

Cost: confirmed live at one data point — 20 generations for a 256x192 canvas, the low end of the create_ui_asset MCP tool's "20–40 generations" claim. PixelKiln still estimates with the same canvas-tier formula as 1dir/tiles, which predicts the 40 ceiling for every valid uiAsset size (its 192px floor is already past that formula's top tier) — the measured call proves the formula wrong here, since it billed the floor price at an area well above where 1dir/tiles would bill the ceiling. Left as an over-read for --budget until a second size is measured; see ENDPOINTS.md for the full writeup.

imageProFlash

imageProFlash wraps PixelLab's /create-image-pro-flash: one native pixel-art image on the Pro Flash model, the same model the character and objectPro pro-flash engines draw with, as a plain still. It sits between pixflux/map (1 generation, no style reference) and imagePro (10–25 by canvas):

{
  "styles": {
    "stills": {
      "generator": "imageProFlash",
      "styleImages": [{ "path": "refs/house-style.png" }],
      "styleTraits": { "palette": true, "outline": true, "detail": false, "shading": true },
      "outDir": "art/stills"
    }
  },
  "assets": {
    "knight": { "prompt": "a knight in blue armor, facing the viewer", "width": 64, "height": 64 }
  }
}
  • Sizes run 16 to 256 per side in multiples of 4, and can be non-square. PixelLab's native sizes (24, 32, 32×48, 64, 96×64, 96) are its most reliable; other sizes are its "custom (beta)" range.
  • One styleImages entry is the style image, and styleTraits choose what it lends (palette, outline, detail, shading; each on by default), the same switches a pro-flash character base takes. Traits without a style image are refused.
  • One call returns one image, recorded straight away. The lock also records PixelLab's image_id and source_image_id for it: a Pro Flash character or objectPro base whose reference is this image's downloaded file reuses it by that id instead of uploading the same pixels again (see Characters).
  • Cost: 5 generations up to 96px on the longer side, 6 up to 208px, 9 beyond, from PixelLab's own /pro-flash/cost quotes, which PixelLab calls provisional. The billed amount on the finished job is what the lock keeps. plan and gen use these tiers offline. The gallery's price quote (--edit) asks the endpoint itself when the project has a PIXELLAB_API_KEY, and marks those rows live.

The same model also edits and inpaints: "engine": "pro-flash" on an image-to-image or inpaint revision; see Controlled asset revisions.

uiElement

uiElement wraps PixelLab's /generate-ui-v2 ("Generate UI (Pro)"): one UI element — a button, a health bar, an inventory slot, a dialogue box — from the prompt alone. Where uiAsset lays a panel out from pieces/elements on a 192px-and-up canvas, uiElement has no layout vocabulary and goes down to 16×16, which suits icons and small widgets:

{
  "styles": {
    "hud": {
      "generator": "uiElement",
      "uiColorPalette": "brown and gold",
      "styleImages": [{ "path": "refs/hud-concept.png" }],
      "outDir": "art/ui"
    }
  },
  "assets": {
    "slot": { "prompt": "wooden inventory slot with metal corners", "width": 32, "height": 32 },
    "hp-bar": { "prompt": "health bar with a red fill", "width": 96, "height": 16 }
  }
}
  • width/height default to 256×256 and can be non-square: 16 up to 792 wide and 688 tall, with the exact ceiling set by aspect ratio upstream (square tops out at 512×512, 16:9 at 688×384).
  • The style's single styleImages entry, if any, is sent as the endpoint's concept_image: design guidance for the element, not a strict style transfer. More than one is refused.
  • uiColorPalette is sent as color_palette, the same free-text hint uiAsset takes. PixelLab removes the background by default; set noBackground: false on the style to keep it.
  • One call is expected to return one image, recorded straight away. If the endpoint ever returns several, they go to candidate review like imagePro's.

Unmeasured. The schema carries no usage example and no call has been billed yet. The plan prices it on the same 10/15/25 canvas tiers as 1dir/tiles, the safe over-read for a Pro endpoint, and the completed job's shape is read defensively (pollUiElement names the keys it got if the shape is not the documented images list).

vfx

vfx renders animated pixel-art effects with PixelLab's VFX workbench: spells, hits, explosions, auras, shields, status icons, weather. The workbench is a renderer, not a model. An effect is a recipe of layers, most of them dropped in as tuned parts, and it renders the same pixels every time. It is free on a PixelLab subscription, and PixelLab offers it only over MCP, which pixelkiln calls with the same PIXELLAB_API_KEY. An effect can also be described in words for PixelLab's paid VFX artist; see Described effects.

{
  "styles": {
    "fx": { "generator": "vfx", "outDir": "art/fx" }
  },
  "assets": {
    "robot.zap": {
      "prompt": "lightning on the robot",
      "vfx": { "preset": "lightning_strike", "sprite": "art/chars/robot-south.png" }
    },
    "boom": {
      "vfx": { "preset": "explosion", "parts": [{ "name": "scorch_mark" }], "fps": 12 }
    },
    "zap.tuned": {
      "vfx": { "recipe": "fx/zap.vfx.json" }
    }
  }
}
  • Start from one preset (pixelkiln vfx presets lists them) or one recipe, and add parts (pixelkiln vfx parts) on top. parts alone also start an effect. Each part is { "name": … } plus any of the workbench's own options, sent as given: size, colour, amount, speed, start, end, anchor, at, offset, travel, role, params.
  • recipe is a bare recipe JSON or a .vfx.json record written by pixelkiln vfx. That is how an effect tuned by hand, in the workbench or with the sliders on pixellab.ai, enters a manifest: export it with pixelkiln vfx --effect <id> --out fx/zap, then point recipe at the record.
  • sprite builds the effect around a character: a manifest-relative PNG or JPEG, or a character:<id>:<direction>, object:<id>, or gallery:<id> reference. A path may be another asset's output. Until that file exists the effect is blocked, and gen renders it in a later wave once it does. The exported frames include the sprite.
  • fps overrides the preset's or recipe's own rate. name is the effect's name in your PixelLab My effects; it defaults to pixelkiln:<style>/<asset>. prompt is optional and only a label.
  • An asset that lists no styles joins every style of its own kind: a vfx style takes the assets with a vfx block, and every other style the assets without one. A mirror or revision of an effect names its style.

The workbench builds an effect from tuned parts. An effect that is a drawn object or a character's own motion, like a sword turning into lightning or a mage casting a fireball, is a job for generation instead: an imagePro sheet of candidates, then an animate-pixminimax revision with an optional lastFrame. PixelLab's VFX tutorial shows that workflow, and Set up PixelLab maps it onto PixelKiln.

Outputs. The exported spritesheet is cut into frames, <asset>-frame-00.png onward, recorded as an ordered frame set with the effect's fps and whether it loops. pack lays them out like any loop, and pack --format godot writes a one-shot effect with loop: false. The gallery plays them, shows the rendered size, and links each generation to its effect on pixellab.ai.

Identity. An effect goes stale when its preset, parts, fps, recipe content, or sprite content changes. It does not go stale for a renamed or moved file, a new name or prompt, or a style's prompt, size, or palette settings, none of which reach the workbench. Plan cannot see slider changes made on pixellab.ai or changes to PixelLab's own presets.

Regenerating. A regeneration exports over the effect the asset rendered last time, so My effects keeps one entry per asset. If that effect was changed on pixellab.ai since, or deleted, a new effect is saved instead and the edited one is left alone; the lock records why.

Described effects: the paid VFX artist

A description in place of a preset, recipe, or parts asks PixelLab's VFX artist (POST /vfx, added in 0.4.130) to build the effect. The artist is the same one behind the website's VFX creator: it picks and tunes parts from your words, renders the effect, checks its own work, and saves it to My effects.

"zap.described": {
  "vfx": {
    "description": "a blue lightning strike that hits the ground and leaves sparks",
    "artist": "pro",
    "sprite": "art/chars/robot-south.png"
  }
}

Use the free workbench when a preset or a few parts get you there, or when you want to tune the effect by hand; it renders the same pixels every time. Use the artist when you would rather describe the effect than assemble it. It costs generations, and the same description draws a different effect each time.

  • description is the effect in plain words: what it is, its colours, how it moves, how long. It cannot be combined with preset, recipe, parts, or fps; the artist picks those itself.
  • artist is lite (the default, quick and cheap) or pro (the stronger artist, for detailed effects).
  • sprite must be a local PNG up to 512×512, another asset's output included. The endpoint takes the sprite's pixels, so character:, object:, and gallery: references are refused; point at the character's own output file instead. JPEG is refused too.
  • name is capped at 80 characters, and the default is cut to fit.

Cost. PixelLab quotes each job when it is submitted and bills on delivery: the quote, or more when the effect ran long, never more than twice the quote. The quote comes from this table (generations):

litepro
no sprite, or a sprite up to 128 px16 (8 with a sprite)
sprite up to 256 px314
sprite up to 512 px528

plan and --budget count twice the quote, the most a job can bill, so a budget is never overrun. A sprite that is another asset's output not drawn yet is priced at the 512 px tier until it exists. The lock records PixelLab's own quote (quotedGenerations) and the bill read from the finished job. These prices are PixelLab's published table; no artist bill has been measured here yet.

Outputs and identity. The artist's spritesheet is cut into the same ordered frame set as the workbench's, with its fps and loop flag. The lock records the effect id, its edit link, the artist's message, the anchor, the parts it used, and the file names. The asset goes stale when its description, artist, or sprite content changes, and not for name or prompt. Adding these fields left every workbench effect's identity as it was.

Regenerating. Every regeneration is a new effect, billed again. The manifest's description is the whole effect, not a change to the last one, so it is never sent as one. The previous effect stays in My effects, and the lock names it (previousEffect). To change one saved effect in place at the change price, use pixelkiln vfx --description "<what to change>" --effect <id> (CLI). To turn a described effect into a free, repeatable recipe, export it with pixelkiln vfx --effect <id> --out fx/zap and point a workbench recipe at the record.

Style variants

Styles are namespaces. Add another style to re-derive the same asset ids into a separate output directory and separate lock keys:

"styles": {
  "base": { "generator": "map", "outDir": "art/base" },
  "neon": {
    "generator": "1dir",
    "size": 64,
    "promptPrefix": "neon-noir game icon",
    "promptSuffix": "magenta/cyan rim light, transparent background",
    "styleImages": [{ "path": "art/style-refs/neon.png" }],
    "outDir": "art/neon"
  }
}

Seed a prose-only variant with two or three assets, commit the best results as dedicated references, then generate the remainder. Reference images control inherent subject colors more reliably than prose alone.

Limits and post-processing

PixelLab submissions must be spaced more than two seconds apart and concurrent background jobs are tier-limited. PixelKiln enforces both globally.

Image-in/image-out resize, rotate, and pixel-art conversion endpoints are generative and can change a closed palette or alpha channel. They cost the same as a fresh one-generation image. Regenerate at the target dimensions when palette fidelity matters; background removal is the measured exception, a real de-fringe pass.

PixelLab's portrait, outfit-transfer, lip-sync, and skeleton-driven animation endpoints are outside the current library scope; the character family itself is the character generator.