feat(website): add homepage navigation and faster reading paths
This commit is contained in:
parent
5b769d3a78
commit
c94f06d98f
|
|
@ -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 <http://127.0.0.1:4173/>. 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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
<script src="assets/home.js" defer></script>
|
||||
<script type="module" src="assets/dino-demo.js"></script>
|
||||
</head>
|
||||
<body id="top">
|
||||
<body class="home-page" id="top">
|
||||
<a class="skip-link" href="#main">Skip to content</a>
|
||||
<header class="site-header">
|
||||
<div class="container header-inner">
|
||||
|
|
@ -51,8 +51,33 @@
|
|||
</a>
|
||||
</div>
|
||||
</header>
|
||||
<details class="home-page-nav" data-home-nav open>
|
||||
<summary class="container">
|
||||
<span>On this page</span>
|
||||
<span class="home-nav-current" data-home-nav-current aria-hidden="true"
|
||||
>Set up REA</span
|
||||
>
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" aria-hidden="true">
|
||||
<path d="m2 4 4 4 4-4" fill="none" stroke="currentColor" />
|
||||
</svg>
|
||||
</summary>
|
||||
<nav class="home-nav-links" aria-label="On this page">
|
||||
<div class="container">
|
||||
<p class="home-nav-title">On this page</p>
|
||||
<ul>
|
||||
<li><a href="#setup" aria-current="location">Set up REA</a></li>
|
||||
<li><a href="#what-is-re">What is RE?</a></li>
|
||||
<li><a href="#how-rea-helps">How REA helps</a></li>
|
||||
<li><a href="#dinosaur">Dinosaur game</a></li>
|
||||
<li><a href="#calculator">Calculator</a></li>
|
||||
<li><a href="#try-rea">Try REA</a></li>
|
||||
<li><a href="#analyze">Analysis guides</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</details>
|
||||
<main id="main">
|
||||
<section class="container hero home-hero">
|
||||
<section class="container hero home-hero" id="setup">
|
||||
<div class="home-start-grid">
|
||||
<div>
|
||||
<p class="eyebrow">Reverse engineering, with your coding agent</p>
|
||||
|
|
@ -64,7 +89,12 @@
|
|||
<div class="actions">
|
||||
<a class="button" href="#what-is-re">See how REA works ↓</a>
|
||||
<a class="text-link" href="get-started/">Setup guide</a>
|
||||
<a class="text-link" href="showcase/">Showcases →</a>
|
||||
</div>
|
||||
<p class="home-expert-shortcut">
|
||||
Already know RE?
|
||||
<a href="#analyze">Skip to analysis guides →</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="home-setup">
|
||||
<h2>Set up REA</h2>
|
||||
|
|
@ -132,7 +162,7 @@
|
|||
One question:
|
||||
<strong>why does Calculator give 220 for 200 + 10%?</strong>
|
||||
</p>
|
||||
<figure class="home-role-comparison">
|
||||
<figure class="home-role-comparison" id="how-rea-helps">
|
||||
<div
|
||||
class="manual-investigation step-comparison"
|
||||
data-step-comparison
|
||||
|
|
@ -830,10 +860,10 @@ SPEED: 6</code></pre>
|
|||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<section class="section" id="analyze">
|
||||
<div class="container">
|
||||
<div class="section-heading">
|
||||
<h2>What REA can analyze</h2>
|
||||
<h2>Analyze your software</h2>
|
||||
<p>
|
||||
Choose a guide for your binary, JavaScript app or browser session.
|
||||
</p>
|
||||
|
|
@ -866,161 +896,6 @@ SPEED: 6</code></pre>
|
|||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<div class="container feature-case">
|
||||
<div>
|
||||
<p class="eyebrow">Case study · Native</p>
|
||||
<h2>Rebuilding DX-Ball</h2>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
<p>
|
||||
<a class="text-link" href="showcase/dx-ball/"
|
||||
>Follow the investigation</a
|
||||
>
|
||||
</p>
|
||||
<p class="case-note">
|
||||
Work so far covers boards, resources, brick hits, animations,
|
||||
particles and bonus production. The playable game is still in
|
||||
progress.
|
||||
</p>
|
||||
</div>
|
||||
<dl class="stats case-stats">
|
||||
<div>
|
||||
<dt>55</dt>
|
||||
<dd>functions in maintained C</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>45,380</dt>
|
||||
<dd>original-x86 differential cases</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>33</dt>
|
||||
<dd>complete functions with matching compiled bytes</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<div class="container feature-case">
|
||||
<div>
|
||||
<p class="eyebrow">Case study · Electron</p>
|
||||
<h2>Notion's Electron clipboard</h2>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
<p>
|
||||
Short code excerpts show each handoff. A second figure explains
|
||||
how an HTML marker connects ordinary clipboard text to Notion's
|
||||
structured block data.
|
||||
</p>
|
||||
<a class="text-link" href="showcase/notion/"
|
||||
>Follow the clipboard bridge</a
|
||||
>
|
||||
</div>
|
||||
<figure class="workflow-figure case-preview">
|
||||
<p class="figure-title">Clipboard IPC channel</p>
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>Preload · send</span></div>
|
||||
<pre><code>invokerInMain(
|
||||
<span class="notion-channel">"notion:clipboard:write"</span>
|
||||
)</code></pre>
|
||||
</div>
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>Main process · receive</span></div>
|
||||
<pre><code>addListener(
|
||||
<span class="notion-channel">"notion:clipboard:write"</span>,
|
||||
handler
|
||||
)</code></pre>
|
||||
</div>
|
||||
<figcaption>
|
||||
Matching names give the investigation a path to follow.
|
||||
</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<div class="container feature-case">
|
||||
<div>
|
||||
<p class="eyebrow">Case study · PC-98 DOS</p>
|
||||
<h2>TH04's aimed bullet rings</h2>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
<a class="text-link" href="showcase/th04/"
|
||||
>See the bullet calculation</a
|
||||
>
|
||||
</div>
|
||||
<figure class="workflow-figure case-preview th04-preview">
|
||||
<p class="figure-title">Fixed and aimed rings</p>
|
||||
<img
|
||||
src="assets/figures/th04-bullet-ring.svg"
|
||||
width="1000"
|
||||
height="520"
|
||||
alt="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."
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
<figcaption>
|
||||
Adding the player's direction rotates every bullet by the same
|
||||
angle.
|
||||
</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<div class="container feature-case">
|
||||
<div>
|
||||
<p class="eyebrow">Case study · CTF</p>
|
||||
<h2>Solve a CTF flag checker</h2>
|
||||
<p>
|
||||
Use REA to inspect an easy DownUnderCTF binary. Extract its
|
||||
checking rules, solve for the flag and confirm that the original
|
||||
program accepts it.
|
||||
</p>
|
||||
<a class="text-link" href="showcase/ctf/">See the CTF solution</a>
|
||||
</div>
|
||||
<figure class="workflow-figure case-preview">
|
||||
<p class="figure-title">One check reveals one character</p>
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>From REA's code and data</span>
|
||||
</div>
|
||||
<pre><code>Mask: skip 21, select 1, skip 14
|
||||
Target: 55
|
||||
|
||||
code[21] = 55 → '7'</code></pre>
|
||||
</div>
|
||||
<figcaption>
|
||||
Each mask selects characters whose codes must add up to a stored
|
||||
number. This one selects a single character.
|
||||
</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<div class="container start-row">
|
||||
<div>
|
||||
<h2>What would you like to understand?</h2>
|
||||
<p>
|
||||
Connect REA to your coding agent, or run your first analysis from
|
||||
the terminal.
|
||||
</p>
|
||||
</div>
|
||||
<a class="button" href="get-started/">Get started</a>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<footer class="site-footer">
|
||||
<div class="container footer-inner">
|
||||
|
|
|
|||
|
|
@ -69,6 +69,13 @@ prompt and the ordinary setup command. Then explain what reverse engineering
|
|||
means and what it lets someone do, before the worked examples.
|
||||
Begin each example with its goal and the reason to inspect that program.
|
||||
Name the actual evidence REA returned and what the agent did with it.
|
||||
Give long pages a short table of contents with concrete section names. Preserve
|
||||
the reading width: the homepage uses the side gutter when it has room,
|
||||
and a collapsible sticky menu on smaller screens. Highlight the current
|
||||
section, keep fragment links usable without JavaScript, and leave room above
|
||||
the destination for the sticky control. Offer experienced readers a direct
|
||||
route from setup to the analysis guides. Keep full case-study previews on the
|
||||
Showcases page, linked from the opening actions.
|
||||
Use short labels, selective bold text and the shared blue highlight to make
|
||||
those facts visible when scanning. Keep source, interpretation and new code
|
||||
attributed to their respective roles. On mobile, the demo can precede its
|
||||
|
|
|
|||
Loading…
Reference in New Issue