From 5f735aa2dab858ad88e13af8869f40588299fa4f Mon Sep 17 00:00:00 2001 From: jexpy Date: Tue, 25 Aug 2026 00:31:55 +0400 Subject: [PATCH] docs(readme): explain how to actually use the LQIP placeholders The readme gained the two fields in the sample record but no guidance on consuming them, which leaves out the one thing an integrator has to know: `blur_data_url` is a real 16px image and is deliberately NOT pre-blurred, so dropped into an `` untouched it renders as a visibly blocky postage stamp rather than a placeholder. Verified visually against real iPhone photos. Adds a "Rendering placeholders while an image loads" subsection under The Record with a copy-pasteable HTML/CSS pattern (including the `scale(1.1)` trick that hides the soft edges blur leaves at the borders), the Next.js `placeholder="blur"` equivalent, and the two behaviours that surprise people: both fields are present on private records unlike every other extra, and both are null for pre-feature and non-image records. docs/FILEMANAGER_INTEGRATION.md already covered this; the readme is where people actually start. --- readme.md | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/readme.md b/readme.md index 214fd6a..6f0f9e4 100644 --- a/readme.md +++ b/readme.md @@ -503,6 +503,63 @@ Retrieve record details via `GET /files/{id}`: - **`thumbnail_url` / `poster_url`:** Public-only accelerators (withheld on private records). - **`GET /files`:** Returns paginated records: `{"files": [...], "total_count": N, "limit": L, "offset": O}`. +#### Rendering placeholders while an image loads + +Every ready image carries two placeholder values so a page can paint something +immediately, with no extra request and no client-side library: + +| Field | What it is | Typical size | +|---|---|---| +| `dominant_color` | Average colour as `#rrggbb` | 7 bytes | +| `blur_data_url` | A 16px WebP as a `data:image/webp;base64,...` URI | 135-170 bytes | + +**The tile is not pre-blurred — you must blur it.** It is a real 16px image, so +dropped into an `` untouched it renders as a visibly blocky postage stamp. +Blurring is left to the consumer so you control the radius and the server does +not pay for an effect CSS applies for free: + +```html +
+ + Fjords +
+``` + +```css +.ph { position: relative; overflow: hidden; } /* dominant_color fills any gap */ +.ph-blur { position: absolute; inset: 0; width: 100%; height: 100%; + object-fit: cover; filter: blur(16px); transform: scale(1.1); } +.ph-real { position: relative; width: 100%; display: block; + opacity: 0; transition: opacity .3s; } +.ph-real[data-loaded] { opacity: 1; } +``` + +`transform: scale(1.1)` hides the soft edges blur leaves at the borders. Set +`data-loaded` in the real image's `onload` handler. + +Next.js consumes both directly: + +```jsx + +``` + +Two things worth knowing: + +- Both fields are present on **private** records too, unlike `storage_key`, + `renditions`, `thumbnail_url` and `poster_url`. They carry no storage key and + no URL, so there is nothing to withhold — a private gallery gets placeholders + exactly like a public one. +- Both are `null` on records uploaded before this feature shipped, and on + non-image records. Treat them as optional; fall back to a neutral background. + --- ### Files, Playback, and Sharing