Image slot with a locked crop
Add an image slot the editor crops to a fixed ratio.
Add an image slot the editor crops to a fixed ratio.
The delta
Section titled “The delta”Starting from the starter’s hero section, add a second image slot shaped
like hero_image — a crop config, an image-assign decision, an <Image>
in the Renderer, and a fixture value.
// schema.ts — a second image slot, same shape as hero_image, own aspectinterior_image: { type: "image", editable_by_user: true, required: true, produced_by: "interior_image_assign", display_name: "Interior image", crop: { mode: "locked", aspect: 4 / 3, aspectLabel: "4:3" },},// fill-spec.ts — the decision producing it{ id: "interior_image_assign", type: "image-assign", produces: ["interior_image"], tag_query: "category:interior", selection_prompt: "Pick a bright, decluttered interior shot.",},// Renderer.tsx — copy the starter's <Image> usage for hero_image<Image slotId="interior_image" src={slots.interior_image.url} responsive={slots.interior_image.responsive} alt={slots.interior_image.alt} className="w-full"/>// fixtures.ts — the photo's asset id, exactly as a saved page states itimport { scenarios } from "@homepages/template-kit/fixtures";
const interiorImage = scenarios.luxuryMultiUnit.photos[3]!;// ...interior_image: { photo_id: interiorImage.id, alt: interiorImage.alt,},The url and the responsive ladder the Renderer reads are attached when the fixture
loads — see Media is stated by id.
An image slot supports two independent geometry configs — use one, not both, per slot:
crop— steers the editor’s cropper only:mode: "locked"fixes anaspect(w/h) and shows theaspectLabelpill;mode: "free"lets the user resize any edge. This is what the recipe above uses.frame— a per-breakpoint aspect (desktop/mobile, switching at a declaredbreakpoint) that is the single source of truth for BOTH the cropper’s target ratio and the Renderer’s own layout box (imported as a shared constant on both sides — see schema-system.md). Reach forframeinstead ofcropwhen the section’s markup itself needs to know the ratio (e.g. to size a wrapper), not just the editor.
Either way, framing is baked into the served asset — the Renderer never
applies an aspect ratio to the pixels itself; it only reads url, alt,
responsive (and mobile) off the slot’s ImageValue.
Commands
Section titled “Commands”None — this is a pure content edit. No CLI command beyond the author loop below.
Verify
Section titled “Verify”Verify with the author loop.
See also
Section titled “See also”- The schema system —
ImageValue, the fields a Renderer reads vs. only carries, andframe. - Contract primitives — the
Imageprimitive’s full prop table. image-bare-needs-reason— the rule that fires if you reach for<Image bare>instead of the framed default this recipe uses.