Inspiration
Every small seller I know has an AI image tool on their phone now. Their promo posters still look cheap.
The AI isn't the problem. The prompt is. "make me a sale poster" is five words and gets you a generic image. A poster that actually sells needs 150+ words of art direction: composition, lighting, type hierarchy, where the brand name sits, how the countdown reads. Nobody running a café or an online shop has time to write that, or knows what to write.
So I built the thing I wished existed: a library of those 150-word prompts, already written and ready to personalize.
What it does
PromptPoster is a curated library of 100+ hand-written AI image prompts for promo posters, sale & discount creatives, product launches, menus, events and Instagram carousels. Every card shows an example of what the prompt produces.
The core loop takes under a minute:
- Pick a poster: browse Home (spotlight rails, categories), search, or the Library: one filterable wall with a sticky filter bar (category, type, free/PRO) and honest sorting (Curated, New first, A–Z).
- Read the whole prompt: every prompt is written out in full, with its variables
{BRAND_NAME},{TAGLINE},{DATE},{TIME},{HASHTAG}highlighted. - Personalize: fill in your brand once and the prompt rewrites itself with a live preview. Brand Kit remembers your details on-device, so the next prompt is faster.
- Copy and paste into any AI image tool you already use.
Plus:
- Moments: seasonal collections (Black Friday, Ramadan sales, year-end) surfaced before the date, with optional local reminders.
- History & Saved: every prompt you've copied stays in your history, and re-copying never costs a copy again.
- Content drops via push (opt-in, off by default), light & dark themes, in-app updates.
It is honest by design: PromptPoster is a prompt library, not an image generator. The app never pretends to make the image, and the store listing says so.
How I built it
- 100% Kotlin + Jetpack Compose (Material 3), Navigation 3, Hilt, Room, DataStore, WorkManager, Coil.
- 24 Gradle modules (
:feature:*,:shared:ui,:core:*) with Konsist architecture tests that fail the build if a feature imports another feature or an SDK leaks outside its core module. - RevenueCat lives entirely in
:core:billing:Offerings.currentdecides which packages are sold, their order, localized prices and trial eligibility. Nothing about price is hardcoded.- The "Antasena Pro" entitlement drives PRO state as a
Flow<Entitlements>that every screen observes. - A custom native Compose paywall driven by RevenueCat Offering Metadata: headline, description, benefits, CTA, featured package, trial badge and layout variant can all come from the dashboard, with safe in-app defaults. Today the live offering uses it to feature the Yearly plan (
featured_package_id: $rc_annual). Copy and layout can change, and be A/B tested with RevenueCat Experiments and Targeting, without an app release. - Customer Center for self-serve subscription management, plus restore purchases.
- Server-driven catalog: a static JSON manifest plus WebP thumbnails on Cloudflare, versioned through Firebase Remote Config, so new prompts ship without an app update.
- Google Mobile Ads with UMP consent (rewarded + tightly capped placements), Firebase Analytics/Crashlytics, an FCM topic for content drops, Play in-app updates.
Challenges I ran into
- Making "free" honest and still sustainable. The quota meter shows what's left ("3/5 today"), rewarded ads add copies but never unlock PRO, and re-copying from history is always free. Getting those rules right mattered more than any single screen.
- The paywall. RevenueCat's hosted paywall didn't match the app's visual identity, but I didn't want to give up Offerings, Targeting or Experiments. I rebuilt it natively in Compose on top of Offering Metadata, with defaults for missing or future-version fields so a dashboard typo can never break checkout.
- Designing for the catalog I'll have, not the one I had. The offline seed had 6 items and the live catalog has 104. I redesigned the catalog screen (Library) for 300–500 items with a sticky filter bar, and only offered sorts I could back with real data.
- Release engineering. R8 and bundletool ran out of heap on release builds, and I added a build gate that refuses to produce a release bundle with test ad IDs.
Accomplishments that I'm proud of
- Shipped a complete, working monetization stack on day one: three subscription plans (Monthly, 3-Month, Yearly with a free trial), a native paywall, Customer Center, rewarded ads and capped ads.
- A distinct visual identity (Soft Studio) instead of default Material: warm sand and terracotta, a cocoa & gold PRO language, Nunito display type, JetBrains Mono for prompts.
- A copy flow that goes from app open to prompt on the clipboard in under a minute.
What I learned
- Let RevenueCat own what should change without a release (packages, prices, paywall copy, experiments) and keep in code what shouldn't (brand colors, contrast, accessibility).
- Being honest about what the product is (a prompt library) makes the value proposition clearer, not weaker.
What's next for PromptPoster
- Grow the catalog toward 300–500 prompts and add popularity/newest sorting once the catalog carries that data.
- Run paywall experiments through Offering Metadata (copy, featured package, layout variant).
- More carousel packs and regional Moments, plus purchasing-power-adjusted pricing.
Shipaton categories I'm entering
RevenueCat Design Award and HAMM Award. Details for each are in the category answers.
Built With
- android
- cloudflare
- coil
- firebase
- google-admob
- google-play
- gradle
- hilt
- jetpack-compose
- kotlin
- material-design
- revenuecat
- room
Log in or sign up for Devpost to join the conversation.