Devlog #38 – Fuzzy Search, Mobile UX and PWA Reliability

Wave 18 lands three deep-dive posts on plasma physics, topology and materials science, while under the hood we ship the search improvements teased in Devlog #37: Levenshtein fuzzy matching, phonetic soundex correction, and a full round of mobile UX fixes.

Platform at a Glance

345
Simulations
75
Categories
110
Blog posts
18
Content waves
36
Spotlights
28
Learning posts

Wave 18 Retrospective

Fuzzy Search

Devlog #37 deferred fuzzy matching as follow-up work. With the Wave 18 content complete, we shipped the full fuzzy search layer on top of the existing inverted-index infrastructure. The key design constraint was to stay under 15 ms p95 latency on a mid-range phone with zero network round-trips.

Levenshtein Edit-Distance Search

Algorithm: Wagner-Fischer DP (O(m·n) time, O(m) space)
  costs: insert=1, delete=1, substitute=1
  Transpositions (Damerau extension): +1 for adjacent-char swap

Matching policy:
  Query length 1–3: exact match only  (very short queries, no fuzzy)
  Query length 4–6: edit distance ≤ 1 accepted
  Query length ≥ 7: edit distance ≤ 2 accepted

Candidate filtering (pre-pruning):
  Shared trigrams: candidate must share ≥ 1 trigram with query
  Reduces DP invocations by ~95% vs naïve all-pairs approach

"Did you mean" ranking:
  Candidates sorted by: (edit distance, TF-IDF score)
  Shown as inline suggestion: "Showing results for bernoulli — did you mean bernoulli?"

Index size impact:
  Original inverted index: 28 KB gzip
  + Trigram index for candidate generation: +22 KB gzip
  Total: 50 KB gzip  (target was 54 KB; 7% under budget)

Latency (Moto G Power equivalent, 2× CPU throttle):
  Exact query:  6 ms p95
  1-edit query: 11 ms p95
  2-edit query: 14 ms p95  (within 15 ms target)
          

Phonetic Soundex Matching

Soundex algorithm (US NIST variant):
  1. Keep first letter
  2. Map remaining consonants: B,F,P,V → 1;  C,G,J,K,Q,S,X,Z → 2;
     D,T → 3;  L → 4;  M,N → 5;  R → 6
  3. Remove consecutive duplicates; remove vowels
  4. Truncate or pad to 4 characters

Example:
  "bernoulli" → B654
  "bernuly"   → B654   (same code → phonetic match)

Coverage:
  Phonetic matches fire only when Levenshtein distance > threshold
  Adds ~8% recall on misspelled queries vs Levenshtein alone
  False-positive rate: 0.3% of queries surface an unrelated hit first

Combined pipeline per keypress:
  1. Tokenise query
  2. Inverted-index exact lookup (< 1ms)
  3. Trigram-filtered Levenshtein candidates (< 8ms)
  4. Soundex fallback if < 3 results (< 3ms)
  5. Merge, score, render suggestions
          

Mobile UX Improvements

Mobile traffic accounts for 48% of sessions but historically had worse engagement time due to controls designed for desktop. This wave hardened touch interactions across all 345 simulations without changing any simulation logic.

Touch-Drag Sliders

Problem: <input type="range"> on mobile is thumb-unfriendly and ignores pointer-lock
New implementation:
  - Custom <div role="slider"> with 44px minimum touch target (WCAG 2.5.5)
  - pointerdown → pointermove → pointerup event contract (handles mouse + touch + pen)
  - setPointerCapture() avoids losing track during fast swipes
  - Velocity-based acceleration: |dx| > 8px/frame → 2× step size
Migration: 1 shared slider.js module, zero sim-specific changes
          

Pinch-Zoom on Canvas Simulations

Applies to: 3D Three.js sims (OrbitControls) and 2D canvas sims

Three.js sims (100+ simulations):
  OrbitControls already handles pinch; issue was touch-action CSS defaulting to pan
  Fix: canvas element gets touch-action: none; prevents page scroll on sim canvas
  Result: zero accidental page scrolls during 3D cam orbit on mobile

2D canvas sims (~80 simulations):
  New shared pinch.js utility:
    Track two-touch Euclidean distance → emit synthetic "wheel" event (deltaY = −Δdist)
    Sims listening to wheel zoom work automatically
    Scale factor = new_dist / old_dist, clamped to [0.2, 10×]

Double-tap reset:
  TouchEnd sequence < 300ms and < 5px movement → fires "resetView" custom event
  All sims with a reset button now also respond to double-tap
          

Bottom-Sheet Parameter Panels

Old: side-panel floats over canvas → covers 40% of small screen
New: bottom-sheet (Material Design pattern) on viewport < 640px

Implementation:
  - position: fixed; bottom: 0;  transition: transform 300ms ease
  - "handle" drag: threshold > 60px upswipe → opens; downswipe → collapses
  - Collapsed state: 48px peek (shows first 2 controls by count or importance)
  - Fully open: 55vh max-height, overflow-y: auto
  - Back-drop: dim main content when open, tap-to-close

Adoption: 22 simulations with most number of parameters migrated first
Lab-bench simulations (beam-deflection, bridge-truss, etc.): special 2-column grid layout at <480px
          

PWA Reliability

Service Worker v18 – Stale-While-Revalidate

Cache strategy changes:
  Navigation requests: NetworkFirst (was CacheFirst)
    → Always try network first; fall back to cache if offline
  Static assets (JS/CSS/WASM): StaleWhileRevalidate
    → Serve cached immediately; revalidate in background
  API / CDN Three.js: CacheFirst with 7-day TTL
    → Three.js r160 (1.2 MB) never re-downloaded unnecessarily

Offline fallback pages:
  75 category landing pages now pre-cached (was 0)
  Custom offline.html with Recently Viewed list from IndexedDB
  Offline indicator in navbar: "You're offline — showing cached content"

Background sync:
  Deferred recently-viewed writes when offline
  Uses BackgroundSync API (sync tag "rv-write")
  Fallback: beacon on visibilitychange for browsers without BackgroundSync
  Storage: IndexedDB, keyed by sim slug, max 50 entries, FIFO eviction

Lighthouse audit results (mobile, throttled):
  Performance:      94  (+6 from wave 17)
  Accessibility:    99  (unchanged)
  Best Practices:  100
  SEO:             100
  PWA:             100  (new — InstallPrompt + offline fallback)
          

Wave 18 Platform Audit Checklist

Wave 19 Preview

⭐ Spotlight #38

Cosmology & Dark Matter

CMB acoustic peaks, inflation, dark matter N-body simulations, large-scale structure filaments, and baryon acoustic oscillations.

📖 Learning #29

General Relativity & Curved Spacetime

Riemann tensor, Einstein field equations, Schwarzschild metric, geodesic precession, gravitational waves and LIGO sensitivity.

⭐ Spotlight #39

Physical Chemistry & Reaction Dynamics

Transition state theory, Eyring equation, Marcus electron transfer, femtosecond spectroscopy, and photochemical quantum yields.

🛠️ Devlog #39

PWA Offline Mode & Search Highlighting

Full offline-first architecture, in-page search term highlighting, and a structured data (JSON-LD) audit for all 345 simulations.

Contribution welcome: the mobile bottom-sheet panel system needs real-device testing on a broader range of phones — especially Samsung Galaxy Fold (nested scroll) and iPad mini (mid-size breakpoint). If you test on physical hardware and find a layout bug, please open an issue on GitHub or use the contact form. Minimal reproduction cases (device + browser + screenshot) are especially useful.