Ninety-second vertical episodes. The screen cracks in two and the viewer decides which way it falls — one path costs coins, the other is free, and they lead to genuinely different endings.
Flutter app · Node + PostgreSQL backend · branch-graph editor · runs with no server at all in demo mode
Thirty-two screens, all built and wired — not a gallery of mockups. This is the loop a viewer actually walks.
Feed
Ordered by the tropes you picked
Player
Vertical video, seek and resume
The cliff
The screen cracks along the seam
Branch map
Solid = walked. Dim = still sealed.
Where the operator writes the story. The branch editor is the part no competing item has — and the validator below it is why a broken story cannot go live.
Watch, hit the cliff, choose, watch the consequence. The choice is the product — not a feature bolted onto a player.
Full-bleed vertical video with a progress bar that is really a countdown to a decision. Range-request seeking, resume where you left off.
The screen cracks along a seam. EMBER is the risky path and usually the paid one; TIDE is safe and free. The prompt is about the story, never the transaction.
Each side leads to a different episode. A series ends in two, four or more places, and the branch map shows how much of it you have not seen.
This is the whole difference, and it goes all the way down to the schema. An episode is a node; a branch option is an edge to another episode. Nothing in the product assumes episode 12 is followed by episode 13.
| Typical short-drama app | CLIFF | |
|---|---|---|
| Episode order | A list. Next is next. | A directed graph with validated edges |
| What the viewer buys | The next episode | A branch — and the episode stays theirs |
| Endings | One | As many as the graph produces, counted automatically |
| The path not taken | — | Openable later and rewatchable |
| Admin | Episode list | Branch editor that refuses to publish a broken story |
| Rewarded ads | Credited by the phone | Credited from AdMob's signed server callback |
| Purchases | Often trusted from the client | Verified against Apple and Google server-side |
The app and the backend are developed against each other. The app is not a mockup and the backend is not a stub.
Age gate, onboarding, guest-first auth, feed, search, library, series detail, player, the branch moment, branch map, wallet, streak, VIP, rewarded ads, and the compliance screens stores look for — data export and real account deletion.
Node 20, Express, PostgreSQL. No build step, no framework, no bundler — you can read every file. An installer sets up nginx, a certificate, a service and a daily job on Ubuntu in about ten minutes.
Lay out cliffs, point each side at an episode, mark your endings. A validator blocks publication while an episode is unreachable, a cliff has one side, or a choice leads nowhere — every one of which reads to a viewer as a broken app.
Every coin movement is idempotent and written in one transaction behind a row lock. The wallet always equals the sum of the ledger, and the test suite proves it under concurrent spends.
One zip. Both halves of the product, the design system that produced the look, and documentation that covers the whole thing.
cliff/ ├── flutter_app/ iOS + Android, full source │ ├── lib/data/ repository, models, state │ ├── lib/features/ 32 screens in 7 areas │ ├── lib/core/ theme, router, widgets │ └── test/ unit + live integration ├── backend/ Node 20 + PostgreSQL │ ├── src/core/ ledger, access, branching │ ├── src/api/ the mobile API │ ├── src/panel/ operator panel │ ├── src/providers/ video, IAP, ads │ ├── src/db/schema.sql 23 tables, commented │ ├── scripts/ install, seed, purge │ └── test/ 16 tests ├── design_system/ tokens, components, UI kit ├── documentation/ one file, opens in a browser ├── README.md └── CHANGELOG.md
No build step on the server, no bundler, no framework. No AWS SDK, no Google API client, no RevenueCat — the request signing each of those would provide is written against the standard library, so you can read the sixty lines that do it.
| Piece | Size |
|---|---|
| Backend source | ~5,100 lines · 32 files |
| Flutter source | ~3,750 lines · 32 screens |
| Database | 23 tables, one commented file |
| Tests | 16 backend + 7 app |
| Server dependencies | 3 |
| Documentation | install → API → troubleshooting |
Not a feature list of intentions. Each of these is built, wired to the backend and walkable in the live demo.
With no server, no database and no account. Demo mode holds the same branching story the backend seeds — four endings, three priced cliffs, coins that actually get spent.
cd flutter_app
flutter pub get
flutter run
cd backend
npm install && npm run migrate
npm run seed && npm start
flutter run \
--dart-define=CLIFF_API=https://your-domain/app/api/v1
Two files carry the whole look — swap the two accent colours and three Google fonts, and it is your brand. The full design system ships with it.
Requires a VPS and a domain. Apple and Google developer accounts are needed to publish. None of these are included in the item price — see the documentation for the full list.