One image, every screen: resizing, smart crops, splits and layouts

The deterministic image operations on Kugel Platform: responsive variants, smart crops, exact transforms, layouts and splits, and QR codes or barcodes, with live examples from 2026-10-15, the limits as read that day, and the warnings to expect.

19 min read By Platform Documentation Guide #Publishing

Image operations

One source image, every shape a page needs

A single illustration often has to serve as a wide hero, a square thumbnail, a social card, a phone-sized banner and a round avatar. Exporting each one by hand is slow, and a hand crop can cut through the subject.

Kugel Platform includes a set of deterministic image operations for this work: resize, crop by rectangle or by content, convert between formats, split an image into pieces, combine images into one layout, and draw a QR code or barcode. Deterministic means the same image and the same settings produce the same result, and no image model is involved.

Every operation saves its result as a new artifact, which is a stored image file with its own address, and leaves the original untouched. Running one does not publish anything. This article was produced the same way: every image in it was made on 2026-10-15 by the operations it describes, starting from two images that already existed in this site's store.

Core terms

Seven terms cover everything below

Each term is defined once here and used in the same sense in the rest of the article.

  • Artifact. A stored image file that belongs to one article or page. Its public address starts with /img/, followed by the owner's id and a fingerprint of the file's content, so a changed file always has a new address.

  • Adopt. An image operation accepts only a source that belongs to the same request as the article it serves. The adopt_artifact tool brings an existing image from another request into this one by reference, and no file is copied. Both source images in this article were adopted this way.

  • Manifest. The record saved with every result: the source's fingerprint, the tool, the settings, the limits that applied and the method version, which read image-ops/1 on 2026-10-15.

  • Variant. The same picture at another width or in another format. A variant is never enlarged beyond its source.

  • Smart crop. A crop to a requested shape, such as 1:1, 16:9 or 3:1, whose position is chosen by an estimate of which part of the picture draws the eye most (saliency). The reply gives the chosen rectangle and a score.

  • Layout and split. A layout places several images on one canvas as a grid, a collage or a contact sheet, which is a grid with captions. A split does the reverse: detect_regions finds the pieces and split_image saves each one as its own artifact.

  • Code. A QR code or barcode drawn from exact text, then decoded again with read_codes to confirm that it says what was intended.

How it fits together

Write tools, read-only tools, and the order to use them

The tools fall into two groups. Seven write something new: image_transform, smart_crop, make_variants, split_image, compose_layout, generate_code and adopt_artifact. Three only look and change nothing: detect_regions, read_codes and measure_image_geometry. The diagram shows the order every writing operation follows.

How an agent uses them, in order

  1. Find the source. list_artifacts_by_kind lists the images already in the store, and search_artifacts is the other way to look. adopt_artifact brings the chosen image into the article's request.

  2. Choose the operation by the result needed. An exact size, a format or a mask: image_transform. A crop that keeps the subject in frame: smart_crop. Several widths and formats: make_variants. Cutting one image apart: split_image, with detect_regions to preview the cuts. Putting images together: compose_layout. A QR code or barcode: generate_code.

  3. Read the reply. Every reply lists its warnings and the limits it used. Warnings never block. A refusal returns a short message and writes nothing.

  4. Look at the result and, where it helps, measure it. Open the returned address, run measure_image_geometry against an expected aspect ratio, or run read_codes against a code.

  5. Embed the result. Use the returned public address, which starts with /img/, in the article. The article then follows its normal save, validate and publish path.

An agent connected to this site calls the tools in this order. How the admin chat words such a request was not tested for this article.

A four-step vertical diagram. Step 1, source stays untouched: adopt the image into the article's request first. Step 2, one deterministic operation runs, naming image_transform, smart_crop, make_variants, split_image, compose_layout and generate_code. Step 3, new artifacts are saved, each with its own address and a manifest. Step 4, read-only checks confirm it, naming detect_regions, read_codes and the measure tools.
Every writing operation follows the same four steps. Only step 3 saves anything, and the source is never changed.

Example 1

Responsive variants of one image

The source was an illustration of two people at a planning board, 1792 by 1024 pixels and 23,088 bytes as a WebP. One make_variants call with the default widths and the default formats, WebP and JPEG, returned ten files.

The default width list ends at 1920, which is wider than the source. The call skipped it, reported IMAGE_OPS_VARIANT_SKIPPED ("Width 1920 exceeds source width 1792; skipped (no upscaling).") and added the source's own width as the largest variant, reported as IMAGE_OPS_VARIANT_NATIVE_ADDED. Both are information, not errors.

File sizes in bytes, WebP then JPEG

  • 320 pixels wide: 2,990 and 5,864

  • 640 pixels wide: 6,292 and 14,209

  • 960 pixels wide: 10,282 and 24,542

  • 1280 pixels wide: 13,880 and 35,193

  • 1792 pixels wide: 21,460 and 52,224

For this flat-colour illustration the WebP was between 39 and 51 percent of the size of the JPEG at every width. Photographs behave differently, so measure rather than assume.

A second call asked for AVIF, WebP and JPEG at 640 and 1280 pixels wide. At 640 wide the files were 4,380 bytes (AVIF), 6,292 (WebP) and 14,209 (JPEG). At 1280 wide they were 10,469, 13,880 and 35,193. The three formats use different quality scales, with defaults of 55 for AVIF, 80 for WebP and 82 for JPEG, so this compares what the defaults produce and not equal visual quality. Whether a site should serve AVIF depends on the browsers it must support, which this article did not test.

The reply also carries a thumbhash, a very short text string (here 9igGDIL4ljh6h3Z9hYQGhXJgOA==) that a page can turn into a blurred placeholder while the real image loads. Repeat calls with the same settings returned files with identical fingerprints, so repeating a call does not create duplicates.

Five copies of an illustration of two people working at a planning board, in a grid of equal captioned cells. The captions read 320, 640, 960, 1280 and 1792 pixels wide, with file sizes from 2,990 to 21,460 bytes.
The five WebP variants on one contact sheet, from 320 pixels wide (2,990 bytes) to the native 1792 (21,460 bytes).

Example 2

A square crop and a 16:9 crop of the same image

One smart_crop call on the planning-board illustration asked for the shapes 1:1 and 16:9 at an output width of 900 pixels. It returned two crops and no warnings.

  • 1:1. The chosen rectangle starts 18.7 percent in from the left and spans the full height (source pixels 335 to 1359 across, 0 to 1024 down). Saved at 900 by 900 pixels, 16,580 bytes, score 0.001651.

  • 16:9. The rectangle covers nearly the whole picture (1792 by 1008 source pixels), because the source is already close to 16:9. Saved at 900 by 506 pixels, 9,716 bytes, score 0.001227.

measure_image_geometry confirmed the shapes. The 16:9 file measured 900 by 506 pixels with an aspect ratio of 1.7787 against an expected 1.7778, and the check passed. The square measured exactly 1.

Look at the square before using it. The person on the left and the board are whole, but the person on the right is cut at the edge of the frame. The same measurement shows why: the brightness of the right-hand 8-pixel edge strip averaged 0.8981, against about 0.945 on the other three edges, which means something darker than the pale background touches that edge. smart_crop picks the region its estimate favours, which is not always the one an editor would choose. When a subject must stay whole, use image_transform with a fixed rectangle instead.

The scores are small on flat illustrations, so compare crops of the same image with each other and do not read a score as a grade.

Square crop of an illustration. A seated person points at a planning board covered in cards on the left, and a second person seated on the right is cut off by the right-hand edge of the frame.
Smart crop to 1:1: 900 by 900 pixels, 16,580 bytes. The person on the right is cut by the edge.
Wide crop of the same illustration. Two people sit either side of a planning board covered in cards, and both are fully in frame.
Smart crop to 16:9: 900 by 506 pixels, 9,716 bytes. Almost the whole picture is kept.

Example 3

Smart crop against a fixed centre crop

The second source was an illustration of a woman reading a book, 1024 by 1024 pixels and 77,514 bytes. It was cropped to 16:9 twice.

  • Fixed centre crop, made with image_transform: a rectangle starting 224 pixels from the top and spanning the full width, then resized to 900 pixels wide and saved as WebP at quality 80. Result: 900 by 506 pixels, 30,936 bytes.

  • Smart crop, made with smart_crop: a rectangle starting 32 pixels from the top. Result: 900 by 506 pixels, 21,112 bytes, score 0.000433.

The fixed crop cuts through the eyes. The smart crop keeps the hair, the face and the top of the book in frame. The smart crop is also the smaller file, 21,112 bytes against 30,936.

The same call also asked for a 3:1 banner. It came back at 900 by 300 pixels, 11,790 bytes, score 0.000174. A shape that wide leaves room for little more than the face, so the hair and the chin are trimmed. An extreme shape loses content whatever method chooses the position.

Two crops of an illustration of a woman reading a book, side by side with captions. The left one, captioned fixed centre crop to 16:9, cuts the top of her face off at the eyes. The right one, captioned smart crop to 16:9, keeps her whole head and the top of the book.
Left: fixed centre crop to 16:9. Right: smart crop to 16:9 of the same image.
Very wide banner crop showing the head of a woman with dark hair and closed eyes, with the top of her hair and her chin trimmed by the frame.
Smart crop to 3:1: 900 by 300 pixels, 11,790 bytes.

Example 4

Exact sizes and shapes with image_transform

image_transform takes an ordered list of pixel operations, runs them in that order and saves one new artifact. Two jobs show the range.

  • A share card. Resize the planning-board illustration to 1200 by 630 pixels with fit cover, centred, then sharpen, then save as WebP at quality 85 with a ceiling of 40,000 bytes. Result: 1200 by 630 pixels, 17,640 bytes. The ceiling was met on the first encode, so no warning appeared.

  • A round avatar. Crop the reader illustration to a rectangle (10 percent in from the left, full top, 80 percent wide and high), resize to 480 by 480 pixels with fit cover, apply a circle mask, then save. Saved as PNG the file was 300,740 bytes. Saved as WebP at quality 82 it was 16,408 bytes. Both keep transparent corners.

measure_image_geometry on the WebP avatar reported that it has transparency and that 78.85 percent of its pixels are opaque, which is what a circle inside a square should give (a circle fills about 78.5 percent of its square). With no expected values supplied, the status was reported as not evaluated.

The PNG avatar shows why format matters. At 300,740 bytes it is nearly twice the 153,600-byte budget for article images. Validating an article that embeds it returned a media_budget warning naming the size and the budget and pointing to WebP as the preferred format. The warning does not stop a save. The WebP version is under the budget by a wide margin.

A misspelt option is refused before anything is written. The first share-card attempt used the position centre and came back with this message: invalid ops: ops[0].position: must be "center", "attention", "entropy" or {focal:{x,y}} with x,y in 0..1. Correcting the spelling to center and running it again produced the card above. The message also lists the accepted values: center, attention, entropy, or a focal point given as x and y between 0 and 1.

Wide card-shaped illustration of two people seated either side of a large planning board with coloured cards, on a cream background.
Share card: the planning-board illustration at 1200 by 630 pixels, centred, sharpened, saved as WebP (17,640 bytes).
Circular portrait of a woman with dark hair reading an open book, on a cream background inside the circle.
Round avatar: crop, resize to 480 by 480, circle mask, saved as WebP with transparent corners (16,408 bytes).

Example 5

A layout composed from the results, then split apart again

compose_layout placed six earlier results on one canvas: the square crop, the 16:9 crop, the share card, the reader's 16:9 smart crop, the round avatar and the QR code from Example 6. The settings were a grid of 3 columns, 360-pixel cells, 16-pixel gaps, a dark background and fit contain, which keeps every image whole and leaves margins around those that do not fill their cell. The canvas came out at 1112 by 736 pixels.

The same layout saved as PNG was 331,457 bytes. Saved as WebP it was 32,192 bytes, about a tenth. The WebP is the one shown here.

Going back the other way

  • detect_regions looked at the PNG version and wrote nothing. It found six panels and reported a confidence for each: 1, 1, 1, 0.75, 0.69 and 1. The two lower values, 0.75 and 0.69, belong to the reader's smart crop and the round avatar.

  • split_image in auto mode, told that the gutters were dark, saved six tiles at 360 by 360, 360 by 202, 360 by 189, 360 by 196, 354 by 353 and 360 by 360 pixels. The tiles follow the pictures' own proportions, so the margins from contain were trimmed away.

  • read_codes found the QR code again inside the composite, at 268 by 268 pixels, with the same text as before.

  • split_image in grid mode cut the planning-board illustration into three vertical slices of 597, 597 and 598 pixels by 1024, at 4,820, 12,902 and 5,014 bytes, the kind of cut used for a swipe carousel. The middle slice is shown below.

One call in this example returned Error POSTing to endpoint: Bad Gateway, the first grid split. It had in fact succeeded. Retrying with the same retry key (idempotency_key) returned the original three tiles, marked as replayed, and created nothing new.

Six images in a grid of three columns and two rows on a dark background: a square view of two people at a planning board, a wider crop of the same, a share card of the same scene, a crop of a woman reading, her round avatar, and a black-and-white QR code.
Six earlier results composed into one 1112 by 736 pixel layout (32,192 bytes as WebP).
Tall slice of the planning-board illustration showing most of the planning board and parts of both seated people.
The middle slice of a one-row, three-column grid split: 597 by 1024 pixels, 12,902 bytes.

Example 6

A QR code and barcodes, checked by reading them back

generate_code draws a code from exact text and saves it as an image. read_codes decodes an image and reports each code it finds, so a generated code can be verified before anyone prints it.

  • QR code for https://kugel-platform.netlify.app/. Error correction M, 8 pixels per module, saved as PNG at 624 by 624 pixels (11,715 bytes). read_codes, filtered to QRCode, returned one code whose text matched the address exactly, with its box at 80, 80 and 464 by 464 pixels and no warnings.

  • Code 128 asset tag, text KUGEL-DOCS-0042, with the text printed under the bars. 836 by 400 pixels, 26,727 bytes. Read back as Code128 with identical text.

  • EAN-13 retail code, digits 4006381333931. 460 by 400 pixels, 14,357 bytes. Read back as EAN13 with identical digits.

A payload that breaks a symbology's rule is refused and writes nothing. The EAN-13 request 40063813339AB returned ean13 requires 12 or 13 digits. The tool also supports ean8, upca, code39, datamatrix, pdf417 and itf14; those six were not generated for this article.

A black-and-white QR code on a white square.
QR code for the Kugel Platform home page. Reading it back returned https://kugel-platform.netlify.app/.
A Code 128 barcode of vertical black bars on white, with the text KUGEL-DOCS-0042 printed beneath.
Code 128 barcode for the text KUGEL-DOCS-0042, read back correctly.
An EAN-13 barcode of vertical black bars on white, with the digits 4006381333931 printed beneath.
EAN-13 barcode for 4006381333931, read back correctly.

Boundary

Limits, as read on 2026-10-15

The limits below were read from get_image_model_policy on 2026-10-15. Each figure is the site's current value, with the administrator's ceiling in brackets where one exists. They are values to re-read, not constants.

  • Pixel operations per transform call: 32 (ceiling 128).

  • Output size: 8,192 pixels on the longest side (ceiling 16,384), and 40,000,000 pixels in total (ceiling 100,000,000).

  • Input size: 40,000,000 pixels (ceiling 100,000,000).

  • Tiles per split: 64 (ceiling 256). Images per layout: 36 (ceiling 100).

  • Variants: the setting is called maxVariantsPerCall, currently 8 (ceiling 16). In practice the check was widths multiplied by formats against three times the setting: with the setting lowered to 1 for one call, four widths in one format were refused with "widths x formats (4) exceeds 3." At the current value of 8 that suggests 24 files in one call. Ten files in one call and nine files in another were accepted. The 24 itself was not tested.

  • Default quality: JPEG 82, WebP 80, AVIF 55. The policy's re-encode settings, used when a byte ceiling is set, are a quality step of 8, a minimum quality of 40 and up to 6 attempts.

  • Default variant widths: 320, 640, 960, 1280 and 1920 pixels. The placeholder string is computed from a copy of at most 100 pixels, the policy's thumbhash setting.

  • Layout defaults: 3 columns, 320-pixel cells, 8-pixel gaps, a 28-pixel caption strip, captions up to 80 characters, fit contain. A crop beyond 10 percent of an image's area raises a warning.

  • Article image budget: 153,600 bytes per image, WebP preferred. This comes from the article contract and is separate from the operation limits above.

  • Writes: 60 per 10 minutes per member, shared by every agent working as that member. Several refusals of this kind occurred while this article was made.

Where the limits live and how to override one

The operation limits sit inside the site's image model policy, which get_image_model_policy reads. Every writing tool also accepts a limits object for one call and reports the values it used as limitsUsed. Lowering a limit this way worked: an image_transform request for a 1,200-pixel width with maxOutputSide set to 1000 was refused with "ops[0].width: must be an integer >= 1 and <= 1000". Whether a per-call value can exceed the site's value was not tested.

Changing the site's stored limits is an administrator task. The tool that replaces the policy, set_image_model_policy, was not used for this article, and this article does not document its syntax.

Boundary

Warnings, refusals and what to do about each

Warnings: the call succeeded and the report says something

  • IMAGE_OPS_VARIANT_SKIPPED and IMAGE_OPS_VARIANT_NATIVE_ADDED: a requested width was larger than the source. Observed in Example 1. Nothing to fix. Ask for widths at or below the source to avoid the notice.

  • COMPOSE_CROPPED: a layout cell with fit cover cut away more than 10 percent of an image. Observed here with three images forced into 300-pixel square cells: "Image 0 loses 67% of its area to fit its 300x300 cell (fit "cover"); use fit "contain" to keep it whole." Image 1 lost 44 percent, and the square image lost nothing and drew no warning. Use contain, or size the cells to the images.

  • IMAGE_OPS_MAX_BYTES_MISSED: the tool description says a missed byte ceiling warns. It did not occur in this session, so its wording is unverified.

  • media_budget at validation: an embedded image is over 153,600 bytes. Observed with the 300,740-byte PNG avatar. The article still saved. Re-encode as WebP.

Refusals: nothing was written

  • A bad option, such as the position centre.

  • A value beyond a limit, such as a width of 8500 against the 8,192 limit: "ops[0].width: must be an integer >= 1 and <= 8192".

  • A payload that breaks a code's rule, such as letters in an EAN-13.

  • In each case, read the message, correct the one named field and run the call again. The tool descriptions name a code, IMAGE_OPS_INVALID, for refusals of this kind. In these calls the code did not appear and the reply was a plain message.

Ambiguous failures: check before repeating

  • A 502 or timeout. The write may have succeeded. Retry with the same idempotency_key to get the original result back without a second write, as in Example 5.

  • The write rate limit. The message states how many seconds to wait. Wait that long, and do not retry in a loop.

A successful read is not a scanning guarantee

A QR code was also drawn in a very pale colour, #e2dccf on white, a contrast of about 1.4 to 1. read_codes still decoded it with the correct text. The decoder is more forgiving than a phone held at an angle in poor light. Read-back proves the payload. It does not prove that every camera will scan the printed code, so print codes in a dark colour on a light ground.

Three square cells side by side. The first shows only a woman's face and hair, heavily cropped. The second shows a planning board with two people, with their sides trimmed. The third shows a square view of the same board scene, uncropped.
Fit cover forced three differently shaped images into square cells. The report named the first two as cropped by 67 and 44 percent.
A QR code drawn in very pale beige on a white square, hard to see against the background.
A pale QR code that still decoded correctly: a successful read-back does not mean a phone will scan it.

Boundary

What this article did not verify

Everything above was observed in calls made on 2026-10-15. These points were not:

  • How the admin chat words a request for these operations. The tool order is what an agent calls, not a script the chat follows.

  • Changing the stored limits, and whether a per-call limit can exceed the site's value.

  • The real ceiling for files in one make_variants call beyond ten, and the inferred figure of 24.

  • The six code types other than QR, Code 128 and EAN-13.

  • How AVIF files display across browsers.

  • Results on photographs. Both sources were flat-colour illustrations, so file sizes and crop scores will differ for photos.

Related reading

Related reading and the next safe step

Other articles in this series on images and PDFs:

The next safe step is to read the limits with get_image_model_policy. It changes nothing. After that, running make_variants on an image in an article's request saves new artifacts and publishes nothing.

Back to Library