TENTA.DEV v5.0
--:--:-- CET
← ALL PROJECTS / 02 / UMTIL-SUITE
02 Mobile 2024 — Present UmtilScrub shipped · UmtilNote in development

Umtil Suite

A family of small, opinionated mobile apps — single-purpose, design-forward, on-device first — sharing a React Native / Expo stack and a freemium-via-RevenueCat model.

ROLE
Solo developer
YEAR
2024 — Present
STATUS
UmtilScrub shipped · UmtilNote in development
Expo SDK 54React Native 0.81TypeScriptExpo RouterZustandReanimated v4MMKVRevenueCati18nextHonoDrizzleNeon PostgresEAS Build
§01 OVERVIEW

Umtil Suite is a family of single-purpose mobile apps published under the `umtil` / `com.umtilsuite` org. Each app is on-device first, design-forward, and built on a shared Expo + React Native stack with a common theme system, animation grammar, subscription flow, and 11-language i18n pipeline. Cloud is always a Pro upsell, never a requirement. Two apps exist today: UmtilScrub (shipped) — a privacy-focused EXIF metadata scrubber — and UmtilNote (planning + scaffolding) — a bubble-based ephemeral note app where notes age visually through five stages and disappear at midnight unless popped or archived.

§02 PROBLEM

Most "utility" mobile apps are either bloated do-everything suites or thin wrappers around a single API call with ads bolted on. The goal was the opposite: a family of apps that each do exactly one thing, look distinctive, work fully offline, and treat Pro as an expansion of the free experience rather than a paywall around it. For UmtilScrub specifically — every existing metadata stripper either ships data to a server, locks the basic action behind a subscription, or leaves orientation mangled after the strip. None handled JPEG, PNG, HEIC, and WEBP cleanly on-device with one strategy.

§03 APPROACH

Built a shared scaffold across both apps: Expo Router with typed routes and the React Compiler, a `constants/theme.ts` system (Colors / Spacing / Typography / SpringConfig / Timing / Glow) consumed via `ThemedText` / `ThemedView`, an animated custom tab bar, a Zustand store template with no side effects in actions, and an animation toolkit (`AnimatedPressable`, `GlowBorder`, `StaggeredListItem`, spring + timing presets). Subscriptions go through `lib/subscription/service.ts` → `useSubscription` → `useProGate`, with a mock mode that activates when the RevenueCat key starts with `"YOUR_"` so the entire flow is testable without real keys. UmtilScrub uses `piexifjs` (pure JS) over native EXIF libs to dodge bridge friction. Strip strategy branches by format: `piexif.remove()` for un-rotated JPEGs, `manipulateAsync` re-encode for rotated JPEGs (bakes orientation, strips EXIF), and re-encode to JPEG for PNG / HEIC / WEBP. Output writes to a cache dir that auto-cleans on reset. The processing screen runs a staggered "redaction" animation per EXIF field in parallel with the actual strip, and both must finish before the results screen shows. UmtilNote treats notes as bubbles on a graph-paper grid. Aging is computed at render time, never persisted — a `useNow()` hook ticks every 30 s to drive the visual stages (`fresh → mature → aging → fading → critical`). Expiration cleanup runs on `AppState` foreground + a 60 s interval + a per-bubble render guard, with no real background tasks. MMKV is chosen over AsyncStorage for synchronous reads (no first-render loading state) and iOS App Group widget compatibility. The pop animation is a four-phase ritual — anticipation squeeze → burst + fade → 8–12 particles → cleanup — with haptics tuned per phase. A Hono + Drizzle + Neon Postgres backend is scaffolded for future cloud sync and shared boards.

§04 OUTCOME

UmtilScrub is shipped (build #5) on iOS and Android with full localization across 11 languages, RTL auto-toggle for Arabic, and a freemium split that gates batch processing, video support, and custom metadata templates behind Pro. The app works fully offline; no data leaves the device. UmtilNote has plans complete, server scaffolded, and a design system locked in — graph-paper background, 5-stage visual aging, multi-phase pop animation, daily recap modal, and a Pro tier covering unlimited archive, custom lifespans, cloud sync, and premium pop variants. The shared scaffolding (theme, animation toolkit, subscription flow, i18n pipeline, custom tab bar) carried over from UmtilScrub with no rework.

2
Apps in suite
11
Supported languages
JPEG · PNG · HEIC · WEBP
Strip formats handled
5
Aging stages
§05 NOTES TO SELF
  • On-device first is a product position, not just an engineering choice — it's the entire reason a metadata scrubber is trustworthy and the entire reason ephemeral notes feel safe to write.
  • A shared scaffold across small apps pays off fast — the second app inherits the theme system, animation grammar, subscription flow, and i18n pipeline for free, so the only work left is the thing that makes it different.
  • Mock mode for RevenueCat (triggered by a `"YOUR_"` key prefix) made the paywall and gating logic fully testable without real keys, real purchases, or sandbox accounts.
  • Computing aging at render time instead of persisting it kept the data model honest — a bubble's visual stage is a pure function of `now` and `expiresAt`, never out of sync with reality.