Skip to content

DebateOwl polish: sentence case, even rows, touch targets, prerendered owl - #243

Merged
Programcode merged 12 commits into
mainfrom
design/debateowl-polish
Oct 27, 2026
Merged

Programcode merged 12 commits into
mainfrom
design/debateowl-polish

Conversation

@Programcode

@Programcode Programcode commented Oct 27, 2026 •

Copy link
Copy Markdown
Owner

Implements section 2 of the 27 Oct polish study (P1, P2 and P3, in the study's commit order) plus the prerender owl fix. It is visual polish only: no new features, and no feature or label is removed. Buttons and labels change case only; headings, toasts, empty states and the intro get the study's new copy where it gave some. Section 3 ("For Adam to decide") is left out.

Prerender fix

The prerendered /, /hu, /es and /404 pages pointed the owl at /src/assets/owl/owl-*.svg, which 404s on the deployed site. scripts/prerender.mjs runs the pages through Vite's dev SSR loader, and that loader resolved import point from '@/assets/owl/owl-point.svg' in Owl.tsx to the source path. A small plugin now resolves asset imports to the hashed file from the build manifest, and the build fails if any page still names a /src/ URL.

Checked in the built dist/ HTML:

dist/index.html:     src="/assets/owl-point-XF4NE1OK.svg"
dist/hu/index.html:  src="/assets/owl-point-XF4NE1OK.svg"
dist/es/index.html:  src="/assets/owl-point-XF4NE1OK.svg"
dist/404.html:       src="/assets/owl-surprised-CXFDqMUa.svg"

No "/src/ URL is left in any built HTML file (main had 4).

What changed

P1-1 Sentence case. About 230 English strings from the title-case list are now in sentence case: headings, toasts, dialog titles, form labels, results sections, export headings and Settings sections. Proper nouns, tool names used as names (Crossfire, Active Grounding™), speech and role names (timer speeches, Sparring turns, R1/R2 roles) and the legal and SEO strings (termsPage, privacyPage, pageHead, admin) are unchanged. Where the study gave new copy for a heading or message, Spanish and Hungarian get it too: "Sign-in required", "Too many requests", "Something went wrong", the limit dialog titles, Settings' "General" and "Delete data", and "Could not save/delete flowchart" (the house form; "Could not" outnumbers "Couldn't" 44 to 1).

Library names are not changed in this PR. #238 (design/library-name) handles the library's name. Every library-name string stays as it is on main, in all three languages: libraryPage.title, libraryPage.yourKBTitle, "Save to Library", "Saved to Library", the saved and auto-saved source toasts, Crossfire's "Use Source Library grounding", features.library and the running-text mentions.

P1-2 Intro. The copy is cut to the study's version ("Hi, I'm Ollie!", "DebateLab is becoming DebateOwl", "Your account and saved work stay the same."). On phones the owl is 112 px, the title balances across lines, and both footer buttons are 44 px tall, with "Got it" filling the row. It fits without scrolling at 390×844, 820×1180 and 1440×900 in English and Hungarian (Hungarian at 390: 614 px tall, no inner scroll).

P1-3 Not-found pages. /anything and /share/<bad> both render EmptyState with the surprised owl at 112 px (the 404 owl was 168 px). The 404 shows "404" as a muted line above the h1 "Page not found", plus a one-line description. The button labels keep their current words (see Not done).

P1-4 Tool empty panels. Generate, Attack, Brainstorm and Factoids get plain titles ("Your case will appear here" and so on) and short descriptions. EmptyState gains compact and compact-below-lg sizes. Below lg the panel under the form uses a 56 px owl with no badge.

P1-5 Balanced rows and touch targets.

  • Home utilities: one equal row of three at every width. On phones the icon sits above the label, so "Előzmények" fits.
  • History tabs: one sideways-scrolling row below lg, with the last tab fading out, and seven equal columns from lg. Hungarian "Keresztkérdezés" doesn't fit seven columns at 820 px, so iPad gets the scroll row, the study's own fallback. TAB_CLASS uses pointer-fine:min-h-0, so iPads keep 44 px.
  • Toasts: on touch screens the action button is 44 px tall and the close button 32 px.
  • Free tool pages: inline links get 4 px of padding above and below without moving the text. Breadcrumb and format-source links are at least 24 px tall, and the flow sheet's strip checkbox sits in a 44 px row. The login "Back to DebateLab" link is at least 24 px tall.

P2-1 Hero stats. Three across at every width, smaller on phones. The CTA was already above them. On phones the labels drop their letter-spacing and use tighter padding (10 px text below 380 px, hyphenated where the browser has the language), so every label fits two lines from 360 to 414 px in all three languages, including "PREPARACIÓN DIARIA CON IA".

P2-2 Timer chips. Every speech is in view, in balanced rows of at most 4 (phone), 6 (sm) and 8 (md). For example, 8 speeches are 4+4 on a phone and one row on iPad; 11 are 4+4+3. Codes wrap between words, the side dot sits next to the time, and every chip is as tall as the tallest (equal rows), never under 44 px.

P2-3 Login link. Covered by P1-5.

P2-4 iPad navigation. The top bar starts at md. Between md and lg only the active link shows its label; the others are icons that keep their names for screen readers. The menu-closing media query and two e2e nav helpers use 768 px.

P2-6 Ellipses. The single "…" character, in all three languages.

P2-7 Tour. The last step uses the first step's Fredoka heading and a 72 px celebrating owl in place of the emoji. "Welcome to DebateLab" and "You're ready" drop their emoji, and the button reads "Get started" without the "!".

P2-8 Landing. Section headings are in sentence case, with the study's copy for pricing and the final CTA heading. On iPad the hero is one centred column.

P3. Provider errors end "Try again in a minute." "Promo code applied" loses its "!". The unused home.title and home.subtitle are deleted. The 404 owl now uses the empty-state size.

Not done, and why

  • Button and label words keep their current wording; only their case changes, per the brief. So the 404 keeps "Return to home", the error page "Go to home", the Generate form "Motion / topic" (not "Motion or topic") and "Listening… Speak your motion clearly", and the final CTA "Launch DebateLab". Library grounding badges read "Grounding active" and "Grounding disabled".
  • Flowchart starter nodes keep "Your Thesis", "Opponent Attack" and "Your Rebuttal". src/lib/flowchart.ts matches saved charts to their translation key by that exact text, so changing it would stop older saved charts from translating.
  • P2-5 (pinned start button) is left out; the study marks it optional. Sparring's "Start round" sits inside the summary card, so sticky can only pin it inside that card. Pinning it across the form needs a fixed bar, which covers the motion field when the phone keyboard is open.
  • P3-2 (legal and SEO title case) and the Google Docs export headings in supabase/functions/export-gdoc (an Edge Function, deployed separately) are unchanged.
  • Agentic replay cache: some agentic/replay/ entries hold old screen text. They miss the cache and re-record on the next agentic run. No agentic test asserts the old strings.

Tests

Unit tests, e2e specs, verify-debatelab recipes and feature notes use the new strings. The production canary and staging specs match the Ask placeholder without its ellipsis, so they pass both before and after deploy.

Verification

npm run verify passes locally at 04e2bc5a (exit 0): docs check, lint, typecheck, unit tests 663/663, collaboration 30/30, Edge Function tests 482/482, build (including check-site and check-links), the service-worker test, and the desktop Chromium @smoke e2e set 47/47. None of the failures known on main (loading-performance:63, navigation-performance:344, search-quality:7) occurred in this run. This is a local pass, not CI.

The first run found one failure caused by this PR (first-run.spec.ts expected the old "Welcome to DebateLab!"). The tour specs were fixed in 00bc9cb5, and the whole ladder was rerun.

Checked in a browser at 390, 820 and 1440, in English and Hungarian:

  • Public pages: /, /hu, /login, /tools/debate-timer, /hu/eszkozok/vitaidomero, /tools/debate-flow-sheet, /nope and /share/x, served from the production build. No horizontal overflow, no broken images and no page errors.
  • Signed-in screens on a stubbed session: /app (and ?intro=show), /app/history, /app/generate, /app/attack and /app/timer. Measured: utilities in one row of three, History tabs in one row (390, 820) or seven equal columns (1440) with no clipped labels, the intro with no inner scroll, and timer chips in balanced rows for 5 formats.

Not checked: a real touch device (the 44 px coarse-pointer sizes were not measured), and the verify-debatelab recipes against the local backend stack.

Screens whose look changed

Landing /, /hu, /es (hero stats, iPad hero, section headings, What's new and use-case titles) · /login · /tools, /tools/debate-timer, /tools/debate-flow-sheet, /tools/debate-motion-generator, /tools/speech-time-calculator and their hu/es versions · /embed/debate-timer · 404 · /share/<bad code> · /app (utilities row, one-time intro, tour last step) · app header on every /app/* route at 768–1023 px · /app/generate, /app/attack, /app/brainstorm, /app/factoids (empty panel, form labels, result headings) · /app/history (tabs, card titles) · /app/timer · /app/ask · /app/flowchart · /app/settings · /app/crossfire · limit, rate-limit and pricing dialogs · toasts.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • The onboarding tour now ends with a celebratory owl screen.
    • Debate timer speech options display in a responsive grid, with labels that wrap on smaller screens.
  • Improvements
    • Updated navigation, history tabs, tool tiles, and empty states for clearer, more comfortable use across screen sizes.
    • Touch controls have larger tap targets in several areas.
    • Interface wording and labels have been refined across the app.
  • Bug Fixes
    • AI provider error messages now recommend retrying in a minute.
    • Page generation now checks for unresolved source links before output is written.

Programcode and others added 11 commits October 27, 2026 08:46
The prerender step runs the pages through Vite's dev SSR loader, which
resolved `import point from '@/assets/owl/owl-point.svg'` to
/src/assets/owl/owl-point.svg. That path 404s on the deployed site, so /,
/hu, /es and /404 showed no owl until hydration. Asset imports now resolve
to the hashed file from the build manifest, and the build fails if a page
still names a /src/ URL.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Headings, toasts, dialog titles, form labels and section names move to
sentence case (polish study P1-1, P2-8). Proper nouns, tool names used as
names, speech and role names, and the legal and SEO strings keep their
capitals. Buttons and labels keep their words; only their case changes.

Where the study gave new copy for a heading or a message, it is used in
English, Spanish and Hungarian: the tool pages' empty panels (P1-4), the
one-time intro (P1-2), the 404 heading (P1-3), the limit dialogs, the tour's
last step (P2-7), landing headings (P2-8) and the provider error tail
"Try again in a minute." (P3-1). Ellipses use the single character (P2-6).
Running text says "library"; the page title says "Source library".

The flowchart's starter node labels keep "Your Thesis": saved charts are
matched to their translation key by that exact text. home.title and
home.subtitle had no callers and are gone (P3-3).

Unit tests, e2e specs, verify-debatelab recipes and feature notes follow
the new strings. The production canary and staging specs match the Ask
placeholder without its ellipsis, so they pass before and after deploy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
EmptyState gains a compact size (56 px owl, no badge, tighter padding) and
compact-below-lg, which Generate, Attack, Brainstorm and Factoids use: below
lg the panel stacks under a form that is already the next step, so it no
longer sits there as a tall block. Titles balance across lines.

It also takes an optional icon, an h1 level, an eyebrow line and an action
element, for the not-found pages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both render EmptyState with the surprised owl at 112 px, an h1 title, a
short line and the home link. The 404 page's giant "404" becomes a muted
line above "Page not found", and the share page's grey share icon makes way
for the owl. The 404 owl drops from 168 px to the empty-state size.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Home: the three utilities are one equal row; on phones the icon sits
  above the label so Hungarian fits.
- History: the seven tabs are one sideways row below lg, fading at the
  right edge, and seven equal columns from lg, icon above label. They keep
  44 px on every touch screen, iPads included.
- Timer: every speech chip is in view, in balanced rows (8 speeches are
  4 + 4 on a phone, one row from md), with the time under the code.
- Landing hero: the three plan stats stay three across on phones, and on
  iPad the text and preview sit in one centred column.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Toasts: on touch screens the action button is 44 px tall and the close
  button 32 px (they were 32 and about 20).
- Free tool pages: inline links get 4 px above and below without moving
  the text, breadcrumbs and format source links are at least 24 px, and the
  flow sheet's strip checkbox sits in a 44 px row.
- Login: "Back to DebateLab" is at least 24 px tall with a mouse, as well
  as 44 px on touch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- One-time intro: on phones the owl circle is 112 px instead of 144, the
  title balances across lines, and both footer buttons are 44 px with Got it
  filling the row. With the shorter copy it fits 390 x 844 without scrolling.
- Tour: the last step uses the first step's Fredoka heading and a small
  celebrating owl, in place of the rocket emoji.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The app's top navigation now starts at md (768 px) instead of lg, so an
iPad shows Tools, Current debate, Library, History and Settings in the bar
instead of the menu button and a second Current debate row. Between md and
lg only the active link shows its label; the others are icons that keep
their names for screen readers, so Hungarian fits at 768 px. The theme
toggle still appears from lg.

The e2e helpers that open the menu on narrow screens use the same 768 px.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The library's name is settled in its own PR (#238), so this one keeps
every library-name string as main has it: the page title, the list card,
"Save to Library", the saved and auto-saved toasts, Crossfire's grounding
label and the running-text mentions, in all three languages. Tests and
recipes go back to the same strings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With every chip in view, long speech codes such as "A Rebuttal" no longer
fit on one line at 390 px. They now wrap between words instead of
truncating, the side dot moves next to the time so the code has the full
width, and chips in a row share one height.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Caution

Review failed

The pull request is closed.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between bbe42d9 and 04e2bc5.

Files selected for processing: 78
  • .claude/skills/verify-debatelab/features/account-data.md
  • .claude/skills/verify-debatelab/features/ai-tools.md
  • .claude/skills/verify-debatelab/features/auth-demo-login.md
  • .claude/skills/verify-debatelab/features/case-generation.md
  • .claude/skills/verify-debatelab/features/current-debate.md
  • .claude/skills/verify-debatelab/features/library-sources.md
  • .claude/skills/verify-debatelab/features/live-generation.md
  • .claude/skills/verify-debatelab/features/practice.md
  • .claude/skills/verify-debatelab/features/usage-limits.md
  • .claude/skills/verify-debatelab/recipes/account.spec.ts
  • .claude/skills/verify-debatelab/recipes/ai-tools.spec.ts
  • .claude/skills/verify-debatelab/recipes/auth.spec.ts
  • .claude/skills/verify-debatelab/recipes/billing-states.spec.ts
  • .claude/skills/verify-debatelab/recipes/billing.spec.ts
  • .claude/skills/verify-debatelab/recipes/case-generation.spec.ts
  • .claude/skills/verify-debatelab/recipes/current-debate.spec.ts
  • .claude/skills/verify-debatelab/recipes/library.spec.ts
  • .claude/skills/verify-debatelab/recipes/live-generation.spec.ts
  • .claude/skills/verify-debatelab/recipes/model-defaults.spec.ts
  • .claude/skills/verify-debatelab/recipes/usage-limits.spec.ts
  • docs/operations.md
  • e2e/admin-announcements.spec.ts
  • e2e/animation-polish.spec.ts
  • e2e/authed-pages.spec.ts
  • e2e/first-run.spec.ts
  • e2e/full-stack/account-data.spec.ts
  • e2e/full-stack/ai-tools.spec.ts
  • e2e/full-stack/auth.spec.ts
  • e2e/full-stack/billing.spec.ts
  • e2e/full-stack/case-generation.spec.ts
  • e2e/full-stack/current-debate.spec.ts
  • e2e/full-stack/debate-context.spec.ts
  • e2e/full-stack/first-run.spec.ts
  • e2e/home-navigation.spec.ts
  • e2e/hungarian-parity.spec.ts
  • e2e/live/models.spec.ts
  • e2e/live/research.spec.ts
  • e2e/loading-performance.spec.ts
  • e2e/model-matrix/generate.spec.ts
  • e2e/navigation-performance.spec.ts
  • e2e/production/canary.spec.ts
  • e2e/staging-switch.spec.ts
  • e2e/staging/authed-flows.spec.ts
  • scripts/prerender.mjs
  • src/components/features/onboarding/DebateOwlIntro.tsx
  • src/components/features/onboarding/OnboardingTour.tsx
  • src/components/features/tools/result-actions.tsx
  • src/components/features/tools/tool-links.tsx
  • src/components/free-tools/DebateTimer.tsx
  • src/components/free-tools/FlowSheet.tsx
  • src/components/free-tools/FormatReference.tsx
  • src/components/free-tools/ToolPageLayout.tsx
  • src/components/landing/Hero.tsx
  • src/components/layout/AppLayout.tsx
  • src/components/ui/empty-state.tsx
  • src/components/ui/sonner.tsx
  • src/lib/ai/error-display.ts
  • src/lib/debateowl-intro.ts
  • src/locales/en.json
  • src/locales/es.json
  • src/locales/hu.json
  • src/pages/AttackPage.tsx
  • src/pages/BrainstormPage.tsx
  • src/pages/FactoidsPage.tsx
  • src/pages/GeneratePage.tsx
  • src/pages/HistoryPage.tsx
  • src/pages/HomePage.tsx
  • src/pages/LoginPage.tsx
  • src/pages/NotFound.tsx
  • src/pages/SharedPage.tsx
  • src/test/a11y/names-and-headings.test.tsx
  • src/test/components/EnvironmentSwitcher.test.tsx
  • src/test/components/LimitReachedModal.test.tsx
  • src/test/components/SubscriptionStatus.test.tsx
  • src/test/generate/generate-form-role.test.tsx
  • src/test/i18n-untranslated.test.ts
  • src/test/onboarding/debateowl-intro.test.tsx
  • src/test/pages/SharedPage.test.tsx

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Walkthrough

The pull request revises interface wording and related test expectations, updates responsive navigation and page layouts, expands shared empty-state and onboarding components, and changes prerender asset resolution and validation.

Changes: Interface updates

Layer / File(s) Summary
Align interface copy and test expectations
.claude/skills/verify-debatelab/*, docs/operations.md, e2e/*, src/locales/*, src/lib/ai/error-display.ts, src/test/*
Locale strings, verification instructions, and test selectors and assertions are updated to match revised wording, capitalization, and punctuation. Provider-error messages now recommend retrying in a minute.
Extend shared empty states and onboarding
src/components/ui/empty-state.tsx, src/components/features/onboarding/*, src/pages/AttackPage.tsx, src/pages/BrainstormPage.tsx, src/pages/FactoidsPage.tsx, src/pages/GeneratePage.tsx, src/pages/NotFound.tsx, src/pages/SharedPage.tsx, src/test/onboarding/*, src/test/pages/SharedPage.test.tsx
The shared empty-state component gains layout, heading, and action options. Pages use the shared component, and onboarding layouts add responsive owl sizing and a celebrating owl on the final tour step.
Adjust responsive navigation and tool layouts
src/components/features/tools/*, src/components/free-tools/*, src/components/landing/Hero.tsx, src/components/layout/AppLayout.tsx, src/components/ui/sonner.tsx, src/pages/HistoryPage.tsx, src/pages/HomePage.tsx, src/pages/LoginPage.tsx, e2e/admin-announcements.spec.ts, e2e/navigation-performance.spec.ts
Navigation breakpoints move to 768px. Tool, history, landing-page, and timer layouts change for responsive display. Several links and toast controls gain touch-target sizing.

Prerender asset resolution

Layer / File(s) Summary
Resolve built assets and validate rendered pages
scripts/prerender.mjs
The prerender Vite plugin maps eligible project imports to emitted manifest URLs. The script throws when a prerendered page body contains a matched source URL.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Vite as Vite prerender server
  participant Plugin as builtAssetUrls
  participant Manifest as Vite manifest
  participant Writer as Prerender page writer
  Vite->>Plugin: Resolve project-root import
  Plugin->>Manifest: Look up eligible manifest entry
  Manifest-->>Plugin: Return emitted asset URL
  Plugin-->>Vite: Resolve import to emitted URL
  Vite->>Writer: Provide rendered page body
  Writer->>Writer: Check for matched /src/ URL
  Writer-->>Vite: Throw route and source-path error if found
Loading
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Essentials by visiting https://app.coderabbit.ai/settings/billing.

Comment @coderabbitai help to get the list of available commands.

- Timer: the speech grid uses equal rows (auto-rows-fr) and each tile
  stretches through a flex item instead of a percentage height, so a row
  with a wrapped name ("A Rebuttal", "B Summary") no longer has tiles of
  different heights. Every tile is at least 44 px.
- Landing hero: on phones the stat labels drop their extra letter-spacing,
  the cards use tighter side padding, and below 380 px the label steps down
  to 10 px, with hyphenation where the browser has the language.
  "PREPARACIÓN DIARIA CON IA" and the Hungarian trial label fit two lines
  at 360 to 414 px. The copy is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Programcode
Programcode marked this pull request as ready for review October 27, 2026 10:11
Copilot AI balanced review requested due to automatic review settings October 27, 2026 10:11
@Programcode
Programcode merged commit dc131c8 into main Oct 27, 2026
3 of 13 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants