From 11b9f0346cf5413045b41ff552a024e11ba46ccc Mon Sep 17 00:00:00 2001 From: N0zoM1z0 <1705004398@qq.com> Date: Fri, 9 Oct 2026 11:06:05 +0800 Subject: [PATCH] feat(website): explain REA with Calculator and a playable dinosaur lab --- website/README.md | 31 +- website/evidence/calculator-and-dino.md | 132 ++++ website/evidence/dx-ball-sound-pan.md | 6 - website/figures.md | 15 + website/public/assets/dino-demo.js | 235 ++++++ website/public/assets/dino-speed.js | 21 + website/public/assets/home.js | 56 ++ website/public/assets/licenses/dinosaur.txt | 34 + website/public/assets/styles.css | 332 ++++++++ website/public/examples/dino-lab/index.html | 332 ++++++++ website/public/first-investigation/index.html | 2 +- website/public/index.html | 711 +++++++++++++----- website/style-guide.md | 28 +- 13 files changed, 1716 insertions(+), 219 deletions(-) create mode 100644 website/evidence/calculator-and-dino.md create mode 100644 website/public/assets/dino-demo.js create mode 100644 website/public/assets/dino-speed.js create mode 100644 website/public/assets/home.js create mode 100644 website/public/assets/licenses/dinosaur.txt create mode 100644 website/public/examples/dino-lab/index.html diff --git a/website/README.md b/website/README.md index 896dac213..cbe151232 100644 --- a/website/README.md +++ b/website/README.md @@ -6,7 +6,8 @@ An English static website with explanatory figures, worked guides and DX-Ball, Notion, TH04 and CTF investigations. The public files are in `website/public/`. The site uses HTML, CSS and a small -script for copying code and following the assembly-to-C comparison. Python +scripts for copying code, following code comparisons and playing the dinosaur +speed reconstruction. Python packages the downloadable example; there is no frontend bundler or npm dependency. [style-guide.md](style-guide.md) explains the writing, page structure, figures, @@ -25,7 +26,8 @@ Open . Refresh the browser after editing a file. ## Pages -- `public/index.html`: DX-Ball introduction, agent example, setup and case-study overviews. +- `public/index.html`: compact setup, manual/agent comparison, Calculator percentage example, playable dinosaur reconstruction and case-study overviews. +- `public/examples/dino-lab/index.html`: adjustable-speed mini-game, recovered rule, original-game check and browser analysis steps. - `public/first-investigation/index.html`: a guided Notes export investigation, from setup to a checked CSV prediction. - `public/showcase/index.html`: the case-study index. - `public/showcase/dx-ball/index.html`: sound-pan investigation and project status. @@ -95,11 +97,26 @@ Evidence. [evidence/dx-ball-sound-pan.md](evidence/dx-ball-sound-pan.md) records their provenance and the scope of the validation claims. The original executable and complete private Evidence records are not website assets. -The homepage's code comparison, position examples and evidence flow are -selectable HTML. The pan positions 0, 320 and 640 illustrate the inspected -calculation at its recorded initial scale of 1; the C panel is a readable -summary. The linked case study retains the maintained source and its checks. -The agent response is an example explanation based on those findings. +The homepage starts with a short installation prompt and the ordinary setup +command. It compares manual investigation with asking an agent, using the same +Calculator percentage question. The native excerpt comes from an installed +model DLL; Microsoft’s public implementation supplies names and a crosscheck. +The Calculator controls illustrate that rule with generic inputs. + +The dinosaur example connects an inspected running script to a new playable +mini-game. `public/assets/dino-speed.js` owns the recovered speed rule and replay; +`dino-demo.js` imports it for automatic acceleration. The slider chooses a fixed +speed instead. Drawing, jumping and collision code are newly authored for this +teaching game. It starts on input, pauses when hidden or outside the viewport, +and retains a static SVG when JavaScript is disabled. The lab links the speed +module and complete game source, and replays the rule against recorded +original-game values. + +[evidence/calculator-and-dino.md](evidence/calculator-and-dino.md) records both +targets, selected findings, attribution and verification scope. Update the +speed rule, game, check table and evidence together. The original script excerpt +and its BSD license are credited on the pages. Prompt responses are example +explanations based on findings. The general investigation and DX-Ball overview diagrams are maintained as SVG source. Initial layout references were created with the built-in image generation tool; [figures.md](figures.md) retains diff --git a/website/evidence/calculator-and-dino.md b/website/evidence/calculator-and-dino.md new file mode 100644 index 000000000..67d816014 --- /dev/null +++ b/website/evidence/calculator-and-dino.md @@ -0,0 +1,132 @@ +# Calculator and dinosaur beginner examples + +Evidence collected on 9 October 2026 with the published REA 4.1.0 package. +The homepage offers compact setup first, then a manual/agent comparison and +two familiar behavior questions. Prompts and replies are examples based on the +findings below. Selected code and generic inputs are public; raw captures stay +outside the website. + +## Windows Calculator + +### Inspected artifacts + +The installed Windows Calculator package is version `11.2508.4.0`, x64. + +| Artifact | SHA-256 | +| --------------------------- | ------------------------------------------------------------------ | +| Windows `calc.exe` launcher | `9c2c8a8588fe6db09c09337e78437cb056cd557db1bcf5240112cbfb7b600efb` | +| Package `CalcViewModel.dll` | `07a1953bbf828a3495662c4b4bde1c80c9075061e0e389eabac5f8c544710df5` | + +REA's function dossier for launcher `0x1400019f4` includes the call to +`ShellExecuteW` with `ms-calculator:`. Evidence: +`ev_e97a6a1a61bfe63476a13e6285d71dd838101066f7863c9af822861050203ea5`. + +The calculation is in the installed app's model DLL. REA inspected function +`0x1801245d0`, whose body occupies two ranges, totaling 10,656 bytes: +`0x1801245d0–0x180126f4c` and `0x180126f55–0x180126f77`. +Evidence: +`ev_830a710c7fb55a08ac896fb5783c14339480a57a96d6d45c57c024b6a43239d0`. + +REA supplied pseudocode, original instructions, calls and references. Its +`case 0x76` checks the operator field against `0x5c` and `0x5b` and constructs +the constant 100 in both paths. One path divides the current value by 100; +the other combines the current value with the previous value divided by 100. +The published assembly is selected exactly from the returned instruction list. + +The binary is stripped. A local instruction scan located candidates using +operator IDs and the constant 100; REA then produced the complete function +dossier. Function selection was analyst-assisted. The illustrative agent +prompt is not a recording of an autonomous end-to-end discovery. + +### Source interpretation and check + +Microsoft's MIT-licensed source at commit +`d125246a4e19842ce1332e6c7839cf0e110027d8` supplies the operator meanings and +an independently readable implementation: + +- [Operator IDs](https://github.com/microsoft/calculator/blob/d125246a4e19842ce1332e6c7839cf0e110027d8/src/CalcManager/Header%20Files/CCommand.h): `IDC_DIV = 91`, `IDC_MUL = 92`, `IDC_PERCENT = 118`. +- [Percentage branch](https://github.com/microsoft/calculator/blob/d125246a4e19842ce1332e6c7839cf0e110027d8/src/CalcManager/CEngine/scifunc.cpp#L98-L111): multiply/divide uses `rat / 100`; other operators use `rat * (m_lastVal / 100)`. +- [Standard-mode tests](https://github.com/microsoft/calculator/blob/d125246a4e19842ce1332e6c7839cf0e110027d8/src/CalculatorUnitTests/CalculatorManagerTest.cpp#L350-L370): `6 × 6 % = 0.36` and `50 + 20 % = 60`. + +These source branches agree with the operator checks and two paths observed +in the installed DLL. The public source commit is a crosscheck; it is not an +identified build commit for that installed package. No PDB symbols were loaded. + +The homepage's named C-like rule is an explanatory summary. Its `200 + 10%` +and `200 × 10%` displays are derived from that rule. Browser checks exercise +both percentage illustrations, their results, operator selection and reset. +The Microsoft tests were inspected, not executed. A probe-owned Calculator +window could be inspected, but it was no longer present at the input-check +step; no completed Windows GUI input result is claimed. + +## Dinosaur speed + +### Running target and source + +REA inspected the HTTP page + in an owned Chrome 150.0.7871.124 +session through a loopback debugging connection. This is wayou's +Chromium-derived browser edition. REA's HTTP(S) page inspection does not +select `chrome://dino/`; the website identifies the HTTP edition as its target. + +The returned `index.js` source contains 90,241 UTF-8 bytes, SHA-256 +`e7a50d337bdbe4299068de034e4564cfe5fd45ca9257ded37b6ada9330cedf0f`. +Evidence: +`ev_7a09de570cf6b64907504046485cab69ad444828964106eabc05958799749905`. + +This digest also matches `index.js` in repository commit +`5455bfa408ec6b707c7300ff194b7390733a766d`. Source locations: + +- [Settings](https://github.com/wayou/t-rex-runner/blob/5455bfa408ec6b707c7300ff194b7390733a766d/index.js#L106-L135): `ACCELERATION: 0.001`, `MAX_SPEED: 13`, `SPEED: 6`. +- [Update branch](https://github.com/wayou/t-rex-runner/blob/5455bfa408ec6b707c7300ff194b7390733a766d/index.js#L565-L571): increment speed on a collision-free update while speed is below the threshold. + +The source begins with the Chromium Authors' 2014 copyright notice. Selected +excerpts are credited on the page. The repository's BSD license and the source +copyright are reproduced in `public/assets/licenses/dinosaur.txt`. + +### Controlled original-game check + +After the passive REA inspection, a separate Playwright controller called the +original page's `Runner.update()` repeatedly. It disabled future update +scheduling and obstacle generation, set the starting speed to 6, and kept the +game in its playing state. The control is credited separately from REA's +read-only inspection. + +| Update count | Observed speed | Display rounded to 3 decimals | +| ------------ | ------------------ | ----------------------------- | +| 0 | 6 | 6.000 | +| 1,000 | 7.000000000000334 | 7.000 | +| 4,000 | 9.99999999999956 | 10.000 | +| 7,000 | 12.999999999997897 | 13.000 | +| 10,000 | 13.000999999997896 | 13.001 | + +The branch compares before adding. Floating-point increments can cross the +threshold by one increment; the reconstruction preserves this behavior rather +than introducing a clamp. + +### New game and reader experiment + +`public/assets/dino-speed.js` contains the reconstructed rule and an update-count +replay. Its rounded results match the original-game check above. The website's +mini-game imports this rule. It advances its own simulation at 60 updates per +second, avoiding a different frame rate changing its demonstration pace. + +The canvas drawing, dinosaur shape, jump physics, rectangle collision detection, +spacing and controls are newly authored teaching code. The reconstruction claim +is scoped to the speed rule. Changing the slider selects a fixed speed between +2 and 18; selecting automatic acceleration restores the starting speed of 6. + +The new game starts only after user input. It supports Play/Pause, Jump, Restart, +canvas Space/Up keys and touch. It pauses when hidden or scrolled out of view. +Without JavaScript, a static SVG, source excerpts and recorded results remain +available. The downloadable speed module and complete game source are linked +from the lab. + +## Review checks + +Website checks cover root and `/rea/` hosting, 320/390/850/1440px layouts, +expanded evidence, copying, no-JavaScript content, reduced motion, the two +percentage rules and the game controls. Game checks include speed selection, +automatic acceleration, a collision, restart, jump height on the rendered +canvas, pause and the original-rule replay. Existing Notes and DX-Ball pages +remain part of layout checks. diff --git a/website/evidence/dx-ball-sound-pan.md b/website/evidence/dx-ball-sound-pan.md index ec02d2705..60b7e0e61 100644 --- a/website/evidence/dx-ball-sound-pan.md +++ b/website/evidence/dx-ball-sound-pan.md @@ -96,12 +96,6 @@ signature, declaration and return. ## Validation scope -The homepage reuses these observations in a selected seven-instruction excerpt -and a shortened C summary. Its agent answer is an example explanation, not a -recorded transcript. Its position figure uses illustrative inputs 0, 320 and -640 with the recorded initial scale of 1, producing −500, 0 and 500. The checks -below apply to the maintained project function, not the shortened summary. - The reconstruction project's recorded checks establish: - 3,205 direct original-x86 differential cases: integer positions 0–640 at diff --git a/website/figures.md b/website/figures.md index ff8f7bba3..c94db54f9 100644 --- a/website/figures.md +++ b/website/figures.md @@ -42,6 +42,21 @@ branches when changing these figures. Match progress claims to the pinned reconstruction checkpoint. Validate the SVG as XML and inspect its browser rendering at desktop and mobile widths. +## Beginner homepage and dinosaur reconstruction + +The Calculator role comparison and its percentage controls are semantic HTML. +The assembly comes from a real installed model DLL; the named calculation is +a readable summary crosschecked against Microsoft’s public source. See +[evidence/calculator-and-dino.md](evidence/calculator-and-dino.md). + +The dinosaur sequence uses an HTML flow: inspect the loaded script, rebuild the +speed rule, then change and play. Its canvas mini-game and static SVG fallback +are authored code, without generated images or copied game sprites. The game +imports the recovered rule from `public/assets/dino-speed.js`; other mechanics +are new teaching code. Check that the fallback is visible with JavaScript +disabled and hidden when the playable canvas loads. Keep the speed settings, +source excerpt, reconstruction and original-result table consistent. + ## Original image generation prompts ## Prompt 1 diff --git a/website/public/assets/dino-demo.js b/website/public/assets/dino-demo.js new file mode 100644 index 000000000..9988e9f52 --- /dev/null +++ b/website/public/assets/dino-demo.js @@ -0,0 +1,235 @@ +import { advanceSpeed, simulateSpeed, SPEED_RULE } from "./dino-speed.js"; + +// A new teaching game around the recovered speed rule. Drawing, jump physics +// and rectangle collision checks are authored for this demo. +function initializeDinoDemo(demo) { + const canvas = demo.querySelector("canvas"); + const context = canvas.getContext("2d"); + if (context === null) return; + const start = demo.querySelector("[data-dino-start]"); + const slider = demo.querySelector("[data-dino-slider]"); + const auto = demo.querySelector("[data-dino-auto]"); + const output = demo.querySelector("[data-dino-speed]"); + const status = demo.querySelector("[data-dino-status]"); + const ground = 148; + const dinosaurX = 52; + const dinosaur = new Path2D( + "M16 18V2H48V24H35V32H25V43H16V53H8V32H0V23H6V29H16Z M12 47V59H5V54H8V47Z M24 42V54H31V59H20V47Z M34 29H44V35H39V32H34Z", + ); + let speed = SPEED_RULE.start; + let height = 0; + let velocity = 0; + let distance = 0; + let obstacles = []; + let running = false; + let crashed = false; + let frame = 0; + let lastTime = 0; + let elapsed = 0; + + const updateSpeedDisplay = () => { + output.value = speed.toFixed(1); + slider.value = speed.toFixed(1); + }; + + const draw = () => { + context.clearRect(0, 0, canvas.width, canvas.height); + context.strokeStyle = "#b7c0c9"; + context.beginPath(); + context.moveTo(0, ground); + context.lineTo(canvas.width, ground); + for (let x = -(distance % 70); x < canvas.width; x += 70) { + context.moveTo(x, ground + 7); + context.lineTo(x + 12, ground + 7); + } + context.stroke(); + context.fillStyle = "#5b6570"; + for (const obstacle of obstacles) { + context.fillRect( + obstacle.x + 6, + ground - obstacle.height, + 8, + obstacle.height, + ); + context.fillRect(obstacle.x, ground - obstacle.height + 12, 6, 7); + context.fillRect(obstacle.x, ground - obstacle.height + 3, 5, 15); + context.fillRect(obstacle.x + 14, ground - obstacle.height + 19, 7, 6); + context.fillRect(obstacle.x + 17, ground - obstacle.height + 8, 4, 17); + } + context.save(); + context.translate(dinosaurX, ground - 59 - height); + context.fillStyle = crashed ? "#8c4b40" : "#294f82"; + context.fill(dinosaur); + context.fillStyle = "#ffffff"; + context.fillRect(39, 7, 4, 4); + context.restore(); + context.fillStyle = "#5b6570"; + context.font = "13px monospace"; + context.textAlign = "right"; + context.fillText( + `DISTANCE ${String(Math.floor(distance / 100)).padStart(4, "0")}`, + 580, + 28, + ); + if (!running) { + context.textAlign = "center"; + context.font = "15px system-ui"; + context.fillText( + crashed ? "Hit a cactus. Try another speed." : "Space or Jump ↑", + 330, + 85, + ); + } + }; + + const stop = (message) => { + running = false; + cancelAnimationFrame(frame); + start.textContent = crashed ? "Play again" : "Play"; + if (message) status.textContent = message; + draw(); + }; + + const reset = () => { + stop(); + crashed = false; + height = 0; + velocity = 0; + distance = 0; + obstacles = [{ x: 550, height: 38 }]; + if (auto.checked) speed = SPEED_RULE.start; + elapsed = 0; + start.textContent = "Play"; + status.textContent = "Press Play, then jump over the cactus."; + updateSpeedDisplay(); + draw(); + }; + + const update = () => { + if (auto.checked) speed = advanceSpeed(speed); + distance += speed; + if (height > 0 || velocity > 0) { + height = Math.max(0, height + velocity); + velocity -= 0.55; + if (height === 0) velocity = 0; + } + obstacles.forEach((obstacle) => { + obstacle.x -= speed; + }); + obstacles = obstacles.filter((obstacle) => obstacle.x > -25); + const last = obstacles[obstacles.length - 1]; + const gap = 400 + speed * 18; + if (last === undefined || last.x < 600 - gap) { + obstacles.push({ x: 600, height: 38 }); + } + const left = dinosaurX + 8; + const right = dinosaurX + 39; + const bottom = ground - height; + if ( + obstacles.some( + (obstacle) => + right > obstacle.x && + left < obstacle.x + 21 && + bottom > ground - obstacle.height + 4, + ) + ) { + crashed = true; + stop("Hit a cactus. Press Play again, or change the speed and restart."); + } + }; + + const animate = (time) => { + if (!running) return; + elapsed += Math.min(time - lastTime, 100); + lastTime = time; + while (elapsed >= 1000 / 60 && running) { + elapsed -= 1000 / 60; + update(); + } + updateSpeedDisplay(); + draw(); + if (running) frame = requestAnimationFrame(animate); + }; + + const play = () => { + if (crashed) reset(); + if (running) return; + running = true; + lastTime = performance.now(); + elapsed = 0; + start.textContent = "Pause"; + status.textContent = "Running. Space or Jump clears a cactus."; + frame = requestAnimationFrame(animate); + }; + + const jump = () => { + if (crashed) reset(); + play(); + if (height === 0) velocity = 10.5; + }; + + start.addEventListener("click", () => { + if (running) stop("Paused. Press Play to continue."); + else play(); + }); + demo.querySelector("[data-dino-jump]").addEventListener("click", jump); + demo.querySelector("[data-dino-reset]").addEventListener("click", reset); + canvas.addEventListener("keydown", (event) => { + if (event.code === "Space" || event.code === "ArrowUp") { + event.preventDefault(); + if (!event.repeat) jump(); + } + }); + canvas.addEventListener("pointerdown", () => { + canvas.focus(); + jump(); + }); + slider.addEventListener("input", () => { + auto.checked = false; + speed = Number(slider.value); + updateSpeedDisplay(); + status.textContent = running + ? `Fixed speed: ${speed.toFixed(1)}. Space or Jump clears a cactus.` + : `Fixed speed: ${speed.toFixed(1)}. Press Play to try it.`; + draw(); + }); + auto.addEventListener("change", () => { + if (auto.checked) speed = SPEED_RULE.start; + updateSpeedDisplay(); + status.textContent = auto.checked + ? "Recovered rule: start at 6, then increase toward 13." + : `Fixed speed: ${speed.toFixed(1)}.`; + }); + document.addEventListener("visibilitychange", () => { + if (document.hidden && running) stop("Paused. Press Play to continue."); + }); + if ("IntersectionObserver" in window) { + new IntersectionObserver((entries) => { + if (!entries[0].isIntersecting && running) + stop("Paused. Press Play to continue."); + }).observe(demo); + } + demo.querySelector(".dino-fallback").setAttribute("hidden", ""); + demo.querySelector(".dino-controls").hidden = false; + canvas.hidden = false; + reset(); +} + +document.querySelectorAll("[data-dino-demo]").forEach(initializeDinoDemo); + +const speedCheck = document.querySelector("[data-speed-check]"); +if (speedCheck !== null) speedCheck.hidden = false; +speedCheck?.addEventListener("click", () => { + let matches = true; + document.querySelectorAll("[data-speed-updates]").forEach((cell) => { + const speed = simulateSpeed( + Number(cell.getAttribute("data-speed-updates")), + ).toFixed(3); + cell.textContent = speed; + matches = + matches && speed === cell.parentElement.children[1].textContent.trim(); + }); + document.querySelector("[data-speed-check-status]").textContent = matches + ? "Replayed the recovered rule. All four values match the controlled original-game check when rounded to three decimals." + : "The replay differs from the recorded original-game values. Compare the speed rule and settings above."; +}); diff --git a/website/public/assets/dino-speed.js b/website/public/assets/dino-speed.js new file mode 100644 index 000000000..df90fcfa4 --- /dev/null +++ b/website/public/assets/dino-speed.js @@ -0,0 +1,21 @@ +// Speed rule recovered from wayou's Chromium-derived browser edition. +// Source and controlled checks: website/evidence/calculator-and-dino.md. +export const SPEED_RULE = Object.freeze({ + start: 6, + acceleration: 0.001, + threshold: 13, +}); + +/** Advance one collision-free update using the inspected speed rule. */ +export function advanceSpeed(speed) { + return speed < SPEED_RULE.threshold ? speed + SPEED_RULE.acceleration : speed; +} + +/** Replay the recovered rule for a chosen number of updates. */ +export function simulateSpeed(updates) { + let speed = SPEED_RULE.start; + for (let update = 0; update < updates; update += 1) { + speed = advanceSpeed(speed); + } + return speed; +} diff --git a/website/public/assets/home.js b/website/public/assets/home.js new file mode 100644 index 000000000..61f22231b --- /dev/null +++ b/website/public/assets/home.js @@ -0,0 +1,56 @@ +function initializePercentDemo() { + const demo = document.querySelector("[data-percent-demo]"); + if (demo === null) return; + const display = demo.querySelector("[data-percent-display]"); + const expression = demo.querySelector("[data-percent-expression]"); + const status = demo.querySelector("[data-percent-status]"); + const equals = demo.querySelector('[data-percent-key="equals"]'); + const operations = demo.querySelectorAll("[data-percent-operation]"); + let operation = "add"; + let stage = "input"; + + const render = () => { + const adding = operation === "add"; + const percent = adding ? 20 : 0.1; + const result = adding ? 220 : 20; + const operator = adding ? "+" : "×"; + expression.textContent = + stage === "result" ? `200 ${operator} ${percent} =` : `200 ${operator}`; + display.textContent = String( + stage === "input" ? 10 : stage === "percent" ? percent : result, + ); + equals.disabled = stage !== "percent"; + status.textContent = + stage === "input" + ? "Press % to see what happens to 10." + : stage === "percent" + ? adding + ? "10% of 200 is 20. Press = to add it." + : "For multiplication, 10 becomes 0.1. Press = to multiply." + : `200 ${operator} ${percent} = ${result}.`; + }; + + operations.forEach((button) => { + button.addEventListener("click", () => { + operation = button.getAttribute("data-percent-operation"); + stage = "input"; + operations.forEach((candidate) => { + candidate.setAttribute("aria-pressed", String(candidate === button)); + }); + render(); + }); + }); + demo.querySelectorAll("[data-percent-key]").forEach((button) => { + button.addEventListener("click", () => { + const key = button.getAttribute("data-percent-key"); + stage = + key === "reset" ? "input" : key === "percent" ? "percent" : "result"; + render(); + }); + }); + demo.querySelector(".percent-operation").hidden = false; + demo.querySelector(".percent-controls").hidden = false; + render(); +} + +initializePercentDemo(); diff --git a/website/public/assets/licenses/dinosaur.txt b/website/public/assets/licenses/dinosaur.txt new file mode 100644 index 000000000..88ec041e7 --- /dev/null +++ b/website/public/assets/licenses/dinosaur.txt @@ -0,0 +1,34 @@ +Selected script excerpts from wayou/t-rex-runner +Copyright (c) 2014 The Chromium Authors. All rights reserved. + +Repository license at commit 5455bfa408ec6b707c7300ff194b7390733a766d: + +BSD 3-Clause License + +Copyright (c) 2022, 牛さん +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/website/public/assets/styles.css b/website/public/assets/styles.css index 9a49919cc..54bf52f67 100644 --- a/website/public/assets/styles.css +++ b/website/public/assets/styles.css @@ -1218,6 +1218,338 @@ pre code { border: 0; } +.home-start-grid { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); + gap: 3.5rem; + align-items: center; +} +.home-start-grid h1 { + font-size: clamp(2.8rem, 5vw, 4.2rem); +} +.home-start-grid .home-setup h2 { + font-size: 1.3rem; + letter-spacing: -0.02em; + margin-bottom: 0.7rem; +} +.home-start-grid .home-setup > p { + font-size: 0.9rem; + color: var(--muted); +} +.home-question { + margin-block: 0 1.8rem; + color: var(--muted); +} +.home-question strong { + color: var(--ink); + font-weight: 500; +} +.home-role-comparison { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); + gap: 0 2.5rem; + margin: 0; +} +.comparison-label { + padding-bottom: 0.8rem; + border-bottom: 1px solid var(--line); + font-size: 0.875rem; + font-weight: 600; +} +.agent-investigation > .comparison-label { + color: var(--accent); +} +.manual-steps { + display: grid; + gap: 1rem; + padding: 0; + list-style: none; +} +.manual-steps li { + display: flex; + gap: 1rem; + margin: 0; +} +.manual-steps li > span { + padding-top: 0.2rem; + color: var(--muted); + font: + 0.75rem "SFMono-Regular", + Consolas, + "Liberation Mono", + monospace; +} +.manual-steps strong, +.manual-steps small { + display: block; +} +.manual-steps strong { + font-size: 0.95rem; + font-weight: 500; +} +.manual-steps small { + margin-top: 0.15rem; + color: var(--muted); + font-size: 0.8rem; +} +.manual-code { + margin-top: 1.3rem; + padding: 1rem 1.25rem; + border-left: 2px solid var(--line); + background: var(--soft); + color: var(--muted); + font-size: 0.8rem; + line-height: 1.65; +} +.agent-investigation-note { + color: var(--muted); + font-size: 0.875rem; +} +.home-role-comparison figcaption { + grid-column: 1 / -1; + margin-top: 1.2rem; + font-size: 0.8rem; + color: var(--muted); +} +.home-example-grid { + display: grid; + grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr); + align-items: start; + gap: 3rem; +} +.percent-figure, +.dino-demo { + min-width: 0; + margin: 0; + padding: 1.5rem; + border: 1px solid var(--line); + border-radius: 5px; +} +.percent-operation, +.percent-controls, +.dino-buttons { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; +} +.percent-operation button, +.percent-controls button, +.dino-buttons button { + min-height: 44px; + border: 1px solid var(--line); + border-radius: 4px; + padding: 0.5rem 0.8rem; + font: inherit; + font-size: 0.85rem; + color: var(--ink); + background: var(--page); + cursor: pointer; +} +.percent-operation button[aria-pressed="true"] { + color: var(--accent); + border-color: var(--accent); + background: #edf2f8; +} +.percent-display { + padding: 1.2rem; + margin-block: 1rem; + border-radius: 4px; + background: var(--soft); + text-align: right; + font-variant-numeric: tabular-nums; +} +.percent-expression { + display: block; + min-height: 1.5rem; + color: var(--muted); + font-size: 0.9rem; +} +.percent-display strong { + font-size: 3rem; + font-weight: 500; + letter-spacing: -0.04em; +} +.percent-controls .percent-key { + min-width: 68px; + font-size: 1.25rem; + color: var(--accent); + border-color: #bbcce0; +} +.percent-controls button:disabled { + opacity: 0.45; + cursor: default; +} +.percent-controls .percent-reset { + margin-left: auto; + border-color: transparent; + color: var(--muted); +} +.percent-status { + min-height: 3rem; + margin-top: 1rem; + font-size: 0.9rem; +} +.percent-figure figcaption, +.dino-demo figcaption { + margin-top: 0.8rem; + color: var(--muted); + font-size: 0.8rem; +} +.percent-explanation h3 { + font-size: 1.2rem; +} +.percent-explanation > p { + color: var(--muted); +} +.percent-rules { + margin-bottom: 0; +} +.percent-rules > div { + padding-block: 0.55rem; +} +.percent-rules dt { + font-size: 0.8rem; + color: var(--muted); + margin-bottom: 0.25rem; +} +.percent-rules dd { + margin: 0; + font-size: 0.9rem; +} +.home-evidence-details { + margin-top: 2rem; + padding-block: 1rem; + border-top: 1px solid var(--line); + border-bottom: 1px solid var(--line); +} +.home-evidence-details > summary { + cursor: pointer; + font-size: 0.875rem; + font-weight: 500; +} +.home-evidence-details[open] > summary { + margin-bottom: 1.5rem; +} +.calculator-trace { + margin-block: 1.5rem; +} +.dino-example-grid { + grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr); + gap: 2.5rem; +} +.dino-stage { + overflow: hidden; + margin-block: 0.8rem; + background: var(--soft); + border-radius: 4px; + color: var(--muted); +} +.dino-stage canvas, +.dino-fallback { + display: block; + width: 100%; + height: auto; +} +.dino-stage canvas { + touch-action: manipulation; +} +.dino-buttons .button { + background: var(--ink); + border-color: var(--ink); + color: white; +} +.dino-controls { + display: grid; + gap: 1.2rem; +} +.dino-speed-label { + display: grid; + grid-template-columns: 1fr auto; + gap: 0.5rem; + font-size: 0.875rem; +} +.dino-speed-label output { + font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace; + font-variant-numeric: tabular-nums; + color: var(--accent); +} +.dino-speed-label input { + grid-column: 1 / -1; + width: 100%; + margin: 0; + min-height: 30px; + accent-color: var(--accent); +} +.dino-auto-label { + display: flex; + align-items: center; + gap: 0.6rem; + min-height: 36px; + font-size: 0.8rem; + color: var(--muted); +} +.dino-auto-label input { + width: 17px; + height: 17px; + flex-shrink: 0; + accent-color: var(--accent); +} +.dino-status { + min-height: 2.6rem; + margin: 1rem 0 0; + font-size: 0.8rem; + color: var(--muted); +} +.dino-rule { + color: var(--muted); + font-size: 0.95rem; +} +.dino-rule strong { + color: var(--ink); +} +.dino-loop { + margin-top: 2rem; +} +.dino-lab-demo { + margin-block: 2rem; +} +.dino-lab-demo .dino-stage { + margin-block: 1.5rem; +} +.speed-check-table td:last-child, +.speed-check-table th:last-child { + text-align: right; +} +[hidden] { + display: none !important; +} +@media (max-width: 850px) { + .home-start-grid, + .home-role-comparison, + .home-example-grid { + grid-template-columns: minmax(0, 1fr); + gap: 2rem; + } + .home-start-grid .home-setup { + max-width: 620px; + } + .home-start-grid h1 { + font-size: clamp(2.7rem, 9vw, 4.65rem); + } + .home-role-comparison figcaption { + margin-top: 0; + } +} +@media (max-width: 640px) { + .home-hero { + padding-block: 2.8rem; + } + .percent-figure, + .dino-demo { + padding: 1.1rem; + } +} + @media (max-width: 850px) { .home-agent-grid, .home-try-grid { diff --git a/website/public/examples/dino-lab/index.html b/website/public/examples/dino-lab/index.html new file mode 100644 index 000000000..a0578a487 --- /dev/null +++ b/website/public/examples/dino-lab/index.html @@ -0,0 +1,332 @@ + + + + + + Dinosaur speed lab — REA + + + + + + + + + + +
+
+ +

Inspect → rebuild → change

+

Rebuild the dinosaur’s speed rule.

+

+ REA found how the running game increases its speed. This small + reconstruction lets you keep that rule or choose a new speed and play. +

+
+
+ +
+
+

Play and change the speed

+

+ Press Play, then jump over the cactus. Move the speed slider to + try a slower or faster game; it switches to a fixed speed. Select + the recovered rule to start at 6 and gradually accelerate again. +

+
+

Play the reconstruction

+
+ + + + 6 → 10 → 13 + + + +
+ +

+ Original rule: start at 6, then increase toward 13. +

+
+ Move the slider to set your own speed. Space or Jump clears a + cactus. +
+ +
+
+
+

What REA found

+

+ We inspected + wayou’s Chromium-derived browser edition + with REA. It returned the loaded index.js, including + this branch in the game’s update function: +

+
+
+ REA · selected script source +
+
if (this.currentSpeed < this.config.MAX_SPEED) {
+  this.currentSpeed += this.config.ACCELERATION;
+}
+
+

+ The settings are SPEED: 6, + ACCELERATION: 0.001 and MAX_SPEED: 13. + The game runs this branch on an update without a collision. +

+

Use the same rule in the new game

+
+
+ Reconstruction · dino-speed.js +
+
function advanceSpeed(speed) {
+  return speed < 13 ? speed + 0.001 : speed;
+}
+
+

+ The mini-game uses this function for automatic acceleration. + Moving the slider supplies a fixed speed instead. Drawing, jump + physics and rectangle collision checks are new code for this + teaching game; its simulation advances at 60 updates per second. +

+

+ Download the speed rule + · Read the game code +

+
+
+

Check the reconstruction

+

+ We called the original game’s update function with obstacles and + automatic scheduling disabled. Compare those recorded speeds with + a replay of the recovered rule. +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
UpdatesOriginal gameReconstructed rule
06.0006.000
1,0007.0007.000
4,00010.00010.000
10,00013.00113.001
+
+ +

+ Values rounded to three decimals. The branch checks before adding, + so the final increment can take speed just above 13. +

+
+
+

Try the analysis yourself

+
    +
  1. + Set up REA with your coding + agent. +
  2. +
  3. + Follow the + browser connection steps, using https://wayou.github.io/t-rex-runner/ as + the page URL. +
  4. +
  5. + Give your agent the page URL and local debugging endpoint, then + copy this prompt. +
  6. +
+
+
+ Your coding agent +
+

+ Use REA to inspect this dinosaur game. Why does it get + faster? Show the speed rule, then build a small version with + an adjustable speed. +

+
+

+ Ask a follow-up: + “Where is jump height calculated? Add a jump-height control to + the new version.” +

+

+ Source: + inspected speed code, Chromium Authors. + Copyright and BSD license. REA 4.1.0 inspected the running HTTP edition in Chrome 150. +

+
+
+
+
+ +

+ Top + + diff --git a/website/public/first-investigation/index.html b/website/public/first-investigation/index.html index ed687aa70..3c4828cd2 100644 --- a/website/public/first-investigation/index.html +++ b/website/public/first-investigation/index.html @@ -336,7 +336,7 @@ JS How DX-Ball calculates sound panningContinue from the homepage into the original instructions and + >Read the original instructions and the reconstruction’s checks. diff --git a/website/public/index.html b/website/public/index.html index c04b4c6b2..747e1715b 100644 --- a/website/public/index.html +++ b/website/public/index.html @@ -12,6 +12,8 @@ + + @@ -51,207 +53,22 @@
-

Reverse engineering, with your coding agent

-

Find out how
software works.

-

- REA gives your agent the tools to inspect a program and explain what - it does. -

- -
- -
-
-
-

What is reverse engineering?

-

- Finding out how software works by examining the program. -

-
-
-

- DX-Ball: how does the game place a sound on the left or right? -

-
-
-
- Original instructions · selected excerpt -
-
MOV EAX, dword ptr [EBP + 0x8]
-MOV dword ptr [EBP + -0xc], EAX
-FILD dword ptr [EBP + -0xc]
-FMUL double ptr [0x00420068]
-FSUB double ptr [0x00420070]
-FMUL double ptr [0x004210a0]
-CALL 0x0041678c
-
-
-
Readable summary · C
-
// x is the horizontal position
-double pan = (double)x;
-pan *= 1.5625;
-pan -= 500.0;
-pan *= pan_scale;
-return (int)pan;
-
-
-
-
- Left side - - x = 0 → pan = −500 - Sound to the left -
-
- Center - - x = 320 → pan = 0 - Centered sound -
-
- Right side - - x = 640 → pan = +500 - Sound to the right -
-
-
- Examples of the calculation with the recorded initial scale of 1. - The code is a readable summary of the inspected function. -
-
-

- To explain this, an analyst identifies the input, follows the caller - and reads the values at those addresses. -

-
-
- -
-
-
-
-

Do I need to read assembly to get started?

-

No.

-

Ask your agent about the behavior you want to understand.

-
-
-
-
- Example analysis · DX-Ball - -
-

Target · DXBALL.EXE

-

- Use REA to inspect this DX-Ball executable. How does it - calculate left/right sound panning? Show the relevant - code. -

-
-

- Agent · explanation from the findings -

-

- This function converts a brick’s horizontal position into a - left/right sound value. -

-

- At the initial scale of 1, the screen center produces zero. - Positions to the left produce negative values; positions to - the right produce positive values. -

-
-
-

- Example prompt and explanation based on the recorded - investigation. Supply the executable to your agent. -

-
-
-
-

What REA found for the agent

-
    -
  1. - 01 · Inspect the function - An integer input - The instructions read [EBP + 0x8]. The initial - pseudocode had missed this input. -
  2. -
  3. - 02 · Follow the caller - A brick’s screen position - The caller passes 20 + 30 × tile_x, giving the - input its meaning. -
  4. -
  5. - 03 · Read the stored data - The calculation’s constants - Byte reads supply 1.5625, 500.0 and - the initial scale 1.0. -
  6. -
-
- The agent uses these findings to explain the behavior and write - readable C. -
-
-

- The reconstruction project checked its maintained C function against - 3,205 original-x86 input cases and all 63 compiled bytes. - See the code and checks. -

-
-
- -
-
+
-

Your first investigation

-

Try REA on a small app.

-

- Find out where an app exports its notes, then check how it formats - a title containing commas and quotes. +

Reverse engineering, with your coding agent

+

Find out how
software works.

+

+ REA gives your agent the tools to inspect a program and explain + what it does.

-

We provide the example files, a prompt and a result to check.

-

Set up REA with your agent

+

Set up REA

+

Copy this into your coding agent:

>

-

Or run this command in your terminal:

+

Or run this in your terminal:

npx rea-agents@latest setup

- Setup shows a plan for approval. Restart your agent after setup. + Approve the setup plan, then restart your agent.

+
+
+
+

What is reverse engineering?

+

+ Finding out how software works by examining the program. +

+
+

+ For example: + why does Calculator turn 200 + 10% into + 220? +

+
+
+

Before REA · You investigate

+
    +
  1. + 01 +
    + Find the code behind the button.Which executable or library handles %? +
    +
  2. +
  3. + 02 +
    + Read the instructions.What do these branches and calls mean? +
    +
  4. +
  5. + 03 +
    + Recover the calculation.Follow the inputs, operators and constants. +
    +
  6. +
  7. + 04 +
    + Check your explanation.Does it agree with the program? +
    +
  8. +
+
+ CMP EAX, 0x5c
JZ 0x180124aba
CMP EAX, 0x5b
JZ + 0x180124aba
MOV EDX, 0x64
+
+
+
+

With REA · You ask your agent

+
+
+ Example prompt · Calculator + +
+

+ Use REA to inspect Windows Calculator. Why does 200 + 10% + give 220? Show the code behind the % button. +

+
+

+ Example explanation from the findings +

+

+ With addition, % calculates a percentage of the first + number. +

+

+ 10% of 200 is 20.
Then 200 + 20 = 220.
+

+
+
+

+ Your agent uses REA to locate and read the code, then connects + the findings to your question. +

+
+
+ You describe the behavior. The agent carries out the investigation + with REA. +
+
+
+
+ +
+
+
+

Example 01 · Windows Calculator

+

What does the % button actually do?

+

+ The answer depends on the operator. Compare addition and + multiplication. +

+
+
+
+

Try the calculation

+ +
+ 200 + + 20 +
+ +

+ 10% of 200 = 20. Then 200 + 20 = 220. +

+
+ Interactive illustration of the inspected percentage rule. +
+
+
+

REA finds the branch. The agent explains it.

+

+ The installed app’s calculation code checks for multiplication + or division before computing the percentage. +

+
+
+ Readable summary of the % handler +
+
if (operation == multiply || operation == divide) {
+  percent = current / 100;
+} else {
+  percent = current * previous / 100;
+}
+
+
+
+
Addition
+
200 + 10% → 200 + 20 → 220
+
+
+
Multiplication
+
200 × 10% → 200 × 0.1 → 20
+
+
+
+
+
+ See the real code and how the answer was checked +
    +
  1. + 01 · Inspect calc.exeA launcherREA finds ShellExecuteW opening + ms-calculator:. +
  2. +
  3. + 02 · Inspect the appCalcViewModel.dllIts % handler checks two operator IDs and uses the constant + 100. +
  4. +
  5. + 03 · Interpret and checkTwo percentage rulesMicrosoft’s public implementation and unit tests explain the + same distinction. +
  6. +
+
+
+
+ REA · selected original instructions +
+
0x180124945: MOV EAX, dword ptr [R13 + 0x18]
+0x180124949: CMP EAX, 0x5c
+0x18012494c: JZ 0x180124aba
+0x180124952: CMP EAX, 0x5b
+0x180124955: JZ 0x180124aba
+0x18012495b: MOV EDX, 0x64
+
+
+
+ Operator IDs · Microsoft’s source +
+
#define IDC_MUL 92      // 0x5c
+#define IDC_DIV 91      // 0x5b
+#define IDC_PERCENT 118 // 0x76
+
+0x64 = 100
+
+
+

+ Inspected with REA 4.1.0: Windows Calculator 11.2508.4.0, x64. The + readable summary uses names from Microsoft’s public source to + explain the recovered branch. +

+

+ Percentage implementation + · + Microsoft’s test cases + · Native setup guide +

+
+
+
+ +
+
+
+

Example 02 · Chrome’s dinosaur game

+

Find the speed rule. Rebuild it. Change it.

+

+ Why does the dinosaur game get faster? Use REA to read the running + page’s script, then turn the answer into a game you can adjust. +

+
+
+
+
+
+ Example prompt · Dinosaur game + +
+

+ Use REA to inspect this dinosaur game. Why does it get + faster? Show the speed rule, then build a small version with + an adjustable speed. +

+
+

+ Inspected target: + wayou’s Chromium-derived browser edition. +

+
+
+ REA · loaded index.js · selected lines +
+
if (this.currentSpeed < this.config.MAX_SPEED) {
+  this.currentSpeed += this.config.ACCELERATION;
+}
+
+

+ Start at 6. Add 0.001 each + update without a collision, while speed is below + 13. +

+ Open the speed lab → +
+
+

Play the reconstruction

+
+ + + + 6 → 10 → 13 + + + +
+ +

+ Original rule: start at 6, then increase toward 13. +

+
+ Move the slider to set your own speed. Space or Jump clears a + cactus. +
+ +
+
+
+

From the running game to a new version

+
    +
  1. + 01 · InspectREA returns the loaded scriptThe agent reads the update function and its speed + settings. +
  2. +
  3. + 02 · RebuildUse the recovered ruleStart at 6 and add 0.001 while speed is below 13. +
  4. +
  5. + 03 · Change and playMake speed adjustableKeep the original acceleration, or choose your own + pace. +
  6. +
+
+
+ + See the script, checks and how to try the analysis + +

+ REA inspected the HTTP browser edition through a local debugging + connection and returned the loaded index.js, + including its source and digest. +

+
+
+ Selected settings from the inspected script +
+
ACCELERATION: 0.001,
+MAX_SPEED: 13,
+SPEED: 6
+
+

+ We called the original game’s update function in a controlled + browser check, with obstacles and automatic scheduling disabled. + After 4,000 updates, speed was 10.0; after 10,000, it was 13.0, + rounded to one decimal. +

+

+ The new mini-game keeps that speed rule. Its drawing, jumping and + collision code are a small teaching implementation. + Open the lab to see the new code + and run the same speed check. +

+

+ To inspect the target yourself, follow the + browser connection steps + using + the dinosaur page. Give your agent that page URL and your local debugging + endpoint, then copy the prompt above. +

+

+ Inspected speed code + · + Chromium Authors · BSD license +

+
+
+
+ +
+
+
+

Your first investigation

+

Try REA on a small app.

+

+ Download our Notes example, trace its CSV export, and check one + changed input. +

+
+ Try the guided example +
+
+
diff --git a/website/style-guide.md b/website/style-guide.md index 28a007fb5..c322c1acd 100644 --- a/website/style-guide.md +++ b/website/style-guide.md @@ -64,8 +64,17 @@ code excerpt with readable logic and a figure that explains the result without requiring the reader to understand either language. Show a simple agent prompt and the specific facts REA supplies to answer it. -Offer a supplied target for the next step. Keep the installation prompt and -normal setup command visible. A first exercise should take the reader through +Put compact setup at the beginning of the homepage: a copyable installation +prompt and the ordinary setup command. Follow it with the beginner examples. +Show how the reader's task changes using the same question on both sides of a +manual/agent comparison. Let returned evidence make REA's contribution visible. + +When a small reconstruction makes the finding tangible, let readers change an +input or setting and try the result. Connect inspection, recovered logic, +reconstruction and the new experiment. Keep the recovered rule distinct from +new teaching mechanics, and check it against the inspected program. + +Offer a supplied target for the next step. A first exercise should take the reader through setup, a question, an answer with source references, one prediction they can check, and a follow-up. Introduce specialized prerequisites when the chosen target requires them. @@ -114,13 +123,14 @@ purposes, and immutable commit links for checkpoint-dependent facts. Each figure should answer a question that a reader can name. Choose the visual form that fits it: -| Relationship | Existing example | Useful form | -| ----------------------------------------- | ---------------------------------------- | -------------------------------------------------- | -| Analysis and verification steps | DX-Ball sound pan | Flow with separate verification branches | -| Code across process boundaries | Electron CSV export and Notion clipboard | HTML flow with APIs and channel names | -| A mathematical transformation | TH04's fixed and aimed rings | SVG drawn from the angle formula | -| Original instructions and readable source | DX-Ball and TH04 | Selectable HTML code with matching step highlights | -| A request caused by an action | Notes browser export | Flow, observed result table and script excerpt | +| Relationship | Existing example | Useful form | +| ----------------------------------------- | ---------------------------------------- | ------------------------------------------------------- | +| Analysis and verification steps | DX-Ball sound pan | Flow with separate verification branches | +| Code across process boundaries | Electron CSV export and Notion clipboard | HTML flow with APIs and channel names | +| A mathematical transformation | TH04's fixed and aimed rings | SVG drawn from the angle formula | +| Original instructions and readable source | DX-Ball and TH04 | Selectable HTML code with matching step highlights | +| A request caused by an action | Notes browser export | Flow, observed result table and script excerpt | +| Recovered behavior and a new experiment | Dinosaur speed reconstruction | Inspected code, playable demo and original-result check | Use SVG or semantic HTML for diagrams with exact text, numbers and arrows. Generated illustrations can help explore a layout, but the published labels,