From f1878304da92a5ddbe59535ad0d6a3ccc9c170c5 Mon Sep 17 00:00:00 2001 From: Aiden Bai Date: Sun, 31 May 2026 22:07:42 -0700 Subject: [PATCH 01/16] feat(react-grab): render scan with copyable performance trace Adds a toolbar render scan that outlines re-rendering components on a canvas overlay. Stopping the scan copies an agent-readable JSON trace (per-component render cost ranked by actualDuration, plus long-animation-frames captured via PerformanceObserver) to the clipboard and flashes a "Copied" pill on the toolbar. Scan state persists across reloads via sessionStorage (SSR-guarded) so it survives dev-server HMR. Structured into focused modules: scan-trace-recorder (DOM-free profiling model), scanner (canvas outlines), and scan-controller (lifecycle, copy, persistence). Extracts shared drawRoundedRectangle/parseBorderRadiusValue utils out of overlay-canvas. --- .changeset/render-scan-trace.md | 5 + apps/website-v2/app/layout.tsx | 5 +- .../react-grab/src/components/copied-pill.tsx | 24 ++ .../src/components/icons/icon-scan.tsx | 30 +++ .../src/components/icons/icon-stop.tsx | 23 ++ .../src/components/overlay-canvas.tsx | 40 +-- .../react-grab/src/components/renderer.tsx | 3 + .../src/components/toolbar/index.tsx | 54 +++- packages/react-grab/src/constants.ts | 17 ++ packages/react-grab/src/core/index.tsx | 8 + packages/react-grab/src/core/plugins/scan.ts | 10 + .../react-grab/src/core/scan-controller.ts | 67 +++++ .../src/core/scan-trace-recorder.ts | 152 ++++++++++++ packages/react-grab/src/core/scanner.ts | 233 ++++++++++++++++++ packages/react-grab/src/types.ts | 38 +++ .../src/utils/draw-rounded-rectangle.ts | 31 +++ .../src/utils/parse-border-radius-value.ts | 5 + .../src/utils/scan-active-storage.ts | 21 ++ .../src/utils/serialize-scan-trace.ts | 51 ++++ 19 files changed, 777 insertions(+), 40 deletions(-) create mode 100644 .changeset/render-scan-trace.md create mode 100644 packages/react-grab/src/components/copied-pill.tsx create mode 100644 packages/react-grab/src/components/icons/icon-scan.tsx create mode 100644 packages/react-grab/src/components/icons/icon-stop.tsx create mode 100644 packages/react-grab/src/core/plugins/scan.ts create mode 100644 packages/react-grab/src/core/scan-controller.ts create mode 100644 packages/react-grab/src/core/scan-trace-recorder.ts create mode 100644 packages/react-grab/src/core/scanner.ts create mode 100644 packages/react-grab/src/utils/draw-rounded-rectangle.ts create mode 100644 packages/react-grab/src/utils/parse-border-radius-value.ts create mode 100644 packages/react-grab/src/utils/scan-active-storage.ts create mode 100644 packages/react-grab/src/utils/serialize-scan-trace.ts diff --git a/.changeset/render-scan-trace.md b/.changeset/render-scan-trace.md new file mode 100644 index 000000000..b2575be54 --- /dev/null +++ b/.changeset/render-scan-trace.md @@ -0,0 +1,5 @@ +--- +"react-grab": minor +--- + +Add a render scan that highlights re-rendering components on a canvas overlay, and copies an agent-readable performance trace (per-component render cost + long-animation-frames) to the clipboard when you stop scanning. The toolbar shows a "Copied" pill on stop, and the scan state persists across reloads via sessionStorage. diff --git a/apps/website-v2/app/layout.tsx b/apps/website-v2/app/layout.tsx index 593196d1f..87a615869 100644 --- a/apps/website-v2/app/layout.tsx +++ b/apps/website-v2/app/layout.tsx @@ -3,6 +3,7 @@ import { Geist_Mono, Inter } from "next/font/google"; import { ThemeProvider } from "next-themes"; import { TooltipProvider } from "@/components/ui/tooltip"; import "./globals.css"; +import Script from "next/script"; const inter = Inter({ variable: "--font-inter", @@ -35,8 +36,10 @@ export default function RootLayout({ suppressHydrationWarning className={`${inter.variable} ${geistMono.variable} antialiased`} > + +