Skip to content

Figma parity audit

Date: 2026-08-26 · Figma: FANCPIgWZwUJNuM0QPCplp (modified 2026-07-11) · App: apps/mobile @ 4bba76f

An honest screen-by-screen comparison of the shipped Flutter app against the 17-frame Figma design, plus what it would take to close each gap.

Verdict in one line

Every designed screen now exists and carries the design's structure; what is still missing is the artwork. All 17 frames have a counterpart — splash and the review screen were built from scratch — and the Material chrome is gone. Final fidelity now waits on illustrations that cannot be extracted from the Figma.

Status — updated 2026-08-26

Brand primitives are aligned in both apps, measured from the Figma:

Before (web / mobile) Now
Brand yellow #ffe500 / #FBC02D #FECC2D
Ink #0b0b0b / #1A1712 #000000
Secondary text #6b6b6b / #6A6252 #646465
Borders #ececec / #EDE8DC #EAEAEA
Default radius 0.9rem / 16–18px 14px
Primary CTA 16px rounded fully pill
Category tints invented pastels measured from the design

The mobile app's warm sand palette (#EDE8DC, #6A6252, #948B78 and friends — 112 usages) appeared nowhere in the design and is now entirely gone: grep returns zero hits.

Chrome pass: complete. mainAppBar was deleted and every screen carries a bespoke header. One raw Material AppBar remains, in planner.dart, because it hosts a TabBar that YamAppBar does not model — an events-first Scale screen with no Figma frame.

  • core/yam_header.dartYamHeader, CircleAction, YamPageTitle, and YamAppBar (a PreferredSizeWidget drop-in used by 11 screens).
  • core/app_scaffold.dart — rewired to YamHeader, converting 23 screens at once; adds StickyBar.
  • core/brand_art.dart — the artwork swap-in point (see below).

Bottom navigation is the design's floating pill: inset 20px, raised off the edge, radius 20, on a neutral-50 plate with a raised circular AI disc. The active tab is marked with a yellow indicator bar rather than yellow text, because the Figma's own active label is #FECC2D on white (~1.6:1).

Per-screen state

# Screen State
01 Splash Built — did not exist. Yellow ground, lockup, bilingual tagline, glyph scatter, skyline, tap-to-skip
02–04 Onboarding Rebuilt — device-frame heroes, service-tile collage, numbered step rail, itemised AI plan card. Copy is now mode-aware: the Figma's super-app deck when super_app_enabled is on, events-first otherwise
05 OTP Rebuilt — six discrete code boxes over one transparent field (paste and SMS autofill still work), live 00:45 resend countdown, phone chip with inline edit, security illustration
06 Login Rebuilt — phone/Google/Apple moved above the form as designed, drawn Google mark, password eye-toggle, field icons, lockup, corner glow, skyline
07 Home Rebuilt — mascot hero, search with AI sparkle + mic + yellow submit, recent-search chips, domains as a horizontal tinted rail, "near you" photo carousel with floating rating badges
08 Service detail Rebuilt — 260px full-bleed hero with floating back/favourite, social-proof chip, meta chips, package tiers side by side with escalating icons and a check badge, inclusions rail
09 Booking details Updated — bespoke header with a help affordance; time slots became a horizontal card rail matching the date strip
10 Payment Rebuilt — branded tile grid, secure badge, sticky total with a lock CTA and an encryption reassurance
11 Order confirmed Rebuilt — celebration mascot over confetti, copyable order number, four-stat row, "finding a provider" banner, four-stage tracker
12 Live tracking Built — real Google map with the service pin and the provider's live position, refreshed every 20s while en route, plus the en-route band beneath. Backed by a new provider location ping (see below). Needs a mobile-restricted Maps key to switch on — see the gating note
13 Review Built — did not exist as a screen. Mascot header, five large stars, tag chips, note with counter, up-to-4 photo upload. Replaced the old bottom sheet, whose sub-ratings were folded in so nothing regressed
14 My bookings Updated — large page title with the bell as a circular chip
15 Messages Updated — large page title, bell chip
16 Account Rebuilt — avatar with camera badge, loyalty tier chip, four-stat row, six colour-coded quick tiles
17 AI assistant Rebuilt — mascot header, category tiles that seed the prompt, three "picked for you" cards wired to real catalogue sorts

Live tracking — how to switch the map on

Screen 12 is built end to end, but the Maps SDK needs a mobile-restricted API key (Android package + SHA-1, iOS bundle id). The project's existing GOOGLE_MAPS_KEY is IP-restricted to the server for geocoding and cannot be used from a device, so a new key has to be issued. Until then kMapsEnabled is false, TrackingMap renders nothing, and the en-route band carries the same facts — no broken grey rectangle.

To enable:

  1. Create a mobile-restricted key in Google Cloud (Maps SDK for Android + iOS).
  2. Android: flutter build apk -PMAPS_API_KEY=… — the manifest placeholder defaults to empty, so a build without it still succeeds.
  3. iOS: set the MAPS_API_KEY build setting; Info.plist reads $(MAPS_API_KEY) and AppDelegate skips provideAPIKey when it is empty.
  4. Add --dart-define=MAPS_ENABLED=true.

The provider's position comes from POST /vendor/orders/{id}/location, accepted only while the order is on_the_way or in_progress and cleared on completion.

Where the build deliberately differs from the design

Beyond the type-scale and radii normalisation below, three controls in the Figma have no backend, so they were not drawn:

  • ~~Tip selector~~ — BUILT 2026-08-26. POST /orders/{order}/tip now exists: wallet-funded, completed orders only, one tip per order, and the whole amount flows to the vendor's pending settlement with no commission (matching OrderSettlement::record). A paid-out settlement is never retroactively adjusted. Six tests in OrderTipTest. The screen offers 1/3/5 KWD and disables amounts the wallet cannot cover — the design's 20/50/100 suited a wedding-scale basket, not a 10 KWD cleaning.
  • Apple Pay and STC Pay tiles (payment) — the API settles cash, KNET and card only. Three tiles are offered, not six.
  • Camera and mic in the AI composer, and the mic in the home search field — there is no speech-to-text dependency, so those buttons would only be a second "open search". Adding one is a native plugin with its own permission strings; worth doing deliberately, not as a side effect of a design pass.

Review tag keys were kept as the previous sheet wrote them (friendly, professional, on_time, thorough, great_value) so existing review data keeps aggregating; speed and cleanliness were added for the design.

The three structural blockers

1. The app has no artwork. apps/mobile/assets/ contains exactly two files: logo.png and icon.png. The Figma is illustration-led on every screen — 3D-rendered camel mascot in ~8 different poses, 3D category icons, photographic service imagery, decorative Kuwait-skyline and mosque silhouettes, and payment brand marks (Apple Pay, KNET, Visa, Mastercard, STC Pay). None of it exists as an exportable asset; it is baked into flattened frames. No amount of Flutter work closes this — someone has to produce or license the artwork.

2. ~~Chrome is Material, not custom.~~ CLOSED 2026-08-26mainAppBar deleted, every screen on a bespoke header, one documented exception (planner.dart).

3. Half the designed flow is switched off in production. Screens 07–13 are the multi-service super-app (browse categories → package tiers → direct booking → dispatch → live map). Production runs events-first with super_app_enabled off, so this flow is unreachable. Rebuilding those seven screens perfects a UI no user can currently open.

Screen-by-screen

Effort: S ≈ ½–1 day · M ≈ 1–2 days · L ≈ 3–5 days. "Assets" marks work blocked on artwork that does not exist.

# Screen App file State Principal gaps Effort
01 Splash Missing No splash screen exists at all. Design: yellow ground, mascot lockup, bilingual tagline, faint service glyphs + skyline S + assets
02–04 Onboarding ×3 onboarding.dart Exists, wrong art Three Material icons (grid_view, bolt, auto_awesome) on invented pastel grounds vs. 3D device mockups, photo collages, mascot, numbered step rail, language switcher M + assets
05 OTP otp_login.dart Exists, close Has the 6-digit entry and resend timer. Missing: hero illustration, phone-number chip with inline edit, pill CTA, "contact us" footer. Wrapped in an AppBar S
06 Login login.dart Exists, inverted Social buttons are below the form; design puts phone/Google/Apple first. Material Icons.g_mobiledata/Icons.apple instead of brand marks. No logo lockup, no "مرحبًا بعودتك" headline, no decorative art, no password eye-toggle, no field icons M
07 Home home.dart Exists, generic Design: mascot hero header, AI-sparkle + mic search, recent-search chips, 5 photographic category cards, dark AI-assistant banner, "near you" carousel, floating pill bottom nav. App: AppBar + plain list L + assets
08 Service detail service_detail.dart Exists, generic Full-bleed hero photo, "+128 booked this week" social proof, three package tier cards (سريع/شامل/VIP) with icons, inclusions grid, provider card, sticky price+CTA bar M–L + assets
09 Booking details booking_flow.dart Exists, generic Horizontal date strip, time-slot grid, address card with map thumbnail, 0/200 notes counter, priced add-on checkboxes, sticky total bar M
10 Payment payment.dart Exists, generic Six payment tiles with real brand marks, promo-code field, itemised price breakdown, sticky secure-pay bar M + assets
11 Order confirmed order_confirmation.dart Exists, generic Mascot celebration + confetti, copyable order number, 4-stat summary row, "finding a provider" banner, 4-stage tracker M + assets
12 Live tracking order_detail.dart Exists, no map Design is a full-screen map with route, vehicle marker and ETA bubble over a provider sheet with timeline and four actions. Needs Google Maps SDK + a live location channel L
13 Review + tip (inline in booking_detail.dart) No dedicated screen Mascot header, five large stars, quality tag chips, free-text area, up-to-4 photo upload, tip selector (20/50/100 KD) M + assets
14 My bookings bookings.dart Exists, generic Four status tabs, rich cards with service photo, provider avatar, inline progress bar, per-status action buttons M
15 Messages messages.dart Exists, generic Search field, four filter chips, avatar rows with presence dots, unread badges, status chips, mascot empty state M
16 Account account.dart Exists, generic Avatar with camera badge, gold-member chip, 4-stat row, six colour-coded tiles, grouped settings rows M
17 AI assistant ai_assistant.dart Exists, generic Mascot header, large composer with attach/camera/mic, five category tiles, quick-prompt chips, three personalised cards, CTA banner M + assets

Rough total: ~28–35 development days for the app screens, and that assumes the artwork already exists. It does not.

Where we deliberately do not match

Type sizes. The Figma's home screen sets category titles at 10px and subtitles at 6px; rating badges and nav labels at 8px. These are traced values from scaled-down renders, not design intent, and they sit far below any legible floor — Arabic especially. The token file keeps its 15px body floor (design-tokens.md §2) and the build normalises upward. Matching literally would regress the accessibility work in 3137ef0.

Radii. The Figma carries scaling artefacts (14.23888874, 31.54999923, 11.64999961). We round to a 6/10/14/20/pill scale that preserves the intent.

Typeface. The design uses FF Shamel Family for 66 of its 73 text layers — a commercial Monotype face with no licence in this project. Both apps ship Tajawal + Reem Kufi from Google Fonts. A licence purchase would make this a one-line change.

Yellow as text. The design's active nav label paints #FECC2D text on white — about 1.6:1, failing AA badly. We use ink with a yellow indicator instead.

  1. Commission the artwork first. Everything visual is downstream of it. Minimum set: mascot in ~8 poses, five category images, six payment brand marks, three onboarding scenes, two decorative backgrounds. Until this lands, screen work can only be structural.
  2. Ship the chrome pass — replace AppBar with the design's custom headers app-wide, and adopt the floating pill bottom nav. One coherent change, immediately visible, no assets needed.
  3. Do the events-first screens before the super-app ones. Screens 05, 06, 14, 15, 16, 17 are live for users today; 07–13 are behind the flag. Fix what people can actually see.
  4. Splash + onboarding (01–04) — highest first-impression value per day spent.
  5. Defer 12 (live tracking) until the Maps key and a realtime channel are in place; it is the only screen with a hard infrastructure dependency.

Caveat on "matching the Figma"

Eleven of the seventeen frames are flattened images with zero text layers — service detail, booking, payment, confirmation, tracking, review, bookings, messages, account, AI assistant, and splash. For those, no spacing, size, or colour can be measured; every spec is an eyeball interpretation. Reaching genuine pixel parity on them requires either the layered source or a decision to treat the render as approximate and rebuild to our own token scale. Recommendation: the latter — the tokens now carry the brand faithfully, and the renders are reference, not contract.