Repository navigation
feat(skills): verify-responsive — render the UI at real viewport widths - #38
Merged
Merged
Conversation
A media query only proves itself when something evaluates it at that width. When a browser-automation window resize doesn't change the viewport the page actually sees, the screenshot comes back desktop-width, the desktop branch renders, and the mobile layout is never exercised — a quiet false pass. The skill is one throwaway harness: fixed-width iframes pointed at the running app, written into the app's own static dir so the parent stays same-origin and can script into the frame, drive it, and assert the width from inside rather than eyeballing a screenshot. Verified in Chrome while writing it: a 390-wide frame reports innerWidth 390 and matches (max-width: 640px) while a 1280 frame does not, and each renders its own branch of the same page; contentDocument is null from a cross-origin harness, which is why placement in the static dir is load-bearing; and inside the frame pointer:fine and hover:hover stay true with maxTouchPoints 0, so the skill states plainly that it narrows the viewport but does not emulate a device. install.js hardcoded the shipped skill dirs at four sites, so lift them to one SKILLS array — adding the third skill now costs one entry instead of four.
…allback The description and intro framed the skill as what you reach for when a window-resize tool fails, which undersells it and makes a worse method the first choice. Plain window resize is strictly dominated: it buys a narrower viewport, which is exactly what the iframe gives you, while the iframe adds both breakpoints in one screenshot, a frame the parent can script and assert from inside, and no dependency on the resize having taken effect. Resize being unreliable is now the third supporting reason rather than the trigger. The method that genuinely beats the harness is device emulation — touch, DPR, UA — which the limitations section already covers and now links to.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a third runnable skill:
verify-responsive— the default way to look at a UI at a given width.Why
A media query only proves itself when something evaluates it at that width. The skill is a throwaway harness of fixed-width
<iframe>s pointed at the running app. An iframe is a nested browsing context, so its viewport is the iframe box.Why not just resize the window? Resizing buys exactly one thing — a narrower viewport — which is the same thing the iframe gives you. The iframe adds three more:
innerWidth/matchMedia(...)from inside — a resized window can only be photographed;The method that genuinely beats this harness is device emulation, not window resizing.
The load-bearing rule
The harness goes in the app’s own static dir, not on a second server. Same-origin is what makes the frame scriptable.
Verified in Chrome while writing it
innerWidth=390,(max-width: 640px)matches; the 1280 frame does not — each rendered its own branch of the same pagelocalStoragecontentDocumentisnull(not a thrownSecurityError)pointer:fineandhover:hoverstay true,maxTouchPoints=0,dpr=1That last row is documented as an explicit limitation: a layout branching on
hover/pointer, UA sniffing, or DPR will render its desktop arm at 390px and mislead you. Width-based layout is covered honestly; anything else needs real device emulation.Registration
Reachable from every index:
skills/README.md, the root README table, and the installer.bin/install.jshardcoded the shipped skill dirs at four sites — lifted to oneSKILLSarray, so this addition costs one entry instead of four (net −1 line).Checks
node scripts/build-rules.js --check→ no drift (CLAUDE.md untouched)node --check bin/install.js→ OKHOMEfor--only claude --only openclaw: the skill lands in~/.claude/skills/and~/.openclaw/workspace/skills/, and--uninstallremoves all three cleanly