Tags

Next.js 15TypeScriptTailwind CSS 4Zustand 5Framer Motion 11use-gesturetoolconverterpwamobile

Americanizer is a tactile, mobile-first unit converter built to feel like a premium piece of physical hardware. The design is deliberately minimal — near-white canvas, pure-black ink, a single blue accent — and every interaction is engineered to feel satisfying, from the scrub trackpad to the pseudo-haptic click audio.

What It Does

  • Full-area scrub trackpad — drag anywhere on the screen to adjust values; no knob, no slider
  • Velocity-tiered steps — slow scrubs nudge by 0.1, fast flicks jump by 100
  • Native keypad entry — tap the number to open the device's numeric keyboard directly
  • Pseudo-haptic audio — a 25 ms square-wave click fires on every detent via Web Audio
  • Context-aware motion — ambient gradient shifts with temperature, Inter's variable weight axis tracks mass, an accent fill rises with volume
  • Per-category state — each category remembers its own units and value across switches
  • PWA install prompt — detects iOS vs Android and surfaces the right A2HS instructions on first visit

Categories

CategoryDefaultNotes
Temperature22 °C → 71.6 °FFixed axis; no swap; floor −273.15 °C
Weight70 kg → 154.3 lbVariable font weight effect; floor 0
Length1 m → 39.37 inFloor 0
Volume1 L → 33.81 fl ozCulinary fractions (½, ¼, ⅛…); floor 0
Speed100 km/h → 62.1 mphFloor 0
Area100 m² → 1076.4 ft²Floor 0
Currency1 USD → INRLive exchange rates

Tech Stack

Next.js 15 (App Router, Turbopack), TypeScript (strict), Tailwind CSS 4, Zustand 5 with `persist` middleware, Framer Motion 11 (motion values and springs), `@use-gesture/react` for the scrub trackpad, and Vaul for the unit picker bottom sheet.

State is persisted under `americanizer:v1` via `partialize` to keep localStorage minimal. The displayed "to" value is always derived — `convert(category, value, fromUnit, toUnit)` — so the store holds a single source of truth.

Design Details

The scrub trackpad accumulates `(mx − my)` gesture input — up and right both increase, down and left both decrease — and fires a detent every 12 px of travel. Each detent plays a click and emits `onDelta`, which routes to the active zone's value setter.

Volume and culinary US units (`cup`, `tbsp`, `tsp`, `floz`) render fractional remainders as the nearest Unicode vulgar fraction rather than raw decimals. Everything else uses decimal display.

The entire context-aware motion pipeline runs through Framer Motion values — no React state updates, no re-renders. Category-specific `useTransform` chains drive the ambient gradient, font weight axis, and fill height entirely off a single spring.