Imagine your daughter asks you for a story at bedtime.
This is exactly what I built this little Tiiny app for.
Imagine:
She types what she wants. About half a minute later a painted page appears in an open book on the little screen and a warm voice starts reading her a story that has never existed before. Then it writes and paints the next page while the first one is still being read, so after that there is no waiting at all.
The part that got her was the characters coming back. The dog Biscuit still has the folded ear and the red collar three nights later.
All of it happens on the Tiiny. The story, the illustration, the voice. Nothing is sent anywhere. There is no cloud account behind this and no API bill, which for a device in a child's bedroom felt like the only acceptable answer.
Writes | A fresh story, never from a canned set |
Paints | Every page, 512x512, about 8 seconds each |
Narrates | Read aloud in a warm voice |
Remembers | Characters keep their look and their manner across nights |
Checks | Every single page, before she hears a word of it |
This is the part I kept redoing until it was right. It is not a slideshow with a fade. It is a spread, with the picture on the left page and the words on the right, and the wider margin at the gutter the way a real bound book is set.
When the page turns, a sheet pivots on the spine and the back of that sheet carries the next illustration. That is how an actual leaf works. The page you were reading rotates away, the picture you are turning to arrives on the back of it, and the next page's words are already waiting underneath. The lamp light runs off the paper as it lifts and the sheet throws its shadow across the page it uncovers.
I tried a plain flip first and it read as a zoom, not a page. Turned out the perspective was far too short, so the sheet swelled toward you instead of closing. Long perspective, and it became paper.
The first page takes about thirty three seconds, because the model plans the whole story before it writes a word of it. A candle sitting there doing nothing for thirty three seconds does not read as thinking, it reads as broken.
So the lamp shows its work. It dreams up the story, then the whole storyboard lays itself out, one plate per page, with the actual beats of the story written on them as they are written. Then the plate being made right now tells you whether it is being written, checked, voiced or painted.
Every bit of that is a real event off the engine. There is no fake progress bar anywhere in it. I caught myself lying once, when it said "making sure it is kind" for fourteen seconds it actually spent loading the voice model, and moved the label.
Pause and play, a star for a new story, and a book for every story she has already told it. Big round wooden buttons a five year old can hit without aiming.
The shelf is the one I did not expect to matter. Every story is kept with its pictures and its narration, so tapping one replays it instantly, straight out of the database, without touching the device at all. A kid asking for the dragon story again should not have to wait thirty three seconds for a story that already exists.
An unmoderated model writing bedtime content for a small child is the failure mode that actually matters, so that is where most of the work went.
Three independent things run before she hears anything. A deterministic backstop on the request that never depends on a model being in a good mood. A charter check on what she asked for, which redirects warmly rather than ever showing a child a refusal. Then a classifier pass on every generated page against a rubric written for ages 3 to 8.
It fails closed. If a page cannot be checked, she does not hear it. She gets a slightly shorter story instead, using a warm pre-written ending that was already there. That was a deliberate reversal during review, because "we logged it loudly" is no help once a child has already heard something.
I am not going to tell you it is a guarantee. It is a serious auditable attempt, and safety.py is right there. python3 safety.py runs it against a table of both innocent and genuinely nasty requests so you can watch it work before you point it at your own kid.
Numbers off one real eight page story's own transcript log, not from memory.
Plan the whole story | 23.3s, one call |
Write a page | 4.7s |
Safety check a page | 2.4s |
Narrate a page | 8.7s |
Paint a page | 7.9s |
Ask to first page reading aloud | 33.3s |
Only that last number is a wait. A page takes about 23 seconds to make and about 27 seconds to read out loud, so from page two onward the device is always a page ahead and there is nothing to wait for.
Load these two on your Tiiny first. The lantern will not load them for you.
deepreinforce-ai/Ornith-1.0-35B, 50u, writes the story and checks it
Tongyi-MAI/Z-Image-Turbo, 32u, paints the pages
The voice, Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice at 7u, the lantern starts and releases on its own. That is 89 of your 100 units with the voice in, so unload anything else first or the image model will refuse to start.
git clone https://github.com/webdevtodayjason/story-lantern
cd story-lantern
export TIINY_HOST=<your tiiny>
export TIINY_KEY='<Settings -> API key>'
python3 lantern.py --selfcheck # one real story end to end, prints timings
python3 lantern.py
Python standard library only. No pip install, no virtualenv, no build step. It runs on 3.9 and up.
You can look at it without a Tiiny. http://localhost:8420/show?demo=1&go runs a fake story with painted plates and never calls the device, so you can see the book and the page turn before you commit to anything.
There is a parent view as well, at /parent, showing every story, every verdict, and every page that was held back and why. It hides nothing.
The Tiiny does one inference at a time, so if you run anything else against the same device you will meet error 150004. Story Lantern retries with backoff and coexists fine. If you are running several apps on one Tiiny, OneLane handles it properly across separate programs.
https://github.com/webdevtodayjason/story-lantern
MIT. If you build one, I would genuinely like to hear what your kid asked it for first.
Thats impressive