Find the perfect emoji using your own words. All ranking and inference run fully client‑side (No API Keys, no telemetry).
https://emoji.samcarlton.com
- Mobile‑first layout tuned for iOS Safari: sticky search header, instant results, safe‑area insets, 44×44pt hit targets.
- Type = search with
enterkeyhint="search", live updates as you type (no explicit submit). - Tap to copy with a polite toast and light haptic feedback when available.
- Accessibility first: clear labels,
role="img"on glyphs,aria-labelon buttons,role="status"for the toast. - Works offline after first load; artifacts are cached by the browser.
- Liquid‑glass UI vibe: heavier rounded corners, soft shadows, subtle blur, reduced‑motion friendly.
- Astro + React (
client:loadislands) - PGlite (WASM) + pgvector fully in the browser
- Hugging Face Transformers.js (Xenova
gte-smallONNX) - WebAssembly SIMD + Threads when cross‑origin isolated; WebGPU used if supported by runtime
- Artifacts streamed & cached in the browser; large files compressed (zstd with brotli fallback)
- Tailwind v4 (via Vite plugin)
- The vector table is prebuilt and packed into a tarball that PGlite restores at runtime.
- Source lists include the core emoji set (≈3k) plus curated synonyms and verb→emoji hints.
- Artifacts live in
src/artifacts/.
Optional seed helper (builds/refreshes artifacts): pnpm seed
src/components/App.tsx— UI & interactions (instant search, chips, copy toast, bottom sheet)src/components/Root.tsx— wraps app inStrictModeand anErrorBoundarysrc/components/ErrorBoundary.tsx— lightweight crash guard with a reload fallbacksrc/utils/db.ts— loads the prebuilt DB and runs vector searchsrc/utils/worker.ts— hosts Transformers.js embedding work off the main thread
- Target <100ms perceived keystroke → result update
- Preload models/DB after first paint; lazy‑init non‑critical work
- Use
content-visibility, minimal reflows, memoized lists - Artifacts compressed (zstd preferred; brotli fallback) and range‑request friendly for cold starts
- Recommend: automatic Zstandard compression and caching via Cloudflare Rules
- Each emoji button has a clear, descriptive
aria-label - Copy confirmation is a non‑blocking
role="status"toast - Keyboard users keep focus in the field; results update live (ARIA‑live polite)
- Respect
prefers-reduced-motion; maintain AA/AAA contrast targets
- Optimized for iOS Safari; also works on recent Chrome/Edge/Firefox
- Uses WASM SIMD everywhere; WASM Threads when cross‑origin isolation is enabled
- If threads aren’t available, it gracefully runs single‑threaded (slower, still functional)
Static build; no server required. Recommended shape:
- Host large artifacts (models/DB tar) in Cloudflare R2 behind Cloudflare CDN
- Immutable, content‑hashed filenames + long‑lived cache headers
- Cross‑Origin Isolation headers to unlock WASM Threads/SharedArrayBuffer
Example response headers (set via Cloudflare Rules/Workers):
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Resource-Policy: cross-origin
Permissions-Policy: vibrate=*, gyroscope=()
Timing-Allow-Origin: *
Cache-Control: public, max-age=31536000, immutable
If artifacts are on a different origin, ensure CORS + Cross-Origin-Resource-Policy allow embedding under COEP.
Install deps:
pnpm iRun locally:
pnpm devBuild and preview:
pnpm build
pnpm previewSeed helper (optional for scripts that prepare artifacts):
pnpm seedTest (Vitest):
pnpm test --runNotes
- Output is static (
dist/). Host on any CDN/static host. - Large assets are included via Vite
assetsIncludeso tar files ship.
- Benchmarks & accuracy tests (top‑k precision/recall)
- Multimodal descriptors research
- Quantize model toward ~17 MB target
- Auto‑expand synonyms/tags for ~3k emojis
- Cache DB in browser storage for instant warm starts
- Mirror HF LFS repos into object storage
- SEO/LLM discovery routes (e.g.,
/emoji-for-attachment) - Hunspell‑based spelling tolerance
- Progressive loaders for cold start
- Start model + emoji downloads ASAP; preconnects for model host
- zstd experiment with WASM polyfill (for non‑zstd hosts)
- CMD+K launcher &
/to focus search - Trending intents (e.g., film/album releases) via external signals
Done
- Threads for worker inference via Cloudflare header rule (COOP/COEP)
- Transformers.js updates
- Initial page‑speed work
- Model compression first pass
- Emoji loading end‑to‑end
- Mobile layout refinements (safe areas, non‑wrapping search row, a11y labels)
- 100% client‑side; no prompts or text leave the browser
- No cookies, no analytics by default (add your own if you must)
- Transformers.js example that inspired this repo:
https://github.com/huggingface/transformers.js-examples/tree/main/pglite-semantic-search - In‑browser semantic search article:
https://supabase.com/blog/in-browser-semantic-search-pglite - Uses Signal's Emoji Search Index for keywords
https://github.com/signalapp/emoji-search-index