travisEATSbugs is part of the Travis design family. This doc captures how the widget enforces the family's design canon and how downstream products (Theoria, travisFIXES, travisMAKES, plus any host install) recolor the widget for their own brand.
- Family canon: memory/design-canon.md (CODE monorepo). Authoritative. Reference before any new surface.
- Voice canon: .claude/rules/voice.md. Authoritative for copy.
- This doc: how travisEATSbugs specifically applies the canon.
-
No-Shift Principle. No interaction on the widget shifts host-page layout. Hover, focus, click, drag all use composite-only transforms (translate, scale, rotate). No border-thickness change, no padding/margin change on state, no font-weight change. Run the "click everything once" test before any release.
-
prefers-reduced-motionkill switch. MANDATORY on every animated property. The breathing glow, hover scale, drag momentum, all of it: zero on reduced motion. Already wired inbug-mode.tsand the playground stylesheet. -
No em dashes. Anywhere. Code comments, docs, copy, commit messages. Use colons, periods, parens. The em-dash CI gate in
.github/workflows/ci.ymlenforces this. -
Easing:
cubic-bezier(0.45, 0, 0.55, 1)for ambient and hover.cubic-bezier(0.16, 1, 0.3, 1)for entrance reveals. 4-6s cycles on ambient motion. -
Mobile-first. 44px minimum touch target, 48-52px on narrow viewports. The widget scales up on mobile, not down. No hover-dependent interactions on touch devices.
-
Lightweight + portable. Widget bundle target: <30KB gzipped including all v0.1 features. No heavy framework dependencies in the widget itself. The widget runs anywhere a
<script>tag does.
Per canon §0, color is not a fixed palette. Roles repeat, values change per host. The widget exposes these tokens as CSS custom properties on :host (Shadow DOM root). Host pages override by setting the same custom properties at :root or body. CSS custom properties pierce Shadow DOM boundaries.
:host {
--teb-signal: #ff2a6d; /* primary accent, button background */
--teb-signal-glow: rgba(255, 42, 109, 0.35);
--teb-fg: #ffffff; /* icon color on the button */
--teb-shadow: rgba(0, 0, 0, 0.18);
--teb-z: 2147483647; /* top of stacking context */
--teb-size: 48px; /* button diameter desktop */
--teb-offset: 20px; /* distance from edge */
--teb-ease: cubic-bezier(0.45, 0, 0.55, 1);
}Deep blue host theme:
:root {
--teb-signal: #1a4d8f; /* deep blue */
--teb-signal-glow: rgba(26, 77, 143, 0.35);
}Gold host theme:
:root {
--teb-signal: #c9a449; /* gold accent */
--teb-signal-glow: rgba(201, 164, 73, 0.35);
}Theoria PWA:
:root {
--teb-signal: #7a5fa8; /* purple-mid */
--teb-signal-glow: rgba(122, 95, 168, 0.35);
}Default (no override): the widget ships with Travis signal pink. Hosts who care recolor. Hosts who don't get a tasteful default that holds up against any background.
Per Travis's design decision on 2026-05-14: per-product visual canon. Each brand (Theoria, travisFIXES, travisMAKES, travisEATSbugs marketing surface, plus any host install) keeps its own distinct visual identity. They share architectural roles and easing curves, not concrete values.
This means:
- The widget recolors per host. It does NOT impose travisFIXES pink on any other install.
- The marketing site at
eats.travisfixes.comis a travisFIXES property and follows the travisFIXES signature (warm void + signal pink + grain + crosshair cursor). - Documentation pages, playground, and example integrations show the widget recolored to each downstream brand to demonstrate flexibility.
The pin is the differentiating UX layer. No OSS project ships this well today. Build from primitives per canon §11 motion canon + §5e flourish moves:
- CSS
transform: rotate(<deterministic-from-pin-id>deg)for individual tilt. Deterministic so pins don't reshuffle on re-render. - Paper-texture SVG noise overlay (canon §1a fractalNoise pattern at higher opacity).
- Motion
whileHoverfor lift-and-tilt. Cap at scale 1.04 (canon §17c). - Motion
whileDrag+dragMomentumfor physics-based reposition. - Color-coded by pin kind:
- bug:
--teb-signal(host's signal color) - idea:
--teb-secondary(typically blue or teal in host's palette) - question:
--teb-tertiary(typically gold or purple) - praise:
--teb-success(typically green)
- bug:
- Themeable so each downstream product overrides all four.
Per canon §12, voice signatures the widget can use:
- Form success: "Signal received." (after submitting a bug, in the host's success color, replacing the form per canon §7a)
- Empty state: "Nothing pinned here yet."
- Loading: nothing. No spinners (canon §17c: "spinners read as 'didn't think about loading'"). Use skeleton or blur-up.
- Error: short, declarative. "That didn't go through. Try again." NOT "Oops! Something went wrong."
- All interactive elements have
aria-label. - The bug button uses
aria-pressedto communicate mode state. - Focus rings via
:focus-visiblewithoutline: 2px solid var(--teb-fg)andoutline-offset: 3px. - Color contrast: signal-on-bg ≥ 4.5:1 minimum. Test each host's recolor before approving.
prefers-reduced-motionkills all animation.- Keyboard navigation through all flows. The widget must be operable without a mouse.
- Screen-reader testing on every release (VoiceOver, NVDA at minimum).
Per canon §11 plus widget-specific:
- Glassmorphism stacked on glassmorphism on the pin.
- Gradient mesh hero on the marketing site.
- Inter for the headline on the marketing site (use Unbounded).
- Animated counter stats on the marketing site.
- Generic 3-col rounded-2xl card grids.
- "Hope this helps" / "Oops!" / "Let's build the future together" microcopy.
- A spinner anywhere.
- A loading screen on the widget itself. The widget should render the first paint of its UI within one frame of
init(). - Color flash on click (canon §17c: "scale-down to 0.97 / 80ms / no color flash").
- No em dashes in the diff
-
prefers-reduced-motionkills every new animation - No layout shift on any new hover/focus/active state (click-everything-once test)
- All new interactive elements have
aria-labeland visible focus state - Touch targets ≥ 44px on every viewport
- No spinner introduced
- No "Oops!" / "Hope this helps" / "Let's build the future" copy
- Bundle size delta < 5KB gzipped (or justified in PR)
- Tested on the three reference recolors (deep blue, gold, default pink)