Skip to content

Mini Game v2: Dependency bump#34

Merged
gianzamboni merged 13 commits intomini-game-v2from
mini-game-v2-dependency-bump
Mar 1, 2026
Merged

Mini Game v2: Dependency bump#34
gianzamboni merged 13 commits intomini-game-v2from
mini-game-v2-dependency-bump

Conversation

@gianzamboni
Copy link
Owner

@gianzamboni gianzamboni commented Feb 27, 2026

Summary by CodeRabbit

  • New Features

    • Demo pages accept URL params to control home button and debug mode.
    • 3D scene components now accept external refs for improved interaction/control.
    • New bottom settings panel and settings button for the control UI.
    • Added a project conventions document and CI review config.
  • Style

    • Updated icon sizing, spacing, typography, and form font inheritance.
    • Simplified component spacing, cleaned up several CSS rules, and adjusted panel/button positioning.
  • Chores

    • Updated Node.js engine target and added a static Node version file.
    • Removed the existing multi-stage Dockerfile.

@vercel
Copy link

vercel bot commented Feb 27, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
three-js-react Ready Ready Preview, Comment Mar 1, 2026 4:38am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 27, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • ✅ Review completed - (🔄 Check again to review again)
📝 Walkthrough

Walkthrough

This PR refactors 3D components to use direct ref props instead of forwardRef, establishes project conventions via documentation, updates Node.js version (20), reorganizes Leva panel controls with a new SettingsButton component, introduces a URL search parameter hook for demo navigation, and refactors styling across CSS modules. The Dockerfile is removed.

Changes

Cohort / File(s) Summary
Configuration & Environment
.coderabbit.yaml, .nvmrc, package.json, Dockerfile
Added CodeRabbit auto-review config, Node.js version specification, updated Node engine range to ^20.19.0 || >=22.12.0, and removed multi-stage Dockerfile entirely.
Project Conventions Documentation
.cursor/rules/project-conventions.mdc
Added new project conventions guide defining React component patterns (functional components, typed props, ref handling), import path aliases, CSS module styling, 3D/R3F preferences, and phased implementation approach.
3D Components - Ref Forwarding
app/3d/cube.tsx, app/3d/sphere.tsx
Migrated Cube and Sphere from default exports to named exports, added ref?: Ref<Mesh> to props, and changed from forwardRef to direct ref prop pattern. Updated PurpleCube and OrangeSphere to accept and forward refs. Sphere now exports OrangeSphereProps type.
3D Component Usage
app/routes/demos/02-drei-app/main-scene.tsx, app/routes/demos/03-debug-ui/main-scene.tsx
Updated ref types from Object3D to Mesh, added ref attributes to OrangeSphere and PurpleCube. Changed Sphere import from default to named import.
Demo Layout & Navigation
app/routes/demos/layout.tsx, app/utils/hooks/use-demo-params.ts
Created new useDemoParams hook to read URL search parameters (hideHomeButton, debugMode). Updated layout to conditionally render home link and SketchyLevaPanel based on params and debug mode state.
Global Styling
app/app.css
Converted icon/font size units to rem, spacing to pixels, added global font: inherit for form elements, removed .row flex container, replaced with typographic adjustments (line-height: 1.5, text-wrap: pretty).
Home Page
app/routes/home/index.tsx, app/routes/home/styles.module.css
Changed outer container from div to main element, wrapped header in new title-container div. Added .title-container CSS class with centered flex layout, removed responsive gap media query.
Label Component Migration
app/sketched-components/label/label.tsx, app/sketched-components/label/styles.module.css
Migrated .label class from common styles to dedicated module. Updated component to wrap children in span. Updated import references accordingly.
Card & Common Styles Cleanup
app/sketched-components/card/index.tsx, app/sketched-components/card/styles.module.css, app/sketched-components/common.module.css
Removed sketchy-container-margin from Card's SketchyBorder className, deleted .label and .sketchy-container-margin from common styles. Simplified card CSS, removed thumbnail/description display overrides.
Button & Title Simplification
app/sketched-components/button/styles.module.css, app/sketched-components/title/h1.tsx, app/sketched-components/title/styles.module.css
Removed explicit padding/position/z-index from button, replaced with single padding: var(--spacing-sm). Removed commonStyles dependency from title. Updated title font-size to CSS variable var(--font-size-lg).
Leva Panel - Bottom Panel Refactoring
app/sketched-components/leva-panel/bottom-panel/index.tsx, app/sketched-components/leva-panel/bottom-panel/styles.module.css
Changed BottomPanel from forwardRef to direct ref prop in component signature. Added new CSS module with responsive panel layout, transform-based closed state, and disabled pointer events for number inputs on small screens.
Leva Panel - Settings Button
app/sketched-components/leva-panel/settings-button/index.tsx, app/sketched-components/leva-panel/settings-button/styles.module.css
Created new SettingsButton component wrapping SketchyButton and SettingsIcon. Added CSS module with absolute positioning and responsive spacing for the settings button icon.
Leva Panel - Main Component Updates
app/sketched-components/leva-panel/index.tsx, app/sketched-components/leva-panel/sketchy-leva-panel/index.tsx, app/sketched-components/leva-panel/leva-theme.ts, app/sketched-components/leva-panel/styles.module.css
Replaced SketchyButton/SettingsIcon with new SettingsButton component. Added className prop to SketchyLevaPanel. Fixed import paths in sketchy-leva-panel. Removed 67 lines of CSS class definitions migrated to separate modules.
Demo Route Styling
app/routes/demos/styles.module.css, app/routes/demos/02-drei-app/styles.module.css
Removed .sketchy-link-icon responsive styling from demos root styles. Added .leva-panel-container class with z-index. Removed .label class from 02-drei-app styles.
Link Component Styling
app/sketched-components/link/styles.module.css
Reduced .link-container z-index from 20000000 to 1. Updated responsive icon sizing (reduced at 728px breakpoint), added padding increase at 2048px breakpoint, removed padding from sketchy-link-icon at large breakpoints.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 Refs are flowing like morning dew,
Components forwarding—old patterns through!
Styles migrate, layouts refine,
Settings button placed just right in line,
A demo params dance, navigation's true,
Node twenty arrived—conventions debut! 🌱

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title 'Mini Game v2: Dependency bump' is vague and does not accurately reflect the scope of changes. The PR encompasses major refactoring across multiple areas (ref forwarding, component exports, CSS reorganization, hook creation, Dockerfile removal, style updates) far beyond a simple dependency version update. Consider a more descriptive title that captures the main objective, such as 'Mini Game v2: Refactor components for ref forwarding and reorganize styles' or 'Mini Game v2: Update Node version, refactor component refs, and simplify styles'.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch mini-game-v2-dependency-bump

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.

❤️ Share

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

@gianzamboni gianzamboni changed the title Dependency bump Mini Game v2: Dependency bump Feb 27, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
Dockerfile (1)

17-22: Consider running the container as a non-root user.

The container currently runs as root, which is flagged by static analysis (Trivy DS-0002). Running as a non-root user is a security best practice that limits the impact of potential container escapes.

🛡️ Proposed fix to add a non-root user
 FROM node:20.19.0-alpine
 COPY ./package.json package-lock.json /app/
 COPY --from=production-dependencies-env /app/node_modules /app/node_modules
 COPY --from=build-env /app/build /app/build
 WORKDIR /app
+USER node
 CMD ["npm", "run", "start"]

Note: The node user is pre-created in the official Node.js Alpine images. Ensure the /app directory and its contents have appropriate permissions for the node user.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Dockerfile` around lines 17 - 22, Change the Dockerfile to run the container
as a non-root user by ensuring /app and its contents are owned by the non-root
user (the pre-created node user in the Node.js Alpine image) and switching to
that user before CMD; specifically, adjust the COPY/creation steps so /app is
writable by node (e.g., set ownership of /app and copied files to node or use an
equivalent chown/--chown approach), keep WORKDIR /app, and add a USER node
before the CMD ["npm","run","start"] so the application runs with non-root
privileges.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@Dockerfile`:
- Around line 17-22: Change the Dockerfile to run the container as a non-root
user by ensuring /app and its contents are owned by the non-root user (the
pre-created node user in the Node.js Alpine image) and switching to that user
before CMD; specifically, adjust the COPY/creation steps so /app is writable by
node (e.g., set ownership of /app and copied files to node or use an equivalent
chown/--chown approach), keep WORKDIR /app, and add a USER node before the CMD
["npm","run","start"] so the application runs with non-root privileges.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9fe3f97 and e1ff690.

📒 Files selected for processing (2)
  • Dockerfile
  • package.json

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
app/routes/home/styles.module.css (1)

29-31: Consider removing the redundant media query.

The gap: var(--spacing-lg) at 1200px now matches the value at 728px. If no other properties need the 1200px breakpoint for .home-container, this media query block could be removed to reduce duplication.

♻️ Proposed simplification
 .home-container {
   padding: var(--spacing-lg);
   gap: var(--spacing-md);
 
   `@media` (min-width: 728px) {
     gap: var(--spacing-lg);
   }
-
-  `@media` (min-width: 1200px) {
-    gap: var(--spacing-lg);
-  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/routes/home/styles.module.css` around lines 29 - 31, Remove the redundant
1200px media query for .home-container since gap: var(--spacing-lg) is already
applied at 728px; locate the rule targeting .home-container inside the `@media`
(min-width: 1200px) block and delete that block (or at minimum remove the gap
declaration) so duplication is eliminated and only the 728px breakpoint controls
the gap value.
Dockerfile (1)

17-22: Consider adding a non-root user for improved security.

The container currently runs as root. Adding a non-root user reduces the attack surface if the container is compromised.

🛡️ Proposed fix to run as non-root
 FROM node:20.19.0-alpine
 COPY ./package.json package-lock.json /app/
 COPY --from=production-dependencies-env /app/node_modules /app/node_modules
 COPY --from=build-env /app/build /app/build
 WORKDIR /app
+USER node
 CMD ["npm", "run", "start"]

Note: The node user is pre-created in the official Node Alpine images. Ensure file permissions allow the node user to read the application files.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Dockerfile` around lines 17 - 22, The Dockerfile currently runs as root;
update it to switch to a non-root user (use the existing node user in the
official Node Alpine image) after copying files and setting WORKDIR so the
process runs without root privileges; ensure application files and /app
ownership/permissions are adjusted (chown to node:node or chmod as needed) so
the node user can access /app and then add USER node before the CMD
["npm","run","start"] to run the container as that user.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@app/routes/home/styles.module.css`:
- Around line 29-31: Remove the redundant 1200px media query for .home-container
since gap: var(--spacing-lg) is already applied at 728px; locate the rule
targeting .home-container inside the `@media` (min-width: 1200px) block and delete
that block (or at minimum remove the gap declaration) so duplication is
eliminated and only the 728px breakpoint controls the gap value.

In `@Dockerfile`:
- Around line 17-22: The Dockerfile currently runs as root; update it to switch
to a non-root user (use the existing node user in the official Node Alpine
image) after copying files and setting WORKDIR so the process runs without root
privileges; ensure application files and /app ownership/permissions are adjusted
(chown to node:node or chmod as needed) so the node user can access /app and
then add USER node before the CMD ["npm","run","start"] to run the container as
that user.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9fe3f97 and 1dbef9a.

📒 Files selected for processing (11)
  • .coderabbit.yaml
  • .nvmrc
  • Dockerfile
  • app/app.css
  • app/routes/demos/layout.tsx
  • app/routes/home/index.tsx
  • app/routes/home/styles.module.css
  • app/sketched-components/leva-panel/bottom-panel.tsx
  • app/sketched-components/leva-panel/styles.module.css
  • app/utils/hooks/use-demo-params.ts
  • package.json

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (2)
app/sketched-components/title/h1.tsx (1)

9-10: styles.title applied to both parent div and child h1.

The .title class is applied to both elements (line 9 and line 10). Since font properties in .title (font-weight, font-family, font-size) are inherited, applying them to the outer div should suffice. Consider removing it from the inner h1 to avoid redundancy, unless there's a specific styling reason for both.

💡 Suggested simplification
     <div className={`relative ${styles['title']}`}> 
-    <h1 className={styles.title}>
+    <h1>
       {children}
     </h1>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/sketched-components/title/h1.tsx` around lines 9 - 10, The .title class
is redundantly applied to both the outer div and the inner h1 in the H1
component; remove the className={styles.title} from the inner h1 (leave
className={`relative ${styles['title']}`} on the parent div) so font properties
are only set on the container, and confirm there’s no separate h1-specific
styling or behavior in the H1 component that requires the class on the h1
element.
.nvmrc (1)

1-1: Consider specifying the minimum version for consistency.

The .nvmrc specifies 20, but package.json requires ^20.19.0. If nvm resolves to an older 20.x version (e.g., from a stale cache), it may not satisfy the engines constraint. Consider using 20.19.0 or lts/iron to ensure alignment.

💡 Suggested fix
-20
+20.19.0
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.nvmrc at line 1, The .nvmrc currently pins "20" which can resolve to an
older 20.x not satisfying package.json's engines (^20.19.0); update .nvmrc to a
specific minimum matching the package.json (e.g., replace "20" with "20.19.0")
or use a stable alias like "lts/iron" to ensure nvm selects a compatible Node
version.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.cursor/rules/project-conventions.mdc:
- Line 11: Update the doc line to clarify import origins: state that mesh refs
should be typed as Ref<Mesh> with Ref imported from 'react' and Mesh imported
from 'three' (e.g., use Ref from React and Mesh from three), and keep the
existing recommendation for `@react-three/fiber` and `@react-three/drei` plus
declarative elements like <mesh> and <meshStandardMaterial>; reference the
symbols Ref and Mesh so readers know which package each comes from.

In `@app/sketched-components/leva-panel/index.tsx`:
- Line 45: The className template in the JSX div (`<div
className={`${styles["panel-container"]} ${className}`}>`) can render the
literal "undefined" when className is not provided; change the composition to a
null-safe join (e.g. combine styles["panel-container"] and className into an
array, filter(Boolean) and join(' ')) or use a small helper/utility like
classnames to only include defined classes so "undefined" is never emitted.

In `@app/sketched-components/leva-panel/settings-button/index.tsx`:
- Around line 15-17: The Settings button is icon-only and needs an accessible
name: update the JSX where SketchyButton is rendered (the element containing
SettingsIcon, using props className and onClick) to include an aria-label (e.g.
aria-label="Open settings" or "Settings") and optionally a title with the same
text; ensure the aria-label is applied directly to the SketchyButton component
so assistive tech receives the accessible name.

---

Nitpick comments:
In @.nvmrc:
- Line 1: The .nvmrc currently pins "20" which can resolve to an older 20.x not
satisfying package.json's engines (^20.19.0); update .nvmrc to a specific
minimum matching the package.json (e.g., replace "20" with "20.19.0") or use a
stable alias like "lts/iron" to ensure nvm selects a compatible Node version.

In `@app/sketched-components/title/h1.tsx`:
- Around line 9-10: The .title class is redundantly applied to both the outer
div and the inner h1 in the H1 component; remove the className={styles.title}
from the inner h1 (leave className={`relative ${styles['title']}`} on the parent
div) so font properties are only set on the container, and confirm there’s no
separate h1-specific styling or behavior in the H1 component that requires the
class on the h1 element.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9fe3f97 and a4a6eaa.

📒 Files selected for processing (33)
  • .coderabbit.yaml
  • .cursor/rules/project-conventions.mdc
  • .nvmrc
  • Dockerfile
  • app/3d/cube.tsx
  • app/3d/sphere.tsx
  • app/app.css
  • app/routes/demos/02-drei-app/main-scene.tsx
  • app/routes/demos/02-drei-app/styles.module.css
  • app/routes/demos/03-debug-ui/main-scene.tsx
  • app/routes/demos/layout.tsx
  • app/routes/demos/styles.module.css
  • app/routes/home/index.tsx
  • app/routes/home/styles.module.css
  • app/sketched-components/button/styles.module.css
  • app/sketched-components/card/index.tsx
  • app/sketched-components/card/styles.module.css
  • app/sketched-components/common.module.css
  • app/sketched-components/label/label.tsx
  • app/sketched-components/label/styles.module.css
  • app/sketched-components/leva-panel/bottom-panel/index.tsx
  • app/sketched-components/leva-panel/bottom-panel/styles.module.css
  • app/sketched-components/leva-panel/index.tsx
  • app/sketched-components/leva-panel/settings-button/index.tsx
  • app/sketched-components/leva-panel/settings-button/styles.module.css
  • app/sketched-components/leva-panel/sketchy-leva-panel/index.tsx
  • app/sketched-components/leva-panel/sketchy-leva-panel/leva-theme.ts
  • app/sketched-components/leva-panel/styles.module.css
  • app/sketched-components/link/styles.module.css
  • app/sketched-components/title/h1.tsx
  • app/sketched-components/title/styles.module.css
  • app/utils/hooks/use-demo-params.ts
  • package.json
💤 Files with no reviewable changes (4)
  • app/sketched-components/leva-panel/styles.module.css
  • app/routes/demos/02-drei-app/styles.module.css
  • Dockerfile
  • app/sketched-components/common.module.css

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/sketched-components/leva-panel/bottom-panel/index.tsx (1)

48-50: ⚠️ Potential issue | 🟠 Major

Reference to undefined CSS class .opened.

Line 49 references styles["opened"] but this class is not defined in styles.module.css. This will inject undefined into the className string. The fix should be applied in the CSS file (already flagged there).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/sketched-components/leva-panel/bottom-panel/index.tsx` around lines 48 -
50, The JSX in BottomPanel uses styles["opened"] (in the div with className
combining commonStyles["animated"] and isAtBottom ? styles["closed"] :
styles["opened"]) but the `.opened` class is missing from the CSS module; add a
matching `.opened` rule to the component's styles.module.css with the intended
styles (mirror or complement the existing `.closed` behavior) so
styles["opened"] is defined and the className no longer injects undefined.
🧹 Nitpick comments (3)
app/sketched-components/leva-panel/settings-button/index.tsx (1)

8-17: Expose toggle state with aria-pressed and a dynamic label.

Since this button toggles panel visibility, a static "Open settings panel" label can become misleading after opening.

♿ Suggested improvement
 type SettingsButtonProps = Readonly<{
   onClick: () => void;
   className?: string;
+  isOpen: boolean;
 }>;
 
-export default function SettingsButton({ onClick, className }: SettingsButtonProps) {
+export default function SettingsButton({ onClick, className, isOpen }: SettingsButtonProps) {
+  const label = isOpen ? "Close settings panel" : "Open settings panel";
   return (
-    <SketchyButton className={`${styles["settings-button"]} ${className ?? ""}`} onClick={onClick} aria-label="Open settings panel" title="Open settings panel">
+    <SketchyButton
+      className={`${styles["settings-button"]} ${className ?? ""}`}
+      onClick={onClick}
+      aria-label={label}
+      title={label}
+      aria-pressed={isOpen}
+    >
       <SettingsIcon className={styles["settings-icon"]} />
     </SketchyButton>
   );
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/sketched-components/leva-panel/settings-button/index.tsx` around lines 8
- 17, The SettingsButton currently always uses a static label and doesn't expose
toggle state; change the component signature (SettingsButton) to accept a
boolean prop (e.g., isOpen or isPressed) and use it to set aria-pressed
(aria-pressed={isOpen}) and a dynamic accessible label/title (e.g., "Open
settings panel" when false and "Close settings panel" when true). Update the
component to derive the title and aria-label from that prop and keep existing
onClick and className behavior, and then update any call sites to pass the new
boolean prop reflecting the panel's visibility.
.nvmrc (1)

1-1: Pin .nvmrc to an explicit patch version that satisfies engines.node.

Currently .nvmrc specifies only 20, which is resolved by nvm to the latest available v20.x version. While this likely satisfies the constraint ^20.19.0 || >=22.12.0 in practice, explicitly pinning the patch version improves clarity and ensures consistency across different nvm versions and developer environments.

🔧 Proposed fix
-20
+20.19.0
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.nvmrc at line 1, Update .nvmrc to pin an explicit Node patch version that
satisfies the package.json engines.node constraint (e.g., replace "20" with
"20.19.0" or whatever exact 20.x patch you choose that meets ^20.19.0 ||
>=22.12.0); ensure the chosen patch matches the engines.node entry in
package.json so all developers use the same resolved Node version.
app/sketched-components/leva-panel/index.tsx (1)

18-21: Consider documenting the @ts-ignore with a more specific suppression.

The comment explains why the unused _store variable is needed, but using @ts-ignore suppresses all TypeScript errors. Consider using @ts-expect-error with a specific explanation, which will error if the suppression becomes unnecessary.

📝 Proposed refinement
     // Used as a triger for a levaStore changes; Not used directly though. 
     // If removed, this component won't work.
-    // `@ts-ignore`
+    // `@ts-expect-error` -- Variable unused but subscription triggers re-render
     const _store = levaStore.useStore();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/sketched-components/leva-panel/index.tsx` around lines 18 - 21, Replace
the broad "@ts-ignore" used above the _store declaration with a narrower
suppression: change it to "@ts-expect-error" and add a short comment explaining
why the suppression is required (e.g., keeps component subscribed to levaStore
via levaStore.useStore() despite the variable being unused) so TypeScript will
surface an error if the suppression is no longer necessary; update the comment
that documents the purpose of the _store binding (referencing _store and
levaStore.useStore) to include that it's intentionally unused but required to
trigger leva store updates.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/sketched-components/button/styles.module.css`:
- Around line 1-6: Add a positioned container to restore anchoring for the
sketch overlays: update the .sketchy-button rule in styles.module.css to include
position: relative so SketchyBorder and SketchyShadow can anchor to the button,
and add overflow: hidden (or overflow: visible if you want overlays to extend)
to prevent stray traces from bleeding outside the control; this change targets
the .sketchy-button CSS class used by the SketchyBorder/SketchyShadow overlays.

In `@app/sketched-components/leva-panel/bottom-panel/styles.module.css`:
- Around line 34-42: The CSS module is missing the .opened class referenced as
styles["opened"] in bottom-panel/index.tsx; add a .opened rule to this CSS
(alongside .closed and .noNumberInput) that defines the open state (e.g., no
translateY or translateY(0) and any matching transition/visibility styles used
by the component) so styles["opened"] resolves to a valid class name and the
panel opens correctly.

In `@app/sketched-components/title/h1.tsx`:
- Around line 9-10: The outer <div> and inner <h1> are both using
styles['title'], causing heading font styles to be applied twice; update the JSX
so only the <h1> uses styles.title and remove styles['title'] from the container
(or replace it with a distinct container class such as styles.titleContainer if
layout-specific rules are needed), and update the CSS module to add the new
container rule if you introduce styles.titleContainer; touch the JSX in the
component where className={`relative ${styles['title']}`} and the <h1
className={styles.title}> to make this change.

In `@app/sketched-components/title/styles.module.css`:
- Around line 1-3: The .sketchy-trace CSS rule (selector .sketchy-trace) is
missing positioning coordinates; update that rule to include top: 0 and left: 0
so the absolutely positioned SVG overlays the title correctly (i.e., keep
position: absolute and add top: 0; left: 0; to the .sketchy-trace declaration).

---

Outside diff comments:
In `@app/sketched-components/leva-panel/bottom-panel/index.tsx`:
- Around line 48-50: The JSX in BottomPanel uses styles["opened"] (in the div
with className combining commonStyles["animated"] and isAtBottom ?
styles["closed"] : styles["opened"]) but the `.opened` class is missing from the
CSS module; add a matching `.opened` rule to the component's styles.module.css
with the intended styles (mirror or complement the existing `.closed` behavior)
so styles["opened"] is defined and the className no longer injects undefined.

---

Nitpick comments:
In @.nvmrc:
- Line 1: Update .nvmrc to pin an explicit Node patch version that satisfies the
package.json engines.node constraint (e.g., replace "20" with "20.19.0" or
whatever exact 20.x patch you choose that meets ^20.19.0 || >=22.12.0); ensure
the chosen patch matches the engines.node entry in package.json so all
developers use the same resolved Node version.

In `@app/sketched-components/leva-panel/index.tsx`:
- Around line 18-21: Replace the broad "@ts-ignore" used above the _store
declaration with a narrower suppression: change it to "@ts-expect-error" and add
a short comment explaining why the suppression is required (e.g., keeps
component subscribed to levaStore via levaStore.useStore() despite the variable
being unused) so TypeScript will surface an error if the suppression is no
longer necessary; update the comment that documents the purpose of the _store
binding (referencing _store and levaStore.useStore) to include that it's
intentionally unused but required to trigger leva store updates.

In `@app/sketched-components/leva-panel/settings-button/index.tsx`:
- Around line 8-17: The SettingsButton currently always uses a static label and
doesn't expose toggle state; change the component signature (SettingsButton) to
accept a boolean prop (e.g., isOpen or isPressed) and use it to set aria-pressed
(aria-pressed={isOpen}) and a dynamic accessible label/title (e.g., "Open
settings panel" when false and "Close settings panel" when true). Update the
component to derive the title and aria-label from that prop and keep existing
onClick and className behavior, and then update any call sites to pass the new
boolean prop reflecting the panel's visibility.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9fe3f97 and 8c651f3.

📒 Files selected for processing (33)
  • .coderabbit.yaml
  • .cursor/rules/project-conventions.mdc
  • .nvmrc
  • Dockerfile
  • app/3d/cube.tsx
  • app/3d/sphere.tsx
  • app/app.css
  • app/routes/demos/02-drei-app/main-scene.tsx
  • app/routes/demos/02-drei-app/styles.module.css
  • app/routes/demos/03-debug-ui/main-scene.tsx
  • app/routes/demos/layout.tsx
  • app/routes/demos/styles.module.css
  • app/routes/home/index.tsx
  • app/routes/home/styles.module.css
  • app/sketched-components/button/styles.module.css
  • app/sketched-components/card/index.tsx
  • app/sketched-components/card/styles.module.css
  • app/sketched-components/common.module.css
  • app/sketched-components/label/label.tsx
  • app/sketched-components/label/styles.module.css
  • app/sketched-components/leva-panel/bottom-panel/index.tsx
  • app/sketched-components/leva-panel/bottom-panel/styles.module.css
  • app/sketched-components/leva-panel/index.tsx
  • app/sketched-components/leva-panel/settings-button/index.tsx
  • app/sketched-components/leva-panel/settings-button/styles.module.css
  • app/sketched-components/leva-panel/sketchy-leva-panel/index.tsx
  • app/sketched-components/leva-panel/sketchy-leva-panel/leva-theme.ts
  • app/sketched-components/leva-panel/styles.module.css
  • app/sketched-components/link/styles.module.css
  • app/sketched-components/title/h1.tsx
  • app/sketched-components/title/styles.module.css
  • app/utils/hooks/use-demo-params.ts
  • package.json
💤 Files with no reviewable changes (4)
  • app/sketched-components/leva-panel/styles.module.css
  • app/routes/demos/02-drei-app/styles.module.css
  • app/sketched-components/common.module.css
  • Dockerfile

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

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 `@app/routes/home/index.tsx`:
- Line 25: The external LinkedIn anchor in the JSX (the <a
href="https://www.linkedin.com/in/gianfranco-zamboni/" target="_blank"> element
in app/routes/home/index.tsx) is missing rel attributes; update that anchor to
include rel="noopener noreferrer" so the target="_blank" link has proper tab
isolation and prevents access to window.opener.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9fe3f97 and 8c651f3.

📒 Files selected for processing (33)
  • .coderabbit.yaml
  • .cursor/rules/project-conventions.mdc
  • .nvmrc
  • Dockerfile
  • app/3d/cube.tsx
  • app/3d/sphere.tsx
  • app/app.css
  • app/routes/demos/02-drei-app/main-scene.tsx
  • app/routes/demos/02-drei-app/styles.module.css
  • app/routes/demos/03-debug-ui/main-scene.tsx
  • app/routes/demos/layout.tsx
  • app/routes/demos/styles.module.css
  • app/routes/home/index.tsx
  • app/routes/home/styles.module.css
  • app/sketched-components/button/styles.module.css
  • app/sketched-components/card/index.tsx
  • app/sketched-components/card/styles.module.css
  • app/sketched-components/common.module.css
  • app/sketched-components/label/label.tsx
  • app/sketched-components/label/styles.module.css
  • app/sketched-components/leva-panel/bottom-panel/index.tsx
  • app/sketched-components/leva-panel/bottom-panel/styles.module.css
  • app/sketched-components/leva-panel/index.tsx
  • app/sketched-components/leva-panel/settings-button/index.tsx
  • app/sketched-components/leva-panel/settings-button/styles.module.css
  • app/sketched-components/leva-panel/sketchy-leva-panel/index.tsx
  • app/sketched-components/leva-panel/sketchy-leva-panel/leva-theme.ts
  • app/sketched-components/leva-panel/styles.module.css
  • app/sketched-components/link/styles.module.css
  • app/sketched-components/title/h1.tsx
  • app/sketched-components/title/styles.module.css
  • app/utils/hooks/use-demo-params.ts
  • package.json
💤 Files with no reviewable changes (4)
  • app/routes/demos/02-drei-app/styles.module.css
  • app/sketched-components/leva-panel/styles.module.css
  • app/sketched-components/common.module.css
  • Dockerfile

@gianzamboni
Copy link
Owner Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 28, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
app/sketched-components/link/styles.module.css (1)

19-23: Keep minimum interactive hit area while reducing icon widths.

The smaller icon sizes at Line 19 and Line 23 are fine visually, but please ensure the clickable element still meets a minimum touch target (commonly 44x44 CSS px).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/sketched-components/link/styles.module.css` around lines 19 - 23, The
reduced icon widths use var(--icon-size-sm) and var(--icon-size-md) but can
produce too-small hit targets; update the CSS rule(s) that set width:
var(--icon-size-sm) and width: var(--icon-size-md) to enforce a minimum
interactive area by adding a min-width: 44px and min-height: 44px (and ensure
display: inline-flex; align-items: center; justify-content: center to keep the
icon centered), or alternatively add padding so the visual icon remains the
desired size while the clickable element is at least 44x44 CSS px.
.nvmrc (1)

1-1: Pin .nvmrc to the engine floor for consistency.

The .nvmrc file currently specifies 20 (major-only), while package.json declares ^20.19.0 || >=22.12.0. This creates a drift risk: a developer using .nvmrc could install Node 20.0.0 or 20.18.0, but package.json requires at least 20.19.0, causing potential engine mismatch surprises. Pin to 20.19.0 to match the declared minimum.

Proposed change
-20
+20.19.0
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.nvmrc at line 1, Update the .nvmrc value from the major-only "20" to the
minimum engine version declared in package.json by pinning it to "20.19.0" so
local nvm usage matches the project's engine requirement; edit the .nvmrc file
to contain the exact version string "20.19.0".
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In @.nvmrc:
- Line 1: Update the .nvmrc value from the major-only "20" to the minimum engine
version declared in package.json by pinning it to "20.19.0" so local nvm usage
matches the project's engine requirement; edit the .nvmrc file to contain the
exact version string "20.19.0".

In `@app/sketched-components/link/styles.module.css`:
- Around line 19-23: The reduced icon widths use var(--icon-size-sm) and
var(--icon-size-md) but can produce too-small hit targets; update the CSS
rule(s) that set width: var(--icon-size-sm) and width: var(--icon-size-md) to
enforce a minimum interactive area by adding a min-width: 44px and min-height:
44px (and ensure display: inline-flex; align-items: center; justify-content:
center to keep the icon centered), or alternatively add padding so the visual
icon remains the desired size while the clickable element is at least 44x44 CSS
px.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9fe3f97 and 8c651f3.

📒 Files selected for processing (33)
  • .coderabbit.yaml
  • .cursor/rules/project-conventions.mdc
  • .nvmrc
  • Dockerfile
  • app/3d/cube.tsx
  • app/3d/sphere.tsx
  • app/app.css
  • app/routes/demos/02-drei-app/main-scene.tsx
  • app/routes/demos/02-drei-app/styles.module.css
  • app/routes/demos/03-debug-ui/main-scene.tsx
  • app/routes/demos/layout.tsx
  • app/routes/demos/styles.module.css
  • app/routes/home/index.tsx
  • app/routes/home/styles.module.css
  • app/sketched-components/button/styles.module.css
  • app/sketched-components/card/index.tsx
  • app/sketched-components/card/styles.module.css
  • app/sketched-components/common.module.css
  • app/sketched-components/label/label.tsx
  • app/sketched-components/label/styles.module.css
  • app/sketched-components/leva-panel/bottom-panel/index.tsx
  • app/sketched-components/leva-panel/bottom-panel/styles.module.css
  • app/sketched-components/leva-panel/index.tsx
  • app/sketched-components/leva-panel/settings-button/index.tsx
  • app/sketched-components/leva-panel/settings-button/styles.module.css
  • app/sketched-components/leva-panel/sketchy-leva-panel/index.tsx
  • app/sketched-components/leva-panel/sketchy-leva-panel/leva-theme.ts
  • app/sketched-components/leva-panel/styles.module.css
  • app/sketched-components/link/styles.module.css
  • app/sketched-components/title/h1.tsx
  • app/sketched-components/title/styles.module.css
  • app/utils/hooks/use-demo-params.ts
  • package.json
💤 Files with no reviewable changes (4)
  • app/sketched-components/common.module.css
  • app/routes/demos/02-drei-app/styles.module.css
  • Dockerfile
  • app/sketched-components/leva-panel/styles.module.css

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/sketched-components/leva-panel/bottom-panel/index.tsx (1)

48-50: ⚠️ Potential issue | 🔴 Critical

styles["opened"] references a missing CSS class.

This line uses styles["opened"] when isAtBottom is false, but the .opened class is not defined in styles.module.css. This will apply undefined as the class name. Either add the .opened class to the CSS module or simplify the logic to only apply the closed class conditionally.

🐛 Alternative fix if no explicit open state styling is needed
-          className={`${commonStyles["animated"]} ${isAtBottom ? styles["closed"] : styles["opened"]}`}
+          className={`${commonStyles["animated"]} ${isAtBottom ? styles["closed"] : ""}`}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/sketched-components/leva-panel/bottom-panel/index.tsx` around lines 48 -
50, The component is applying styles["opened"] which doesn't exist in the CSS
module; either add an .opened class to the CSS module or change the JSX in the
bottom-panel component to only apply styles["closed"] conditionally; update the
div that uses isAtBottom, commonStyles["animated"], styles["closed"], and
styles["opened"] so that when isAtBottom is false you do not reference
styles["opened"] (e.g., render `${commonStyles["animated"]} ${!isAtBottom ?
styles["closed"] : ''}`) or add a corresponding .opened rule to the CSS module
to match the existing reference.
🧹 Nitpick comments (3)
.cursor/rules/project-conventions.mdc (1)

8-8: Consider explicitly noting React 19+ in the ref guidance for clarity.

The repository targets React 19.2.4, so line 8's guidance on ref-as-prop and avoiding forwardRef is appropriate. However, adding an explicit React 19+ qualifier in the document itself (e.g., "React 19+: Use ref as a normal prop...") would improve clarity for future readers and make the version assumption explicit, especially if conventions are shared across projects.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/rules/project-conventions.mdc at line 8, Update the rule text to
explicitly reference React 19+ so readers know the ref-as-prop guidance applies
to modern React; change the sentence that currently begins "**React**: Use
functional components..." to something like "**React 19+**: Use functional
components (we target React 19.2.4): use `ref` as a normal prop (include `ref?:
Ref<T>` in props, destructure `{ ref, ...props }` in the signature and pass it
through) and keep the note to not use `forwardRef`—this makes the version
assumption explicit while preserving the existing instructions.
app/sketched-components/leva-panel/bottom-panel/styles.module.css (1)

38-42: Stylelint warning for :global() is a false positive.

The :global() pseudo-class is valid CSS Modules syntax used to escape module scoping and target global selectors. The Stylelint rule selector-pseudo-class-no-unknown needs configuration to recognize this. Consider adding :global to the ignorePseudoClasses option in your Stylelint config if you want to suppress this warning.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/sketched-components/leva-panel/bottom-panel/styles.module.css` around
lines 38 - 42, The Stylelint warning for the :global() pseudo-class is a false
positive; update the Stylelint configuration to add ":global" to the
selector-pseudo-class-no-unknown rule's ignorePseudoClasses option so CSS
Modules escapes like .noNumberInput :global(input[leva-type="number"]) are
allowed; specifically, modify your Stylelint config to include ":global" in
ignorePseudoClasses (or add it to the equivalent overrides) so the
selector-pseudo-class-no-unknown rule no longer flags the :global pseudo-class.
app/sketched-components/leva-panel/bottom-panel/index.tsx (1)

38-41: Inconsistent className handling between root div and inner div.

The root div (lines 38-41) conditionally appends only the closed class when !isOpen, defaulting to no additional class when open. However, the inner div (line 49) explicitly references styles["opened"]. Consider aligning these patterns for consistency—either both should use an explicit opened class, or both should omit styling when in the open state.

Also applies to: 48-50

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/sketched-components/leva-panel/bottom-panel/index.tsx` around lines 38 -
41, The root className builds `${styles["bottom-panel"]}
${commonStyles["animated"]}` and only appends styles["closed"] when !isOpen,
while the inner div explicitly uses styles["opened"]; make them consistent by
updating the root class construction to append styles["opened"] when isOpen and
styles["closed"] when not (so className includes either styles["opened"] or
styles["closed"]), and ensure the inner div uses the same predicate (remove
hardcoded styles["opened"] if you prefer the root to control state classes) —
adjust references to className and the inner div's class usage of
styles["opened"]/styles["closed"] accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@app/sketched-components/leva-panel/bottom-panel/index.tsx`:
- Around line 48-50: The component is applying styles["opened"] which doesn't
exist in the CSS module; either add an .opened class to the CSS module or change
the JSX in the bottom-panel component to only apply styles["closed"]
conditionally; update the div that uses isAtBottom, commonStyles["animated"],
styles["closed"], and styles["opened"] so that when isAtBottom is false you do
not reference styles["opened"] (e.g., render `${commonStyles["animated"]}
${!isAtBottom ? styles["closed"] : ''}`) or add a corresponding .opened rule to
the CSS module to match the existing reference.

---

Nitpick comments:
In @.cursor/rules/project-conventions.mdc:
- Line 8: Update the rule text to explicitly reference React 19+ so readers know
the ref-as-prop guidance applies to modern React; change the sentence that
currently begins "**React**: Use functional components..." to something like
"**React 19+**: Use functional components (we target React 19.2.4): use `ref` as
a normal prop (include `ref?: Ref<T>` in props, destructure `{ ref, ...props }`
in the signature and pass it through) and keep the note to not use
`forwardRef`—this makes the version assumption explicit while preserving the
existing instructions.

In `@app/sketched-components/leva-panel/bottom-panel/index.tsx`:
- Around line 38-41: The root className builds `${styles["bottom-panel"]}
${commonStyles["animated"]}` and only appends styles["closed"] when !isOpen,
while the inner div explicitly uses styles["opened"]; make them consistent by
updating the root class construction to append styles["opened"] when isOpen and
styles["closed"] when not (so className includes either styles["opened"] or
styles["closed"]), and ensure the inner div uses the same predicate (remove
hardcoded styles["opened"] if you prefer the root to control state classes) —
adjust references to className and the inner div's class usage of
styles["opened"]/styles["closed"] accordingly.

In `@app/sketched-components/leva-panel/bottom-panel/styles.module.css`:
- Around line 38-42: The Stylelint warning for the :global() pseudo-class is a
false positive; update the Stylelint configuration to add ":global" to the
selector-pseudo-class-no-unknown rule's ignorePseudoClasses option so CSS
Modules escapes like .noNumberInput :global(input[leva-type="number"]) are
allowed; specifically, modify your Stylelint config to include ":global" in
ignorePseudoClasses (or add it to the equivalent overrides) so the
selector-pseudo-class-no-unknown rule no longer flags the :global pseudo-class.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9fe3f97 and 8c651f3.

📒 Files selected for processing (33)
  • .coderabbit.yaml
  • .cursor/rules/project-conventions.mdc
  • .nvmrc
  • Dockerfile
  • app/3d/cube.tsx
  • app/3d/sphere.tsx
  • app/app.css
  • app/routes/demos/02-drei-app/main-scene.tsx
  • app/routes/demos/02-drei-app/styles.module.css
  • app/routes/demos/03-debug-ui/main-scene.tsx
  • app/routes/demos/layout.tsx
  • app/routes/demos/styles.module.css
  • app/routes/home/index.tsx
  • app/routes/home/styles.module.css
  • app/sketched-components/button/styles.module.css
  • app/sketched-components/card/index.tsx
  • app/sketched-components/card/styles.module.css
  • app/sketched-components/common.module.css
  • app/sketched-components/label/label.tsx
  • app/sketched-components/label/styles.module.css
  • app/sketched-components/leva-panel/bottom-panel/index.tsx
  • app/sketched-components/leva-panel/bottom-panel/styles.module.css
  • app/sketched-components/leva-panel/index.tsx
  • app/sketched-components/leva-panel/settings-button/index.tsx
  • app/sketched-components/leva-panel/settings-button/styles.module.css
  • app/sketched-components/leva-panel/sketchy-leva-panel/index.tsx
  • app/sketched-components/leva-panel/sketchy-leva-panel/leva-theme.ts
  • app/sketched-components/leva-panel/styles.module.css
  • app/sketched-components/link/styles.module.css
  • app/sketched-components/title/h1.tsx
  • app/sketched-components/title/styles.module.css
  • app/utils/hooks/use-demo-params.ts
  • package.json
💤 Files with no reviewable changes (4)
  • app/routes/demos/02-drei-app/styles.module.css
  • app/sketched-components/leva-panel/styles.module.css
  • app/sketched-components/common.module.css
  • Dockerfile

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
app/sketched-components/leva-panel/bottom-panel/index.tsx (1)

47-47: Move static z-index styling into CSS module.

zIndex: -1 is static; keeping it in styles.module.css will simplify maintenance and reduce inline style overrides.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/sketched-components/leva-panel/bottom-panel/index.tsx` at line 47, The
inline static style style={{ zIndex: `-1` }} in bottom-panel/index.tsx should be
moved into the component's CSS module: add a rule (e.g., .below or .panelZIndex)
with z-index: -1 in the corresponding styles.module.css, remove the style prop
from the JSX (the exact token style={{ zIndex: `-1` }}), and add the new CSS
class to the element's className (merging with existing classes or the imported
styles object used in this file). Ensure you update any className concatenation
or class composition in the BottomPanel component so the new module class is
applied instead of the inline style.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@app/sketched-components/leva-panel/bottom-panel/index.tsx`:
- Line 47: The inline static style style={{ zIndex: `-1` }} in
bottom-panel/index.tsx should be moved into the component's CSS module: add a
rule (e.g., .below or .panelZIndex) with z-index: -1 in the corresponding
styles.module.css, remove the style prop from the JSX (the exact token style={{
zIndex: `-1` }}), and add the new CSS class to the element's className (merging
with existing classes or the imported styles object used in this file). Ensure
you update any className concatenation or class composition in the BottomPanel
component so the new module class is applied instead of the inline style.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8c651f3 and f9d2011.

📒 Files selected for processing (5)
  • .cursor/rules/project-conventions.mdc
  • .nvmrc
  • app/sketched-components/leva-panel/bottom-panel/index.tsx
  • app/sketched-components/leva-panel/index.tsx
  • app/sketched-components/title/h1.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • app/sketched-components/title/h1.tsx
  • .nvmrc
  • .cursor/rules/project-conventions.mdc

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
app/routes/home/index.tsx (2)

37-37: ⚠️ Potential issue | 🟡 Minor

Grammatical error: "This are" should be "These are".

✏️ Proposed fix
-          description="This are the demos made for the Three JS Journey Course before reaching the React Three Fiber Chapter."
+          description="These are the demos made for the Three JS Journey Course before reaching the React Three Fiber Chapter."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/routes/home/index.tsx` at line 37, The description prop in
app/routes/home/index.tsx currently reads "This are the demos..." and has a
grammatical error; update the string passed to the description prop (the
description="...") to "These are the demos made for the Three JS Journey Course
before reaching the React Three Fiber Chapter." so subject-verb agreement is
correct.

32-40: ⚠️ Potential issue | 🟡 Minor

Add rel="noopener noreferrer" to the SketchedCard component for external links.

The component sets target="_blank" when the targetBlank prop is passed but does not include the rel attribute. This is a security oversight. When opening links in a new tab, the rel="noopener noreferrer" attribute should always be set to prevent the opened page from accessing window.opener. Update the Link element in app/sketched-components/card/index.tsx to conditionally apply rel="noopener noreferrer" when targetBlank is true.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/routes/home/index.tsx` around lines 32 - 40, The SketchedCard component
is setting targetBlank but not adding rel, which is a security risk; update the
SketchedCard render (the Link element inside the sketched card component) to
conditionally add rel="noopener noreferrer" whenever the targetBlank prop is
true (i.e., when rendering <Link ... target="_blank"> include rel="noopener
noreferrer"). Ensure the prop name targetBlank is used to decide adding the rel
attribute so external links opened in a new tab include rel="noopener
noreferrer".
🧹 Nitpick comments (1)
app/sketched-components/leva-panel/bottom-panel/index.tsx (1)

45-48: Consider using a number for zIndex.

The zIndex style value is passed as a string. While this works, using a number is more idiomatic for numeric CSS properties in React.

✨ Suggested change
       <div
         className={`${commonStyles["animated"]} ${isContextPanelSlidDown ? styles["closed"] : ""}`}
-        style={{ zIndex: `-1` }}
+        style={{ zIndex: -1 }}
       >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/sketched-components/leva-panel/bottom-panel/index.tsx` around lines 45 -
48, The inline style on the bottom-panel div uses a string zIndex value; update
the div in app/sketched-components/leva-panel/bottom-panel/index.tsx so the
style uses a numeric zIndex (e.g., change style={{ zIndex: `-1` }} to a numeric
-1) to be idiomatic in React while leaving the surrounding logic
(commonStyles["animated"], styles["closed"], isContextPanelSlidDown) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@app/routes/home/index.tsx`:
- Line 37: The description prop in app/routes/home/index.tsx currently reads
"This are the demos..." and has a grammatical error; update the string passed to
the description prop (the description="...") to "These are the demos made for
the Three JS Journey Course before reaching the React Three Fiber Chapter." so
subject-verb agreement is correct.
- Around line 32-40: The SketchedCard component is setting targetBlank but not
adding rel, which is a security risk; update the SketchedCard render (the Link
element inside the sketched card component) to conditionally add rel="noopener
noreferrer" whenever the targetBlank prop is true (i.e., when rendering <Link
... target="_blank"> include rel="noopener noreferrer"). Ensure the prop name
targetBlank is used to decide adding the rel attribute so external links opened
in a new tab include rel="noopener noreferrer".

---

Nitpick comments:
In `@app/sketched-components/leva-panel/bottom-panel/index.tsx`:
- Around line 45-48: The inline style on the bottom-panel div uses a string
zIndex value; update the div in
app/sketched-components/leva-panel/bottom-panel/index.tsx so the style uses a
numeric zIndex (e.g., change style={{ zIndex: `-1` }} to a numeric -1) to be
idiomatic in React while leaving the surrounding logic
(commonStyles["animated"], styles["closed"], isContextPanelSlidDown) unchanged.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8c651f3 and 0f7807e.

📒 Files selected for processing (6)
  • .cursor/rules/project-conventions.mdc
  • .nvmrc
  • app/routes/home/index.tsx
  • app/sketched-components/leva-panel/bottom-panel/index.tsx
  • app/sketched-components/leva-panel/index.tsx
  • app/sketched-components/title/h1.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • .nvmrc

@gianzamboni gianzamboni merged commit 9ca5a29 into mini-game-v2 Mar 1, 2026
3 checks passed
This was referenced Mar 1, 2026
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.

1 participant