diff --git a/website/README.md b/website/README.md index 300f000c11..515e772383 100644 --- a/website/README.md +++ b/website/README.md @@ -1,6 +1,6 @@ # REA website -An English static website with explanatory figures, worked guides and DX-Ball and Notion investigations. +An English static website with explanatory figures, worked guides and DX-Ball, Notion and TH04 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 packages the downloadable example; there is no frontend bundler or npm dependency. @@ -22,6 +22,7 @@ Open . Refresh the browser after editing a file. - `public/showcase/index.html`: the case-study index. - `public/showcase/dx-ball/index.html`: sound-pan investigation and project status. - `public/showcase/notion/index.html`: Notion's Electron clipboard bridge and rich clipboard format. +- `public/showcase/th04/index.html`: TH04's 16-bit DOS bullet-angle calculation and compiler checks. - `public/get-started/index.html`: agent setup, first CLI result and provider guides. - `public/guides/`: a guide hub and native, JavaScript/Electron and browser examples. - `public/examples/`: downloadable Electron source and an interactive Notes browser app. @@ -84,6 +85,15 @@ the website. [evidence/notion-clipboard.md](evidence/notion-clipboard.md) records the REA package version, selected findings, source anchors and module-probe scope. +## TH04 case study + +The TH04 case inspects the original PC-98 DOS angle helper through REA 4.1.0. +Its selected instructions are paired with readable C++ and a source SVG of +fixed and aimed rings. [evidence/th04-bullet-ring.md](evidence/th04-bullet-ring.md) +records the fresh load-image/function evidence and separately credited TH04 +source and historical compiler replay. The figure illustrates the calculation; +original game assets and executable bytes are not website downloads. + ## GitHub Pages `.github/workflows/website-pages.yml` prepares and deploys only `website/public`. diff --git a/website/evidence/th04-bullet-ring.md b/website/evidence/th04-bullet-ring.md new file mode 100644 index 0000000000..8f358119b4 --- /dev/null +++ b/website/evidence/th04-bullet-ring.md @@ -0,0 +1,136 @@ +# TH04 aimed-ring evidence + +This case examines one helper in the Japanese PC-98 DOS TH04 (Lotus Land Story) +reconstruction. Source and historical compiler checks are pinned to +`0d72e9801a5c14c10384efcbb6734ceccb74ee63` in +[N0zoM1z0/th04](https://github.com/N0zoM1z0/th04). The page adds a fresh inspection +of the supplied original target through REA on 7 October 2026. + +## Original target and analysis + +- Target: `MAIN.EXE`, 156,258 bytes, DOS MZ, x86 real mode. +- SHA-256: `077440a3c4e9ab52e72e9bae411276c47edc11995b5c2b83dfc83fbc039dc58b`. +- Header: 6,144 bytes (`0x1800`); module: 150,114 bytes; relocations: 1,136. +- Connected analysis: published REA 4.1.0, Ghidra 12.1.4, Linux x64. +- The connected runtime's 761 files under `dist`, `bridge` and `scripts` match + the cached published REA 4.1.0 package byte for byte. +- Load-image profile: `MzLoader`, `x86:LE:16:Real Mode`, compiler `default`, + fixed load segment `0x1000`, linear byte addresses. +- Profile digest: `0d7ec8473c44e8d0a979c0308f7260b7572866613a369c30550026c81beff0e9`. +- Helper: `bullet_velocity_and_angle_set`, REA entry `0x2cfc8`, original + file offset `0x1e7c8` (124,872). + +The executable's identity passes the reconstruction manifest and MZ checks. Its +manifest provenance is `candidate-local-attested`; no independent pristine-dump +claim is added. Windows is an emulator or port host here, not this executable's +format. + +## Fresh REA requests + +1. `open_binary` binds the original target with provider `ghidra`. The displayed + input is compact: its local path is shortened to `MAIN.EXE` and the explicit + provider selection is omitted from the product narrative. +2. `inspect_native_load_image {}` returns `status: verified`, header 6,144, + module 150,114, and load segment 4,096. Every returned check matches. + Evidence: `ev_dc53b8af38910ed3dc40b29dc003110b79842957d6f8ab7da8737847a4b4d3fb`. +3. `analyze_function {"procedure":"0x2cfc8"}` returns instructions, pseudocode, + callers, callees, data references and complete reported function-body ranges. + Evidence: `ev_d79b6834ff615b5b59df1e31f3ba01c32491582ddfd4f9383c6f05d83b59f77d`. +4. `address_to_file_offset {"address":"0x2cfc8"}` returns original file offset + 124,872. Evidence: + `ev_aae51edacb1a224d1b52ecccc4c43f506f28b3216f255d05fb07efdfaf10eb4b`. +5. `read_bytes {"address":"0x2d0eb","length":19}` returns all 19 requested + bytes: `8bc6c1e0088a16af53b60052995bf7fb8946fe`. They match the original + target at file `0x1e8eb`. Evidence: + `ev_d984b3df53cc8cd63c0b7bdfdf8822d84f0ea594c3c10c00419ed9f8d4036108`. + +The selected helper comes from the project's reviewed source boundary. The +example prompt is an invitation to the reader's agent, not a transcript or a +claim that this inspection independently discovered every source owner. +The ephemeral REA session was closed after these queries. The original +executable and the reconstruction's saved database were not modified. + +The returned function body is noncontiguous: `0x2cfc8..0x2d14f` and +`0x2d15e..0x2d1cc`, 503 body bytes across a 517-byte enclosing span. The page's +selected ring, aim and store instructions lie within those reported ranges. +The historical project reconciles the omitted 14 bytes with raw decoding and +reviewed compiler ownership; the page does not claim REA reported a contiguous +517-byte body. + +## Instructions and source meaning + +| REA instruction evidence | Meaning supported by the maintained source | +| ------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------- | +| `0x2cfcf: MOV SI, word ptr [BP + 0x4]` | Group-member index | +| `0x2d0ed: SHL AX, 0x8` followed by count load and `IDIV BX` | `(index * 256) / count`, multiplication before integer division | +| Coordinate loads/subtractions at `0x2d18d..0x2d198`, far call at `0x2d19d`, then addition at `0x2d1a2` | Add `iatan2(player - origin)` for an aimed ring | +| `0x2d1bc: ADD AL, byte ptr [0x53ad]` | Add template rotation | +| `0x2d1c0: MOV [0xbcc8], AL` | Store the final byte angle, wrapping at 256 | + +Assembly is transcribed verbatim from the fresh REA result. Short request/result +panels select instructions, while the five-step comparison retains the complete +19-byte ring quotient sequence. The names `count`, player/origin fields, +`iatan2`, template rotation and spawn angle come from the maintained source and +reviewed original reconstruction, not recovered original symbols. + +The readable `aimed_ring_angle` function is explanatory C++, not the +compiler-sensitive complete helper or the source compiled by historical checks. +The ring macro display expands its TH04 branch and removes preprocessor +continuations for reading. The source labels and details distinguish those +summaries from linked complete source. + +Real-mode near-call segment aliases can produce misleading static call edges. +The case uses instruction/data anchors and the project's reviewed source +relationships, not a claim of automatically verified whole-program call flow. + +## Figure + +The SVG draws sixteen directions using `index * 256 / 16`. The left ring has +zero aim, zero rotation; the right adds illustrative player direction 40 and +keeps zero rotation. The clockwise coordinates match the source's byte-angle +contract: right 0, down 64, left 128, up 192. The highlighted first ray points +at the illustrated player; every subsequent ray retains the same 16-unit step. +This is a mathematical diagram, not captured game output. + +Elly's real source initially requests `BG_RING_AIMED`, count 16 and angle 0, +then calls `bullet_template_tune`. The page preserves that tuning call and +labels the figure's count explicitly; it does not claim every difficulty or +performance state emits sixteen bullets. + +## Recorded compiler validation + +The linked semantic-bullet note records two isolated cold builds on +3 October 2026 of owner `th04-main-module-th04-bullet-a-cpp-1cc33`, using the +pinned Turbo C++ 4.0J/TASM/TLINK toolchain. Both reproduce the complete +2,139-byte (`0x85b`) original extent starting at file `0x1e433`, plus exact MAP +contribution and overlapping relocation. Target and candidate slice SHA-256: +`f7dfaeae5b18749d6687a94139488a825f86f00b85a4eb4072985223a5f1cc5e`. + +The retained receipt was read from the project's archive into private scratch +storage. Receipt SHA-256: +`76a361da712d8203f410068df0a864192ecdb64671e173ea15db358796b71e49`. +Its digest matches the archive manifest. It reports `pass: true`, no failures, +and both builds have `raw_exact`, `map_exact`, `relocations_exact` and +`object_valid` true. Recorded input snapshots match the current `add.cpp`, +`add_impl.hpp` and `types.hpp` bytes. No fresh compiler build or ledger +promotion was needed for the website update. + +Public evidence reference: `ev-th04-semantic-bullet-exact-v1236` in the TH04 +evidence ledger. The matching extent contains the full helper and surrounding +bullet-add functions; it is not a whole-executable or full-game equivalence +claim. The original reconstruction used project-specific analysis and replay +scripts. Its source and compiler evidence are credited separately from the +fresh REA inspection. + +## Public source anchors + +- [Ring macro](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/src/main/bullet/add_impl.hpp#L4). +- [Complete angle helper](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/src/main/bullet/add.cpp#L292). +- [Aim and velocity](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/src/main/bullet/add.cpp#L422). +- [Angle representation](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/src/main/bullet/types.hpp#L6). +- [Elly's firing template](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/src/main/boss/elly_phase_ring16.cpp#L26). +- [Compiler checks](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/docs/reconstruction/product/TH04_SEMANTIC_BULLET_GENERATION_V1236.md#validation). + +Original executables, game assets, complete raw Evidence, machine paths, +account/configuration details and private compiler products remain outside +the website. diff --git a/website/figures.md b/website/figures.md index 20bda270eb..ddd2336772 100644 --- a/website/figures.md +++ b/website/figures.md @@ -4,6 +4,7 @@ The published diagrams are SVG source assets: - `public/assets/figures/rea-investigation-flow.svg` — 1774 × 887 viewBox. - `public/assets/figures/dx-ball-sound-pan-investigation.svg` — 1774 × 887 viewBox. +- `public/assets/figures/th04-bullet-ring.svg` — 1000 × 520 viewBox. Two original layout references were generated with the built-in image generation tool and reviewed visually. Their prompts are retained below. The final SVGs @@ -18,6 +19,14 @@ the maintained C and separate execution/compiler checks. Recorded tool requests, instruction excerpts and decoded byte reads appear as HTML text in the case study; source reconstruction is the agent's work informed by REA results. +## TH04 figure + +The TH04 figure is drawn directly as SVG from the byte-angle formula. It uses +16 bullets, zero template rotation and illustrative player direction 40, with +clockwise screen coordinates. The HTML overview separates REA's original-code +inspection from the reconstruction project's C++ and compiler replay. No +image generation or game screenshot is used for this mathematical figure. + ## Review Check spelling, arithmetic order, arrow directions and the separate verification diff --git a/website/public/assets/figures/th04-bullet-ring.svg b/website/public/assets/figures/th04-bullet-ring.svg new file mode 100644 index 0000000000..77a4887a95 --- /dev/null +++ b/website/public/assets/figures/th04-bullet-ring.svg @@ -0,0 +1,95 @@ + + TH04: spacing and aiming a ring of bullets + A full clockwise turn has 256 angle units. Sixteen bullets start at angles zero, sixteen, thirty-two, through 240. Adding an example player direction of forty turns all sixteen directions together; the first bullet points at the player. Template rotation is zero. + + + + + Fixed ring + First bullet: angle 0 + Aimed ring + First bullet: player direction + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Origin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Origin + + + Player + + 0, 16, 32, …, 240 + 40, 56, 72, …, 24 + + Same spacing: 256 ÷ 16 = 16 angle units = 22.5° + diff --git a/website/public/assets/styles.css b/website/public/assets/styles.css index 66bf75dbbc..ce65e9ad3b 100644 --- a/website/public/assets/styles.css +++ b/website/public/assets/styles.css @@ -841,6 +841,20 @@ pre code { .notion-bridge-flow { grid-template-columns: repeat(4, minmax(0, 1fr)); } +.th04-flow { + grid-template-columns: repeat(4, minmax(0, 1fr)); +} +.th04-overview { + margin-bottom: 3.2rem; +} +.th04-ring-figure img { + min-width: 680px; +} +.th04-preview img { + display: block; + width: 100%; + height: auto; +} .notion-channel { color: var(--accent); background: #edf2f8; @@ -994,7 +1008,8 @@ pre code { grid-template-columns: 1fr; } .flow-steps, - .notion-bridge-flow { + .notion-bridge-flow, + .th04-flow { grid-template-columns: 1fr; gap: 2rem; } diff --git a/website/public/index.html b/website/public/index.html index ce3bb6ff14..d81f55447b 100644 --- a/website/public/index.html +++ b/website/public/index.html @@ -232,6 +232,38 @@ +
+
+
+

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. +
+
+
+
+
diff --git a/website/public/showcase/index.html b/website/public/showcase/index.html index d8cc20bb39..88bae4637c 100644 --- a/website/public/showcase/index.html +++ b/website/public/showcase/index.html @@ -6,7 +6,7 @@ Case studies — REA @@ -76,6 +76,24 @@ Read the Notion case study
+
+

PC-98 DOS · Reconstruction

+
+

Understanding TH04's bullet patterns

+

+ Inspect the original 16-bit angle helper with REA. Match its + multiply, divide and coordinate operations to readable C++, then + see how they produce a ring aimed at the player. +

+
+ Original DOS code + REA instructions + Angle calculation + Bullet ring +
+ Read the TH04 case study +
+

Try a smaller example first.

diff --git a/website/public/showcase/th04/index.html b/website/public/showcase/th04/index.html new file mode 100644 index 0000000000..07de3370ae --- /dev/null +++ b/website/public/showcase/th04/index.html @@ -0,0 +1,637 @@ + + + + + + TH04 bullet patterns — REA + + + + + + + + + +
+
+ +

Case study · Touhou 4: Lotus Land Story

+

Reconstructing TH04's
bullet patterns.

+

+ A ring of bullets starts with a short angle calculation. Use REA to + inspect the original DOS function, then follow its instructions into + readable C++. +

+

PC-98 · 16-bit DOS · C++ and assembly

+ View the TH04 reconstruction +
+ +
+

From original instructions to checked source

+
    +
  1. + 01 · Original gameMAIN.EXEThe PC-98 executable and a reviewed bullet helper. +
  2. +
  3. + 02 · Inspect with REAInstructions + referencesCheck the loaded image, read the arithmetic and anchor it to file + bytes. +
  4. +
  5. + 03 · Read the C++Space → aim → rotateConnect each operation to the maintained reconstruction. +
  6. +
  7. + 04 · Check the source2,139 matching bytesRecorded compiler checks cover the containing bullet-add + code. +
  8. +
+
+ REA returns the original code and its analysis evidence. The TH04 + project supplies the maintained source and compiler checks. +
+
+ +
+ +
+
+

How a ring aims at the player

+

+ Elly's attack requests an aimed ring with an initial count of 16. + One helper calculates the direction of each bullet. The same ring + can face a fixed direction or turn toward the player. +

+
+
+ Your coding agent + +
+

+ Use REA to find how TH04 creates a ring of bullets and aims + it at the player. Explain the calculation and show the + code. +

+
+

+ An example prompt, with the original executable and reconstruction + checkout available locally. +

+

+ TH04 stores a full clockwise turn in 256 angle units. For 16 + bullets, each index adds 16 units: 0, 16, 32, …, 240. + Adding the player's direction rotates those positions together. +

+
+
+ Two diagrams of a 16-bullet ring. The fixed ring starts at angle zero. Adding a player direction of 40 rotates every direction by the same amount; the highlighted first bullet points toward the player. Both keep a spacing of 16 angle units, or 22.5 degrees. +
+
+ An illustration of the recovered angle math for count 16, player + direction 40 and template rotation 0. + Open figure +
+
+

+ The firing template in the recovered source +

+
+
+ Elly's ring attack · source excerpt +
+
bullet_template.angle = 0;
+bullet_template.group = BG_RING_AIMED;
+bullet_template.count = 16;
+bullet_template_tune();
+
+

+ These lines select the pattern before difficulty and performance + tuning. + Read the attack's source. +

+
+ +
+

What REA returns

+

+ The project already has a reviewed boundary for + bullet_velocity_and_angle_set(). Inspecting that + original function through REA returns its instructions, pseudocode + and references together. Here are three parts of the result that + explain the pattern. +

+
    +
  1. +

    Check the DOS image before reading its code

    +
    +
    +
    Agent → REA
    +
    open_binary
    +{"path": "MAIN.EXE"}
    +
    +inspect_native_load_image
    +{}
    +
    +
    +
    + REA → agent · selected fields +
    +
    status: "verified"
    +format: "dos-mz"
    +load_segment: 4096
    +header_bytes: 6144
    +module_bytes: 150114
    +
    +
    +

    + The check ties the loaded code and relocation records to the + supplied executable. The path above is shortened for display. +

    +
  2. +
  3. +

    Read the ring's multiply and divide

    +
    +
    +
    + Agent → REA · analyze_function +
    +
    {"procedure": "0x2cfc8"}
    +
    +
    +
    + REA → agent · instruction excerpt +
    +
    0x2d0eb: MOV AX, SI
    +0x2d0ed: SHL AX, 0x8
    +0x2d0f0: MOV DL, byte ptr [0x53af]
    +0x2d0f9: IDIV BX
    +
    +
    +

    + SI holds the bullet index. The shift multiplies + it by 256, then the division uses the count read from + DS:53AF. The maintained source names that field + bullet_template.count. The complete sequence + appears below. +

    +
  4. +
  5. +

    Find where the pattern turns toward the player

    +
    +
    +
    + Same function result · aim excerpt +
    +
    0x2d190: SUB AX, word ptr [0x53a6]
    +0x2d198: SUB AX, word ptr [0x53a4]
    +0x2d19d: CALLF 0x1000:1da8
    +0x2d1a2: ADD word ptr [BP + -0x2], AX
    +
    +
    +
    + Corresponding maintained C++ +
    +
    group_angle_offset += iatan2(
    +  player_pos.cur.y - bullet_template.origin.y,
    +  player_pos.cur.x - bullet_template.origin.x
    +);
    +
    +
    +

    + The instruction operands expose two coordinate differences and + a direction helper. Its return value is added to the relative + ring angle. Source names make those addresses readable; REA + lets the agent check the original operations behind them. +

    +
  6. +
+
+ +
+

From assembly to readable C++

+

+ Select a step to match the original instructions with the angle + calculation. This summary follows the aimed-ring path; the full + source also handles spreads, stacks and random patterns. +

+
+
+ + + + + +
+
+
+
+ REA · original 16-bit instructions +
+
0x2cfcf: MOV SI, word ptr [BP + 0x4]
+0x2d0eb: MOV AX, SI
+0x2d0ed: SHL AX, 0x8
+0x2d0f0: MOV DL, byte ptr [0x53af]
+0x2d0f4: MOV DH, 0x0
+0x2d0f6: PUSH DX
+0x2d0f7: CWD
+0x2d0f8: POP BX
+0x2d0f9: IDIV BX
+0x2d0fb: MOV word ptr [BP + -0x2], AX
+0x2d18d: MOV AX, [0x4650]
+0x2d190: SUB AX, word ptr [0x53a6]
+0x2d194: PUSH AX
+0x2d195: MOV AX, [0x464e]
+0x2d198: SUB AX, word ptr [0x53a4]
+0x2d19c: PUSH AX
+0x2d19d: CALLF 0x1000:1da8
+0x2d1a2: ADD word ptr [BP + -0x2], AX
+0x2d1b9: MOV AL, byte ptr [BP + -0x2]
+0x2d1bc: ADD AL, byte ptr [0x53ad]
+0x2d1c0: MOV [0xbcc8], AL
+
+
+
+ Readable C++ · aimed-ring summary +
+
unsigned char aimed_ring_angle(
+    int index, int count,
+    int player_direction,
+    unsigned char rotation)
+{
+    int angle = index;
+    angle = (angle * 256) / count;
+    angle += player_direction;
+    angle += rotation;
+    return (unsigned char)angle;
+}
+
+
+
+

+ 01 · Read the bullet index. The stack + argument is loaded into SI. In a 16-bullet ring, + this member index runs from 0 through 15. +

+ + + + +
+
+

+ The assembly selects the aimed-ring branch, aim calculation and + final store. The C++ above is a readable summary. Compiler checks + below apply to the maintained source in the linked project. +

+
+ Read the maintained ring and aim source +
+
+ Ring macro · TH04 branch, excerpt +
+
angle_offset = (i * BULLET_ANGLE_FULL_TURN) / count;
+if (i >= (count - 1)) {
+    group_complete = true;
+}
+goto aim_or_no_aim;
+
+
+
+ Angle and velocity · source excerpt +
+
aim:
+    group_angle_offset += iatan2(
+        (player_pos.cur.y - bullet_template.origin.y),
+        (player_pos.cur.x - bullet_template.origin.x)
+    );
+
+no_aim:
+    vector2_near(
+        bullet_template.velocity,
+        (group_angle_offset + bullet_template.angle),
+        speed
+    );
+    bullet_spawn_angle = (group_angle_offset + bullet_template.angle);
+
+

+ Ring macro + · + Aim and velocity source + · + Angle representation +

+
+
+ +
+

Checking the maintained source

+

+ The TH04 project checks this compiler-sensitive C++ with its + pinned Turbo C++ 4.0J toolchain. Recorded checks cover the + complete bullet-add source owner containing this helper. +

+
+
+

2,139 matching bytes

+

+ The rebuilt code matches the complete original target extent. + The comparison also checks the MAP contribution and + overlapping relocation. +

+
+
+

Two clean builds

+

+ Two isolated compiler runs produce the same matching result. + The recorded input hashes match the maintained bullet source + shown here. +

+
+
+

+ Recorded on 3 October 2026. + Read the compiler checks. +

+
+ Target identity and analysis scope +
+ + + + + + + + + + + + + + + + + + + +
Original targetMAIN.EXE, 156,258 bytes, DOS MZ
Helper entry0x2cfc8 in REA's loaded image
Original file offset + 0x1e7c8, returned by + address_to_file_offset +
Recorded code inspectionREA 4.1.0 · 7 October 2026
+
+

+ REA verified the static DOS load image at load segment + 0x1000. Its addresses describe that analysis image. + The function result reports 503 body bytes in two ranges across + a 517-byte span; the selected instructions above lie in those + reported ranges. +

+

+ The source names and compiler checks come from TH04 checkpoint + 0d72e980. Earlier reconstruction observations used + the project's own analysis scripts; this page adds a fresh REA + inspection of the same original target. The supplied game's + identity is pinned by its repository manifest, with independent + pristine-dump provenance still open. +

+

+ The figure illustrates the angle calculation. Full-game + controls, timing and PC-98 hardware behavior have separate + runtime checks in the reconstruction project. +

+
+
+ +
+

The full TH04 reconstruction

+

+ The project builds the game's four DOS products from maintained + C++ and assembly. Beyond bullet generation, the source covers + stages, bosses, rendering, input, menus, endings and score + handling. +

+

+ Explore the TH04 repository +

+ +
+
+
+
+ +

+ +