docs(review): the Blender-vs-in-game comparison lives in Screenshots/README.md

Merged COMPARISON.md into the review README as a generated section between
<!-- blender-comparison:begin/end --> markers, so there is one place to look and one place
to sign off. Tools/build_comparison_md.py rewrites only that block - the hand-written
sections around it are untouched - and formats the file with prettier afterwards, because a
generated table is never byte-identical to prettier's output and the repo gates on
--check.

Run it after every capture or Blender render; it is the routine that keeps the page current
with new images rather than a one-off export.
This commit is contained in:
zwitschi committed 2026-11-09 16:10:47 +01:00
1 parent cb94438e0d
commit 046e2c8b9e
12 files changed
+317 -61

No files matched your search

+41 -8
View File
@@ -19,10 +19,14 @@ from __future__ import annotations
import os
import re
import shutil
import subprocess
DEMO_DIR = "Screenshots/demo"
BLENDER_DIR = "Screenshots/blender"
OUT = "Screenshots/COMPARISON.md"
OUT = "Screenshots/README.md"
BEGIN = "<!-- blender-comparison:begin -->"
END = "<!-- blender-comparison:end -->"
# Shots that are about a modelled asset pair with a Blender render; the street and
# building shots have no Blender counterpart because those meshes come from the Geo
@@ -94,9 +98,10 @@ def build():
shots = demo_shots()
renders = blender_renders()
lines = [
"# Blender vs in-game",
"## Blender vs in-game",
"",
"Generated by `Tools/build_comparison_md.py` — do not edit by hand.",
"Regenerated by `Tools/build_comparison_md.py`; everything between the markers is",
"rewritten, so edit outside them.",
"",
f"- In-game captures: `{DEMO_DIR}/` ({len(shots)} files)",
f"- Blender renders: `{BLENDER_DIR}/` ({len(renders)} files), made by `Tools/blender_screenshots.py`",
@@ -105,7 +110,7 @@ def build():
"import problem, not a taste problem: scale, material colour, missing parts and split",
"systems all show up here before they show up in a review.",
"",
"## Side by side",
"### Side by side",
"",
"| In-game | Blender | Shot |",
"| --- | --- | --- |",
@@ -128,7 +133,7 @@ def build():
f"{matched} of {len(shots)} in-game captures have a Blender counterpart; the rest are",
"street and building shots whose meshes come from the Geo pipeline rather than a .blend.",
"",
"## Signoff",
"### Signoff",
"",
"One row per in-game screen. `—` in Blender means there is nothing to compare against.",
"",
@@ -148,10 +153,38 @@ def build():
"in [README.md](README.md); this page exists to compare Blender against the engine.",
"",
]
os.makedirs(os.path.dirname(OUT) or ".", exist_ok=True)
block = "\n".join([BEGIN, ""] + lines + ["", END])
if os.path.exists(OUT):
with open(OUT) as handle:
existing = handle.read()
else:
existing = "# Screenshots\n"
# The comparison lives inside the main review README, between markers, so it is
# regenerated in place: the rest of the README is hand-written and must not be
# rewritten by a tool.
if BEGIN in existing and END in existing:
head = existing[:existing.index(BEGIN)]
tail = existing[existing.index(END) + len(END):]
updated = head + block + tail
else:
updated = existing.rstrip("\n") + "\n\n" + block + "\n"
with open(OUT, "w") as handle:
handle.write("\n".join(lines))
print(f"wrote {OUT} ({len(shots)} shots, {matched} paired, {len(renders)} renders)")
handle.write(updated)
# The README is checked by `prettier --check` in the repo's gates, and a generated
# markdown table is never byte-identical to what prettier produces. Format it here so
# regenerating the section cannot leave the tree failing a format check.
formatter = shutil.which("npx")
if formatter:
try:
subprocess.run([formatter, "--no-install", "prettier", "--write", OUT],
check=False, capture_output=True, timeout=120)
except (OSError, subprocess.SubprocessError):
pass
print(f"updated {OUT} ({len(shots)} shots, {matched} paired, {len(renders)} renders)")
return 0