Skip to content

perf(a2ui-playground): cap concurrent iframe mounts on showcase grid#2732

Merged
Huxpro merged 11 commits into
lynx-family:mainfrom
Huxpro:perf/a2ui-bundle-loading
May 28, 2026
Merged

perf(a2ui-playground): cap concurrent iframe mounts on showcase grid#2732
Huxpro merged 11 commits into
lynx-family:mainfrom
Huxpro:perf/a2ui-bundle-loading

Conversation

@Huxpro

@Huxpro Huxpro commented May 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

The A2UI playground's Examples / Showcase tab (DemosListPage) renders a card grid with 43 demos — 8 playground examples + 35 A2UI Gallery entries. Each card previously mounted an <iframe src="render.html?...&instant=1"> immediately, and every iframe:

  1. Imports @lynx-js/web-core/client + @lynx-js/web-elements/all.
  2. Mounts <lynx-view url="/a2ui.web.js" thread-strategy="multi-thread" />.
  3. Spawns a dedicated Web Worker (multi-thread realm) + Lynx app + A2UI render.

43× of that in parallel pinned the main thread and made the page borderline unresponsive. This PR keeps the per-card rendering pipeline exactly as it was, but throttles when each iframe is allowed to start.

How

  • New MountQueue (pure JS, ~80 LOC) lives in src/utils/mountQueue.ts. It holds at most MAX_CONCURRENT = 4 "armed" cards. Selection is priority-driven (OFFSCREEN < NEAR < IN_VIEW); ties broken by registration order.
  • Each card uses two IntersectionObservers (one viewport, one with rootMargin: '50% 0px') to report its current priority to the queue.
  • An armed card receives its src → the iframe mounts → render.tsx boots and posts the already-existing A2UI_RENDER_READY message. The card listens for that on its own iframe's contentWindow and frees the queue slot.
  • Fallback: iframe.onLoad starts a 5 s safety timer that releases the slot if A2UI_RENDER_READY never arrives, so the queue can't stall.
  • A small CardPreviewLoading overlay (centered card title + pulsing dots, prefers-reduced-motion-aware) sits on top of the iframe until RENDER_READY fires — eliminates the white-iframe flash between mount and first render, and hides a pre-existing web-core LynxViewInstance.updateData race (enableJSDataProcessor undefined → createIFrameRealm null contentDocument) that left ~2 cards blank.
  • Theme/protocol toggles flow through the same queue via a resetKey prop on MountQueueProvider, so flipping dark/light no longer reloads all 43 iframes at once.
  • PreviewViewport and render.tsx are unchanged — all gating happens via the src prop and the existing postMessage.

Scope is packages/genui/a2ui-playground only. No web-core / lynx-view changes.

Test plan

  • pnpm --filter a2ui-playground test — 12 / 12 unit cases pass for MountQueue (registration, priority, capacity, ties, sticky-armed, subscribe/unsubscribe, reset)
  • PORT=5371 pnpm -C packages/genui/a2ui-playground dev → open http://localhost:5371/Examples
  • DevTools → Network: at most 4 in-flight a2ui.web.js requests at any moment
  • Page interactive (can scroll / click) within ~1–2 s of navigation
  • Scroll downward → new cards mount as they enter the half-viewport halo
  • Toggle theme (☼ / ☾) → cards re-load in queued waves (not all at once)
  • No white iframe flash during card load — overlay fades to content smoothly

Summary by CodeRabbit

  • New Features

    • Viewport-prioritized, concurrency-capped demo mounting with a provider/hook to gate iframe previews and free slots on readiness/unmount.
  • User Experience

    • Demo cards show a loading overlay until previews signal readiness; includes a safety timeout and IntersectionObserver fallback; previews remount correctly when URLs change.
  • Documentation

    • Added a design spec describing queue behavior, fallbacks, verification steps, and test expectations.
  • Tests

    • Comprehensive unit tests covering queue semantics and subscriber notifications.
  • Styles

    • Loading overlay styles and animations, with reduced-motion support.
  • Chores

    • Test runner config and package test script added.

Review Change Stack

Huxpro added 3 commits May 28, 2026 01:49
Approach B: concurrency-capped, viewport-prioritized mount queue for the
43-card Showcase grid. Caps in-flight iframes to MAX_CONCURRENT=4 and
uses IntersectionObserver to prioritize cards near the viewport.
The Showcase tab (DemosListPage) renders ~43 cards, each previously
mounting an <iframe> immediately. Every iframe spawns a Web Worker,
loads web-core + web-elements, fetches main.web.js, and boots a Lynx
app running an A2UI render. ~43x of that on a single page made TTI
unusable.

Introduces a per-page MountQueue that holds at most MAX_CONCURRENT=4
"armed" cards. Cards register on mount and report their viewport
priority (OFFSCREEN / NEAR / IN_VIEW) via two IntersectionObservers
(rootMargin '50% 0px' for NEAR). The queue picks the top-K visible
pending cards; armed cards get their preview iframe; the rest stay in
the existing PreviewViewport empty state until promoted.

A card frees its slot when the iframe posts A2UI_RENDER_READY
(already sent by render.tsx). Fallback: iframe.onLoad + 5s safety
timeout, so a failed iframe can't stall the queue.

Tests: pure-JS MountQueue covered by 12 unit cases via @rstest/core.
PreviewViewport itself is unchanged - all gating happens upstream via
the src prop.
… requeue)

- Theme/protocol changes now re-run through the mount queue via a new
  resetKey prop on MountQueueProvider, so toggling dark/light no longer
  reloads all 43 iframes at once.

- Each card now overlays a centered "title + pulsing dots" placeholder on
  top of the iframe while it boots, fading out only when the iframe
  emits A2UI_RENDER_READY. This eliminates the white-iframe flash and
  also hides the pre-existing web-core LynxView race
  (enableJSDataProcessor undefined -> createIFrameRealm null
  contentDocument) that left a couple of cards blank - those cards now
  stay in the loading state rather than revealing a broken frame.

- The safety timeout still releases the queue slot after 5s so the queue
  never stalls, but no longer sets rendered=true, keeping the overlay
  on top of slow-or-broken iframes (and still lifting it if the iframe
  eventually fires RENDER_READY).

- Empty-state CSS (.previewEmpty) now fills its container and centers
  vertically, so the un-armed card no longer slumps to the top edge.
Copilot AI review requested due to automatic review settings May 27, 2026 18:24
@changeset-bot

changeset-bot Bot commented May 27, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 93672c7

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c0193e6c-7efa-4ab3-be55-14584c9508a4

📥 Commits

Reviewing files that changed from the base of the PR and between 86b6a9f and 93672c7.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (1)
  • packages/genui/a2ui-playground/src/styles.css
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/genui/a2ui-playground/src/styles.css

📝 Walkthrough

Walkthrough

Adds a concurrency-capped, viewport-prioritized mount queue to A2UI Playground that gates iframe mounts by priority, releases slots when iframes signal A2UI_RENDER_READY (or after a 5s fallback), integrates via a React provider/hook, wires ExampleCard in DemosListPage, adds styles, tests, and rstest infra.

Changes

Queue Mount System

Layer / File(s) Summary
Design Specification
docs/superpowers/specs/2026-05-28-a2ui-showcase-bundle-loading-design.md
Architecture, component/module plan, concurrency cap, viewport prioritization via IntersectionObserver, A2UI_RENDER_READY readiness signaling with timeout fallback, test strategy, and tunable constants (MAX_CONCURRENT, ROOT_MARGIN, RENDER_READY_TIMEOUT_MS).
Mount Queue Core Implementation
packages/genui/a2ui-playground/src/utils/mountQueue.ts
MountQueue class scheduling logic: tracks priority (OFFSCREEN/NEAR/IN_VIEW), arming state, and readiness per card; arms up to maxConcurrent cards by priority tier then registration order; markReady frees capacity without un-arming; notifies subscribers only on armed-set changes via snapshot comparison (setsEqual).
Mount Queue Test Suite
packages/genui/a2ui-playground/src/utils/mountQueue.test.ts
Tests initial arming rules, slot/capacity transitions, priority tie-breaking, subscriber notifications, and demotion behavior to validate queue scheduling semantics.
React Integration Hooks
packages/genui/a2ui-playground/src/hooks/useMountQueue.tsx
MountQueueProvider creates/caches MountQueue instance keyed by maxConcurrent and optional resetKey; useQueuedMount hook registers cards, tracks armed state, updates priority, and provides markReady callback; defaults to armed when no provider.
Page Components and Loading UI
packages/genui/a2ui-playground/src/pages/DemosListPage.tsx, packages/genui/a2ui-playground/src/styles.css
useViewportPriority hook uses IntersectionObserver to assign priority; ExampleCard component gates iframe rendering via useQueuedMount, shows loading overlay until iframe sends A2UI_RENDER_READY or timeout expires, resets on previewUrl change. Page wraps content in MountQueueProvider with concurrency cap and theme/protocol-derived reset key. CSS adds .cardPreviewLoading overlay with staggered dot animation and reduced-motion support; container-query names and .previewEmpty sizing updated.
Test Infrastructure Setup
packages/genui/a2ui-playground/package.json, packages/genui/a2ui-playground/rstest.config.ts, packages/genui/a2ui-playground/tsconfig.json
Adds test script running rstest, includes @rstest/core devDependency, configures test discovery for src/**/*.test.ts, and includes rstest.config.ts in TypeScript compilation scope.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • PupilTong
  • gaoachao
  • HuJean

Poem

🐰 I queued the cards with gentle paws and care,
Near-first they wake, dots blink in patient time,
A tiny "ready" lets the overlay slide,
Slots freed, the playground hums with frames alive,
Hop—render, play—the grid breathes out in rhyme.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'perf(a2ui-playground): cap concurrent iframe mounts on showcase grid' directly and accurately describes the main change: implementing concurrency capping for iframe mounting in the A2UI playground showcase grid to improve performance.
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.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


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.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR improves the A2UI playground Showcase grid’s responsiveness by throttling when preview iframes are allowed to mount, preventing dozens of lynx-view + worker boots from starting in parallel.

Changes:

  • Add a priority-aware MountQueue plus React provider/hook to cap concurrent iframe mounts (default 4).
  • Update DemosListPage cards to gate PreviewViewport’s src via the queue and show a loading overlay until A2UI_RENDER_READY.
  • Add @rstest/core test coverage for the queue and wire up rstest config / script.

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pnpm-lock.yaml Adds lock entry for @rstest/core.
packages/genui/a2ui-playground/tsconfig.json Includes rstest.config.ts in TS project inputs.
packages/genui/a2ui-playground/src/utils/mountQueue.ts Implements the concurrency-capped, priority-based mount scheduler.
packages/genui/a2ui-playground/src/utils/mountQueue.test.ts Adds unit tests validating queue behavior.
packages/genui/a2ui-playground/src/styles.css Adds loading overlay styles and improves empty preview centering.
packages/genui/a2ui-playground/src/pages/DemosListPage.tsx Integrates queue-driven iframe mounting + render-ready handling per card.
packages/genui/a2ui-playground/src/hooks/useMountQueue.tsx Provides MountQueueProvider + useQueuedMount hook.
packages/genui/a2ui-playground/rstest.config.ts Adds rstest config for this package.
packages/genui/a2ui-playground/package.json Adds test script and @rstest/core dev dependency.
docs/superpowers/specs/2026-05-28-a2ui-showcase-bundle-loading-design.md Adds design spec documenting the approach and test plan.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +304 to +312
{EXTENDED_EXAMPLES.map((scenario) => (
<ExampleCard
key={scenario.id}
scenario={scenario}
previewUrl={previewUrls.get(scenario.id)}
onOpen={handleOpenExample}
onKeyDown={handleCardKeyDown}
/>
))}
Comment on lines +12 to +19
Each card immediately mounts a `<PreviewViewport>` that contains an
`<iframe src="render.html?...&instant=1">`. Every iframe:

1. Imports `@lynx-js/web-core/client` + `@lynx-js/web-elements/all`.
2. Mounts `<lynx-view url="/main.web.js" thread-strategy="multi-thread" />`.
3. Web-core spawns a **dedicated Web Worker** per iframe (multi-thread mode).
4. Fetches/parses `main.web.js`, boots the Lynx app, replays the demo
messages with `instant=1`.
Comment on lines +121 to +126
1. `pnpm -C packages/genui/a2ui-playground build:lynx` (one-time).
2. `PORT=5371 pnpm -C packages/genui/a2ui-playground dev` (unique port
avoids conflicting with other devs servers).
3. Open `http://localhost:5371` → click "Examples" tab.
4. DevTools → Network: at most 4 in-flight `main.web.js` requests at
any moment; rest queued/pending.
Comment on lines +328 to +337
{OFFICIAL_EXAMPLES.map((scenario) => (
<ExampleCard
key={scenario.id}
scenario={scenario}
previewUrl={previewUrls.get(scenario.id)}
badge='From A2UI Gallery'
onOpen={handleOpenExample}
onKeyDown={handleCardKeyDown}
/>
))}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
packages/genui/a2ui-playground/src/styles.css (1)

1163-1178: 💤 Low value

Static analysis: Keyframe names and keyword case.

Per Stylelint hints:

  • Line 1167: currentColor should be currentcolor (CSS keywords are case-insensitive, but the linter enforces lowercase).
  • Lines 1180, 1189: Keyframe names should use kebab-case (card-preview-pulse, card-preview-dot) per keyframes-name-pattern.

Note: The existing codebase has mixed conventions (e.g., tagAppear at line 877 also uses camelCase), so this may be a broader cleanup.

🔧 Suggested fixes for lint compliance
 .cardPreviewLoadingDots span {
   width: 4px;
   height: 4px;
   border-radius: 50%;
-  background: currentColor;
+  background: currentcolor;
   opacity: 0.35;
-  animation: cardPreviewDot 1.2s ease-in-out infinite;
+  animation: card-preview-dot 1.2s ease-in-out infinite;
 }

-@keyframes cardPreviewPulse {
+@keyframes card-preview-pulse {
   0%, 100% {
     opacity: 0.55;
   }
   50% {
     opacity: 0.85;
   }
 }

-@keyframes cardPreviewDot {
+@keyframes card-preview-dot {
   0%, 100% {
     transform: translateY(0);
     opacity: 0.25;
   }
   50% {
     transform: translateY(-2px);
     opacity: 0.9;
   }
 }

Also update the animation reference in .cardPreviewLoadingTitle (line 1155):

-  animation: cardPreviewPulse 1.8s ease-in-out infinite;
+  animation: card-preview-pulse 1.8s ease-in-out infinite;

Also applies to: 1180-1198

🤖 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 `@packages/genui/a2ui-playground/src/styles.css` around lines 1163 - 1178,
Update CSS to satisfy stylelint: change the color keyword currentColor to
lowercase currentcolor in .cardPreviewLoadingDots, rename keyframe identifiers
from camelCase (cardPreviewPulse, cardPreviewDot) to kebab-case (e.g.,
card-preview-pulse, card-preview-dot), and update any animation references that
use the old names (including .cardPreviewLoadingTitle and
.cardPreviewLoadingDots span rules) to use the new kebab-case names; ensure
keyframes blocks themselves are renamed to match the new identifiers.
packages/genui/a2ui-playground/src/pages/DemosListPage.tsx (1)

159-170: 💤 Low value

Consider validating message origin for defense-in-depth.

The existing pattern in AIChatPage.tsx validates e.origin before processing postMessages. While the e.source check here ensures the message comes from this card's iframe, adding origin validation would provide an extra layer of defense against potential cross-origin message spoofing.

🛡️ Suggested origin validation
  useEffect(() => {
    if (!armed) return;
    const handler = (e: MessageEvent) => {
      if (e.source !== iframeRef.current?.contentWindow) return;
+     // Optional: validate origin matches the expected render URL origin
+     // if (previewUrl && e.origin !== new URL(previewUrl, window.location.origin).origin) return;
      const data = e.data as { type?: string } | null;
      if (data && data.type === 'A2UI_RENDER_READY') {
        handleRenderReady();
      }
    };
    window.addEventListener('message', handler);
    return () => window.removeEventListener('message', handler);
  }, [armed, handleRenderReady]);
🤖 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 `@packages/genui/a2ui-playground/src/pages/DemosListPage.tsx` around lines 159
- 170, The message handler in useEffect for A2UI_RENDER_READY only checks
e.source and should also validate e.origin for defense-in-depth: in the handler
(function handler) check that iframeRef.current exists, derive the iframe's
expected origin from iframeRef.current.src (e.g., new
URL(iframeRef.current.src).origin) or compare against a configured allowlist,
and return early if e.origin !== expectedOrigin before inspecting e.data and
calling handleRenderReady; keep the existing e.source check and ensure the
origin check is performed prior to processing the message.
🤖 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 `@docs/superpowers/specs/2026-05-28-a2ui-showcase-bundle-loading-design.md`:
- Around line 56-64: The fenced code block lacks a language tag which triggers
MD040; update the block fence surrounding the diagram (the section showing
DemosListPage → MountQueueProvider → ExampleCard → useQueuedMount →
PreviewViewport) to include a language identifier (e.g., "text") so the opening
fence becomes ```text and the closing fence remains ```, ensuring the snippet is
properly labeled without changing the diagram content.

In `@packages/genui/a2ui-playground/src/utils/mountQueue.ts`:
- Around line 46-48: The constructor for MountQueue should validate the
maxConcurrent input: in the constructor function (constructor) check that the
provided maxConcurrent is a finite integer > 0 (use Number.isInteger and
isFinite or coerce +Number and test), and if the value is invalid either throw a
descriptive TypeError or clamp to a safe default (e.g. 1); then assign the
validated value to this.maxConcurrent. Ensure you also guard against NaN and
fractional values so downstream logic that computes slots using
this.maxConcurrent behaves correctly.

---

Nitpick comments:
In `@packages/genui/a2ui-playground/src/pages/DemosListPage.tsx`:
- Around line 159-170: The message handler in useEffect for A2UI_RENDER_READY
only checks e.source and should also validate e.origin for defense-in-depth: in
the handler (function handler) check that iframeRef.current exists, derive the
iframe's expected origin from iframeRef.current.src (e.g., new
URL(iframeRef.current.src).origin) or compare against a configured allowlist,
and return early if e.origin !== expectedOrigin before inspecting e.data and
calling handleRenderReady; keep the existing e.source check and ensure the
origin check is performed prior to processing the message.

In `@packages/genui/a2ui-playground/src/styles.css`:
- Around line 1163-1178: Update CSS to satisfy stylelint: change the color
keyword currentColor to lowercase currentcolor in .cardPreviewLoadingDots,
rename keyframe identifiers from camelCase (cardPreviewPulse, cardPreviewDot) to
kebab-case (e.g., card-preview-pulse, card-preview-dot), and update any
animation references that use the old names (including .cardPreviewLoadingTitle
and .cardPreviewLoadingDots span rules) to use the new kebab-case names; ensure
keyframes blocks themselves are renamed to match the new identifiers.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d42eba45-ecbb-47a5-9c09-e1a2e1f8d2e6

📥 Commits

Reviewing files that changed from the base of the PR and between 0aa3465 and 0a671af.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (9)
  • docs/superpowers/specs/2026-05-28-a2ui-showcase-bundle-loading-design.md
  • packages/genui/a2ui-playground/package.json
  • packages/genui/a2ui-playground/rstest.config.ts
  • packages/genui/a2ui-playground/src/hooks/useMountQueue.tsx
  • packages/genui/a2ui-playground/src/pages/DemosListPage.tsx
  • packages/genui/a2ui-playground/src/styles.css
  • packages/genui/a2ui-playground/src/utils/mountQueue.test.ts
  • packages/genui/a2ui-playground/src/utils/mountQueue.ts
  • packages/genui/a2ui-playground/tsconfig.json

Comment thread docs/superpowers/specs/2026-05-28-a2ui-showcase-bundle-loading-design.md Outdated
Comment thread packages/genui/a2ui-playground/src/utils/mountQueue.ts
@codecov

codecov Bot commented May 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

@codspeed-hq

codspeed-hq Bot commented May 27, 2026

Copy link
Copy Markdown

Merging this PR will improve performance by 9.58%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 1 improved benchmark
✅ 80 untouched benchmarks
⏩ 26 skipped benchmarks1

Performance Changes

Benchmark BASE HEAD Efficiency
transform 1000 view elements 47.3 ms 43.2 ms +9.58%

Tip

Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.


Comparing Huxpro:perf/a2ui-bundle-loading (86b6a9f) with main (f60716d)2

Open in CodSpeed

Footnotes

  1. 26 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

  2. No successful run was found on main (2d84c9f) during the generation of this report, so f60716d was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

Huxpro added 6 commits May 28, 2026 02:51
- CSS: lowercase currentcolor, rename keyframes to kebab-case
  (card-preview-pulse, card-preview-dot) per stylelint rules
- Docs: add `text` language tag to fenced code block (MD040)
- mountQueue: guard constructor against negative/fractional maxConcurrent

https://claude.ai/code/session_01QSss98Q6Zsz76uXcN4AtC1
Add `e.origin !== window.location.origin` guard alongside the existing
`e.source` check so cross-origin frames can never trigger the render-ready
flow, as suggested by CodeRabbit.

https://claude.ai/code/session_014urpkMxFesXKwT8fGh5NfC
Addresses CodeRabbit docstring-coverage pre-merge check (was 0%).
Each public method/constructor now has a one-line summary covering
the non-obvious invariants (slot vs armed distinction, unsubscribe
return value, etc.).
- Replace main.web.js → a2ui.web.js in design spec (problem description
  and manual test step); the playground has always used a2ui.web.js.
- Rename CSS @Keyframes tagAppear → tag-appear (and its animation
  reference) to follow kebab-case naming convention.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
packages/genui/a2ui-playground/src/styles.css (3)

1051-1051: ⚡ Quick win

Use kebab-case for container names.

CSS container names should follow kebab-case convention. Change previewQr to preview-qr at line 1051 and in the @container query at line 1067.

♻️ Proposed fix
- container-name: previewQr;
+ container-name: preview-qr;
-@container previewQr (max-width: 380px) {
+@container preview-qr (max-width: 380px) {

Also applies to: 1067-1067

🤖 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 `@packages/genui/a2ui-playground/src/styles.css` at line 1051, Change the CSS
container name from camelCase to kebab-case: replace the container-name value
"previewQr" with "preview-qr" where it's declared (the container-name property)
and update the matching `@container` rule that currently references previewQr to
use `@container` preview-qr instead so the container name usage is consistent.

736-736: ⚡ Quick win

Use kebab-case for container names.

CSS container names should follow kebab-case convention. Change previewPanel to preview-panel at line 736 and in the @container query at line 768.

♻️ Proposed fix
- container-name: previewPanel;
+ container-name: preview-panel;
-@container previewPanel (max-width: 660px) {
+@container preview-panel (max-width: 660px) {

Also applies to: 768-768

🤖 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 `@packages/genui/a2ui-playground/src/styles.css` at line 736, The CSS uses a
camelCase container name `previewPanel`; change it to kebab-case `preview-panel`
by updating the container declaration `container-name: previewPanel;` to
`container-name: preview-panel;` and update the matching `@container` query that
references `previewPanel` to `@container preview-panel` (also search for any
other occurrences of `previewPanel` and replace them with `preview-panel` to
keep names consistent).

1236-1246: 💤 Low value

Consider modernizing the visually-hidden pattern.

The clip property at line 1243 is deprecated in favor of clip-path. While this pattern still works, consider using the modern equivalent for future compatibility.

♻️ Proposed fix
 .previewShareDescription {
   position: absolute;
   width: 1px;
   height: 1px;
   padding: 0;
   margin: -1px;
   overflow: hidden;
-  clip: rect(0, 0, 0, 0);
+  clip-path: inset(50%);
   white-space: nowrap;
   border: 0;
 }
🤖 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 `@packages/genui/a2ui-playground/src/styles.css` around lines 1236 - 1246, The
visually-hidden CSS in the .previewShareDescription rule uses the deprecated
clip property; update the rule to use the modern clip-path equivalent (e.g.,
clip-path: inset(50%); and include -webkit-clip-path for broader support) while
keeping the existing positioning, size, overflow, white-space, padding, margin
and border declarations so the element remains visually hidden but accessible;
modify the .previewShareDescription selector to replace clip: rect(0, 0, 0, 0);
with clip-path: inset(50%); (and -webkit-clip-path: inset(50%); as a fallback).
🤖 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.

Nitpick comments:
In `@packages/genui/a2ui-playground/src/styles.css`:
- Line 1051: Change the CSS container name from camelCase to kebab-case: replace
the container-name value "previewQr" with "preview-qr" where it's declared (the
container-name property) and update the matching `@container` rule that currently
references previewQr to use `@container` preview-qr instead so the container name
usage is consistent.
- Line 736: The CSS uses a camelCase container name `previewPanel`; change it to
kebab-case `preview-panel` by updating the container declaration
`container-name: previewPanel;` to `container-name: preview-panel;` and update
the matching `@container` query that references `previewPanel` to `@container
preview-panel` (also search for any other occurrences of `previewPanel` and
replace them with `preview-panel` to keep names consistent).
- Around line 1236-1246: The visually-hidden CSS in the .previewShareDescription
rule uses the deprecated clip property; update the rule to use the modern
clip-path equivalent (e.g., clip-path: inset(50%); and include -webkit-clip-path
for broader support) while keeping the existing positioning, size, overflow,
white-space, padding, margin and border declarations so the element remains
visually hidden but accessible; modify the .previewShareDescription selector to
replace clip: rect(0, 0, 0, 0); with clip-path: inset(50%); (and
-webkit-clip-path: inset(50%); as a fallback).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: cff6d08b-a4fa-455b-8f82-31368f8e5622

📥 Commits

Reviewing files that changed from the base of the PR and between 0a671af and ef08c1e.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (6)
  • docs/superpowers/specs/2026-05-28-a2ui-showcase-bundle-loading-design.md
  • packages/genui/a2ui-playground/package.json
  • packages/genui/a2ui-playground/src/hooks/useMountQueue.tsx
  • packages/genui/a2ui-playground/src/pages/DemosListPage.tsx
  • packages/genui/a2ui-playground/src/styles.css
  • packages/genui/a2ui-playground/src/utils/mountQueue.ts
✅ Files skipped from review due to trivial changes (1)
  • docs/superpowers/specs/2026-05-28-a2ui-showcase-bundle-loading-design.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/genui/a2ui-playground/package.json
  • packages/genui/a2ui-playground/src/hooks/useMountQueue.tsx
  • packages/genui/a2ui-playground/src/pages/DemosListPage.tsx
  • packages/genui/a2ui-playground/src/utils/mountQueue.ts

…clip

- Rename container-name `previewPanel` → `preview-panel` and matching
  `@container` query.
- Rename container-name `previewQr` → `preview-qr` and matching
  `@container` query.
- Replace deprecated `clip: rect(0, 0, 0, 0)` with modern
  `clip-path: inset(50%)` in the visually-hidden pattern.

Addresses CodeRabbit review on 2026-05-28.
@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

Actionable comments posted: 0

@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

Actionable comments posted: 0

@Huxpro Huxpro merged commit d62b8b2 into lynx-family:main May 28, 2026
18 of 19 checks 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.

2 participants