Repository navigation
Fill every sample image slot with a real photo or a labelled placeholder - #184
Conversation
A first build left media slots empty or filled them with a gradient, initials or a random Picsum photo, and older notes pointed at image services that no longer answer. This gives the builder one place to pick an image source and a recipe that works from a terminal. - boxel-file-def/references/sample-images.md (new): pick a source by scenario (the user's own, AI-generated with generate-thumbnail, a real CC0 or public-domain photo from the Openverse API, a labelled placeholder), never guess a URL, put a URL in the URL half of the field and a realm file in relationships. - asset-selection-guidelines: every media slot ships with an image; the source order; placeholder rules (theme colours, sized to the slot, a label naming the subject); named fictional people and real copyrighted subjects always get a placeholder; the dead services removed. - host-commands-reference declares generate-thumbnail and download-file-to-realm. - critical-rules: "Images in templates" replaces a src example that put a linksTo(ImageDef) value in src. - attach-remote-image imports ImageDef from @cardstack/base/image-file-def. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Staging Workspace Sync SuccessfulSuccessfully synced changes to staging workspace Sync Details |
Two runs (a terminal build, and the in-app assistant simulated with the
real host commands) and an audit of every image rule in the tree found:
- Image field: say the URL/ImageDef pair (Cardinal Rule 12) or the
catalog ImageSourceField that packages it, instead of putting
ImageSourceField ahead of the rule; base-field-catalog no longer calls
that field unbuilt, and its ImageDef row imports image-file-def.
- generate-thumbnail fails from `boxel run-command` ("Cannot login to realm
server without matrix client"); it does not generate and then fail to
save. Corrected here and in indexing-operations.
- download-file-to-realm runs in the browser: the host must allow CORS,
and the path's extension follows the content type (a .jpg URL can
serve WebP). The load check now sends a user agent and shows the CORS
header; StockSnap's 403 was only curl's default agent.
- The user's own image is downloaded and looked at before it is linked.
- AI images come in the mockup pass when the user asked or the design is
brand-heavy, as the design-playbook says; otherwise they are offered once
after the build, and every call goes in one reply for one approval.
- Openverse: query with plain words, match on title or tags; a made-up
film's poster can take a photo too; one label rule by display size; a
default colour pair with no theme; a fitted tile crops the item's own
image.
- The fitted-layout checklist accepts a verified photo or a labelled
placeholder, never a guessed URL; host command names carry their hash
suffix; icons point at @cardstack/boxel-icons; glossary fixes.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Both re-tests passed (an Openverse photo found with plain words and downloaded into the realm; the assistant looked at the user's image and asked instead of linking a photo of bread as a poster). The wording they still tripped on: - In the app, the "unsure" question leaves out stock photos, which the assistant cannot look up; the AI offer leaves out placeholder-only slots (the example now names dishes, not real film posters); an AI portrait is fine for a fictional person when the user asks. - Download paths are <slug>-<field>.<ext>; in the app the extension comes from the URL. A declined user image is reported as left in Images/. - Prefer Openverse results that allow CORS; one more query with a near word when a query returns only a handful. - One placeholder URL serving an avatar and a tile is labelled for the avatar; ImageSourceField is a default export. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- A placeholder example used Picsum for a named place; it is placehold.co. - An image already in the realm or catalog is a source, found with catalog-reuse's files search. - The draft state (hotlinked photo or placeholder) is said to meet the playbook's realm-hosted photos through the download step, and a later AI pass replaces placeholders. - attach-remote-image's "future direction" points at ImageSourceField; the glossary lists the two media host commands; "no declared tool" for the app's photo lookup; no reference to a route that is not on main. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A full "build me a bakery app" run passed every gate (scan, lint,
indexing, typed counts, render), and showed:
- Labelling one placeholder for the avatar it also serves filled large
photo panels with initials. Label it for the panel instead.
- Placeholder colours are fixed in the URL: grey at a stage-1 mockup,
switched to the theme's once it exists.
- Items the user calls their own ("our cakes") are real products and take
a placeholder until their photos come; invented sample items can take an
Openverse photo. Never change a sample item to fit a photo.
- FittedCard's :placeholder is for an image a user later cleared, not a
first-build instance; a full-width hero is 1920x1080; the download host
command also runs from a terminal through `boxel run-command`.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Takes #184's tested image guidance (sample-images, asset-selection, host commands, the Images-in-templates section) and keeps this branch's own sections around it: never invent proof, main action, visible controls and first-build size in critical-rules, and the boxel-design reference list. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- A by-path table: what a terminal session and the in-app assistant each do for the user's own image, an existing realm or catalog image, a real photo, a failed lookup, AI images and the always-placeholder subjects. - Sample photos stay as URLs, which is faster; an image is downloaded only when it is the user's own, or the app is published, listed or going live. A failed download keeps the URL and is listed in the hand-off. - Openverse: record the source page and creator; a 429 (20 a minute, 200 a day per IP anonymously) falls back to a placeholder with no retry. - Marked as an interim recipe until the platform has a server-side image search; "every slot has an image" is a sample-data rule, and templates still design a no-image state. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
lucaslyl
left a comment
There was a problem hiding this comment.
[Claude Code 🤖] This review went after consistency with the rest of the tree and the host facts the new text asserts (tool names and inputs, the ImageDef import, ImageSourceField field names, the Openverse parameters); it did not re-run the Openverse or placehold.co calls.
No blocking issues.
- Replace the hand-picked
images.unsplash.com/photo-<id>URL in theattach-remote-image/README.mdexample instance (line 87, outside this diff) with a labelled placeholder (https://placehold.co/1600x900/e5e7eb/6b7280.png?text=27+Spruce+Lane); it is the construct-a-URL shape the new rules forbid, and a builder copying the pattern copies it. - Reword the two temporal sentences in
sample-images.md.
The Sync check was still running when I looked.
| This rule is for sample data. A template still shows a designed state for an instance with no image, | ||
| because real records often have none. | ||
|
|
||
| This is an interim recipe. Openverse from a terminal and placeholders in the app stand in until the |
There was a problem hiding this comment.
[Claude Code 🤖] Non-blocking. "This is an interim recipe ... stand in until the platform has a server-side image search" is delivery-state wording that goes stale the day the search ships, and it reads as permission to treat the rules below as optional. State the contract (Openverse from a terminal, placeholders in the app) and drop the forecast.
| not the image's host, and its licence is unknown; | ||
| - the placeholder patterns below, which work for any value. | ||
|
|
||
| Dead patterns still found in older notes, never use them: `source.unsplash.com` (shut down) and |
There was a problem hiding this comment.
[Claude Code 🤖] Non-blocking. "Dead patterns still found in older notes" is temporal and refers to text that no longer exists in the tree. List the patterns that never work (source.unsplash.com, via.placeholder.com) without the history.
A council review of the PR asked for a smaller footprint on files other people wrote, and less repetition in the new reference. - critical-rules keeps its original "Image URL in templates" section and adds three lines on linksTo(ImageDef) values; boxel-design keeps its description and adds one link; attach-remote-image keeps its "Future direction" heading with a pointer; container-query-fitted-layout keeps its sentences, changing only "Unsplash URLs are fine" to a verified URL. - asset-selection-guidelines still drops only the guessed-URL and dead-service sections, and keeps its icons and NASA lines. - host-commands-reference's media entries are one line each; glossary entries are short definitions and GenerateThumbnailCommand is restored. - sample-images.md is 188 lines: one source table for terminal and app, each rule stated once, real links, Picsum removed, a slot never left empty, real people always a placeholder, the terminal download route. - The design-playbook's sample-data step links to sample-images.md. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The decision tree sent an external image URL to contains(StringField). An image now goes to the catalog ImageSourceField (or the URL/ImageDef pair), whose URL half holds it and which can switch to a realm file later with no schema change; a link to a non-image file elsewhere is contains(UrlField), matching base-field-catalog. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A remembered Unsplash, Pexels or Pixabay URL loads and often shows the subject the model expects, but not always, so it is used only after a load check and a look (terminal) or a view-visually of the card (app). This gives the in-app assistant real photos instead of only placeholders. Use the image's own address, never its page; picsum is added to the never-use list. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…and #189's interview record Brings in main (including #184's sample images), takes #188's versions of layout-vocabulary.md and layout-gravity.md, and #189's interview record in domain-interview, its brief template and glossary entry, and its routing skip sentence in index.md. Conflicts keep #151's fuller text and add the newer lines into it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Linear: ECO-594
Why
This came out of the card and app creation process. When someone asks for "a cinema app" or "a bakery app", they expect the first shot to look like a finished app, and a poster or a dish with no picture makes it feel incomplete. Today those slots often come out empty, as a gradient, as a random photo, or broken.
That is mostly because the image guidance was written before the catalog had
ImageSourceField, and some of the services it relied on have since shut down (source.unsplash.com,via.placeholder.com). With no way to search, it asked the model to compose stock URLs from a pattern, which tends to load an unrelated photo or nothing at all.Two things now make a simpler, more reliable default possible:
ImageSourceFieldstores aurland a realmfile(anImageDef), andsourceModepicks which one shows. A slot can start with a photo or placeholder URL and move to a downloaded file later, without changing the card's schema.The result: every slot gets something honest. A real photo when one can be found (a stock photo the model knows and has looked at, or a CC0 Openverse photo from a terminal), otherwise a placeholder that says what belongs there, and never a stock photo standing in for a real person, the user's own product or a real film poster.
Why a new reference file
This guidance touched several files, each covering part of it in its own words. Rather than rewrite them, the rules now live in one place,
boxel-file-def/references/sample-images.md, and the existing files keep their text with a short pointer.asset-selection-guidelinesstays focused on choosing assets that suit a style; only its URL-pattern and retired-service sections are removed.What changes
boxel-file-def/references/sample-images.md: every media slot in sample data gets an image, picked in this order: the user's own (downloaded and looked at before linking), an image already in the realm or catalog, a known Unsplash, Pexels or Pixabay photo once it has been looked at (load check in a terminal,view-visuallyof the card in the app), a CC0 Openverse photo (terminal only, load-checked), a labelled placeholder, AI images (offered once in the app).generate-thumbnailanddownload-file-to-realm; fixes thesrcexample incritical-rulesand theImageDefimport inattach-remote-image; removes the guessed-URL and dead-service sections fromasset-selection-guidelines.Not covered
run-realm-codehas no network), so it uses only photos it already knows, checked on the rendered card, and placeholders for the rest. Next: declareauthed-fetchlimited to Openverse, or a server-sidesearch-imageshost command.generate-thumbnailfails from the CLI.Tested
External URLs: 14 URLs rendered in one Boxel card, each in both an
ImageSourceFieldand aStringField(identical results).images.unsplash.com,images.pexels.com,cdn.pixabay.comand Openverse hosts load; photo pages, made-up IDs,source.unsplash.comandvia.placeholder.comdo not;picsum.photosloads a random photo. Remembered IDs mostly showed the expected subject, but not always, and the old "try sequential Pexels IDs" pattern loads unrelated photos (a hiker, an office, noodles), which is why every known photo is looked at first."Create a recipe app" again with this rule: the terminal kept 3 remembered Unsplash photos and rejected 2 that showed the wrong dish; a simulated in-app assistant (no network, a CLI screenshot standing in for
view-visually) kept 4 and replaced 2 (farfalle for spaghetti, a pineapple pizza for a margherita) after viewing the card. Both clean on scanner, lint, indexing and render.Earlier: One prompt, "create a recipe app", run from a terminal and as the in-app assistant (real host commands, no network): both found
ImageSourceFieldthrough the catalog search and wrote the image URL in itsurlhalf, never inrelationships; the terminal used Openverse photos, the assistant labelled placeholders. Same cinema app built from a terminal and as the in-app assistant (real host commands), a full bakery build (scanner, lint, indexing, render clean), and an audit of every other image rule in the tree.Edits files owned by others:
asset-selection-guidelinesand theboxel-file-defdecision tree (Luke),container-query-fitted-layout(Burcu),host-commands-reference(Matic).🤖 Generated with Claude Code