feat(brand): rebrand DeepBound to Kynd with Linen & Ink design system#33
Open
jeremykamber wants to merge 66 commits into
Open
feat(brand): rebrand DeepBound to Kynd with Linen & Ink design system#33jeremykamber wants to merge 66 commits into
jeremykamber wants to merge 66 commits into
Conversation
- Add rate limiting to analyzePricingPage server action - Use rate-limiter-flexible with configurable limits (default 5 requests/minute) - IP-based limiting with proper error handling - Environment variable configuration for limits - Includes retry-after guidance in error messages Resolves issue with preventing abuse of audit functionality
- Add same rate limiting logic to generatePersonasAction - Remove deprecated GeneratePersonasAction.ts file - Use shared env vars for consistent limits
Implement rate limiting for audit requests
… Avatar, Steps, FlowDialog)
…and minimal aesthetic
…solve type error in chat
…f doc - Updated DeepBound logo SVG with new primary color (#2e5bff) and improved styling for consistency with refreshed UI. - Refined dark mode color scheme in `globals.css` by removing an obsolete sidebar variable and aligning with new design tokens. - Adjusted Next.js type import path for improved dev environment compatibility. - Added implementation strategy handoff document detailing recent UI refinements, dark mode toggle, color updates, bug fixes, and next steps. Supports ongoing UI redesign and improves visual consistency across the app.
- Change default currentStep from 2 to 0 in persona flow (Synthesizing Audience dialog) - Change default currentStep from 3 to 0 in analysis flow (Running Simulations dialog) This prevents the step indicator from briefly showing all steps as completed when the dialogs open with undefined progress state.
SOLID: S=PersonaAdapter handles insight generation; O=LlmServicePort extended with generatePersonaInsight; D=GeneratePersonasUseCase depends on abstraction
SOLID: S=PersonaProfilePanel responsibility limited to summary rendering
SOLID: S=PersonaDetailModal handles detail rendering; D=AudienceView uses PersonaDetailModal abstraction
SOLID: S=PersonaDetailModal handles animation concerns through framer-motion
…veness and streaming updates
- Transform PersonaChat from side panel to centered modal using Radix UI Dialog - Add tooltip parsing for <% text | excerpt %> syntax in chat messages - Add custom --chat-user-bubble and --chat-assistant-bubble CSS variables - Make FlowDialog backgrounds solid instead of blurred/transparent - Remove favoriteColors from Persona entity, schema, prompts, and UI - Style chat bubbles with distinct backgrounds for user vs assistant - Add padding to tooltips for better text spacing - Make popover/tooltip backgrounds solid instead of transparent
- Add scripts/benchmark.ts with CLI flags (--personas-only, --use-mock-personas, --url) - Add tsx dependency for running TypeScript directly - Add npm run benchmark script - Add unit tests for timing and flag parsing - Timing output in X.XXXs format (e.g., 12.345s)
…d scans, browser waits
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
- New POST endpoint at /api/report returns full PricingAnalysis JSON - Ideal for test loops, CI/CD integration, batch processing - Validates url, personas array, and individual persona id/name fields - Uses ParsePricingPageUseCase to generate per-persona analysis - Includes 12 unit tests for validation logic - Added documentation in docs/REPORT_API.md
perf: optimize persona and pricing analysis generation (105s -> 53s)
chore(backlog): update BACKLOG.md to mark completed items (2026-04-06)
- Update globals.css with Linen (#F2F0E9) and Ink (#1A1A1B) color palette - Replace Clay (#D9775F) for destructive actions - Add 400ms breath-like animation timing (ease-in-out) - Add kynd-pulse animation for loading states - Update layout.tsx with Fraunces (headings) and Inter (body) fonts - Update metadata title to 'Kynd' with descriptive tagline - Remove old blue/indigo primary color entirely
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
❌ Deploy Preview for deepbound failed. Why did it fail? →
|
- Verify marketing page loads with Kynd branding elements - Verify dashboard layout has Kynd branding - Verify no DeepBound references remain in codebase - Test color scheme implementation via Playwright E2E
Contributor
There was a problem hiding this comment.
Pull request overview
This PR implements a broad “DeepBound” → “Kynd” rebrand (Linen & Ink styling, Fraunces/Inter typography, refreshed layouts/components) and also introduces notable workflow/performance/infra changes (analysis concurrency + scouting optimizations, rate limiting, new API routes, and benchmarking tooling).
Changes:
- Rebuilds the marketing + dashboard UI around new Kynd-branded layouts and custom components (FlowDialog/StepIndicator/MinimalCard/etc.).
- Speeds up pricing analysis (reduced Playwright waits, parallelized HTML scouting/summarization, increased persona concurrency, token limiting controls).
- Adds operational tooling and guardrails (rate limiting on server actions, benchmark script + tests, new
/api/reportand/api/chatroutes).
Reviewed changes
Copilot reviewed 106 out of 112 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| vitest.config.ts | Adds @ alias for tests |
| thoughts/shared/research/2026-03-04-pricing-analysis-speed-optimizations.md | New performance research doc |
| thoughts/shared/research/2026-02-23-running-simulations-nodes-flash.md | New UI glitch research doc |
| thoughts/shared/research/2026-02-21-ui-refinements.md | New UI refinements research doc |
| thoughts/shared/research/2026-02-21-deepbound-ui-redesign.md | New redesign mapping doc |
| thoughts/shared/research/2026-02-21-deepbound-design-overhaul.md | New design overhaul research doc |
| thoughts/shared/research/2026-02-20-rate-limiting-audits.md | New rate limiting research doc |
| thoughts/shared/plans/2026-03-04-pricing-analysis-speed-optimization.md | New perf optimization plan |
| thoughts/shared/plans/2026-02-23-running-simulations-nodes-flash.md | New UI glitch fix plan |
| thoughts/shared/plans/2026-02-21-deepbound-design-overhaul.md | New design overhaul plan |
| thoughts/shared/plans/2026-02-20-rate-limiting-audits.md | New rate limiting plan |
| thoughts/shared/handoffs/ENG-general/2026-02-21_14-27-38_ENG-general_ui-refinements.md | New eng handoff doc |
| thoughts/research/janitor-report-2026-02-18-0238.md | New janitor report |
| thoughts/research/branch-summary-goose-2026-02-18-0238.md | New branch summary |
| thoughts/research/2026-02-26-persona-cards-research.md | New persona cards research |
| thoughts/research/2026-02-18-0244-goose-finalization.md | New goose finalization research |
| thoughts/plans/2026-02-18-0245-finalize-goose-branch.md | New goose finalization plan |
| test/persona-names.test.ts | Adds deterministic naming test |
| src/ui/dashboard/components/views/SetupView.tsx | New Kynd setup flow UI |
| src/ui/dashboard/components/views/AudienceView.tsx | Persona grid + early chat wiring |
| src/ui/dashboard/components/DashboardClient.tsx | New dashboard client orchestration |
| src/ui/components/dashboard/views/PersonaGridView.tsx | Removes legacy persona grid view |
| src/ui/components/dashboard/views/CustomerInputView.tsx | Removes legacy input view |
| src/ui/components/dashboard/shared/ThoughtfulDialog.tsx | Removes legacy dialog |
| src/ui/components/dashboard/shared/RefinedStep.tsx | Removes legacy step UI |
| src/ui/components/dashboard/shared/PsychologicalRadar.tsx | Removes legacy radar |
| src/ui/components/dashboard/shared/PsychologicalProfile.tsx | Removes legacy profile UI |
| src/ui/components/dashboard/shared/PersonaCard.tsx | Removes legacy persona card |
| src/ui/components/dashboard/shared/MetricBlock.tsx | Removes legacy metrics block |
| src/ui/components/UserForm.tsx | Removes legacy auth form |
| src/ui/components/RegisterUserComponent.tsx | Removes legacy register component |
| src/ui/components/PersonaChat.tsx | Removes legacy persona chat |
| src/ui/components/PersonaAnalysisPDF.tsx | Removes legacy PDF report |
| src/ui/components/Logo.tsx | Removes DeepBound logo component |
| src/ui/components/GazeOverlay.tsx | Removes legacy gaze overlay |
| src/infrastructure/mappers/PersonaMapper.ts | Removes favoriteColors persistence |
| src/infrastructure/adapters/VisionAnalysisAdapter.ts | Adds tokenLimit + tighter JSON rules |
| src/infrastructure/adapters/RemotePlaywrightAdapter.ts | Reduces waits + changes loader waiting |
| src/infrastructure/adapters/LlmServiceImpl.ts | Updates model defaults; disables “thinking”; adds batch persona methods |
| src/hooks/use-theme.ts | Adds localStorage theme hook |
| src/domain/ports/LlmServicePort.ts | Extends port (tokenLimit + persona insight/batch) |
| src/domain/entities/MockPersonas.ts | Adds aiInsight to mock personas |
| src/data/genderless_names.ts | Adds curated neutral name list |
| src/components/ui/tooltip.tsx | Tooltip spacing/style update |
| src/components/ui/input.tsx | Switches to underline input style |
| src/components/ui/dialog.tsx | Darker overlay styling |
| src/components/ui/card.tsx | Updates card variants + adds kynd variant |
| src/components/ui/button.tsx | Updates Kynd button styling |
| src/components/theme-toggle.tsx | Adds theme toggle button |
| src/components/custom/StepIndicator.tsx | New step indicator component |
| src/components/custom/StatusBadge.tsx | New badge component |
| src/components/custom/PersonaProfilePanel.tsx | New persona panel card UI |
| src/components/custom/PersonaAvatar.tsx | New avatar component |
| src/components/custom/MinimalCard.tsx | New card container component |
| src/components/custom/FlowDialog.tsx | New progress dialog component |
| src/components/PartialPersonaCard.tsx | Removes legacy partial card |
| src/application/usecases/tests/ParsePricingPageUseCase.test.ts | Adds tests for new analysis behavior |
| src/application/usecases/tests/GeneratePersonasUseCase.test.ts | Adds tests for persona parallelism/insights |
| src/application/usecases/ParsePricingPageUseCase.ts | Parallelization + concurrency + tokenLimit; scout tweaks |
| src/application/usecases/GeneratePersonasUseCase.ts | Batch backstories + batch insights |
| src/app/layout.tsx | Switches to Fraunces/Inter; adds Vercel analytics |
| src/app/api/report/route.ts | Adds report API endpoint |
| src/app/api/report/tests/route.test.ts | Adds report API validation tests |
| src/app/api/chat/route.ts | Adds chat streaming API endpoint |
| src/app/(marketing)/layout.tsx | Kynd marketing header/footer/layout |
| src/app/(app)/dashboard/page.tsx | Switches to DashboardClient |
| src/app/(app)/dashboard/layout.tsx | Adds Kynd dashboard shell |
| src/actions/generatePersonas.ts | Adds server-action rate limiting |
| src/actions/analyzePricingPage.ts | Adds server-action rate limiting + tokenLimit env |
| src/actions/GeneratePersonasAction.ts | Removes legacy server action |
| setup.sh | Adds local sed-based setup script |
| scripts/benchmark.ts | Adds benchmark runner |
| scripts/tests/benchmark.test.ts | Adds benchmark unit tests |
| results.tsv | Adds perf experiment results |
| public/deepbound_logo.svg | Removes old logo asset |
| prs/ui-refinements.md | Adds PR note doc |
| prs/new_ui_description.md | Adds PR narrative doc |
| prs/1_description.md | Adds benchmark PR narrative doc |
| package.json | Adds dependencies + benchmark script |
| fix_typography_v3.py | Adds typography cleanup script |
| fix_typography_v2.py | Adds typography cleanup script |
| fix_typography.py | Adds typography cleanup script |
| README.md | Updates product branding/docs links |
| DEVELOPER_PROMPT.md | Removes legacy prompt doc |
| DESIGNER_PROMPT.md | Removes legacy prompt doc |
| BRAND_CONSTITUTION.md | Adds Kynd brand constitution |
| BACKLOG.md | Rewrites backlog sections |
| AGENTS.md | Adds agent guidelines doc |
| .sisyphus/ralph-loop.local.md | Adds loop instruction artifact |
| .env.local | Adds local env file (placeholder) |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const result = parseArgs(); | ||
| expect(result.personasOnly).toBe(false); | ||
| expect(result.useMockPersonas).toBe(false); | ||
| expect(result.url).toBe("https://pricing.example.com"); |
| @@ -0,0 +1,79 @@ | |||
| import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; | |||
Comment on lines
+11
to
+12
| keyPrefix: openrouterKey?.slice(0, 15), | ||
| keyLength: openrouterKey?.length, |
Comment on lines
339
to
+352
| // 3. Custom: Wait for no 'loading' text/spinners/skeletons to exist | ||
| const loaders = [ | ||
| // Combine into one selector for efficiency | ||
| const loaderSelector = [ | ||
| ':text-matches("loading", "i")', | ||
| '[class*="skeleton"]', | ||
| '[class*="shimmer"]', | ||
| '[class*="loading-indicator"]' | ||
| ]; | ||
| ].join(', '); | ||
|
|
||
| for (const selector of loaders) { | ||
| await page.locator(selector).first().waitFor({ state: "hidden", timeout: 2000 }).catch(() => { }); | ||
| } | ||
| await page.locator(loaderSelector).first().waitFor({ state: "hidden", timeout: 1500 }).catch(() => { }); | ||
|
|
||
| // 4. Final "Settling" pause (the 1000ms breather) | ||
| // Final "Settling" pause (the 250ms breather) | ||
| // Essential for animations/transitions to finish before a screenshot | ||
| await page.waitForTimeout(1000); | ||
| await page.waitForTimeout(250); |
| "playwright-extra": "^4.3.6", | ||
| "plop": "^4.0.4", | ||
| "puppeteer-extra-plugin-stealth": "^2.11.2", | ||
| "radix-ui": "^1.4.3", |
Comment on lines
57
to
+89
| const abbreviate = GeneratePersonasUseCase.ABBREVIATE_BACKSTORIES; | ||
| const subStepsPerPersona = abbreviate ? 1 : 4; | ||
|
|
||
| // Broadcast initial personas immediately for UI responsiveness | ||
| onProgress?.({ | ||
| step: 'GENERATING_BACKSTORIES', | ||
| personas, | ||
| totalCount: personas.length, | ||
| completedCount: 0, | ||
| totalSubSteps: personas.length * subStepsPerPersona, | ||
| completedSubSteps: 0, | ||
| streamingText: "" | ||
| }); | ||
|
|
||
| const totalCount = personas.length; | ||
| let completedCount = 0; | ||
| let completedSubSteps = 0; | ||
| const totalSubSteps = totalCount * subStepsPerPersona; | ||
|
|
||
| const pLimit = (await import('p-limit')).default; | ||
| const limit = pLimit(2); // Generate 2 backstories in parallel | ||
|
|
||
| await Promise.all(personas.map((persona) => limit(async () => { | ||
| onProgress?.({ | ||
| step: 'GENERATING_BACKSTORIES', | ||
| personaName: persona.name, | ||
| completedCount, | ||
| totalCount, | ||
| completedSubSteps, | ||
| totalSubSteps, | ||
| personas: JSON.parse(JSON.stringify(personas)), | ||
| streamingText: "" | ||
| }); | ||
|
|
||
| console.log(`[GeneratePersonasUseCase] Generating ${abbreviate ? 'abbreviated ' : ''}backstory for ${persona.name}...`); | ||
| // OPTIMIZATION: Use batch generation instead of per-persona calls | ||
| // This reduces 3 LLM calls to 1 for backstories | ||
| console.log("[GeneratePersonasUseCase] Generating batch backstories..."); | ||
| onProgress?.({ | ||
| step: 'GENERATING_BACKSTORIES', | ||
| personas, | ||
| totalCount, | ||
| completedCount: 0, | ||
| totalSubSteps, | ||
| completedSubSteps: 0, | ||
| }); | ||
|
|
||
| const backstory = abbreviate | ||
| ? await this.llmService.generateAbbreviatedBackstory(persona) | ||
| : await this.llmService.generatePersonaBackstory(persona); | ||
| const backstoryTexts = await (this.llmService as any).generateAbbreviatedBackstoriesBatch(personas); | ||
| personas.forEach((persona, i) => { | ||
| persona.backstory = backstoryTexts[i]; | ||
| }); |
Comment on lines
+3
to
+6
| import { MinimalCard } from "./MinimalCard" | ||
| import { PersonaAvatar } from "./PersonaAvatar" | ||
| import { StatusBadge } from "./StatusBadge" | ||
|
|
Comment on lines
+20
to
+33
| {(!hasPersonas || !hasAnalyses) && ( | ||
| <SetupView | ||
| personaFlow={personaFlow} | ||
| analysisFlow={analysisFlow} | ||
| hasPersonas={!!hasPersonas} | ||
| /> | ||
| )} | ||
|
|
||
| {hasPersonas && !hasAnalyses && ( | ||
| <AudienceView | ||
| personas={personaFlow.personas!} | ||
| analysisFlow={analysisFlow} | ||
| /> | ||
| )} |
Comment on lines
+153
to
+156
| const SKIP_VISION_VERIFY_ON_HIGH_CONFIDENCE = true; | ||
| const isHighConfidence = pricingLocation.selector?.startsWith('#') || | ||
| pricingLocation.selector?.toLowerCase().includes('pricing') || | ||
| pricingLocation.anchorText?.toLowerCase().includes('pricing'); |
Comment on lines
+14
to
+16
| "rounded-xl border border-[rgba(26,26,27,0.08)] bg-[#F8F7F2] p-6 md:p-8 text-foreground shadow-sm transition-all duration-400 ease-in-out", | ||
| hoverable && "hover:border-[rgba(26,26,27,0.15] cursor-pointer", | ||
| className |
- Add formatError helper to usePersonaFlow hook - Add formatError helper to useAnalysisFlow hook - Error Rule: never 'System Error' - use warm Kynd messages - Rate limit: 'Kynd hit a limit here...' - Cancelled: 'Kynd stopped here. Ready when you are.' - Generic: 'Kynd lost the trail here. Let's try that again.' chore: rename AGENTS.md title to Kynd chore: archive old DESIGN_SYSTEM.md (superseded by BRAND_CONSTITUTION)
Per Error Rule in BRAND_CONSTITUTION.md: 'Kynd lost the trail here' not 'thread'
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Complete rebrand from DeepBound to Kynd following the Brand Constitution guidelines.
Visual Design Overhaul
Component Updates
Layout & Navigation
Copy Overhaul
Assets
Testing