-
Notifications
You must be signed in to change notification settings - Fork 0
Replace composability demo with agent anatomy walkthrough #249
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
TommyBez
wants to merge
22
commits into
main
Choose a base branch
from
claude/outname-landing-refactor-zh1m9b
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 7 commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
95dea25
refactor(web): restructure landing around an "agent is a directory" n…
claude f663ef4
refactor(web): re-architect the landing IA around eve's full page str…
claude 43584a8
refactor(web): ground the landing in real product facts + add binding…
claude fe9d3e2
refactor(web): adopt eve's hero toggle + alternating code walkthrough
claude f71f4ff
refactor(web): eve-style stacked production cards + two-column primit…
claude 4a4e261
fix(web): replace the sparse alternating walkthrough with a compact f…
claude 5518ee8
feat(web): premium code windows + typed hero terminal
claude 3fa3c5d
refactor(web): rebuild hero + walkthrough to match the real eve layout
claude 7750309
refactor(web): eve-style 3-column production + shorten the page
claude 0180014
refactor(web): give the directory walkthrough panel equal weight
claude e6f19e8
refactor(web): match eve's sticky-swap walkthrough animation
claude 4de88a3
style(web): more breathing room between walkthrough steps
claude c1b01a9
content(web): richer markdown bodies in the directory walkthrough
claude 09e40ba
refactor(web): eve-style "built on primitives" with product cards + C…
claude d773fd4
feat(web): make the hero command copyable + stop the toggle layout bump
claude 1c663ae
refactor(web): fill the hero agent card + align the production columns
claude d29de54
copy(web): final CTA headline → "Give it a sandbox. Watch it work."
claude e150694
refactor(marketing): tighten landing density and unify production mocks
claude 9e3be64
fix(marketing): ground landing copy in real codebase facts
claude d67a562
refactor(marketing): de-dupe landing narrative, unify on outname's terms
claude 8ec0079
feat(marketing): add brand logos to integrations and inference providers
claude c8fe80e
feat(marketing): real brand marks for Neon and the custom-logo integr…
claude File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
134 changes: 134 additions & 0 deletions
134
packages/shared/marketing/components/landing/agent-anatomy/agent-file-tree.tsx
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,134 @@ | ||
| 'use client' | ||
|
|
||
| import { | ||
| type AgentTreeNode, | ||
| type AnatomyStepId, | ||
| agentSlug, | ||
| agentTree, | ||
| type FileOwner, | ||
| } from '@outname/shared/marketing/data/agent-anatomy' | ||
| import { cn } from '@outname/ui/lib/utils' | ||
| import { FileTextIcon, FolderIcon } from 'lucide-react' | ||
|
|
||
| const DEPTH_INDENT_REM = 0.75 | ||
|
|
||
| const ownerDot: Record<FileOwner, string> = { | ||
| agent: 'border border-current opacity-50', | ||
| shared: 'bg-current opacity-50', | ||
| user: 'bg-brand', | ||
| } | ||
|
|
||
| function rowClasses(active: boolean, interactive: boolean) { | ||
| return cn( | ||
| 'ease flex w-full items-center gap-2 border-l-2 py-1.5 pr-3 text-left font-mono text-xs tracking-normal transition-colors duration-150', | ||
| active | ||
| ? 'border-brand bg-foreground text-background' | ||
| : 'border-transparent text-muted-foreground', | ||
| interactive && !active && 'hover:bg-muted hover:text-foreground' | ||
| ) | ||
| } | ||
|
|
||
| function TreeRow({ | ||
| active, | ||
| node, | ||
| onSelectStep, | ||
| }: { | ||
| active: boolean | ||
| node: AgentTreeNode | ||
| onSelectStep?: (id: AnatomyStepId) => void | ||
| }) { | ||
| const Icon = node.kind === 'dir' ? FolderIcon : FileTextIcon | ||
| const isStepNode = Boolean(node.stepId) | ||
| const paddingLeft = `${node.depth * DEPTH_INDENT_REM + 0.5}rem` | ||
|
|
||
| const inner = ( | ||
| <> | ||
| <Icon | ||
| className={cn( | ||
| 'size-3.5 shrink-0', | ||
| active ? 'text-background' : 'text-muted-foreground' | ||
| )} | ||
| /> | ||
| <span | ||
| className={cn( | ||
| 'truncate', | ||
| active && 'font-semibold', | ||
| !(active || isStepNode) && 'opacity-70' | ||
| )} | ||
| > | ||
| {node.label} | ||
| </span> | ||
| {node.owner ? ( | ||
| <span | ||
| aria-hidden | ||
| className={cn('ml-auto size-2 shrink-0', ownerDot[node.owner])} | ||
| /> | ||
| ) : null} | ||
| </> | ||
| ) | ||
|
|
||
| return ( | ||
| <li> | ||
| {node.stepId && onSelectStep ? ( | ||
| <button | ||
| className={rowClasses(active, true)} | ||
| onClick={() => onSelectStep(node.stepId as AnatomyStepId)} | ||
| style={{ paddingLeft }} | ||
| type="button" | ||
| > | ||
| {inner} | ||
| </button> | ||
| ) : ( | ||
| <span className={rowClasses(active, false)} style={{ paddingLeft }}> | ||
| {inner} | ||
| </span> | ||
| )} | ||
| </li> | ||
| ) | ||
| } | ||
|
|
||
| export function AgentFileTree({ | ||
| activeStepId, | ||
| className, | ||
| onSelectStep, | ||
| }: { | ||
| activeStepId?: AnatomyStepId | ||
| className?: string | ||
| onSelectStep?: (id: AnatomyStepId) => void | ||
| }) { | ||
| return ( | ||
| <div className={cn('border border-border bg-background', className)}> | ||
| <div className="flex items-center gap-2 border-border border-b px-4 py-3"> | ||
| <span aria-hidden className="size-2.5 shrink-0 bg-brand" /> | ||
| <span className="truncate font-mono text-xs tracking-normal"> | ||
| {agentSlug}/ | ||
| </span> | ||
| <span className="swiss-label ml-auto text-muted-foreground"> | ||
| sandbox | ||
| </span> | ||
| </div> | ||
| <ul className="py-2"> | ||
| {agentTree.map((node) => ( | ||
| <TreeRow | ||
| active={Boolean(node.stepId && node.stepId === activeStepId)} | ||
| key={node.id} | ||
| node={node} | ||
| onSelectStep={onSelectStep} | ||
| /> | ||
| ))} | ||
| </ul> | ||
| <div className="flex items-center gap-4 border-border border-t px-4 py-2.5 font-mono text-[10px] text-muted-foreground tracking-normal"> | ||
| <span className="flex items-center gap-1.5"> | ||
| <span aria-hidden className="size-2 bg-brand" /> you author | ||
| </span> | ||
| <span className="flex items-center gap-1.5"> | ||
| <span | ||
| aria-hidden | ||
| className="size-2 border border-muted-foreground opacity-50" | ||
| />{' '} | ||
| agent writes | ||
| </span> | ||
| </div> | ||
| </div> | ||
| ) | ||
| } | ||
25 changes: 25 additions & 0 deletions
25
packages/shared/marketing/components/landing/agent-anatomy/constants.ts
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| import type { AnatomyStepId } from '@outname/shared/marketing/data/agent-anatomy' | ||
| import { | ||
| BrainIcon, | ||
| CalendarIcon, | ||
| ContactIcon, | ||
| ListChecksIcon, | ||
| type LucideIcon, | ||
| MoonIcon, | ||
| ScrollTextIcon, | ||
| SparklesIcon, | ||
| TargetIcon, | ||
| UserIcon, | ||
| } from 'lucide-react' | ||
|
|
||
| export const stepIcons: Record<AnatomyStepId, LucideIcon> = { | ||
| calendar: CalendarIcon, | ||
| dreams: MoonIcon, | ||
| goals: TargetIcon, | ||
| identity: ContactIcon, | ||
| instructions: ScrollTextIcon, | ||
| memory: BrainIcon, | ||
| soul: SparklesIcon, | ||
| tasks: ListChecksIcon, | ||
| user: UserIcon, | ||
| } |
162 changes: 162 additions & 0 deletions
162
packages/shared/marketing/components/landing/agent-anatomy/landing-agent-anatomy.tsx
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,162 @@ | ||
| 'use client' | ||
|
|
||
| import { CodeWindow } from '@outname/shared/marketing/components/landing/code-window' | ||
| import { | ||
| revealVariants, | ||
| staggerVariants, | ||
| } from '@outname/shared/marketing/components/landing/landing-motion' | ||
| import { | ||
| type AnatomyStepId, | ||
| agentTree, | ||
| anatomySteps, | ||
| ownerLabel, | ||
| } from '@outname/shared/marketing/data/agent-anatomy' | ||
| import { Badge } from '@outname/ui/components/ui/badge' | ||
| import { cn } from '@outname/ui/lib/utils' | ||
| import { | ||
| AnimatePresence, | ||
| domAnimation, | ||
| LazyMotion, | ||
| m as motion, | ||
| } from 'motion/react' | ||
| import { useEffect, useRef, useState } from 'react' | ||
| import { AgentFileTree } from './agent-file-tree' | ||
| import { stepIcons } from './constants' | ||
|
|
||
| const CYCLE_MS = 2800 | ||
| const fileNameByNode = new Map(agentTree.map((node) => [node.id, node.label])) | ||
|
|
||
| function FileViewer({ activeId }: { activeId: AnatomyStepId }) { | ||
| const step = | ||
| anatomySteps.find((entry) => entry.id === activeId) ?? anatomySteps[0] | ||
| const Icon = stepIcons[step.id] | ||
| const fileName = fileNameByNode.get(step.node) ?? step.node | ||
| const total = String(anatomySteps.length).padStart(2, '0') | ||
|
|
||
| return ( | ||
| <div className="min-h-[26rem] lg:min-h-[30rem]"> | ||
| <AnimatePresence initial={false} mode="wait"> | ||
| <motion.div | ||
| animate={{ opacity: 1, y: 0 }} | ||
| exit={{ opacity: 0, y: -6 }} | ||
| initial={{ opacity: 0, y: 6 }} | ||
| key={step.id} | ||
| transition={{ duration: 0.26, ease: [0.16, 1, 0.3, 1] }} | ||
| > | ||
| <CodeWindow | ||
| code={step.code} | ||
| filename={fileName} | ||
| label={`${step.index} / ${total}`} | ||
| /> | ||
| <div className="mt-6 flex items-start gap-4"> | ||
| <span className="grid size-9 shrink-0 place-items-center border border-border bg-brand text-brand-foreground"> | ||
| <Icon className="size-4" /> | ||
| </span> | ||
| <div className="min-w-0"> | ||
| <h3 className="font-semibold text-xl tracking-tight md:text-2xl"> | ||
| {step.title} | ||
| </h3> | ||
| <p className="mt-2 max-w-md text-muted-foreground text-sm leading-relaxed"> | ||
| {step.caption} | ||
| </p> | ||
| <div className="mt-4 flex flex-wrap items-center gap-2"> | ||
| <Badge | ||
| className={cn( | ||
| step.owner === 'user' && | ||
| 'border-transparent bg-brand text-brand-foreground' | ||
| )} | ||
| variant={step.owner === 'user' ? 'default' : 'outline'} | ||
| > | ||
| {ownerLabel[step.owner]} | ||
| </Badge> | ||
| <span className="swiss-label text-muted-foreground"> | ||
| {step.note} | ||
| </span> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </motion.div> | ||
| </AnimatePresence> | ||
| </div> | ||
| ) | ||
| } | ||
|
|
||
| export function LandingAgentAnatomy({ | ||
| shouldReduceMotion, | ||
| }: { | ||
| shouldReduceMotion: boolean | ||
| }) { | ||
| const [activeId, setActiveId] = useState<AnatomyStepId>(anatomySteps[0].id) | ||
| const timerRef = useRef<ReturnType<typeof setInterval> | null>(null) | ||
|
|
||
| useEffect(() => { | ||
| if (shouldReduceMotion) { | ||
| return | ||
| } | ||
| timerRef.current = setInterval(() => { | ||
| setActiveId((current) => { | ||
| const index = anatomySteps.findIndex((entry) => entry.id === current) | ||
| return anatomySteps[(index + 1) % anatomySteps.length].id | ||
| }) | ||
| }, CYCLE_MS) | ||
| return () => { | ||
| if (timerRef.current) { | ||
| clearInterval(timerRef.current) | ||
| } | ||
| } | ||
| }, [shouldReduceMotion]) | ||
|
|
||
| const handleSelect = (id: AnatomyStepId) => { | ||
| if (timerRef.current) { | ||
| clearInterval(timerRef.current) | ||
| timerRef.current = null | ||
| } | ||
| setActiveId(id) | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
|
|
||
| return ( | ||
| <section | ||
| className="px-4 py-20 sm:px-6 md:px-10 md:py-28 lg:px-12" | ||
| id="anatomy" | ||
| > | ||
| <LazyMotion features={domAnimation}> | ||
| <motion.div | ||
| className="mx-auto max-w-7xl" | ||
| initial={shouldReduceMotion ? false : 'hidden'} | ||
| variants={staggerVariants} | ||
| viewport={{ margin: '-80px', once: true }} | ||
| whileInView="visible" | ||
| > | ||
| <motion.div | ||
| className="grid gap-5 border-border border-t pt-5 md:grid-cols-[minmax(0,0.82fr)_minmax(0,1fr)] md:items-end" | ||
| variants={revealVariants} | ||
| > | ||
| <div> | ||
| <p className="swiss-label text-muted-foreground"> | ||
| The mental model | ||
| </p> | ||
| <h2 className="mt-4 text-balance font-semibold text-3xl leading-tight tracking-tight md:text-4xl"> | ||
| An agent is a directory. | ||
| </h2> | ||
| </div> | ||
| <p className="max-w-2xl text-muted-foreground leading-relaxed"> | ||
| Nine canonical markdown files in a sandbox, each with a job. Some | ||
| you author; the rest it keeps current itself. Open one. | ||
| </p> | ||
| </motion.div> | ||
|
|
||
| <motion.div | ||
| className="mt-10 grid gap-5 lg:grid-cols-[minmax(0,20rem)_minmax(0,1fr)] lg:items-start" | ||
| variants={revealVariants} | ||
| > | ||
| <AgentFileTree | ||
| activeStepId={activeId} | ||
| onSelectStep={handleSelect} | ||
| /> | ||
| <FileViewer activeId={activeId} /> | ||
| </motion.div> | ||
| </motion.div> | ||
| </LazyMotion> | ||
| </section> | ||
| ) | ||
| } | ||
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Expose the selected row to assistive tech.
These buttons drive the active detail pane, but the current selection is only styled visually. Add a selected/current-state attribute here (for example
aria-currenton the active row, or full tab/listbox semantics) so screen-reader users can tell which file is open.As per coding guidelines,
**/*.{jsx,tsx}: "Use semantic HTML and ARIA attributes for accessibility".🤖 Prompt for AI Agents
Source: Coding guidelines