Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds a new Svelte component at src/routes/(marketing)/(components)/ai.svelte and mounts it in the marketing page. The new component composes two SVG animation components (mcp.svelte and skills.svelte) that use GridPaper backdrops, requestAnimationFrame-driven easing animations, and hover/in-view triggers with desktop/mobile behavior. It also adds a full-width ecosystem/tool strip with masked tool icons, per-tool gradients, desktop tooltips, and a tap-to-select mobile interaction. All UI is driven by local state and static arrays; no runtime data fetching or external API changes. Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/routes/`(marketing)/(components)/ai.svelte:
- Around line 63-85: The two Svelte each-blocks are missing stable keys; update
the first each "{`#each` categories as category, i}" to include a key such as
"(category.id ?? category.label ?? i)" and update the second each to include an
index (e.g., "{`#each` categories[active].features as feature, j}") and a key such
as "(feature.id ?? feature.title ?? j)" so Svelte can track items reliably and
satisfy ESLint.
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (1)
src/routes/(marketing)/(components)/ai.svelte (1)
54-87:⚠️ Potential issue | 🟠 MajorAdd a stable key to the
#eachblock.The loop is unkeyed (Line 54), which triggers
svelte/require-each-keyand can cause unstable DOM updates.🛠️ Suggested fix
- {`#each` tools as tool, i} + {`#each` tools as tool, i (tool.name)}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(marketing)/(components)/ai.svelte around lines 54 - 87, The `#each` block iterating "tools" is unkeyed (in the {`#each` tools as tool, i} loop) causing unstable DOM updates; update the each block to include a stable unique key (preferably tool.id, falling back to tool.name or another immutable unique field) so Svelte can track items reliably—locate the loop around the Tooltip.Root/Tooltip.Trigger/Tooltip.Content components and add the key expression to the {`#each`} statement.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/routes/`(marketing)/(components)/(ai-animations)/mcp.svelte:
- Around line 7-14: The SVG is decorative and should be hidden from assistive
tech: update the <svg> element in mcp.svelte to include accessibility attributes
such as aria-hidden="true" and focusable="false" (and remove any role or title
that would expose it) so screen readers ignore the graphic; locate the <svg> tag
in the component and add those attributes to apply AT hiding.
In `@src/routes/`(marketing)/(components)/(ai-animations)/skills.svelte:
- Around line 7-14: The SVG at the top of the component is decorative and should
be hidden from assistive tech; update the opening <svg> element (the SVG with
viewBox="0 0 541 273") to include aria-hidden="true", role="presentation" and
focusable="false" so screen readers ignore it and it is not keyboard-focusable.
In `@src/routes/`(marketing)/(components)/ai.svelte:
- Around line 60-72: Tooltip.Trigger is currently icon-only and lacks an
accessible name; add an accessible label so screen readers can identify each
control by setting an aria-label (or title) on Tooltip.Trigger using the tool's
descriptive property (e.g., tool.name or tool.label) and, for robustness,
include a visually-hidden fallback span (class="sr-only") inside the trigger
with the same text; ensure the trigger remains keyboard-focusable (add
tabindex="0" if Tooltip.Trigger doesn't render a native focusable element).
- Line 2: The module imports the Icon symbol but never uses it; remove the
unused import statement "import Icon from
'$lib/components/ui/icon/icon.svelte';" at the top of the file (or alternatively
use the Icon component where intended) so the unused-import lint error is
resolved; ensure no other references to Icon remain after removal.
---
Duplicate comments:
In `@src/routes/`(marketing)/(components)/ai.svelte:
- Around line 54-87: The `#each` block iterating "tools" is unkeyed (in the {`#each`
tools as tool, i} loop) causing unstable DOM updates; update the each block to
include a stable unique key (preferably tool.id, falling back to tool.name or
another immutable unique field) so Svelte can track items reliably—locate the
loop around the Tooltip.Root/Tooltip.Trigger/Tooltip.Content components and add
the key expression to the {`#each`} statement.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/routes/(marketing)/(components)/(ai-animations)/mcp.sveltesrc/routes/(marketing)/(components)/(ai-animations)/skills.sveltesrc/routes/(marketing)/(components)/ai.svelte
src/routes/(marketing)/(components)/(ai-animations)/skills.svelte
Outdated
Show resolved
Hide resolved
| @@ -0,0 +1,92 @@ | |||
| <script lang="ts"> | |||
| import Icon from '$lib/components/ui/icon/icon.svelte'; | |||
There was a problem hiding this comment.
Remove unused Icon import.
Icon is imported but never used (Line 2), which currently fails lint.
🧹 Suggested fix
- import Icon from '$lib/components/ui/icon/icon.svelte';
import Noise from '$lib/components/fancy/noise.svelte';📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| import Icon from '$lib/components/ui/icon/icon.svelte'; |
🧰 Tools
🪛 ESLint
[error] 2-2: 'Icon' is defined but never used.
(@typescript-eslint/no-unused-vars)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/routes/`(marketing)/(components)/ai.svelte at line 2, The module imports
the Icon symbol but never uses it; remove the unused import statement "import
Icon from '$lib/components/ui/icon/icon.svelte';" at the top of the file (or
alternatively use the Icon component where intended) so the unused-import lint
error is resolved; ensure no other references to Icon remain after removal.
| <Tooltip.Trigger | ||
| class="border-smooth group relative flex h-16 w-full items-center justify-center border-r border-dashed {i === 0 ? 'border-l' : ''}" | ||
| > | ||
| <div | ||
| style="mask-image: url('{tool.src}'); -webkit-mask-image: url('{tool.src}'); mask-size: contain; mask-repeat: no-repeat; mask-position: center;" | ||
| class="h-9 w-9 bg-white/40 transition-colors duration-500 group-hover:bg-[var(--primary-color)]" | ||
| ></div> | ||
| <div | ||
| class="absolute inset-0 opacity-0 transition-opacity group-hover:opacity-100 bg-gradient-to-tl from-(--primary-color)/4 to-(--secondary-color)/10" | ||
| > | ||
| <Noise opacity={0.1} /> | ||
| </div> | ||
| </Tooltip.Trigger> |
There was a problem hiding this comment.
Provide an accessible name for icon-only tooltip triggers.
Tooltip.Trigger is visual-only here; add an accessible label so screen reader users can identify each control (Line 60).
♿ Suggested fix
<Tooltip.Trigger
+ aria-label={tool.name}
class="border-smooth group relative flex h-16 w-full items-center justify-center border-r border-dashed {i === 0 ? 'border-l' : ''}"
>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <Tooltip.Trigger | |
| class="border-smooth group relative flex h-16 w-full items-center justify-center border-r border-dashed {i === 0 ? 'border-l' : ''}" | |
| > | |
| <div | |
| style="mask-image: url('{tool.src}'); -webkit-mask-image: url('{tool.src}'); mask-size: contain; mask-repeat: no-repeat; mask-position: center;" | |
| class="h-9 w-9 bg-white/40 transition-colors duration-500 group-hover:bg-[var(--primary-color)]" | |
| ></div> | |
| <div | |
| class="absolute inset-0 opacity-0 transition-opacity group-hover:opacity-100 bg-gradient-to-tl from-(--primary-color)/4 to-(--secondary-color)/10" | |
| > | |
| <Noise opacity={0.1} /> | |
| </div> | |
| </Tooltip.Trigger> | |
| <Tooltip.Trigger | |
| aria-label={tool.name} | |
| class="border-smooth group relative flex h-16 w-full items-center justify-center border-r border-dashed {i === 0 ? 'border-l' : ''}" | |
| > | |
| <div | |
| style="mask-image: url('{tool.src}'); -webkit-mask-image: url('{tool.src}'); mask-size: contain; mask-repeat: no-repeat; mask-position: center;" | |
| class="h-9 w-9 bg-white/40 transition-colors duration-500 group-hover:bg-[var(--primary-color)]" | |
| ></div> | |
| <div | |
| class="absolute inset-0 opacity-0 transition-opacity group-hover:opacity-100 bg-gradient-to-tl from-(--primary-color)/4 to-(--secondary-color)/10" | |
| > | |
| <Noise opacity={0.1} /> | |
| </div> | |
| </Tooltip.Trigger> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/routes/`(marketing)/(components)/ai.svelte around lines 60 - 72,
Tooltip.Trigger is currently icon-only and lacks an accessible name; add an
accessible label so screen readers can identify each control by setting an
aria-label (or title) on Tooltip.Trigger using the tool's descriptive property
(e.g., tool.name or tool.label) and, for robustness, include a visually-hidden
fallback span (class="sr-only") inside the trigger with the same text; ensure
the trigger remains keyboard-focusable (add tabindex="0" if Tooltip.Trigger
doesn't render a native focusable element).
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/routes/(marketing)/(components)/(ai-animations)/skills.svelte (1)
22-24: Consider extracting shared animation utilities.The
easeOutfunction is identical in bothmcp.svelteandskills.svelte. Consider extracting it to a shared utility module if more animation components are planned.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(marketing)/(components)/(ai-animations)/skills.svelte around lines 22 - 24, The easeOut function is duplicated between the skills.svelte and mcp.svelte components; extract this shared animation utility into a single module (e.g., an animations or easing utility file) and import it in both components. Replace the local function declarations of easeOut in skills.svelte and mcp.svelte with an import of the shared function, ensure the exported function signature matches (easeOut(t: number)), and run the build/tests to confirm no behavior changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/routes/`(marketing)/(components)/(ai-animations)/mcp.svelte:
- Around line 41-57: The $effect currently registers hover(container, ...) and
inView(container, ...) and starts an animation via slideTo/tick using rafId but
does not return a cleanup; update the $effect to return a single cleanup
function that (1) calls the unsubscribe/cleanup functions returned by hover(...)
and inView(...), (2) cancels any pending frame with cancelAnimationFrame(rafId),
and (3) unsubscribes any motion/spring subscriptions that slideTo/tick may have
touched so tick cannot access DOM nodes (leftBlock, rightCluster) after unmount;
locate the setup in the $effect and add this combined teardown to avoid orphaned
raf and subscriptions.
In `@src/routes/`(marketing)/(components)/(ai-animations)/skills.svelte:
- Around line 47-63: The effect registered with $effect must return a teardown
that unsubscribes hover and inView and cancels any in-flight animation frames so
RAF callbacks don't touch an unmounted element; modify the block around $effect
to capture the cleanup handles returned by hover(container, ...) and
inView(container, ...), and capture the cancel function returned by
animateTo(DOCK_X, DOCK_Y) (and animateTo(0,0)) so you can call them on cleanup;
ensure animateTo is updated (if not already) to return a cancel function for its
RAF loop or guard its RAF callback with an alive flag, then return a single
cleanup function from $effect that calls the hover/inView unsubscribers and
cancels any pending animations (so references like container/piece are never
accessed after unmount).
---
Nitpick comments:
In `@src/routes/`(marketing)/(components)/(ai-animations)/skills.svelte:
- Around line 22-24: The easeOut function is duplicated between the
skills.svelte and mcp.svelte components; extract this shared animation utility
into a single module (e.g., an animations or easing utility file) and import it
in both components. Replace the local function declarations of easeOut in
skills.svelte and mcp.svelte with an import of the shared function, ensure the
exported function signature matches (easeOut(t: number)), and run the
build/tests to confirm no behavior changes.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/routes/(marketing)/(components)/(ai-animations)/mcp.sveltesrc/routes/(marketing)/(components)/(ai-animations)/skills.sveltesrc/routes/(marketing)/(components)/ai.svelte
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/routes/`(marketing)/(components)/ai.svelte:
- Around line 174-198: The each-block rendering tools lacks a stable key and
accessible labeling: update the {`#each` tools as tool, i} loop to use a unique
key (e.g., {`#each` tools as tool (tool.id ?? tool.name)}) and add accessible
attributes to the icon-only <button> rendered by handleMobileTap — include
aria-label={tool.name} (or aria-labelledby pointing to a visually hidden label)
and set aria-pressed={activeMobileIndex === i} so screen readers get state; keep
the Noise component and existing styling but ensure the mask div remains
decorative (role="img" with aria-hidden="true" if needed) so the button label is
the accessible name.
| {#each tools as tool, i} | ||
| <button | ||
| onclick={(e) => handleMobileTap(e, i)} | ||
| class="border-smooth relative flex h-16 w-full items-center justify-center border-r border-dashed {i === | ||
| 0 | ||
| ? 'border-l' | ||
| : ''}" | ||
| style="--primary-color:{tool.primary};--secondary-color:transparent" | ||
| > | ||
| <div | ||
| style="mask-image: url('{tool.src}'); -webkit-mask-image: url('{tool.src}'); mask-size: contain; mask-repeat: no-repeat; mask-position: center;" | ||
| class="h-9 w-9 transition-colors duration-500 {activeMobileIndex === | ||
| i | ||
| ? 'bg-[var(--primary-color)]' | ||
| : 'bg-white/40'}" | ||
| ></div> | ||
| {#if activeMobileIndex === i} | ||
| <div | ||
| class="absolute inset-0 bg-gradient-to-tl from-(--primary-color)/4 to-(--secondary-color)/10" | ||
| > | ||
| <Noise opacity={0.1} /> | ||
| </div> | ||
| {/if} | ||
| </button> | ||
| {/each} |
There was a problem hiding this comment.
Add keys and accessible labels to the mobile each-block.
Two issues here:
- Missing stable key for Svelte's diffing.
- Icon-only buttons lack accessible labels for screen reader users.
♿ Proposed fix
- {`#each` tools as tool, i}
+ {`#each` tools as tool, i (tool.name)}
<button
+ aria-label={tool.name}
onclick={(e) => handleMobileTap(e, i)}
class="border-smooth relative flex h-16 w-full items-center justify-center border-r border-dashed ..."🧰 Tools
🪛 ESLint
[error] 174-198: Each block should have a key
(svelte/require-each-key)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/routes/`(marketing)/(components)/ai.svelte around lines 174 - 198, The
each-block rendering tools lacks a stable key and accessible labeling: update
the {`#each` tools as tool, i} loop to use a unique key (e.g., {`#each` tools as
tool (tool.id ?? tool.name)}) and add accessible attributes to the icon-only
<button> rendered by handleMobileTap — include aria-label={tool.name} (or
aria-labelledby pointing to a visually hidden label) and set
aria-pressed={activeMobileIndex === i} so screen readers get state; keep the
Noise component and existing styling but ensure the mask div remains decorative
(role="img" with aria-hidden="true" if needed) so the button label is the
accessible name.
There was a problem hiding this comment.
♻️ Duplicate comments (4)
src/routes/(marketing)/(components)/ai.svelte (4)
196-231:⚠️ Potential issue | 🟡 MinorKey the mobile tools loop and expose button state/accessibility label.
The mobile loop is also unkeyed, and the icon-only button should expose an accessible name and pressed state.
♿ Proposed fix
- {`#each` tools as tool, i} + {`#each` tools as tool, i (tool.name)} <button + aria-label={tool.name} + aria-pressed={activeMobileIndex === i} onclick={(e) => handleMobileTap(e, i)} class="border-smooth relative flex h-16 w-full items-center justify-center border-r border-dashed {i === 0 ? 'border-l' : ''}" style="--primary-color:{tool.primary};--secondary-color:transparent" > + <span class="sr-only">{tool.name}</span>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(marketing)/(components)/ai.svelte around lines 196 - 231, The mobile tools loop lacks a key and the icon-only <button> is missing accessibility attributes; update the {`#each` tools as tool, i} block to include a stable key (e.g., {`#each` tools as tool, i (tool.id ?? tool.name)}) and make the button expose an accessible name and pressed state by adding aria-label={tool.name} and aria-pressed={activeMobileIndex === i}; keep existing click handler (handleMobileTap) and visual active logic using activeMobileIndex unchanged so assistive tech can read the label and current selection.
3-3:⚠️ Potential issue | 🟡 MinorRemove unused
Iconimport.
Iconis imported but never referenced, which keeps lint failing.🧹 Proposed fix
- import Icon from '$lib/components/ui/icon/icon.svelte';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(marketing)/(components)/ai.svelte at line 3, Remove the unused import of Icon in ai.svelte: locate the line importing Icon (import Icon from '$lib/components/ui/icon/icon.svelte';) and delete it so the module no longer imports Icon that isn't referenced, which will resolve the linter failure.
157-172:⚠️ Potential issue | 🟡 MinorAdd an accessible name to icon-only desktop tooltip triggers.
Tooltip.Triggeris icon-only here. Please expose an accessible label so screen readers can identify each control.♿ Proposed fix
<Tooltip.Trigger + aria-label={tool.name} class="border-smooth group relative flex h-16 w-full items-center justify-center border-r border-dashed {i === 0 ? 'border-l' : ''}" > + <span class="sr-only">{tool.name}</span>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(marketing)/(components)/ai.svelte around lines 157 - 172, Tooltip.Trigger is currently icon-only and lacks an accessible name; update the Tooltip.Trigger in the ai.svelte component to expose a descriptive label for screen readers by either adding an aria-label attribute (e.g., aria-label={tool.name || tool.label}) to the Tooltip.Trigger element or by including a visually-hidden text node (e.g., a span with an sr-only class using tool.name) inside the trigger. Ensure the label uses the existing tool identifier (tool.name/tool.label) so each icon has a unique, meaningful accessible name and that the Noise component and mask styling remain unchanged.
151-188:⚠️ Potential issue | 🟡 MinorAdd a stable key to the desktop tools each-block.
The tools loop is unkeyed, which violates
svelte/require-each-keyand can cause unstable DOM diffing during updates.🛠️ Proposed fix
- {`#each` tools as tool, i} + {`#each` tools as tool, i (tool.name)}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/`(marketing)/(components)/ai.svelte around lines 151 - 188, The each-block iterating over tools is unkeyed (the {`#each` tools as tool, i} block), causing unstable DOM updates; add a stable key expression to the loop such as a unique property on each tool (e.g., tool.id or tool.name) so it becomes {`#each` tools as tool (tool.id)} (or use tool.name if id is not available), ensuring Svelte can track items correctly and satisfy svelte/require-each-key.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@src/routes/`(marketing)/(components)/ai.svelte:
- Around line 196-231: The mobile tools loop lacks a key and the icon-only
<button> is missing accessibility attributes; update the {`#each` tools as tool,
i} block to include a stable key (e.g., {`#each` tools as tool, i (tool.id ??
tool.name)}) and make the button expose an accessible name and pressed state by
adding aria-label={tool.name} and aria-pressed={activeMobileIndex === i}; keep
existing click handler (handleMobileTap) and visual active logic using
activeMobileIndex unchanged so assistive tech can read the label and current
selection.
- Line 3: Remove the unused import of Icon in ai.svelte: locate the line
importing Icon (import Icon from '$lib/components/ui/icon/icon.svelte';) and
delete it so the module no longer imports Icon that isn't referenced, which will
resolve the linter failure.
- Around line 157-172: Tooltip.Trigger is currently icon-only and lacks an
accessible name; update the Tooltip.Trigger in the ai.svelte component to expose
a descriptive label for screen readers by either adding an aria-label attribute
(e.g., aria-label={tool.name || tool.label}) to the Tooltip.Trigger element or
by including a visually-hidden text node (e.g., a span with an sr-only class
using tool.name) inside the trigger. Ensure the label uses the existing tool
identifier (tool.name/tool.label) so each icon has a unique, meaningful
accessible name and that the Noise component and mask styling remain unchanged.
- Around line 151-188: The each-block iterating over tools is unkeyed (the
{`#each` tools as tool, i} block), causing unstable DOM updates; add a stable key
expression to the loop such as a unique property on each tool (e.g., tool.id or
tool.name) so it becomes {`#each` tools as tool (tool.id)} (or use tool.name if id
is not available), ensuring Svelte can track items correctly and satisfy
svelte/require-each-key.
What does this PR do?
This PR adds a new AI-focused section below the "Build like a team of hundreds" section on the homepage.
The section showcases AI-related features like MCP, agent skills, agent rules, Supported IDEs.
The section is fully responsive and supports mobile behavior.
**On first commit, local build showed a 500 error on /threads/data.json, but I'm not aware of changes made to it. Tested in the dev server and preview works as expected.
Update: Added benchmark preview + new illustrations
Screen.Recording.2026-03-03.at.18.31.52.mov
Test Plan
(Write your test plan here. If you changed any code, please provide us with clear instructions on how you verified your changes work.)
Related PRs and Issues
(If this PR is related to any other PR or resolves any issue or related to any issue link all related PR and issues here.)
Have you read the Contributing Guidelines on issues?
(Write your answer here.)
Summary by CodeRabbit