crawl-text: static About section + portfolio backlink on the demo page - #40
Merged
Conversation
added 2 commits
September 8, 2026 15:18
The Pages demo is a Vite SPA, so the raw HTML that non-JS fetchers see was 93 chars of text. LLM crawlers and answer-engine fetchers generally do not execute JS, which made the landing page effectively blank for them. Add a real "About AgentXRay" section to frontend/index.html, placed after #root so React cannot overwrite it on mount. It is ordinary visible page content, not hidden markup: the page now scrolls past the dashboard to reach it. #root is pinned to one viewport (100dvh) so the dashboard itself looks and behaves exactly as before, and its scroll panes get overscroll-behavior: contain so they no longer drag the page along. Content is drawn from README.md and frontend/public/llms-full.txt: what the tool is, the seven registered log-format adapters with their default directories, the per-turn token/cost/time ledger, the npx install command, and the fact that this deployment runs on synthetic sample logs. No new numbers beyond claims.json. The section footer carries the repo link, the npm package and a link to the portfolio hub at https://alloevil.github.io/projects/. Built text length (frontend/dist/index.html, scripts and styles stripped): 93 -> 2402 chars.
Follow-up review question turned up a real defect in my own change. The overscroll-behavior: contain rule was meant to stop the dashboard's scroll panes from dragging the page when they hit their end. It also applies to every other scroll container, including the overflow-hidden layout wrappers, and it blocks the scroll chain even when a pane has nothing to scroll. Measured on the built page at 1440x900, where the sample data does not overflow any pane: wheeling over the centre of the app moved the page 0px with the rule in place, and 1000px with it neutralised. The About section was present, laid out and reachable only by scrollbar or keyboard — that is exactly the present-but-unreachable shape this pass exists to avoid. Default chaining is the honest behaviour: panes scroll normally, and once exhausted the wheel carries on to the page and reveals #about.
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.
Why
frontend/distis a Vite SPA build, so the raw HTML a non-JS fetcher receives was 93 chars of text — everything visible came fromassets/index-*.js. Google executes JS sometimes, with delay; LLM crawlers and answer-engine fetchers generally do not. For retrieval the landing page was effectively blank. Separately, no page on this site linked back to the portfolio hub.Generated vs hand-maintained
The publish root is generated:
.github/workflows/pages.ymlrunscd frontend && npm ci && VITE_DEMO=1 npm run buildand uploadsfrontend/dist, which is gitignored. So the source of truth isfrontend/index.html(+frontend/src/index.cssfor styling) and that is what is edited here, not the build output.frontend/public/(robots.txt, sitemap.xml, llms.txt, llms-full.txt, claims.json) is untouched and still copied intodistverbatim.What was added
A static
<section id="about">infrontend/index.html, placed after<div id="root"></div>(index.html line 41) — deliberately outside the mount container, becauseReactDOM.createRoot(document.getElementById('root'))insrc/main.tsxreplaces that container's children on mount, so anything inside would be destroyed. Verified in the live DOM:root.contains(about) === false,about.parentElement === BODY.Content is a genuine "what is this" section for a first-time visitor, worded from
README.mdandfrontend/public/llms-full.txtso the two do not contradict: what AgentXRay is (local-first reader, not a tracing SDK), the seven registered log-format adapters with their default directories (OpenClaw, Codex, Claude Code, OMP, DeepSeek Harness, Gemini CLI, Hermes) plus a pointer to thePLATFORMSregistry, the per-turn tool-call / token / cost ledger and the inference-vs-tool-execution time split, the real install commandnpx @alloevil/agent-xray, the Node.js 22.13+ requirement, and an explicit note that this deployment runs on synthetic sample logs. The only number is the7adapters, which is the published claim infrontend/public/claims.json; verified against the source:Styling lives in
src/index.cssunder#about(Tailwind@apply, existing dark-theme tokens only) rather than as inline style soup. Tailwind already scans./index.html, so the rules land in the built stylesheet.Making it genuinely reachable, not just present
This is the part that needed care, and it is the reason two commits are here.
src/index.csspreviously hadhtml, body, #root { height: 100% }plusbody { overflow: hidden }. Left alone, the new section would have been laid out below a viewport-height#rootinside abodythat cannot scroll: present in the DOM, visible to a text extractor, and unreachable for a human. That is cloaking by accident. So:#rootis pinned to exactly one viewport (height: 100vh; height: 100dvh) andbodyno longer hides its overflow. The dashboard therefore looks and behaves as before above the fold, and the section sits below it like an ordinary footer.overscroll-behavior: containto the dashboard's scroll panes, to stop a pane that hits its end from shoving the whole app up the page. The second commit removes it, because it was wrong.overscroll-behaviorapplies to every scroll container, including theoverflow: hiddenlayout wrappers, and it blocks the chain even when a pane has nothing to scroll. Measured on the built page at 1440x900, where the sample data does not overflow any pane: wheeling over the centre of the app moved the page 0px with the rule in place and 1000px with it neutralised at runtime. The section was reachable only by scrollbar or keyboard — the exact failure this pass exists to prevent. Default chaining is the honest behaviour and is what ships.No
display: none, no<noscript>-only text, no keyword block, nothing that differs from what a visitor sees. Confirmed on the built page:display: block,visibility: visible,opacity: 1, 2319 chars ofinnerText.Backlink
In the section's footer, beside the repo and npm links:
Confirmed in the built DOM as exactly that. English, matching the section's
lang="en"and the page's existing English demo banner / README / llms-full.txt.Verification
Real build, not a simulation —
cd frontend && npm ci && VITE_DEMO=1 npm run build, which istsc -b && vite build, so TypeScript compiled clean too.frontend/dist/index.html(built)frontend/index.html(source)Measured with the contract command (
<script>/<style>stripped, tags removed, whitespace collapsed).Served the built
distover plain HTTP at the/AgentXRay/base and drove it in a real browser at 1440x900, 1440x420 and 390x780:#roothas children,#root h1is "AgentXRay", all four tabs render (会话 / 分析 / Prompts / 资产库), the demo banner and platform bar render, and the sessions view renders a sample session with tool calls and the per-turn ledger. Screenshots taken of the dashboard and of the section.#rootcomputed height equalswindow.innerHeightat every viewport tested (900px / 420px / 780px), and the gap between#root's bottom edge and the section's top edge is exactly 0px.100dvhis supported and applied; the100vhline is the fallback for engines withoutdvh, and it reproduces the previousheight: 100%behaviour exactly, since100%of a100%-heighthtml/bodychain resolved to the same large-viewport height.getComputedStyle(body).overflowY === 'visible'andbody.scrollTopis not movable.Endalso works.overscroll-behaviorno longer appears anywhere in the built CSS.No formatters, no linters, no full suite.
test/contains only server-side tests; nothing in it referencesindex.html,frontend/dist, or the site artifacts, and this change is frontend-only.Not regressed
robots.txt,sitemap.xml,llms.txt,llms-full.txt,claims.json, the JSON-LD block,rel=canonicaland theog:/twitter:tags are all unchanged and all present in the build. No page added, sositemap.xmlis untouched.