lunelet
A little window into what you’re reading.
A free reading shelf for your website.
Lily’s live shelf · click the book to try it
Let your agent set it up
Copy this into the agent building your website. Give it the books you’re reading and anything you’ve finished recently; it can handle the files and the placement.
Add lunelet to my website using this installation guide:
https://lilygeidelberg.com/reading/install.md
Use my own books, not Lily’s feed, and match my existing site.
Start with a JSON file hosted on my site. Use the compact layout and
neutral theme shown in the guide. Keep the collapsible,
book-icon opener with the turning gold page. Put “Currently reading”
inside the expanded panel; no miniature cover previews.
Ask me for any missing book details.
Show me how to update my books afterwards.
The file-based version needs no account, API key or database. Your site must allow custom JavaScript and a public JSON file.
Already use Goodreads?
Keep changing books on Goodreads and let your website follow along. Paste your public profile link to preview your shelf and get an embed for your own books. No Goodreads password or API key.
Put these two lines on your website, or give them to your agent. This does not connect or change Lily’s shelf.
Public profiles only. Shows up to 24 current books and 100 recent reads, with Goodreads book links and covers. Feeds are cached for an hour; Goodreads may also delay updates. It is one-way: the widget cannot change Goodreads. Reviews and ratings are not imported, and unknown dates stay blank.
This option uses the read-only Goodreads adapter hosted here. It depends on Goodreads’ public RSS feed remaining available. For a self-hosted adapter, see the agent guide.
Or add it yourself
-
Create your book list
Save
reading.jsonin your site’s public files, so it is available at/reading.json. Replace the example title and author with your own. For an empty shelf, use"books": [].See the starter JSON
{ "schemaVersion": 1, "revision": 1, "name": "Your name", "updatedAt": null, "books": [ { "id": "book-1", "title": "Your book title", "author": "Author name", "status": "reading", "workId": "", "cover": "", "url": "", "startedAt": null, "finishedAt": null, "progress": null, "note": "" } ] } -
Add the shelf to your page
Put these two lines where you want your reading window. The script supplies the widget;
srcpoints to your book list. If your site lives under a subpath, include it: for example,/portfolio/reading.json.<script type="module" src="https://lunelet.com/v1/reading-shelf.js?v=lunelet-styles-20260915"></script> <reading-shelf collapsible variant="compact" theme="neutral" style="--reading-font-size: .82rem" src="/reading.json"></reading-shelf>You can also download the component and host it yourself. It is one file, with no runtime dependencies. In a server-rendered framework, load it in the browser, not on the server.
-
Change books whenever you like
Update and publish
reading.json, or tell your agent what changed. Keep each book’sidstable. To finish one, change itsstatusto"finished"and setfinishedAtto its finish date inYYYY-MM-DDformat. Add your next book with a new ID and"status": "reading".Increase
revisionwith each edit and setupdatedAtto the edit’s actual ISO timestamp. Keep earlier books in the list; the shelf sorts finished books into history for you.The widget checks for changes every 30 seconds while the page is visible, and when someone returns to the tab. Publishing the JSON is still your responsibility; it does not write changes back to your site.
Make it fit your site
The examples use the compact Loom design: parchment, navy Georgia lettering, rust-red dividers and a woven edge. Lily’s homepage has a softer, washed-out watercolour variation. You can choose from all ten styles on Lunelet, or customise the colours and fonts. Styles stay inside the component, so they do not restyle the rest of your page.
Preview the compact layout and colour options
These are the neutral theme’s colours. The embed above already uses them; set these properties in your stylesheet only if you want to customise them. Use --reading-font for body text, --reading-title-font for headings and --reading-font-size for the compact shelf’s text size. Remove the inline size from the embed if you set it in your stylesheet.
reading-shelf {
--reading-background: #f1e7d1;
--reading-control: #f5eddd;
--reading-ink: #193247;
--reading-muted: #55554e;
--reading-line: #ad5c3c;
--reading-border: #756147;
--reading-accent: #953f24;
}
The page turn and pulse indicate a current reading list, not that someone is online. They settle when opened and are disabled for people who prefer reduced motion.
Want an editor or API-driven updates?
Use a JSON file to get started. If you want to change books in a browser without republishing files, your site needs its own persistent API and a private editor. An agent can build that on your existing host using the lunelet API contract.
This is a reusable widget, not a hosted account service. Lily’s API and editor manage Lily’s books only; they do not create a shelf for you.
How an agent updates a connected shelf
On your own API, read the shelf first, then send an action with your private write key and the quoted current revision. This example’s host, key, book ID and revision are placeholders.
GET https://your-site.example/api/reading
PATCH https://your-site.example/api/reading
Authorization: Bearer YOUR_PRIVATE_WRITE_KEY
If-Match: "3"
Content-Type: application/json
{"action":"finish","id":"BOOK_ID"}
The contract supports starting, finishing, editing, adding history and undoing changes. “Finish & next” can be one atomic action. If the API returns 412, re-read and reconcile the change before retrying.
Keep write keys in your server or agent’s secret storage. Never put them in the embed, a URL, public JSON or public JavaScript. Your reading list and notes are public; only editing is private.
Reference & troubleshooting
Agent guide · MarkdownAPI contract · JSONStarter book listComponent source
The shelf is not appearing
Open your JSON URL directly: it should return JSON, not a login page or your homepage. Check the script has type="module", that the host allows custom scripts, and that the book records use "reading" or "finished" for their status.
If the feed is on another domain, it must allow cross-origin reads with Access-Control-Allow-Origin. A restrictive Content Security Policy also needs to allow the component’s script, its stylesheet inside the component, the feed connection and any cover image hosts. The agent guide has the details.
Adding covers, progress and notes
cover is a public HTTPS image URL or a path such as /covers/my-book.jpg. url is an optional book link. Relative paths resolve against the feed URL. Leave unavailable covers and links empty.
progress is a number from 0 to 100, or null if you do not want to track it. note is an optional short public thought. Leave unknown dates as null; do not invent reading history.
I want to embed Lily’s shelf instead
This is a read-only view of the same shelf shown in the demo. It will show Lily’s books on your website, not your own.
<script type="module" src="https://lunelet.com/v1/reading-shelf.js?v=lunelet-styles-20260915"></script>
<reading-shelf collapsible variant="compact" theme="neutral" style="--reading-font-size: .82rem" src="https://lilygeidelberg.com/api/reading"></reading-shelf>