GlamUp Girls — Mobile Dress-Up Game (Flutter)
Kendi ürünüm — bağımsız yayın
(73 ratings) 9019 views
A dress-up game live on Google Play and the App Store with 14 models, 1,000+ outfits, accessories, hairstyles and makeup options, and four pet packs. It uses a Flutter client and server-side purchase verification on Firebase Cloud Functions; layout defects were closed by measurement rather than guesswork. Started in April 2026; PEGI 3, built under the family-policy rules.
GlamUp Girls — Mobile Dress-Up Game
Available on Google Play and the App Store · English, Turkish and Arabic · Independently developed and published
GlamUp Girls is a dress-up game: pick a model, do the makeup, choose hair and clothes, walk the runway. Fourteen models, 1,000+ outfits, accessories, hairstyles and makeup options, four pet packs, weekly and monthly contests. The tutorial tour includes short spoken narration (TTS). First commit on 7 April 2026. In production on Google Play. Live on the App Store (iPhone and iPad) since 12 September 2026. Rated PEGI 3, listed under Casual, and bound by Play's family policy.
I would rather explain how it was built than what it does. In a casual game the visible part, the art and the animation, is the small part. The time goes into the content pipeline, the scoring math, verifying purchases on the server, and the rules that come with a children's category. Every number below was measured in the repository on 9 September 2026, not estimated.
What Is in the Game
- 👗 14 models and 1,095 distinct options: 817 outfits and accessories, 78 hairstyles and 200 makeup styles (a sprite shared by two models is counted once; Elegance shares part of Glam's pieces; base body sprites excluded)
- 🐾 4 pet packs (cat, dog, pony, unicorn), 193 pieces
- 🌟 Runway score: 4 categories in free style, 5 in contest mode, normalized to 0-100
- 🏆 Weekly and monthly contests, a rare-item collection
- 🌍 TR / EN / AR interface and spoken narration (TTS) during the tutorial tour; more languages are being added in stages
- 🛡️ A parental gate on purchase entry points; child-directed ad treatment with a G content rating
Inside the Game
Five of the places you will spend your time.





Three New Characters



Elegance uses a curated modest wardrobe through the Headscarf tab in the Outfit Studio: 109 pieces selected from the Glam pack, 85 of them shared with Glam's own list. Icon is a plus-size woman and Laid-Back a plus-size man. All three are unlocked on first install; none sit behind a downloadable pack.
The Work
The client is Flutter: 451 Dart files and 180,738 lines under lib/ as of 21 September 2026. Business logic sits in 104 service files directly in the lib/services root and screen state in the 10 classes under lib/store. Persistence is local-first on SharedPreferences scoped to the user id, with cloud sync kept in a separate layer so that offline play never depends on it. The server side is Firebase Cloud Functions: 19 callable functions, a 3,313-line index.js and a separate 945-line module for purchase verification.
Key Outcomes
✅ 18,622 normalized webp sprites across 25 asset packs; color-variant counts enter the code from a 1,418-entry table generated by scanning the assets, never typed by hand
✅ Purchases are never trusted from the client: StoreKit 2 JWS signatures on iOS, the Play Developer API on Android, verified on the server; a receipt cannot be replayed
✅ All 44 screens pass an overflow test at 13 device widths between 320 and 1024 dp
✅ 5,433 test definitions in 607 test files (source count, 21 September 2026), plus 47 emulator test files on the Firestore/Functions side
✅ The Arabic punctuation drift was closed by measurement (36.1 px), and a 261-line guard test keeps it closed
Content Pipeline
The catalogue is modeled as separate lists for each of the 14 models; behind the 1,095 option definitions sit 25 asset packs and 18,622 normalized webp sprites. Color variants took the most time. I used to type the counts by hand. Whenever a pack gained a piece the table went stale and the game showed the wrong variant count. Now an asset scan produces 1,418 (pack, prefix) entries and embeds them straight into the code. The table cannot go stale, because there is no hand-kept table any more.
Outfit Scoring
Scoring lives in its own 15-file module, 1,608 lines, six of them analyzers. A free-style look earns up to 25 points in each of four categories; contest mode adds Theme Fit and normalizes five categories at 20 points each to a 0-100 scale. A five-tier rarity multiplier sits on top, from Common ×1.00 to Legendary ×1.25. These are constants in the code, not notes in a comment, so a design change touches one place.
Localisation
Interface text lives in 51 ARB files across 17 namespaces: 7,568 key lines in English, 7,569 in Turkish, 7,596 in Arabic. Twenty-eight separate i18n tests check parity between the files and catch English leaking into the Arabic screens.
The real lesson was on the Arabic side. When Latin text such as a username lands inside an Arabic sentence, the exclamation mark and the full stop drift to the wrong side. I measured it with TextPainter instead of eyeballing it: unisolated, the exclamation mark rendered at x=0.0; wrapped in Unicode FSI/PDI isolates it rendered at x=36.1. Once the difference was a number, the fix was small. To keep it from coming back, a 261-line source guard test counts the EdgeInsets.only, fromLTRB, Positioned and TextAlign usages that silently draw on the wrong side, and excludes the symmetric ones.
Spoken narration: 32 short lines per language, 24 for the guided tour and 8 reactions, all generated with text-to-speech. Turkish and English come from edge-tts (tr-TR-EmelNeural, en-US-AvaNeural), Arabic from Azure Speech (ar-EG-SalmaNeural). Each language is pinned to a single voice, so the character does not change voice from screen to screen.
Server Side and Purchases
Purchase verification happens on the server, not in the client. iOS uses the StoreKit 2 JWS signature, Android the Play Developer API. A verified transaction is written under verified_purchases/{transactionId} with an atomic create, so the same receipt is valid neither twice nor on another account. Errors fall into three classes: a genuinely invalid receipt and a configuration error are blocked; a transient network error or a 5xx fails open. That last choice is debatable. I preferred a short window of leniency over locking out a child who has already paid because of a server hiccup.
Children's Category and Compliance
In-app purchase entry points sit behind a parental verification dialog that cannot be dismissed by tapping outside it: an addition question with both terms drawn at random from 12 to 19 (answers 24 to 38), a new question 600 ms after a wrong answer, and a passed check cached for 15 minutes.
There is no such gate on the ad side, and I want to say so plainly, because my first draft claimed otherwise and the code proved me wrong. Ads are constrained by child-directed treatment and a G content rating; before the SDK initializes, the Google UMP consent flow runs with an 8-second timeout.
Test Surface
As of 21 September 2026, 5,433 test definitions in 607 test files, with 47 emulator test files on the Firestore and Cloud Functions side. On top of those, 24 regression guards named *_guard_test.dart: some scan the source on disk and lock a code pattern in CI, others assert on behavior. The overflow matrix runs 44 screens at 13 device widths, and a separate coverage test compares the screen register against the *_screen.dart files on disk, so a new screen that is missing from the register turns CI red.
Technical Challenges
- Hand-kept color-variant counts going stale; solved by generating the table from an asset scan
- Latin text inside Arabic sentences shifting punctuation; measurement plus FSI/PDI isolation
- Replaying a purchase receipt, or using it on another account; closed with an atomic create
- Keeping the purchase gate and the ad consent as two separate mechanisms in a children's category
- Forgetting to add a new screen to the overflow matrix; the coverage test catches it in CI
Why It Mattered
From the outside a casual dress-up game is a small job. From the inside it is five problems that have to be managed at once: content production, scoring math, payment security, localisation, and child compliance. In this project I closed all five by measuring and locking each one with a test; the result is visible in the store, in the purchase flow, and on the Arabic screen.
By the Numbers
| Area | Value |
|---|---|
| Codebase | 451 Dart files, 180,738 lines, 104 service files (lib/services root) |
| Wardrobe | 14 models, 1,095 options + 193 pet pieces |
| Sprite pool | 25 packs, 18,622 webp, 1,418 variant entries |
| Localization | 51 ARB files, 17 namespaces, 3 languages, 32 short TTS narration lines per language |
| Tests | 607 files, 5,433 test definitions (source count, 21 September 2026), 47 emulator test files, 24 guards |
| Server | 19 callable functions, server-side purchase verification |
Closing
The build on Play carries every line on this page. The observation I am left with: in a dress-up game the most expensive mistake is not in the art, it is in keeping a table by hand.