diff --git a/.jules/bolt.md b/.jules/bolt.md new file mode 100644 index 0000000..67cddb2 --- /dev/null +++ b/.jules/bolt.md @@ -0,0 +1,3 @@ +## 2024-05-27 - UI Blocking During Text Streaming +**Learning:** During simulated text generation loops (like `setInterval` firing every 24ms), synchronous deterministic scoring and analysis functions that depend on the rapidly updating text state can bottleneck the main thread, leading to jittery render loops or missed frames. +**Action:** Use React's `useDeferredValue` for rapidly updating text state before passing it into complex computations (like `analyzeText` or `scoreDeterministic` in `useMemo`). This allows React to process the updates asynchronously and interruptibly, maintaining UI responsiveness during simulated text streaming. diff --git a/apps/quill/client/components/playground-view.tsx b/apps/quill/client/components/playground-view.tsx index 511226b..1dc4700 100644 --- a/apps/quill/client/components/playground-view.tsx +++ b/apps/quill/client/components/playground-view.tsx @@ -1,6 +1,6 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { AnimatePresence, motion } from "framer-motion"; -import { useEffect, useMemo, useRef, useState } from "react"; +import { useDeferredValue, useEffect, useMemo, useRef, useState } from "react"; import { USE_CASE_PRESETS } from "../../src/lib/presets"; import { analyzeText, scoreDeterministic } from "../../src/lib/rubric"; import type { Guide, UseCase } from "../../src/lib/types"; @@ -255,7 +255,11 @@ export function PlaygroundView({ }; }, [output]); - const snapshot = useMemo(() => analyzeText(visibleOutput), [visibleOutput]); + // Defer the expensive analyzeText and scoreDeterministic calculations to a lower + // priority render cycle. This prevents them from blocking the main UI thread during + // rapid state updates like text streaming (which happens every 24ms). + const deferredOutput = useDeferredValue(visibleOutput); + const snapshot = useMemo(() => analyzeText(deferredOutput), [deferredOutput]); const { score, details } = useMemo( () => guide