-
Notifications
You must be signed in to change notification settings - Fork 139
feat(shadcn): add audio shader components #1266
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
base: main
Are you sure you want to change the base?
Conversation
|
size-limit report 📦
|
792d8ff to
fbbc9dc
Compare
|
@dz for awareness and review of license updates |
| /* | ||
| * Originally developed for Unicorn Studio | ||
| * https://unicorn.studio | ||
| * | ||
| * Licensed under the Polyform Non-Resale License 1.0.0 | ||
| * https://polyformproject.org/licenses/non-resale/1.0.0/ | ||
| * | ||
| * © 2026 UNCRN LLC | ||
| */ |
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.
@mattherzog @davidzhao
Here is the proposed license attributation
fbbc9dc to
5552668
Compare
5552668 to
3b2cf17
Compare
📝 WalkthroughWalkthroughAdds a WebGL ShaderToy component, two shader-based audio visualizers (Wave and Aura) with hooks, Storybook stories, registry/index exports, and a NOTICE license/attribution update. Changes
Sequence Diagram(s)sequenceDiagram
participant Component as AgentAudioVisualizer (Wave/Aura)
participant Hook as useAgentAudioVisualizer*
participant Track as AudioTrack/Volume
participant Shader as ReactShaderToy
participant Canvas as WebGL Canvas
Component->>Hook: provide AgentState + audioTrack
Hook->>Track: subscribe to volume updates
Track-->>Hook: volume data
Hook->>Hook: compute animated values (amplitude, frequency, scale, brightness, opacity)
Hook-->>Component: return animated values
Component->>Shader: set shaderSource, textures, uniforms
Shader->>Shader: compile/link & bind uniforms
Shader->>Canvas: render frame
Canvas-->>Component: visual output displayed
loop On Volume/State Change
Track->>Hook: new volume
Hook->>Component: updated animated values
Component->>Shader: update uniforms
Shader->>Canvas: re-render
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Comment |
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.
Actionable comments posted: 8
🤖 Fix all issues with AI agents
In `@docs/storybook/stories/agents-ui/ReactShaderToy.stories.tsx`:
- Around line 26-31: The two story exports Default and Basic use the wrong type
StoryObj<ReactShaderProps>; update both to StoryObj<ReactShaderToyProps> to
match the imported type (ReactShaderToyProps) already used elsewhere in the
file, ensuring the export signatures for Default and Basic reference
ReactShaderToyProps instead of ReactShaderProps.
In `@packages/shadcn/components/agents-ui/agent-audio-visualizer-aura.tsx`:
- Around line 297-305: The local variable named globalThis in
agent-audio-visualizer-aura.tsx is shadowing the real globalThis and triggers
the lint rule; rename that local (e.g., to envWindow or win) and update the
ReactShaderToy call to read devicePixelRatio from the real globalThis
(globalThis.devicePixelRatio ?? 1) instead of the renamed variable, leaving the
rest (useMemo rgbColor, shaderSource, ReactShaderToy uniforms) unchanged so
references like rgbColor and shaderSource continue to work.
In `@packages/shadcn/components/agents-ui/agent-audio-visualizer-wave.tsx`:
- Around line 237-239: Remove the duplicated/orphaned JSDoc comment for the prop
`audioTrack` that appears before the component definition; keep the correct
JSDoc located later (the one already attached at lines around the actual prop)
and delete the extra comment block (the stray "/** The audio track to visualize.
Can be a local/remote audio track or a track reference. */") in the
AgentAudioVisualizerWave component file so there is only a single JSDoc for
`audioTrack`.
- Line 179: The code declares a local const named globalThis which shadows the
standard ECMAScript global; remove that local declaration and update any uses to
refer to the built-in globalThis (or rename the local variable to something
non-conflicting if you truly need a local reference) so the component
(agent-audio-visualizer-wave / the const globalThis) no longer masks the runtime
global; ensure subsequent lines that currently reference the local const (e.g.,
the usage at the later assignment around line 186) are updated to use the
globalThis global or the new non-conflicting name.
In `@packages/shadcn/components/agents-ui/react-shader-toy.tsx`:
- Around line 89-91: The isVectorType type-guard currently rejects uniforms
whose lengths equal the indicated component count (e.g., "2f","3f","4f") because
it uses ">" when comparing v.length to Number.parseInt(t.charAt(0)); update the
comparison in isVectorType to use ">=" so vectors with exact component counts
are accepted, leaving the rest of the logic (Array.isArray(v) and parsing via
t.charAt(0)) intact; this change affects the isVectorType function and its
type-guard behavior for Vector4.
- Around line 54-59: The three biome suppression comments above the Matrix2,
Matrix3, and Matrix4 type aliases are missing required explanations; update each
directive to include a short reason (for example: "// biome-ignore format:
preserve manual tuple formatting for clarity") so that the biome linter accepts
them—modify the comments immediately preceding the Matrix2, Matrix3, and Matrix4
declarations to append an explanatory string after "biome-ignore format:".
In `@packages/shadcn/hooks/agents-ui/use-agent-audio-visualizer-wave.ts`:
- Around line 97-101: The useEffect currently only updates visuals when state
=== 'speaking' && volume > 0, causing amplitude/frequency to stick at the last
value when volume drops to 0; modify the effect so that when state ===
'speaking' it always calls animateAmplitude and animateFrequency, using the
baseline values (e.g., amplitude baseline 0.015 and frequency baseline 20) when
volume === 0 and the scaled values (0.015 + 0.4 * volume and 20 + 60 * volume)
when volume > 0; update the effect that references state and volume and the
calls to animateAmplitude and animateFrequency accordingly so visuals settle
back to baseline as volume goes to zero.
In `@packages/shadcn/registry.json`:
- Around line 255-259: The description string for the component with "name":
"agent-audio-visualizer-aura" contains incorrect grammar; update the
"description" value from "A aura visualizer for audio tracks." to "An aura
visualizer." so the user-facing copy reads exactly "An aura visualizer." Ensure
you modify the "description" property for the registry component entry that
includes "title": "Agent Audio Visualizer Aura".
🧹 Nitpick comments (4)
packages/shadcn/components/agents-ui/react-shader-toy.tsx (1)
927-972: Confirm props are intended to be static after mount.The init effect runs only once, so changes to
fs,vs,textures,precision, etc. won’t be applied unless the component remounts. If runtime changes are expected (e.g., Storybook controls), consider re‑initializing on prop change or documenting the need to change the component key.packages/shadcn/components/agents-ui/agent-audio-visualizer-wave.tsx (3)
14-31: Try-catch provides no value here.The
try-catchblock is misleading because neithermatch()norparseInt()throws on invalid input—they returnnullandNaNrespectively. As a result, theconsole.errorin the catch block will never execute for invalid hex formats; the code silently falls through to the default.Consider removing the try-catch or restructuring to log when the regex doesn't match:
Suggested refactor
function hexToRgb(hexColor: string) { - try { - const rgbColor = hexColor.match(/^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/); - - if (rgbColor) { - const [, r, g, b] = rgbColor; - const color = [r, g, b].map((c = '00') => parseInt(c, 16) / 255); - - return color; - } - } catch (error) { + const rgbColor = hexColor.match(/^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/); + + if (rgbColor) { + const [, r, g, b] = rgbColor; + return [r, g, b].map((c = '00') => parseInt(c, 16) / 255); + } + + if (hexColor !== DEFAULT_COLOR) { console.error( `Invalid hex color '${hexColor}'.\nFalling back to default color '${DEFAULT_COLOR}'.`, ); } return hexToRgb(DEFAULT_COLOR); }
210-223: Gap classes appear unused.The
gap-[*]classes in each variant have no effect becauseWaveShaderrenders a single child (ReactShaderToy). Gap only applies to flex/grid containers with multiple children. Consider removing them to avoid confusion:Suggested cleanup
export const AgentAudioVisualizerWaveVariants = cva(['aspect-square'], { variants: { size: { - icon: 'h-[24px] gap-[2px]', - sm: 'h-[56px] gap-[4px]', - md: 'h-[112px] gap-[8px]', - lg: 'h-[224px] gap-[16px]', - xl: 'h-[448px] gap-[32px]', + icon: 'h-[24px]', + sm: 'h-[56px]', + md: 'h-[112px]', + lg: 'h-[224px]', + xl: 'h-[448px]', }, }, defaultVariants: { size: 'md', }, });
282-295: Note: Defaultsizediffers from variant default.The component defaults
sizeto'lg'(line 283), whileAgentAudioVisualizerWaveVariantsdefaults to'md'(line 221). This is likely intentional, but the JSDoc at line 228-230 states@defaultValue 'md', which is inconsistent with the actual default.Consider aligning the JSDoc with the actual default:
/** * The size of the visualizer. - * `@defaultValue` 'md' + * `@defaultValue` 'lg' */
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
NOTICEdocs/storybook/stories/agents-ui/AgentAudioVisualizerAura.stories.tsxdocs/storybook/stories/agents-ui/AgentAudioVisualizerWave.stories.tsxdocs/storybook/stories/agents-ui/ReactShaderToy.stories.tsxpackages/shadcn/components/agents-ui/agent-audio-visualizer-aura.tsxpackages/shadcn/components/agents-ui/agent-audio-visualizer-wave.tsxpackages/shadcn/components/agents-ui/react-shader-toy.tsxpackages/shadcn/hooks/agents-ui/use-agent-audio-visualizer-aura.tspackages/shadcn/hooks/agents-ui/use-agent-audio-visualizer-wave.tspackages/shadcn/index.tspackages/shadcn/registry.json
🧰 Additional context used
🧬 Code graph analysis (7)
packages/shadcn/hooks/agents-ui/use-agent-audio-visualizer-wave.ts (1)
packages/react/src/hooks/useTrackVolume.ts (1)
useTrackVolume(14-51)
docs/storybook/stories/agents-ui/ReactShaderToy.stories.tsx (1)
packages/shadcn/components/agents-ui/react-shader-toy.tsx (2)
ReactShaderToy(493-975)ReactShaderToyProps(418-491)
packages/shadcn/hooks/agents-ui/use-agent-audio-visualizer-aura.ts (1)
packages/react/src/hooks/useTrackVolume.ts (1)
useTrackVolume(14-51)
packages/shadcn/components/agents-ui/agent-audio-visualizer-aura.tsx (3)
packages/shadcn/components/agents-ui/react-shader-toy.tsx (1)
ReactShaderToy(493-975)packages/shadcn/hooks/agents-ui/use-agent-audio-visualizer-aura.ts (1)
useAgentAudioVisualizerAura(46-124)packages/shadcn/lib/utils.ts (1)
cn(4-6)
docs/storybook/stories/agents-ui/AgentAudioVisualizerWave.stories.tsx (2)
packages/shadcn/components/agents-ui/agent-audio-visualizer-wave.tsx (2)
AgentAudioVisualizerWave(282-333)AgentAudioVisualizerWaveProps(225-262)docs/storybook/.storybook/lk-decorators/AgentSessionProvider.tsx (1)
useMicrophone(30-46)
packages/shadcn/components/agents-ui/agent-audio-visualizer-wave.tsx (3)
packages/shadcn/components/agents-ui/react-shader-toy.tsx (1)
ReactShaderToy(493-975)packages/shadcn/hooks/agents-ui/use-agent-audio-visualizer-wave.ts (1)
useAgentAudioVisualizerWave(43-110)packages/shadcn/lib/utils.ts (1)
cn(4-6)
docs/storybook/stories/agents-ui/AgentAudioVisualizerAura.stories.tsx (4)
packages/shadcn/components/agents-ui/agent-audio-visualizer-aura.tsx (2)
AgentAudioVisualizerAura(412-450)AgentAudioVisualizerAuraProps(364-394)docs/storybook/.storybook/lk-decorators/AgentSessionProvider.tsx (1)
useMicrophone(30-46)docs/storybook/stories/agents-ui/AgentAudioVisualizerWave.stories.tsx (1)
Default(61-63)docs/storybook/stories/agents-ui/ReactShaderToy.stories.tsx (1)
Default(26-28)
🪛 Biome (2.1.2)
packages/shadcn/components/agents-ui/agent-audio-visualizer-aura.tsx
[error] 297-297: Do not shadow the global "globalThis" property.
Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.
(lint/suspicious/noShadowRestrictedNames)
packages/shadcn/components/agents-ui/react-shader-toy.tsx
[error] 54-54: Incorrect suppression: missing reason. Example of suppression: // biome-ignore lint: false positive
A reason is mandatory: try to explain why the suppression is needed.
Example of suppression: // biome-ignore lint: reason
(suppressions/parse)
[error] 56-56: Incorrect suppression: missing reason. Example of suppression: // biome-ignore lint: false positive
A reason is mandatory: try to explain why the suppression is needed.
Example of suppression: // biome-ignore lint: reason
(suppressions/parse)
[error] 58-58: Incorrect suppression: missing reason. Example of suppression: // biome-ignore lint: false positive
A reason is mandatory: try to explain why the suppression is needed.
Example of suppression: // biome-ignore lint: reason
(suppressions/parse)
[error] 666-666: This hook is being called from a nested function, but all hooks must be called unconditionally from the top-level component.
For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level
(lint/correctness/useHookAtTopLevel)
[error] 959-959: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.
For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level
(lint/correctness/useHookAtTopLevel)
packages/shadcn/components/agents-ui/agent-audio-visualizer-wave.tsx
[error] 179-179: Do not shadow the global "globalThis" property.
Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.
(lint/suspicious/noShadowRestrictedNames)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: test
🔇 Additional comments (19)
NOTICE (1)
15-20: Attribution block looks good.Thanks for adding the upstream license acknowledgment in NOTICE.
packages/shadcn/hooks/agents-ui/use-agent-audio-visualizer-aura.ts (2)
30-44:useAnimatedValuehelper is clean and reusable.Nice encapsulation of motion value + state updates.
46-123: State-driven aura transitions read well.The per-state animation tuning is consistent and easy to follow.
packages/shadcn/components/agents-ui/react-shader-toy.tsx (5)
205-391: Texture loading flow looks solid.Power‑of‑two handling and fallback behavior are well covered.
395-405: Pointer helpers and lerp utilities are straightforward.No concerns here.
418-491: Props surface is clear and well documented.The inline docs make the API easy to consume.
538-735: Initialization and texture setup are well structured.Good separation of WebGL setup, buffer init, and texture preparation.
736-880: Shader preprocessing and render loop are consistent.Uniform updates and draw loop sequencing look good.
docs/storybook/stories/agents-ui/ReactShaderToy.stories.tsx (1)
6-24: Story config looks good.The decorator and centered layout are clean.
packages/shadcn/index.ts (1)
12-14: Exports look good.Re-exports align with the new components.
docs/storybook/stories/agents-ui/AgentAudioVisualizerWave.stories.tsx (1)
9-59: Story wiring looks solid.
Decorator usage and controls line up with the component props.packages/shadcn/components/agents-ui/agent-audio-visualizer-aura.tsx (4)
24-41: Nice defensive color parsing.
Fallback behavior is clear and safe.
43-210: Shader source reviewed at a high level.
No issues spotted in the integration.
349-394: Props/variants shape looks consistent.
Defaults and types align with expected usage.
412-449: Component composition looks good.
Hook outputs are wired cleanly into shader uniforms and class variants.docs/storybook/stories/agents-ui/AgentAudioVisualizerAura.stories.tsx (1)
10-59: Story setup is clean and consistent.
Args and controls map well to the component’s API.packages/shadcn/hooks/agents-ui/use-agent-audio-visualizer-wave.ts (1)
22-35: Animated value helper looks good.
Clear encapsulation around motion value and animation controls.packages/shadcn/components/agents-ui/agent-audio-visualizer-wave.tsx (2)
33-122: GLSL shader implementation looks solid.The shader correctly implements oscilloscope-style wave rendering with bell curve attenuation, distance field sampling for anti-aliased line rendering, and proper uniform bindings. The 50-sample loop is a reasonable trade-off for quality vs. performance.
309-331: Implementation correctly integrates the animation hook.The component properly consumes
useAgentAudioVisualizerWaveto drive shader uniforms and applies opacity via inline styles. The mask gradient for edge fading and the size-dependent line width logic are well thought out.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
packages/shadcn/components/agents-ui/agent-audio-visualizer-aura.tsx
Outdated
Show resolved
Hide resolved
packages/shadcn/components/agents-ui/agent-audio-visualizer-wave.tsx
Outdated
Show resolved
Hide resolved
packages/shadcn/components/agents-ui/agent-audio-visualizer-wave.tsx
Outdated
Show resolved
Hide resolved
packages/shadcn/components/agents-ui/agent-audio-visualizer-aura.tsx
Outdated
Show resolved
Hide resolved
packages/shadcn/components/agents-ui/agent-audio-visualizer-wave.tsx
Outdated
Show resolved
Hide resolved
1egoman
left a comment
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.
Oops, meant to make that an approval - none of my comments are blocking, all suggestions.
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.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@packages/shadcn/components/agents-ui/react-shader-toy.tsx`:
- Around line 395-398: latestPointerClientCoords treats 0 as falsy and also
assumes changedTouches exists; update it to first prefer mouse coords using a
null/undefined check (not ||) on e.clientX/e.clientY, and only fall back to
touch coords if changedTouches exists and has at least one touch. Concretely: in
latestPointerClientCoords, check for presence of numeric e.clientX/e.clientY
(e.g., typeof e.clientX === 'number' or e.clientX != null) and return those when
available; otherwise verify ('changedTouches' in e) && e.changedTouches.length >
0 and return changedTouches[0].clientX/Y. This avoids treating 0 as falsy and
prevents accessing changedTouches on MouseEvent.
♻️ Duplicate comments (2)
packages/shadcn/components/agents-ui/react-shader-toy.tsx (2)
54-59: Biome suppression comments need a reason (or remove them).
Biome requires an explanation afterbiome-ignore format:; otherwise lint fails.🛠️ Option A — add reasons
-// biome-ignore format: +// biome-ignore format: keep tuple types on one line for readability export type Matrix2<T = number> = [T, T, T, T]; -// biome-ignore format: +// biome-ignore format: keep tuple types on one line for readability export type Matrix3<T = number> = [T, T, T, T, T, T, T, T, T]; -// biome-ignore format: +// biome-ignore format: keep tuple types on one line for readability export type Matrix4<T = number> = [T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T];
89-91: Accept exact-length vectors inisVectorType.
Currently2f/3f/4farrays with exact lengths are rejected, so those uniforms can be skipped.🐛 Proposed fix
function isVectorType(t: string, v: number[] | number): v is Vector4 { - return !t.includes('v') && Array.isArray(v) && v.length > Number.parseInt(t.charAt(0)); + return !t.includes('v') && Array.isArray(v) && v.length >= Number.parseInt(t.charAt(0)); }
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
docs/storybook/stories/agents-ui/ReactShaderToy.stories.tsxpackages/shadcn/components/agents-ui/agent-audio-visualizer-aura.tsxpackages/shadcn/components/agents-ui/agent-audio-visualizer-wave.tsxpackages/shadcn/components/agents-ui/react-shader-toy.tsxpackages/shadcn/hooks/agents-ui/use-agent-audio-visualizer-wave.tspackages/shadcn/registry.json
🚧 Files skipped from review as they are similar to previous changes (1)
- docs/storybook/stories/agents-ui/ReactShaderToy.stories.tsx
🧰 Additional context used
🧬 Code graph analysis (2)
packages/shadcn/hooks/agents-ui/use-agent-audio-visualizer-wave.ts (1)
packages/react/src/hooks/useTrackVolume.ts (1)
useTrackVolume(14-51)
packages/shadcn/components/agents-ui/agent-audio-visualizer-wave.tsx (3)
packages/shadcn/components/agents-ui/react-shader-toy.tsx (1)
ReactShaderToy(493-975)packages/shadcn/hooks/agents-ui/use-agent-audio-visualizer-wave.ts (1)
useAgentAudioVisualizerWave(43-110)packages/shadcn/lib/utils.ts (1)
cn(4-6)
🪛 Biome (2.1.2)
packages/shadcn/components/agents-ui/react-shader-toy.tsx
[error] 54-54: Incorrect suppression: missing reason. Example of suppression: // biome-ignore lint: false positive
A reason is mandatory: try to explain why the suppression is needed.
Example of suppression: // biome-ignore lint: reason
(suppressions/parse)
[error] 56-56: Incorrect suppression: missing reason. Example of suppression: // biome-ignore lint: false positive
A reason is mandatory: try to explain why the suppression is needed.
Example of suppression: // biome-ignore lint: reason
(suppressions/parse)
[error] 58-58: Incorrect suppression: missing reason. Example of suppression: // biome-ignore lint: false positive
A reason is mandatory: try to explain why the suppression is needed.
Example of suppression: // biome-ignore lint: reason
(suppressions/parse)
[error] 666-666: This hook is being called from a nested function, but all hooks must be called unconditionally from the top-level component.
For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level
(lint/correctness/useHookAtTopLevel)
[error] 959-959: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.
For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level
(lint/correctness/useHookAtTopLevel)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: test
🔇 Additional comments (2)
packages/shadcn/hooks/agents-ui/use-agent-audio-visualizer-wave.ts (2)
22-35: Animated value helper looks solid.
State syncing via motion value events is clear and safe here.
57-102: State + volume animation logic reads clean and consistent.
The transitions across agent states and speaking volume updates align well.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
58061fd to
a20a889
Compare
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.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@packages/shadcn/components/agents-ui/agent-audio-visualizer-wave.tsx`:
- Around line 292-303: The memo for _lineWidth currently uses a truthy check (if
(lineWidth)) which treats 0 as unset; update the logic in the useMemo inside
agent-audio-visualizer-wave.tsx to respect explicit zero by using a nullish
check (e.g., if (lineWidth !== null && lineWidth !== undefined) or use the
nullish coalescing operator lineWidth ?? ...) so callers can pass lineWidth={0}
to hide the line; keep the existing switch on size as the fallback when
lineWidth is nullish.
In `@packages/shadcn/components/agents-ui/react-shader-toy.tsx`:
- Around line 656-662: The loop over Object.keys(propUniforms) uses `return` to
bail out on a single invalid uniform which aborts updating the rest; change
those `return` statements inside the for-loops (the one handling `propUniforms`
and the similar loop around lines 752-760) to `continue` so only the problematic
uniform is skipped and the loop proceeds; update checks around `if (!uniform)
return;` and `if (!glslType) return;` to `if (!uniform) continue;` and `if
(!glslType) continue;` respectively, keeping the rest of the per-uniform logic
(tempObject creation, value/type handling) unchanged.
♻️ Duplicate comments (1)
packages/shadcn/components/agents-ui/react-shader-toy.tsx (1)
65-66: Vector uniforms with exact length are still rejected.
This is the same issue noted earlier:2f/3f/4farrays with the correct length won’t pass the guard.🐛 Proposed fix
-function isVectorType(t: string, v: number[] | number): v is Vector4 { - return !t.includes('v') && Array.isArray(v) && v.length > Number.parseInt(t.charAt(0)); -} +function isVectorType(t: string, v: number[] | number): v is Vector4 { + return !t.includes('v') && Array.isArray(v) && v.length >= Number.parseInt(t.charAt(0)); +}
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
docs/storybook/stories/agents-ui/ReactShaderToy.stories.tsxpackages/shadcn/components/agents-ui/agent-audio-visualizer-aura.tsxpackages/shadcn/components/agents-ui/agent-audio-visualizer-wave.tsxpackages/shadcn/components/agents-ui/react-shader-toy.tsxpackages/shadcn/hooks/agents-ui/use-agent-audio-visualizer-wave.tspackages/shadcn/registry.json
🚧 Files skipped from review as they are similar to previous changes (2)
- packages/shadcn/registry.json
- packages/shadcn/hooks/agents-ui/use-agent-audio-visualizer-wave.ts
🧰 Additional context used
🧬 Code graph analysis (1)
packages/shadcn/components/agents-ui/agent-audio-visualizer-wave.tsx (3)
packages/shadcn/components/agents-ui/react-shader-toy.tsx (1)
ReactShaderToy(473-955)packages/shadcn/hooks/agents-ui/use-agent-audio-visualizer-wave.ts (1)
useAgentAudioVisualizerWave(43-110)packages/shadcn/lib/utils.ts (1)
cn(4-6)
🪛 Biome (2.1.2)
packages/shadcn/components/agents-ui/react-shader-toy.tsx
[error] 646-646: This hook is being called from a nested function, but all hooks must be called unconditionally from the top-level component.
For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level
(lint/correctness/useHookAtTopLevel)
[error] 939-939: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.
For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level
(lint/correctness/useHookAtTopLevel)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: test
🔇 Additional comments (3)
docs/storybook/stories/agents-ui/ReactShaderToy.stories.tsx (1)
6-38: Clean Storybook setup for the shader component.
Consistent provider decorator and a focused basic shader example make this story easy to validate visually.packages/shadcn/components/agents-ui/agent-audio-visualizer-aura.tsx (1)
280-343: No changes needed—this package targets React 19, which supportsrefas a prop in function components.The code correctly passes
refas a destructured prop to the component. Sincelivekit/components-jsexplicitly targets React 19 in its README,forwardRefis unnecessary here.packages/shadcn/components/agents-ui/agent-audio-visualizer-wave.tsx (1)
167-204: No changes needed. This component is part of the Agents UI, which targets React 19. React 19 supportsrefas a prop directly in function components, so the current implementation is correct and does not requireforwardRef.Likely an incorrect or invalid review comment.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
a20a889 to
344bbb5
Compare
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.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In `@packages/shadcn/components/agents-ui/agent-audio-visualizer-wave.tsx`:
- Around line 224-281: The JSDoc and variants indicate the default size should
be 'md' but the component function sets size='lg'; update the implementation to
use size = 'md' in the AgentAudioVisualizerWave function signature (and verify
AgentAudioVisualizerWaveProps JSDoc stays consistent) so the default across
AgentAudioVisualizerWave, AgentAudioVisualizerWaveProps, and any variant
defaults all match 'md'.
In `@packages/shadcn/components/agents-ui/react-shader-toy.tsx`:
- Around line 518-524: setupChannelRes is writing width/height into
uniformsRef.current.iChannelResolution and when called with TextureParams (which
may lack width/height) it produces NaN; update setupChannelRes (and the similar
block around the other occurrence) to default missing dimensions to 0 (e.g.,
const w = (width ?? 0) * devicePixelRatio, const h = (height ?? 0) *
devicePixelRatio) before assigning to
uniformsRef.current.iChannelResolution.value[id * 3], [id * 3 + 1], and set the
third component to 0, so initialization never writes NaN values.
- Around line 612-625: In createShader, when compilation fails (inside the block
that calls gl.getShaderParameter and gl.deleteShader), ensure you return null
after deleting the shader so that callers like initShaders do not receive a
deleted/invalid shader handle; update the createShader function to delete the
shader and then immediately return null (reference createShader,
gl.deleteShader, and initShaders to locate usage).
♻️ Duplicate comments (2)
packages/shadcn/components/agents-ui/react-shader-toy.tsx (2)
65-66: Exact-length vector uniforms are rejected.
2f/3f/4funiforms with length 2/3/4 fail the guard, so valid vectors can be skipped.🧩 Proposed fix
-function isVectorType(t: string, v: number[] | number): v is Vector4 { - return !t.includes('v') && Array.isArray(v) && v.length > Number.parseInt(t.charAt(0)); -} +function isVectorType(t: string, v: number[] | number): v is Vector4 { + return !t.includes('v') && Array.isArray(v) && v.length >= Number.parseInt(t.charAt(0)); +}
752-760: Don’t abort the full uniform update on a single missing entry.
returninside these loops stops all subsequent uniforms and built‑ins from updating. Usecontinueto skip only the problematic item.🛠️ Suggested change
- if (!shaderProgramRef.current) return; + if (!shaderProgramRef.current) continue; const customUniformLocation = gl.getUniformLocation(shaderProgramRef.current, name); - if (!customUniformLocation) return; + if (!customUniformLocation) continue;- if (!texture) return; + if (!texture) continue; const { isVideo, _webglTexture, source, flipY, isLoaded } = texture; - if (!isLoaded || !_webglTexture || !source) return; + if (!isLoaded || !_webglTexture || !source) continue; if (uniformsRef.current[`iChannel${index}`]?.isNeeded) { - if (!shaderProgramRef.current) return; + if (!shaderProgramRef.current) continue; const iChannel = gl.getUniformLocation(shaderProgramRef.current, `iChannel${index}`);Also applies to: 816-819
🧹 Nitpick comments (1)
packages/shadcn/components/agents-ui/agent-audio-visualizer-aura.tsx (1)
24-41: Consider extractinghexToRgbto a shared util.This helper is duplicated in the wave visualizer; centralizing avoids drift and keeps validation consistent.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
docs/storybook/stories/agents-ui/ReactShaderToy.stories.tsxpackages/shadcn/components/agents-ui/agent-audio-visualizer-aura.tsxpackages/shadcn/components/agents-ui/agent-audio-visualizer-wave.tsxpackages/shadcn/components/agents-ui/react-shader-toy.tsxpackages/shadcn/hooks/agents-ui/use-agent-audio-visualizer-wave.tspackages/shadcn/registry.json
🚧 Files skipped from review as they are similar to previous changes (3)
- packages/shadcn/hooks/agents-ui/use-agent-audio-visualizer-wave.ts
- packages/shadcn/registry.json
- docs/storybook/stories/agents-ui/ReactShaderToy.stories.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
packages/shadcn/components/agents-ui/agent-audio-visualizer-aura.tsx (3)
packages/shadcn/components/agents-ui/react-shader-toy.tsx (1)
ReactShaderToy(473-955)packages/shadcn/hooks/agents-ui/use-agent-audio-visualizer-aura.ts (1)
useAgentAudioVisualizerAura(46-124)packages/shadcn/lib/utils.ts (1)
cn(4-6)
🪛 Biome (2.1.2)
packages/shadcn/components/agents-ui/react-shader-toy.tsx
[error] 646-646: This hook is being called from a nested function, but all hooks must be called unconditionally from the top-level component.
For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level
(lint/correctness/useHookAtTopLevel)
[error] 939-939: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.
For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level
(lint/correctness/useHookAtTopLevel)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: test
🔇 Additional comments (3)
packages/shadcn/components/agents-ui/react-shader-toy.tsx (1)
371-377: Pointer coordinate helper looks solid.The touch vs. mouse split avoids the
clientX/clientYfalsy edge case and preventschangedTouchesaccess on mouse events.packages/shadcn/components/agents-ui/agent-audio-visualizer-aura.tsx (1)
424-447: State-driven uniform wiring looks good.The hook outputs map cleanly to shader uniforms and keep the component API tidy.
packages/shadcn/components/agents-ui/agent-audio-visualizer-wave.tsx (1)
292-303: Line width resolution logic is solid.The nullish check preserves explicit
0and keeps size-based fallback behavior clear.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| export interface AgentAudioVisualizerWaveProps { | ||
| /** | ||
| * The size of the visualizer. | ||
| * @defaultValue 'md' | ||
| */ | ||
| size?: 'icon' | 'sm' | 'md' | 'lg' | 'xl'; | ||
| /** | ||
| * The agent state. | ||
| * @defaultValue 'speaking' | ||
| */ | ||
| state?: AgentState; | ||
| /** | ||
| * The color of the wave in hex format. | ||
| * @defaultValue '#1FD5F9' | ||
| */ | ||
| color?: string; | ||
| /** | ||
| * The line width of the wave in pixels. | ||
| * @defaultValue 2.0 | ||
| */ | ||
| lineWidth?: number; | ||
| /** | ||
| * The smoothing of the wave in pixels. | ||
| * @defaultValue 0.5 | ||
| */ | ||
| smoothing?: number; | ||
| /** | ||
| * The audio track to visualize. Can be a local/remote audio track or a track reference. | ||
| */ | ||
| audioTrack?: LocalAudioTrack | RemoteAudioTrack | TrackReferenceOrPlaceholder; | ||
| /** | ||
| * Additional CSS class names to apply to the container. | ||
| */ | ||
| className?: string; | ||
| } | ||
|
|
||
| /** | ||
| * A wave-style audio visualizer that responds to agent state and audio levels. | ||
| * Displays an animated wave that reacts to the current agent state (connecting, thinking, speaking, etc.) | ||
| * and audio volume when speaking. | ||
| * | ||
| * @extends ComponentProps<'div'> | ||
| * | ||
| * @example ```tsx | ||
| * <AgentAudioVisualizerWave | ||
| * size="lg" | ||
| * state="speaking" | ||
| * color="#1FD5F9" | ||
| * lineWidth={2} | ||
| * smoothing={0.5} | ||
| * audioTrack={audioTrack} | ||
| * /> | ||
| * ``` | ||
| */ | ||
| export function AgentAudioVisualizerWave({ | ||
| size = 'lg', | ||
| state = 'speaking', | ||
| color, |
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.
Default size mismatch between docs and implementation.
The JSDoc says default is 'md', but the component defaults to 'lg' (and variants default to 'md'). Align the default or update the docs.
🛠️ Suggested fix (align with docs/variants)
-export function AgentAudioVisualizerWave({
- size = 'lg',
+export function AgentAudioVisualizerWave({
+ size = 'md',📝 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.
| export interface AgentAudioVisualizerWaveProps { | |
| /** | |
| * The size of the visualizer. | |
| * @defaultValue 'md' | |
| */ | |
| size?: 'icon' | 'sm' | 'md' | 'lg' | 'xl'; | |
| /** | |
| * The agent state. | |
| * @defaultValue 'speaking' | |
| */ | |
| state?: AgentState; | |
| /** | |
| * The color of the wave in hex format. | |
| * @defaultValue '#1FD5F9' | |
| */ | |
| color?: string; | |
| /** | |
| * The line width of the wave in pixels. | |
| * @defaultValue 2.0 | |
| */ | |
| lineWidth?: number; | |
| /** | |
| * The smoothing of the wave in pixels. | |
| * @defaultValue 0.5 | |
| */ | |
| smoothing?: number; | |
| /** | |
| * The audio track to visualize. Can be a local/remote audio track or a track reference. | |
| */ | |
| audioTrack?: LocalAudioTrack | RemoteAudioTrack | TrackReferenceOrPlaceholder; | |
| /** | |
| * Additional CSS class names to apply to the container. | |
| */ | |
| className?: string; | |
| } | |
| /** | |
| * A wave-style audio visualizer that responds to agent state and audio levels. | |
| * Displays an animated wave that reacts to the current agent state (connecting, thinking, speaking, etc.) | |
| * and audio volume when speaking. | |
| * | |
| * @extends ComponentProps<'div'> | |
| * | |
| * @example ```tsx | |
| * <AgentAudioVisualizerWave | |
| * size="lg" | |
| * state="speaking" | |
| * color="#1FD5F9" | |
| * lineWidth={2} | |
| * smoothing={0.5} | |
| * audioTrack={audioTrack} | |
| * /> | |
| * ``` | |
| */ | |
| export function AgentAudioVisualizerWave({ | |
| size = 'lg', | |
| state = 'speaking', | |
| color, | |
| export interface AgentAudioVisualizerWaveProps { | |
| /** | |
| * The size of the visualizer. | |
| * `@defaultValue` 'md' | |
| */ | |
| size?: 'icon' | 'sm' | 'md' | 'lg' | 'xl'; | |
| /** | |
| * The agent state. | |
| * `@defaultValue` 'speaking' | |
| */ | |
| state?: AgentState; | |
| /** | |
| * The color of the wave in hex format. | |
| * `@defaultValue` '#1FD5F9' | |
| */ | |
| color?: string; | |
| /** | |
| * The line width of the wave in pixels. | |
| * `@defaultValue` 2.0 | |
| */ | |
| lineWidth?: number; | |
| /** | |
| * The smoothing of the wave in pixels. | |
| * `@defaultValue` 0.5 | |
| */ | |
| smoothing?: number; | |
| /** | |
| * The audio track to visualize. Can be a local/remote audio track or a track reference. | |
| */ | |
| audioTrack?: LocalAudioTrack | RemoteAudioTrack | TrackReferenceOrPlaceholder; | |
| /** | |
| * Additional CSS class names to apply to the container. | |
| */ | |
| className?: string; | |
| } | |
| /** | |
| * A wave-style audio visualizer that responds to agent state and audio levels. | |
| * Displays an animated wave that reacts to the current agent state (connecting, thinking, speaking, etc.) | |
| * and audio volume when speaking. | |
| * | |
| * `@extends` ComponentProps<'div'> | |
| * | |
| * `@example` |
🤖 Prompt for AI Agents
In `@packages/shadcn/components/agents-ui/agent-audio-visualizer-wave.tsx` around
lines 224 - 281, The JSDoc and variants indicate the default size should be 'md'
but the component function sets size='lg'; update the implementation to use size
= 'md' in the AgentAudioVisualizerWave function signature (and verify
AgentAudioVisualizerWaveProps JSDoc stays consistent) so the default across
AgentAudioVisualizerWave, AgentAudioVisualizerWaveProps, and any variant
defaults all match 'md'.
| const setupChannelRes = ({ width, height }: Texture, id: number) => { | ||
| // @ts-expect-error TODO: Deal with this. | ||
| uniformsRef.current.iChannelResolution.value[id * 3] = width * devicePixelRatio; | ||
| // @ts-expect-error TODO: Deal with this. | ||
| uniformsRef.current.iChannelResolution.value[id * 3 + 1] = height * devicePixelRatio; | ||
| // @ts-expect-error TODO: Deal with this. | ||
| uniformsRef.current.iChannelResolution.value[id * 3 + 2] = 0; |
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.
Avoid NaN in iChannelResolution during texture init.
setupChannelRes(texture, id) is called with TextureParams (no width/height), which yields NaN until the real texture loads. Default to 0 for missing dimensions.
🛠️ Suggested tweak
-const setupChannelRes = ({ width, height }: Texture, id: number) => {
+const setupChannelRes = ({ width, height }: Texture, id: number) => {
+ const w = width ?? 0;
+ const h = height ?? 0;
// `@ts-expect-error` TODO: Deal with this.
- uniformsRef.current.iChannelResolution.value[id * 3] = width * devicePixelRatio;
+ uniformsRef.current.iChannelResolution.value[id * 3] = w * devicePixelRatio;
// `@ts-expect-error` TODO: Deal with this.
- uniformsRef.current.iChannelResolution.value[id * 3 + 1] = height * devicePixelRatio;
+ uniformsRef.current.iChannelResolution.value[id * 3 + 1] = h * devicePixelRatio;Also applies to: 693-699
🤖 Prompt for AI Agents
In `@packages/shadcn/components/agents-ui/react-shader-toy.tsx` around lines 518 -
524, setupChannelRes is writing width/height into
uniformsRef.current.iChannelResolution and when called with TextureParams (which
may lack width/height) it produces NaN; update setupChannelRes (and the similar
block around the other occurrence) to default missing dimensions to 0 (e.g.,
const w = (width ?? 0) * devicePixelRatio, const h = (height ?? 0) *
devicePixelRatio) before assigning to
uniformsRef.current.iChannelResolution.value[id * 3], [id * 3 + 1], and set the
third component to 0, so initialization never writes NaN values.
| const createShader = (type: number, shaderCodeAsText: string) => { | ||
| const gl = glRef.current; | ||
| if (!gl) return null; | ||
| const shader = gl.createShader(type); | ||
| if (!shader) return null; | ||
| gl.shaderSource(shader, shaderCodeAsText); | ||
| gl.compileShader(shader); | ||
| if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { | ||
| onWarning?.(log(`Error compiling the shader:\n${shaderCodeAsText}`)); | ||
| const compilationLog = gl.getShaderInfoLog(shader); | ||
| gl.deleteShader(shader); | ||
| onError?.(log(`Shader compiler log: ${compilationLog}`)); | ||
| } | ||
| return shader; |
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.
🧩 Analysis chain
🏁 Script executed:
cd packages/shadcn/components/agents-ui && wc -l react-shader-toy.tsxRepository: livekit/components-js
Length of output: 89
🏁 Script executed:
cd packages/shadcn/components/agents-ui && sed -n '600,640p' react-shader-toy.tsxRepository: livekit/components-js
Length of output: 2006
🏁 Script executed:
cd packages/shadcn/components/agents-ui && sed -n '630,660p' react-shader-toy.tsxRepository: livekit/components-js
Length of output: 1337
🏁 Script executed:
cd packages/shadcn/components/agents-ui && sed -n '640,680p' react-shader-toy.tsxRepository: livekit/components-js
Length of output: 1627
🌐 Web query:
WebGL spec deleted shader handle attachShader behavior undefined
💡 Result:
Short answer: The WebGL 1.0 spec does not define special behavior for calling attachShader(program, shader) with a shader that has been deleted; you must treat that case as invalid to avoid relying on undefined behavior. The spec only guarantees that linkProgram is the operation that determines a program's executable and link status, and it says that attaching/detaching/modifying shaders does not affect a program's linked executable — but it does not add a rule saying what attachShader must do if passed a shader whose deleteShader has already been called. See the WebGL spec text and related discussion. [1][2]
Sources
- WebGL 1.0 spec: linkProgram is the only API that affects a program's link status/executable; attach/detach/modify shader operations are described but no special rule for attaching deleted shaders. [1]
- WebGL public-mailing-list / community discussion noting the ambiguity around attach/detach/delete interactions and implementations. [2]
References
[1] WebGL Specification (create/attach/link/delete shader / linkProgram paragraph).
[2] WebGL public-mailing-list / forum discussion about detach/attach/delete semantics.
Return null on shader compilation failure.
When shader compilation fails, gl.deleteShader(shader) removes the WebGL resource, but the function continues to return the now-invalid shader object. In initShaders, the null check !vertexShaderObj || !fragmentShaderObj only catches falsy values and does not detect deleted shaders. This allows deleted shader handles to be passed to gl.attachShader(), which results in undefined behavior per the WebGL specification. Add return null; after gl.deleteShader(shader) to prevent invalid shaders from being attached to the program.
Suggested fix
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
onWarning?.(log(`Error compiling the shader:\n${shaderCodeAsText}`));
const compilationLog = gl.getShaderInfoLog(shader);
gl.deleteShader(shader);
onError?.(log(`Shader compiler log: ${compilationLog}`));
+ return null;
}
return shader;📝 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.
| const createShader = (type: number, shaderCodeAsText: string) => { | |
| const gl = glRef.current; | |
| if (!gl) return null; | |
| const shader = gl.createShader(type); | |
| if (!shader) return null; | |
| gl.shaderSource(shader, shaderCodeAsText); | |
| gl.compileShader(shader); | |
| if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { | |
| onWarning?.(log(`Error compiling the shader:\n${shaderCodeAsText}`)); | |
| const compilationLog = gl.getShaderInfoLog(shader); | |
| gl.deleteShader(shader); | |
| onError?.(log(`Shader compiler log: ${compilationLog}`)); | |
| } | |
| return shader; | |
| const createShader = (type: number, shaderCodeAsText: string) => { | |
| const gl = glRef.current; | |
| if (!gl) return null; | |
| const shader = gl.createShader(type); | |
| if (!shader) return null; | |
| gl.shaderSource(shader, shaderCodeAsText); | |
| gl.compileShader(shader); | |
| if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { | |
| onWarning?.(log(`Error compiling the shader:\n${shaderCodeAsText}`)); | |
| const compilationLog = gl.getShaderInfoLog(shader); | |
| gl.deleteShader(shader); | |
| onError?.(log(`Shader compiler log: ${compilationLog}`)); | |
| return null; | |
| } | |
| return shader; |
🤖 Prompt for AI Agents
In `@packages/shadcn/components/agents-ui/react-shader-toy.tsx` around lines 612 -
625, In createShader, when compilation fails (inside the block that calls
gl.getShaderParameter and gl.deleteShader), ensure you return null after
deleting the shader so that callers like initShaders do not receive a
deleted/invalid shader handle; update the createShader function to delete the
shader and then immediately return null (reference createShader,
gl.deleteShader, and initShaders to locate usage).
Summary
ReactShaderToycomponent that provides a Shadertoy-like shader rendering foundation for ReactuseAgentAudioVisualizerWave,useAgentAudioVisualizerAura) that manage shader uniform animations using motion/reactNew Components
ReactShaderToyiTime,iResolution, etc.)AgentAudioVisualizerWaveAgentAudioVisualizerAuraTest plan
ReactShaderToyrenders basic shaders correctly in StorybookAgentAudioVisualizerWaveacross all agent states (idle, connecting, thinking, speaking, listening)AgentAudioVisualizerAuraacross all agent states with both light and dark theme modesaudioTrackis provided and agent is speakingSummary by CodeRabbit
New Features
Documentation
Chores
✏️ Tip: You can customize this high-level summary in your review settings.