Skip to content

feat: introduce dither-kit component library and integrate generative…#33

Merged
samuel025 merged 2 commits into
mainfrom
cloud-storage-segment
Jul 17, 2026
Merged

feat: introduce dither-kit component library and integrate generative…#33
samuel025 merged 2 commits into
mainfrom
cloud-storage-segment

Conversation

@samuel025

@samuel025 samuel025 commented Jul 17, 2026

Copy link
Copy Markdown
Owner

… avatar system

Summary by CodeRabbit

  • New Features
    • Added interactive dither-styled area, line, bar, pie, and radar charts with animations, hover/click selection, legends, tooltips, markers, and optional glow effects.
    • Added dither-styled buttons/avatars and upgraded the telemetry dashboard with richer charts (latency/throughput/system profile), live UTC time, pause/resume, enhanced broker visuals, and activity empty state.
    • Embedded dashboard documentation directly in the app.
  • Bug Fixes
    • Improved broker snapshot install completion to reliably restore and reload broker state.
    • Refined telemetry history normalization and handling when incoming data is missing.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 208bc905-06e0-4165-9af1-63a96351e7c1

📥 Commits

Reviewing files that changed from the base of the PR and between 5c6d1c6 and 2632966.

📒 Files selected for processing (14)
  • drmq-dashboard/src/App.tsx
  • drmq-dashboard/src/components/dither-kit/bar-canvas.tsx
  • drmq-dashboard/src/components/dither-kit/bar.tsx
  • drmq-dashboard/src/components/dither-kit/button.tsx
  • drmq-dashboard/src/components/dither-kit/cartesian-canvas.tsx
  • drmq-dashboard/src/components/dither-kit/chart-context.tsx
  • drmq-dashboard/src/components/dither-kit/legend.tsx
  • drmq-dashboard/src/components/dither-kit/palette.ts
  • drmq-dashboard/src/components/dither-kit/pie-canvas.tsx
  • drmq-dashboard/src/components/dither-kit/polar-context.tsx
  • drmq-dashboard/src/components/dither-kit/radar-canvas.tsx
  • drmq-dashboard/src/components/dither-kit/scales.ts
  • drmq-dashboard/src/pages/Dashboard.tsx
  • drmq-dashboard/src/services/telemetry/MockTelemetryProvider.ts
🚧 Files skipped from review as they are similar to previous changes (14)
  • drmq-dashboard/src/components/dither-kit/radar-canvas.tsx
  • drmq-dashboard/src/components/dither-kit/bar.tsx
  • drmq-dashboard/src/components/dither-kit/palette.ts
  • drmq-dashboard/src/App.tsx
  • drmq-dashboard/src/components/dither-kit/legend.tsx
  • drmq-dashboard/src/components/dither-kit/chart-context.tsx
  • drmq-dashboard/src/components/dither-kit/cartesian-canvas.tsx
  • drmq-dashboard/src/services/telemetry/MockTelemetryProvider.ts
  • drmq-dashboard/src/components/dither-kit/pie-canvas.tsx
  • drmq-dashboard/src/components/dither-kit/bar-canvas.tsx
  • drmq-dashboard/src/components/dither-kit/button.tsx
  • drmq-dashboard/src/components/dither-kit/polar-context.tsx
  • drmq-dashboard/src/components/dither-kit/scales.ts
  • drmq-dashboard/src/pages/Dashboard.tsx

📝 Walkthrough

Walkthrough

The PR adds a dither-kit charting system with Cartesian and polar charts, telemetry-driven dashboard widgets, pause/reconnect controls, styling/tooling configuration, and new chart primitives. It also updates Raft proposal flow and snapshot installation behavior.

Changes

Dither dashboard and telemetry visualization

Layer / File(s) Summary
Chart contracts and rendering primitives
drmq-dashboard/src/components/dither-kit/{chart-context,common-context,scales,dither-paint,pixel,palette,...}
Adds shared chart contexts, scales, palette utilities, canvas painting, bloom styling, animation helpers, dimensions tracking, and series context.
Cartesian chart composition and canvas rendering
drmq-dashboard/src/components/dither-kit/{cartesian-*,area*,bar*,dot*,grid*,x-axis,y-axis,reference-line,sparkline,tooltip}
Adds composable area, line, and bar charts with canvas rendering, series registration, axes, markers, interaction, legends, tooltips, and sparklines.
Polar chart composition and rendering
drmq-dashboard/src/components/dither-kit/{polar*,pie*,radar*}
Adds pie and radar chart roots, geometry helpers, interaction state, SVG frames, canvas renderers, animation, selection, and bloom layers.
Dither UI and dashboard integration
drmq-dashboard/src/{App.tsx,pages/Dashboard.tsx,useClusterTelemetry.ts,services/telemetry/*,types/telemetry.ts,components/DashboardWidgets.tsx,components/ClusterTopology.tsx}
Adds telemetry history fields, provider normalization, pause/reconnect handling, chart data derivation, new dashboard visualizations, widget spark slots, roster avatars, styling, and activity-feed states.
Dashboard tooling and exports
drmq-dashboard/{components.json,dither-kit.json,package.json,tsconfig.app.json,vite.config.ts}, drmq-dashboard/src/{index.css,components/dither-kit/index.ts}
Adds dither-kit configuration and manifest data, dependencies, aliases, theme variables, technical-grid styling, and public barrel exports.

Raft proposal and snapshot handling

Layer / File(s) Summary
Proposal heartbeat flow
drmq-broker/src/main/java/com/drmq/broker/raft/RaftNode.java
Proposal paths now send heartbeats directly after registering pending futures instead of advancing the commit index for empty peer sets.
Snapshot chunk application
drmq-broker/src/main/java/com/drmq/broker/raft/RaftNode.java
Snapshot chunks validate offsets, append data, advance receive state, restore completed snapshots, and reload dependent managers.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

  • samuel025/DRMQ#19 — Overlaps the InstallSnapshot and snapshot restore paths in RaftNode.

Sequence Diagram(s)

sequenceDiagram
  participant Dashboard
  participant useClusterTelemetry
  participant TelemetryProvider
  participant ChartRoot
  participant CanvasRenderer
  Dashboard->>useClusterTelemetry: connect with data and error handlers
  useClusterTelemetry->>TelemetryProvider: receive telemetry frames
  TelemetryProvider-->>Dashboard: normalized metrics and histories
  Dashboard->>ChartRoot: provide chart data and configuration
  ChartRoot->>CanvasRenderer: provide chart context and render targets
  CanvasRenderer-->>Dashboard: draw animated dither chart layers
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the main change: adding the dither-kit component library and generative avatar integration.
Docstring Coverage ✅ Passed Docstring coverage is 85.07% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cloud-storage-segment

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 19

🧹 Nitpick comments (2)
drmq-dashboard/tsconfig.app.json (1)

7-7: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Avoid leaking Node.js types into the client environment.

Including "node" in the compilerOptions.types for the browser environment (tsconfig.app.json) makes Node.js globals like process, Buffer, and __dirname available to client-side code during type checking. This can lead to runtime errors if these globals are accidentally used, as they do not exist in the browser.

Node types should typically be isolated to tsconfig.node.json (which is used to type-check files like vite.config.ts).

♻️ Proposed refactor
-    "types": ["vite/client", "node"],
+    "types": ["vite/client"],
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@drmq-dashboard/tsconfig.app.json` at line 7, Remove "node" from the
compilerOptions.types array in the browser-focused tsconfig.app.json, leaving
only the Vite client types. Keep Node.js typings isolated to tsconfig.node.json
for configuration files such as vite.config.ts.
drmq-dashboard/src/App.tsx (1)

98-105: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Keep provider side effects outside the state updater.

Updater replay under React Strict Mode can call reconnect() twice, creating duplicate intervals or sockets. Derive the action from paused, perform it once, then update state.

Proposed fix
   const handleTogglePause = useCallback(() => {
-    setPaused(prev => {
-      const next = !prev;
-      if (next) provider.disconnect();
-      else provider.reconnect();
-      return next;
-    });
-  }, [provider]);
+    if (paused) provider.reconnect();
+    else provider.disconnect();
+    setPaused(!paused);
+  }, [paused, provider]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@drmq-dashboard/src/App.tsx` around lines 98 - 105, Update handleTogglePause
so it derives the next pause state from the current paused value, performs
provider.disconnect or provider.reconnect outside the setPaused updater exactly
once, then updates state with the derived value. Keep provider in the callback
dependencies and avoid side effects inside the updater passed to setPaused.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@drmq-dashboard/src/components/dither-kit/bar-canvas.tsx`:
- Around line 142-150: The bloom canvases are copied every animation frame even
when the source renderer is unchanged. In bar-canvas.tsx lines 142-150 and
radar-canvas.tsx lines 158-164, gate the bloom clear/draw operation on the
renderer becoming dirty through paint() or bloom transitioning to active, while
preserving the existing bloom enable and hover conditions.
- Around line 103-117: The bar rendering logic around paintColumn must support
reversed orientation for negative bars. Determine negativity from the bar’s
value, pass a reversed-orientation option for negative bars, and update
paintColumn so the outline is drawn at bottom and dithering density progresses
in reverse while positive bars retain the current behavior.
- Around line 156-157: Normalize non-positive animation durations across
bar-canvas.tsx lines 156-157, radar-canvas.tsx lines 170-171, and avatar.tsx
lines 145-152. Update the animation progress logic in the bar and radar canvas
loops to treat duration values at or below zero as instant completion, and
update the avatar animation flow to avoid scheduling its RAF loop for those
durations; preserve normal animation behavior for positive durations.

In `@drmq-dashboard/src/components/dither-kit/bar.tsx`:
- Around line 49-50: Update the dimmed calculation in the bar-series rendering
logic to also apply focusDataKey-based legend spotlight behavior, matching the
existing handling for areas and common tooltip items. Preserve the current
selectedDataKey dimming while dimming non-focused bar children when focusDataKey
is set.

In `@drmq-dashboard/src/components/dither-kit/button.tsx`:
- Around line 20-27: Update DitherButton’s button ref handling so the consumer
ref from DitherButtonProps is composed with the internal buttonRef rather than
overwriting it through prop spreading. Ensure both refs receive the rendered
button element, preserving buttonRef.current for the paint/resize effect;
alternatively, omit ref from the public props if external refs are not
supported.

In `@drmq-dashboard/src/components/dither-kit/cartesian-canvas.tsx`:
- Around line 60-64: Update the long-lived RAF loop around the canvas paint
logic to read the latest animation state on each revision rather than capturing
animate and duration at creation. Extend paintSig to include seedOf(key), or use
a single context paint revision that covers animation settings and palette
seeds, so color-only configuration changes invalidate cached fills and repaint
with current values.

In `@drmq-dashboard/src/components/dither-kit/cartesian-root.tsx`:
- Around line 121-129: Flatten nested React fragments before layer
classification in both the Cartesian root child-routing logic and the Polar root
equivalent. Update the child traversal used by both roots so fragment-wrapped
back and dom children are classified by layer and routed to their respective
arrays instead of defaulting to the SVG layer; apply this at cartesian-root.tsx
lines 121-129 and polar-root.tsx lines 99-107.

In `@drmq-dashboard/src/components/dither-kit/chart-context.tsx`:
- Around line 283-287: Update the entranceDone calculation near the entrance
state so it returns true immediately whenever animate is false, regardless of
the stored entrance.done value or revision. Preserve the existing revision-based
completion behavior while animation remains enabled, ensuring markers are
released if animation is disabled mid-reveal.

In `@drmq-dashboard/src/components/dither-kit/legend.tsx`:
- Around line 24-54: Update the legend entries in the chart.names.map flow so
temporary focus via onPointerEnter, onPointerLeave, onFocus, and onBlur remains
available when isClickable is false. Keep persistent selection disabled in that
mode, but use non-button focusable entries (or equivalent) and restore pointer
events for focus/hover interaction despite the parent pointer-events-none;
retain button behavior and click selection when isClickable is true.

In `@drmq-dashboard/src/components/dither-kit/palette.ts`:
- Around line 39-40: Update isDitherColor to validate only PALETTE’s own
properties instead of using the inherited-property-inclusive in operator, while
preserving the existing string type check.

In `@drmq-dashboard/src/components/dither-kit/pie-canvas.tsx`:
- Around line 131-141: Update the animation loop in draw and the bloom
transition handling near paint so bloomCtx is cleared and redrawn only when
paint() changes the main canvas or bloom transitions between enabled and
disabled states. Remove the per-frame clearRect/drawImage calls while preserving
the existing bloom visibility conditions.
- Around line 57-59: Update the requestAnimationFrame loop around the animation
state handling to read and validate state.current.animate and
state.current.animationDuration on every frame rather than only during resize.
Ensure zero or otherwise invalid durations are handled safely before progress
calculations so the first frame does not produce NaN or leave needsFill active
indefinitely, while preserving reduced-motion behavior.

In `@drmq-dashboard/src/components/dither-kit/polar-context.tsx`:
- Around line 184-190: Clamp and sanitize innerRadiusRatio to the documented 0–1
range before the innerRadius calculation in the geometry setup, treating NaN as
a safe valid fallback. Use the clamped ratio in the chartType === "pie"
computation so donut geometry always remains valid.

In `@drmq-dashboard/src/components/dither-kit/polar.ts`:
- Around line 58-70: Update axisAtAngle to return null when the axes array is
empty, while preserving the existing nearest-axis calculation and index return
for non-empty data. Ensure the return type reflects the nullable result so
PolarRoot.setHoverIndex can receive no hover target.

In `@drmq-dashboard/src/components/dither-kit/scales.ts`:
- Around line 44-62: The bounds scan in the series loop of the scales builder
must inspect both endpoints of every stacked band. Update the logic around bands
and buildYScale’s returned bounds so each point’s point[0] and point[1] can
update both min and max, preserving the existing flat-range fallback when all
values are zero.

In `@drmq-dashboard/src/components/dither-kit/tooltip.tsx`:
- Around line 45-69: Update the tooltip motion configuration in the
AnimatePresence/motion.div block to use the dither kit’s existing reduced-motion
pattern. When reduced motion is enabled, apply immediate positioning and opacity
without spring or fade transitions; preserve the current animated behavior
otherwise.

In `@drmq-dashboard/src/pages/Dashboard.tsx`:
- Around line 115-124: Update the throughputData mapping in Dashboard so the
produce series uses the corresponding total throughput sample minus
consumeHist[i], rather than treating throughputHistory directly as produce
throughput. Preserve the existing scaling, rounding, fallback behavior, and
consume series mapping.
- Around line 138-158: Move the stateful hooks in Dashboard, including
prevCommit, latencyHistory, and their useEffect calls, above the error/loading
early returns, or isolate the loaded view in a child component so hook order
remains consistent. Update the throughput chart to avoid presenting
metrics.throughputHistory as the produce series; use the correct
produce-specific data and label pairing.

In `@drmq-dashboard/src/services/telemetry/MockTelemetryProvider.ts`:
- Around line 67-70: Align the seeded consumeHistory values with the scale
produced for live consume samples by reusing the same conversion helper or
seeding with realistic consumeMB inputs. Update both the initial consumeHistory
generation and the corresponding live-sample path so values do not collapse to
the minimum during the first 30 ticks.

---

Nitpick comments:
In `@drmq-dashboard/src/App.tsx`:
- Around line 98-105: Update handleTogglePause so it derives the next pause
state from the current paused value, performs provider.disconnect or
provider.reconnect outside the setPaused updater exactly once, then updates
state with the derived value. Keep provider in the callback dependencies and
avoid side effects inside the updater passed to setPaused.

In `@drmq-dashboard/tsconfig.app.json`:
- Line 7: Remove "node" from the compilerOptions.types array in the
browser-focused tsconfig.app.json, leaving only the Vite client types. Keep
Node.js typings isolated to tsconfig.node.json for configuration files such as
vite.config.ts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fe78ac80-e1c1-4f4c-af66-804edafc1646

📥 Commits

Reviewing files that changed from the base of the PR and between 72c5ad0 and 5c6d1c6.

⛔ Files ignored due to path filters (1)
  • drmq-dashboard/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (54)
  • drmq-broker/src/main/java/com/drmq/broker/raft/RaftNode.java
  • drmq-dashboard/components.json
  • drmq-dashboard/dither-kit.json
  • drmq-dashboard/package.json
  • drmq-dashboard/src/App.tsx
  • drmq-dashboard/src/components/ClusterTopology.tsx
  • drmq-dashboard/src/components/DashboardWidgets.tsx
  • drmq-dashboard/src/components/dither-kit/area-chart.tsx
  • drmq-dashboard/src/components/dither-kit/area.tsx
  • drmq-dashboard/src/components/dither-kit/avatar.tsx
  • drmq-dashboard/src/components/dither-kit/bar-canvas.tsx
  • drmq-dashboard/src/components/dither-kit/bar-chart.tsx
  • drmq-dashboard/src/components/dither-kit/bar.tsx
  • drmq-dashboard/src/components/dither-kit/block-legend.tsx
  • drmq-dashboard/src/components/dither-kit/button.tsx
  • drmq-dashboard/src/components/dither-kit/cartesian-canvas.tsx
  • drmq-dashboard/src/components/dither-kit/cartesian-root.tsx
  • drmq-dashboard/src/components/dither-kit/chart-context.tsx
  • drmq-dashboard/src/components/dither-kit/common-context.tsx
  • drmq-dashboard/src/components/dither-kit/dither-paint.ts
  • drmq-dashboard/src/components/dither-kit/dot.tsx
  • drmq-dashboard/src/components/dither-kit/gradient.tsx
  • drmq-dashboard/src/components/dither-kit/grid.tsx
  • drmq-dashboard/src/components/dither-kit/index.ts
  • drmq-dashboard/src/components/dither-kit/legend.tsx
  • drmq-dashboard/src/components/dither-kit/lib.ts
  • drmq-dashboard/src/components/dither-kit/palette.ts
  • drmq-dashboard/src/components/dither-kit/pie-canvas.tsx
  • drmq-dashboard/src/components/dither-kit/pie-chart.tsx
  • drmq-dashboard/src/components/dither-kit/pie.tsx
  • drmq-dashboard/src/components/dither-kit/pixel.ts
  • drmq-dashboard/src/components/dither-kit/polar-context.tsx
  • drmq-dashboard/src/components/dither-kit/polar-root.tsx
  • drmq-dashboard/src/components/dither-kit/polar.ts
  • drmq-dashboard/src/components/dither-kit/radar-canvas.tsx
  • drmq-dashboard/src/components/dither-kit/radar-chart.tsx
  • drmq-dashboard/src/components/dither-kit/radar-frame.tsx
  • drmq-dashboard/src/components/dither-kit/radar.tsx
  • drmq-dashboard/src/components/dither-kit/reference-line.tsx
  • drmq-dashboard/src/components/dither-kit/scales.ts
  • drmq-dashboard/src/components/dither-kit/series-context.tsx
  • drmq-dashboard/src/components/dither-kit/sparkline.tsx
  • drmq-dashboard/src/components/dither-kit/tooltip.tsx
  • drmq-dashboard/src/components/dither-kit/use-chart-dimensions.ts
  • drmq-dashboard/src/components/dither-kit/x-axis.tsx
  • drmq-dashboard/src/components/dither-kit/y-axis.tsx
  • drmq-dashboard/src/index.css
  • drmq-dashboard/src/pages/Dashboard.tsx
  • drmq-dashboard/src/services/telemetry/MockTelemetryProvider.ts
  • drmq-dashboard/src/services/telemetry/WebSocketTelemetryProvider.ts
  • drmq-dashboard/src/types/telemetry.ts
  • drmq-dashboard/src/useClusterTelemetry.ts
  • drmq-dashboard/tsconfig.app.json
  • drmq-dashboard/vite.config.ts
💤 Files with no reviewable changes (1)
  • drmq-broker/src/main/java/com/drmq/broker/raft/RaftNode.java

Comment on lines +103 to +117
const base = t.base[i] ?? rows - 1
const grown = base + ((t.top[i] ?? base) - base) * bp
// Bars grow from the zero baseline toward the value. Positive values
// sit above the baseline (smaller pixel), negative ones below it —
// paintColumn wants the higher edge first, so order the pair.
const top = Math.min(grown, base)
const bottom = Math.max(grown, base)
const active = s.hoverIndex === i
const hoverDim =
s.hoverIndex != null && !active && s.isMouseInChart ? 0.5 : 1
const slot = s.barSlot(i, si, keys.length)
const c0 = Math.round(slot.x * fx)
const c1 = Math.round((slot.x + slot.width) * fx)
for (let x = c0; x < c1; x++) {
paintColumn(c, x, top, bottom, seed, {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Reverse the dither edge for negative bars.

For negative values, top is the zero baseline, but paintColumn always draws its outline at top and fades toward it. The visible value edge is therefore placed at zero instead of the negative endpoint. Add a reversed-orientation option that puts the outline at bottom and reverses density for negative bars.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@drmq-dashboard/src/components/dither-kit/bar-canvas.tsx` around lines 103 -
117, The bar rendering logic around paintColumn must support reversed
orientation for negative bars. Determine negativity from the bar’s value, pass a
reversed-orientation option for negative bars, and update paintColumn so the
outline is drawn at bottom and dithering density progresses in reverse while
positive bars retain the current behavior.

Comment on lines +142 to +150
if (bloomCtx) {
const on =
s.bloom !== "off" &&
(!s.bloomOnHover || s.isMouseInChart || s.hovered)
if (on) {
bloomCtx.clearRect(0, 0, cols, rows)
bloomCtx.drawImage(canvas, 0, 0)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

Gate bloom copies on dirty or activation changes. Both renderers copy their complete canvas on every RAF before checking whether a repaint is required.

  • drmq-dashboard/src/components/dither-kit/bar-canvas.tsx#L142-L150: copy to bloom only after paint() or when bloom becomes active.
  • drmq-dashboard/src/components/dither-kit/radar-canvas.tsx#L158-L164: apply the same dirty-state gating.
📍 Affects 2 files
  • drmq-dashboard/src/components/dither-kit/bar-canvas.tsx#L142-L150 (this comment)
  • drmq-dashboard/src/components/dither-kit/radar-canvas.tsx#L158-L164
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@drmq-dashboard/src/components/dither-kit/bar-canvas.tsx` around lines 142 -
150, The bloom canvases are copied every animation frame even when the source
renderer is unchanged. In bar-canvas.tsx lines 142-150 and radar-canvas.tsx
lines 158-164, gate the bloom clear/draw operation on the renderer becoming
dirty through paint() or bloom transitioning to active, while preserving the
existing bloom enable and hover conditions.

Comment on lines +156 to +157
if (!animStart) animStart = now
const prog = animate ? Math.min(1, (now - animStart) / duration) : 1

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Normalize animation durations consistently. Negative public duration values prevent all three animations from completing and leave their RAF loops running indefinitely.

  • drmq-dashboard/src/components/dither-kit/bar-canvas.tsx#L156-L157: treat non-positive duration as instant or clamp it.
  • drmq-dashboard/src/components/dither-kit/radar-canvas.tsx#L170-L171: apply the same normalization.
  • drmq-dashboard/src/components/dither-kit/avatar.tsx#L145-L152: avoid scheduling the loop when duration is non-positive.
📍 Affects 3 files
  • drmq-dashboard/src/components/dither-kit/bar-canvas.tsx#L156-L157 (this comment)
  • drmq-dashboard/src/components/dither-kit/radar-canvas.tsx#L170-L171
  • drmq-dashboard/src/components/dither-kit/avatar.tsx#L145-L152
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@drmq-dashboard/src/components/dither-kit/bar-canvas.tsx` around lines 156 -
157, Normalize non-positive animation durations across bar-canvas.tsx lines
156-157, radar-canvas.tsx lines 170-171, and avatar.tsx lines 145-152. Update
the animation progress logic in the bar and radar canvas loops to treat duration
values at or below zero as instant completion, and update the avatar animation
flow to avoid scheduling its RAF loop for those durations; preserve normal
animation behavior for positive durations.

Comment thread drmq-dashboard/src/components/dither-kit/bar.tsx Outdated
Comment thread drmq-dashboard/src/components/dither-kit/button.tsx Outdated
Comment thread drmq-dashboard/src/components/dither-kit/scales.ts
Comment on lines +45 to +69
<AnimatePresence>
{show && items.length > 0 && (
<motion.div
key="dither-tooltip"
initial={{
opacity: 0,
x: "-50%",
y: "-115%",
top: chart.tooltipTop,
left: chart.tooltipLeft,
}}
animate={{
opacity: 1,
x: "-50%",
y: "-115%",
top: chart.tooltipTop,
left: chart.tooltipLeft,
}}
exit={{ opacity: 0 }}
transition={{
type: "spring",
stiffness: 520,
damping: 38,
mass: 0.6,
}}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== outline tooltip.tsx =="
ast-grep outline drmq-dashboard/src/components/dither-kit/tooltip.tsx --view expanded || true

echo "== relevant lines tooltip.tsx =="
cat -n drmq-dashboard/src/components/dither-kit/tooltip.tsx | sed -n '1,220p'

echo "== search reduced motion in dither-kit =="
rg -n "useReducedMotion|reduced motion|prefers-reduced-motion|reducedMotion" drmq-dashboard/src/components/dither-kit drmq-dashboard/src/components -g '!**/dist/**' || true

Repository: samuel025/DRMQ

Length of output: 5460


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== dither-paint reduced motion block =="
cat -n drmq-dashboard/src/components/dither-kit/dither-paint.ts | sed -n '155,190p'

echo "== pixel reduced motion block =="
cat -n drmq-dashboard/src/components/dither-kit/pixel.ts | sed -n '90,120p'

Repository: samuel025/DRMQ

Length of output: 1992


Honor reduced-motion preferences for tooltip transitions. The tooltip still springs and fades even when OS motion reduction is enabled; follow the same reduced-motion pattern used elsewhere in the dither kit and switch to immediate positioning/opacity in that mode.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@drmq-dashboard/src/components/dither-kit/tooltip.tsx` around lines 45 - 69,
Update the tooltip motion configuration in the AnimatePresence/motion.div block
to use the dither kit’s existing reduced-motion pattern. When reduced motion is
enabled, apply immediate positioning and opacity without spring or fade
transitions; preserve the current animated behavior otherwise.

Comment thread drmq-dashboard/src/pages/Dashboard.tsx Outdated
Comment thread drmq-dashboard/src/pages/Dashboard.tsx Outdated
Comment on lines +67 to +70
consumeHistory: Array.from({ length: 30 }, (_, i) =>
Math.max(3, 30 + Math.sin(i / 4 + 1) * 20 + Math.random() * 8)
),
errorHistory: Array.from({ length: 30 }, () => 0),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use one scale for seeded and live consume history.

The seed is centered near 30, while typical live samples evaluate below 3 and are clamped. The graph therefore collapses to a flat floor over the first 30 ticks. Generate both paths through the same conversion helper or seed from realistic consumeMB values.

Also applies to: 158-159

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@drmq-dashboard/src/services/telemetry/MockTelemetryProvider.ts` around lines
67 - 70, Align the seeded consumeHistory values with the scale produced for live
consume samples by reusing the same conversion helper or seeding with realistic
consumeMB inputs. Update both the initial consumeHistory generation and the
corresponding live-sample path so values do not collapse to the minimum during
the first 30 ticks.

@samuel025
samuel025 merged commit c63d307 into main Jul 17, 2026
1 check passed
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