| name | stock-images |
| description | Find and embed topically-relevant stock photos in a generated lab โ product shots for a catalog, article cover images, profile/team faces, place/venue photos โ using keyless, keyword-matched image URLs that resolve in the user's browser. Invoke when a page or feature needs imagery that should *match its content* (a coffee shop shows coffee), not random filler. Triggered by "stock-images", "product photos", or needing real images for a catalog/feed.
|
stock-images skill
Real, on-topic photos make a lab read like a product. Use this when content
needs imagery that matches it โ a product catalog, an article/blog feed, user
or team profiles, a listings/venue page.
The one constraint
You have no network at build time (no WebFetch, no downloading files), and
images must not bloat the container. So you do not fetch or vendor image
files โ you write <img src="https://โฆ"> tags whose URLs resolve in the lab
user's browser. The trick is choosing URLs that return a relevant photo for
the thing you're rendering.
Content-matched photos โ LoremFlickr (keyword-matched, keyless)
https://loremflickr.com/<w>/<h>/<keywords> returns a Creative-Commons Flickr
photo matching the keywords โ so the image actually depicts the subject.
- Comma-separated keywords narrow the match (AND):
coffee,beans, running,shoe,
mountain,cabin. Use /all after the keywords to match ANY instead of all.
- Pin it with a lock seed so the same item keeps the same photo across reloads
and re-renders (without a lock, the photo changes every request):
https://loremflickr.com/400/300/coffee,beans?lock=42
- Grayscale variant: insert
/g/ โ https://loremflickr.com/g/400/300/coffee.
Pick keywords from the item's real attributes, and a stable lock from its
id so each row is consistent and distinct:
product "Ethiopia Single-Origin" (category coffee, id 7)
โ https://loremflickr.com/600/400/coffee,beans?lock=7
article "Trail-running in the Dolomites" (id 31)
โ https://loremflickr.com/800/450/trail,running,mountains?lock=31
Use 1โ3 concrete nouns (the category beats the exact SKU); skip brand/celebrity
names. Re-use the row id as the lock so the gallery is stable and varied.
People & pure filler
- Faces (avatars, author/team photos):
https://i.pravatar.cc/<size>?u=<seed>.
- Subject-agnostic filler (abstract banners, backgrounds):
https://picsum.photos/seed/<seed>/<w>/<h>.
Always add a fallback (so a flaky photo never breaks the page)
Point onerror at a stable Picsum seed and clear the handler so it can't loop:
<img src="https://loremflickr.com/600/400/coffee,beans?lock=7"
alt="Ethiopia single-origin coffee beans"
width="600" height="400" loading="lazy"
style="object-fit:cover"
onerror="this.onerror=null;this.src='https://picsum.photos/seed/7/600/400'">
Embedding well (every stack)
- Always set explicit
width/height (or a CSS aspect-ratio) so the layout
doesn't jump while the image loads, and object-fit: cover to avoid stretching.
- Give every image a real, descriptive
alt (the product/article name).
loading="lazy" for below-the-fold images (catalog grids, long feeds).
- One consistent source per gallery โ don't mix Picsum filler into a LoremFlickr
product grid.
Per stack:
- react / vue: a small
<img> (or the vendored Avatar/AvatarImage for faces)
inside the Card; build the URL from the row's id + a category keyword.
- vanilla / php: emit the
<img> in the card markup; in PHP keep the URL build
in the template (it's a static client-side embed, not a server fetch).
Pitfalls
- Don't fetch images at build time or save binaries into
app/.
- Always lock/seed by row id โ un-pinned LoremFlickr changes on every render.
- Keep keywords on-topic โ a coffee catalog must not show random landscapes.
- Don't route these URLs through the backend; they are client-side
<img> embeds
(a server-side fetch of a user-influenced URL is a different, deliberate SSRF
feature โ never wire stock images through one).