Imouto

Motivka Embed and UX Overhaul

Ported the imouto frontend into motivka as an embedded route, overhauled the explorer UX with default AU sorting and proportional task bars, built a dot strip chart for the detail page, and aligned everything to the Motif design system.

12 Phases
16 Tasks
2 Days

The Problem

The imouto frontend was living as a standalone SvelteKit app, deployed separately from motivka. It had its own nav, its own design tokens, and a completely different visual language. Caddy was proxying it at /imouto/*, which felt clunky. The explorer page itself had UX issues -- no default country, no obvious sort order, and the task breakdown was raw text counts rather than anything visual. The detail page was worse: a continuous ring chart that could not communicate individual task exposure levels.

What I Built

This was a two-phase initiative: fix the UX first in the standalone, then port everything into motivka.

Phase 1: UX improvements (standalone)

I started with the explorer page. The country filter now defaults to AU with occupations sorted by highest AI exposure. The old CountryToggle became a compact pill ([ AU | US | All ]). I added a sort direction toggle so you can flip between high-to-low and low-to-high.

The biggest visual win was replacing ImoutoMeter -- a thin progress bar with a percentage -- with a proportional segmented bar showing full/partial/human task ratios. You can now compare task distribution across roles at a glance.

On the detail page, I simplified the share card by stripping out the watermark, grid texture, AI tools strip, and footer code. Then I built TaskDotStrip.svelte -- an inline SVG with one circle per task, coloured by exposure level, arranged from highest to lowest. Hovering a dot shows the task name; clicking expands the full task detail inline. This replaced the old ring chart entirely.

Phase 2: Motivka embedding

With the UX validated, I moved dataset.json and matches.json into imouto's app/static/ directory so they are served as static files. In motivka, I created a lib/imouto/ module with types, data helpers, and styles, then scaffolded routes at /experiments/imouto/. The server loaders fetch data from the running imouto service at request time -- SSR, not prerendered -- because the production Docker build only has the motivka monorepo source.

I scoped the navy accent override (--accent: var(--navy-royal)) to a CSS class on the imouto layout wrapper so it does not leak into motivka's fire-engine-red accent. Every component primitive was audited against Motif patterns. The old standalone nav and layout were retired -- motivka's shell replaces them.

Key decisions: Runtime fetch rather than build-time imports (the Vite alias would fail inside the container). UX improvements done in standalone first for faster iteration. Phase 7 (Motif integration stubs) was cancelled since embedding in motivka makes them redundant.

What is Next

The standalone app stays as a local dev fallback. Dot strip / task list hover sync and animated transitions are deferred to a future polish phase. The Caddy proxy route remains until the motivka embed is verified in production on Hetzner.

Features Delivered

Phase 9 -- Explorer UX

  • Default country AU with score-descending sort
  • Compact pill country toggle
  • Sort direction toggle (high/low)
  • Proportional segmented task bar replacing ImoutoMeter

Phase 10 -- Detail Page

  • Simplified share card (removed watermark, grid, tools strip)
  • TaskDotStrip SVG component with per-task circles
  • Hover tooltip and click-to-expand on dot strip
  • Dot strip integrated into detail page, ring chart removed

Phase 11 -- Motivka Embedding

  • Static dataset served from imouto app/static/
  • lib/imouto/ module in motivka (types, data, styles)
  • SSR loaders fetching from imouto service at runtime
  • Navy accent scoped to .imouto-accent layout wrapper

Phase 12 -- Motif Alignment

  • All components audited against Motif tokens
  • Standalone token overrides replaced
  • motivka HeroSection/PageSection used for layout
  • Legacy standalone nav retired

Key Decisions

  • Runtime fetch from imouto service instead of build-time Vite alias (works identically in local Docker Compose and on Hetzner)
  • SSR via +page.server.ts -- no prerendering, data comes from a runtime service
  • UX improvements built in standalone first for faster iteration, then ported
  • Phase 7 Motif integration stubs cancelled -- superseded by motivka embedding