diff --git a/website/README.md b/website/README.md index c011e6435..6f9af6887 100644 --- a/website/README.md +++ b/website/README.md @@ -5,7 +5,7 @@ > — N0zoM1z0 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 +The public files are in `website/public/`. The site uses HTML, CSS and small 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. @@ -26,7 +26,7 @@ Open . Refresh the browser after editing a file. ## Pages -- `public/index.html`: compact setup, reverse-engineering definition and purpose, manual/agent comparison, dinosaur and Calculator examples, and case-study overviews. +- `public/index.html`: compact setup, reverse-engineering definition and purpose, manual/agent comparison, dinosaur and Calculator examples, and analysis-guide links. - `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. @@ -100,6 +100,13 @@ and complete private Evidence records are not website assets. The homepage starts with a short installation prompt and the ordinary setup command, then explains what reverse engineering is and why someone would use it. The manual/agent comparison introduces REA’s role before the examples. +Its opening links directly to Showcases and lets experienced readers skip to +the analysis guides. Case-study previews live on the Showcases page. +A right-side table of contents stays visible at widths of 1440px and above. +On narrower screens it becomes a sticky, native disclosure; selecting a link +closes the menu and focuses the destination. The homepage script follows +the reading position and marks the current link. Without JavaScript, the +menu stays open and its fragment links remain usable. The comparison uses the same Calculator question on both sides: three selectable manual steps pair original instructions with an analyst illustration and thought bubbles; the agent side begins with “One prompt.” and a copyable diff --git a/website/public/assets/home.js b/website/public/assets/home.js index 27cd1b32f..c5e102da6 100644 --- a/website/public/assets/home.js +++ b/website/public/assets/home.js @@ -62,5 +62,79 @@ function initializeExpertAssembly() { } } +function initializeHomeNavigation() { + const menu = document.querySelector("[data-home-nav]"); + if (menu === null) return; + const currentLabel = menu.querySelector("[data-home-nav-current]"); + if (currentLabel === null) return; + const wideScreen = window.matchMedia("(min-width: 1440px)"); + const entries = Array.from(menu.querySelectorAll('a[href^="#"]')) + .map((link) => ({ + link, + target: document.getElementById(link.getAttribute("href").slice(1)), + })) + .filter((entry) => entry.target !== null); + if (entries.length === 0) return; + + const updatePosition = () => { + const offset = wideScreen.matches ? 40 : 88; + let current = entries[0]; + entries.forEach((entry) => { + if (entry.target.getBoundingClientRect().top <= offset) current = entry; + }); + if ( + window.scrollY + window.innerHeight >= + document.documentElement.scrollHeight - 2 + ) { + const selected = entries.find( + (entry) => entry.link.hash === window.location.hash, + ); + const selectedTop = selected?.target.getBoundingClientRect().top; + current = + selectedTop !== undefined && + selectedTop >= 0 && + selectedTop < window.innerHeight + ? selected + : entries[entries.length - 1]; + } + entries.forEach((entry) => { + if (entry === current) + entry.link.setAttribute("aria-current", "location"); + else entry.link.removeAttribute("aria-current"); + }); + currentLabel.textContent = current.link.textContent; + }; + const updateLayout = () => { + menu.open = wideScreen.matches; + updatePosition(); + }; + let scheduled = false; + const schedulePosition = () => { + if (scheduled) return; + scheduled = true; + window.requestAnimationFrame(() => { + scheduled = false; + updatePosition(); + }); + }; + entries.forEach(({ link, target }) => { + link.addEventListener("click", () => { + if (!wideScreen.matches) menu.open = false; + const heading = target.querySelector("h2") ?? target; + heading.setAttribute("tabindex", "-1"); + window.requestAnimationFrame(() => + heading.focus({ preventScroll: true }), + ); + }); + }); + wideScreen.addEventListener("change", updateLayout); + window.addEventListener("scroll", schedulePosition, { passive: true }); + window.addEventListener("resize", schedulePosition, { passive: true }); + window.addEventListener("hashchange", schedulePosition); + window.addEventListener("load", schedulePosition); + updateLayout(); +} + initializeExpertAssembly(); initializePercentDemo(); +initializeHomeNavigation(); diff --git a/website/public/assets/styles.css b/website/public/assets/styles.css index 3bcc84d9e..fc9850f69 100644 --- a/website/public/assets/styles.css +++ b/website/public/assets/styles.css @@ -1218,6 +1218,137 @@ pre code { border: 0; } +.home-page-nav { + position: sticky; + top: 0; + z-index: 6; + background: var(--page); + border-bottom: 1px solid var(--line); +} +.home-page-nav > summary { + display: flex; + align-items: center; + gap: 0.75rem; + min-height: 52px; + color: var(--ink); + font-size: 0.8rem; + font-weight: 600; + list-style: none; + cursor: pointer; +} +.home-page-nav > summary::-webkit-details-marker { + display: none; +} +.home-nav-current { + margin-left: auto; + color: var(--muted); + font-weight: 400; +} +.home-page-nav[open] > summary svg { + transform: rotate(180deg); +} +.home-nav-links { + position: absolute; + inset: 100% 0 auto; + max-height: calc(100svh - 5rem); + overflow-y: auto; + padding-block: 0.4rem 1rem; + background: var(--page); + border-bottom: 1px solid var(--line); +} +.home-nav-title { + display: none; +} +.home-nav-links ul { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0.2rem 1rem; + margin: 0; + padding: 0; + list-style: none; +} +.home-nav-links li + li { + margin: 0; +} +.home-nav-links a { + display: flex; + align-items: center; + min-height: 44px; + padding: 0.5rem 0.65rem; + border-left: 2px solid transparent; + color: var(--muted); + font-size: 0.825rem; + line-height: 1.5; + text-decoration: none; +} +.home-nav-links a:hover { + color: var(--ink); + background: var(--soft); +} +.home-nav-links a[aria-current="location"] { + border-left-color: var(--accent); + background: #f1f5fa; + color: var(--accent); + font-weight: 600; +} +.home-page section[id], +.home-role-comparison[id] { + scroll-margin-top: 5.25rem; +} +.home-expert-shortcut { + margin-block: 1.5rem 0; + color: var(--muted); + font-size: 0.85rem; +} +.home-expert-shortcut a { + white-space: nowrap; +} +@media (min-width: 1440px) { + .home-page-nav { + position: fixed; + top: 7.5rem; + right: max(1.5rem, calc((100vw - 1080px) / 2 - 156px)); + width: 132px; + max-height: calc(100svh - 9rem); + overflow-y: auto; + border: 0; + z-index: 2; + } + .home-page-nav > summary { + display: none; + } + .home-nav-links { + position: static; + max-height: none; + overflow: visible; + padding: 0; + border: 0; + } + .home-nav-links .container { + width: 100%; + } + .home-nav-title { + display: block; + margin-bottom: 0.7rem; + padding-left: 0.75rem; + color: var(--muted); + font-size: 0.75rem; + font-weight: 600; + } + .home-nav-links ul { + display: block; + border-left: 1px solid var(--line); + } + .home-nav-links a { + margin-left: -1px; + font-size: 0.78rem; + } + .home-page section[id], + .home-role-comparison[id] { + scroll-margin-top: 2rem; + } +} + .home-start-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); @@ -1765,6 +1896,16 @@ pre code { } } @media (max-width: 640px) { + .home-start-grid .actions { + display: grid; + grid-template-columns: max-content max-content; + justify-content: start; + gap: 0.9rem 1.4rem; + } + .home-start-grid .actions .button { + grid-column: 1 / -1; + justify-self: start; + } .expert-analysis-grid { grid-template-columns: minmax(0, 1fr); } diff --git a/website/public/index.html b/website/public/index.html index 26f8d2b0a..e3c9a7b0e 100644 --- a/website/public/index.html +++ b/website/public/index.html @@ -15,7 +15,7 @@ - + +
+ + On this page + + + + +
-
+

Reverse engineering, with your coding agent

@@ -64,7 +89,12 @@ +

+ Already know RE? + Skip to analysis guides → +

Set up REA

@@ -132,7 +162,7 @@ One question: why does Calculator give 220 for 200 + 10%?

-
+
-
+
-

What REA can analyze

+

Analyze your software

Choose a guide for your binary, JavaScript app or browser session.

@@ -866,161 +896,6 @@ SPEED: 6
- -
-
-
-

Case study · Native

-

Rebuilding DX-Ball

-

- DX-Ball is a 1996 Windows game. The project is reconstructing it - in C, using REA to inspect the executable and independent tests to - check the recovered behavior. -

-

- Follow the investigation -

-

- Work so far covers boards, resources, brick hits, animations, - particles and bonus production. The playable game is still in - progress. -

-
-
-
-
55
-
functions in maintained C
-
-
-
45,380
-
original-x86 differential cases
-
-
-
33
-
complete functions with matching compiled bytes
-
-
-
-
- -
-
-
-

Case study · Electron

-

Notion's Electron clipboard

-

- A copy operation crosses from the page to Electron's main process. - Inspect Notion's packaged JavaScript with REA, then follow one - channel through the wrappers to the system clipboard. -

-

- Short code excerpts show each handoff. A second figure explains - how an HTML marker connects ordinary clipboard text to Notion's - structured block data. -

- Follow the clipboard bridge -
-
-

Clipboard IPC channel

-
-
Preload · send
-
invokerInMain(
-  "notion:clipboard:write"
-)
-
-
-
Main process · receive
-
addListener(
-  "notion:clipboard:write",
-  handler
-)
-
-
- Matching names give the investigation a path to follow. -
-
-
-
- -
-
-
-

Case study · PC-98 DOS

-

TH04's aimed bullet rings

-

- Inspect a 16-bit DOS function with REA. Follow its angle - calculation from original instructions to readable C++, then see - how adding the player's direction turns a ring of bullets. -

- See the bullet calculation -
-
-

Fixed and aimed rings

- TH04's fixed and aimed 16-bullet rings side by side. The first bullet is highlighted in blue; adding the player direction rotates every bullet while preserving the spacing. -
- Adding the player's direction rotates every bullet by the same - angle. -
-
-
-
- -
-
-
-

Case study · CTF

-

Solve a CTF flag checker

-

- Use REA to inspect an easy DownUnderCTF binary. Extract its - checking rules, solve for the flag and confirm that the original - program accepts it. -

- See the CTF solution -
-
-

One check reveals one character

-
-
- From REA's code and data -
-
Mask: skip 21, select 1, skip 14
-Target: 55
-
-code[21] = 55  →  '7'
-
-
- Each mask selects characters whose codes must add up to a stored - number. This one selects a single character. -
-
-
-
- -
-
-
-

What would you like to understand?

-

- Connect REA to your coding agent, or run your first analysis from - the terminal. -

-
- Get started -
-