78 lines
2.7 KiB
Python
78 lines
2.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Deterministic local checks for the three design-direction coded slices."""
|
|
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import json
|
|
import struct
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
DIRECTIONS = {
|
|
"ledger-studio": ("ledger-desktop.png", "ledger-mobile.png"),
|
|
"signal-trace": ("signal-desktop.png", "signal-mobile.png"),
|
|
"field-manual": ("manual-desktop.png", "manual-mobile.png"),
|
|
}
|
|
REQUIRED = (
|
|
"개념을 알고 있어요",
|
|
"증상만 알고 있어요",
|
|
"Predict",
|
|
"Observe",
|
|
"Compare",
|
|
"Explain",
|
|
"Transfer",
|
|
)
|
|
|
|
|
|
def sha256(path: Path) -> str:
|
|
return hashlib.sha256(path.read_bytes()).hexdigest()
|
|
|
|
|
|
def png_size(path: Path) -> tuple[int, int]:
|
|
raw = path.read_bytes()[:24]
|
|
if len(raw) != 24 or raw[:8] != b"\x89PNG\r\n\x1a\n" or raw[12:16] != b"IHDR":
|
|
raise AssertionError(f"not a PNG: {path}")
|
|
return struct.unpack(">II", raw[16:24])
|
|
|
|
|
|
def main() -> None:
|
|
records = []
|
|
previews = ROOT / "previews"
|
|
for direction, (desktop_name, mobile_name) in DIRECTIONS.items():
|
|
folder = ROOT / "directions" / direction
|
|
html = folder / "index.html"
|
|
concept = folder / "concept.yaml"
|
|
assert html.is_file(), html
|
|
assert concept.is_file(), concept
|
|
source = html.read_text(encoding="utf-8")
|
|
for marker in REQUIRED:
|
|
assert marker in source, f"{direction}: missing {marker}"
|
|
assert "focus-visible" in source, f"{direction}: focus style missing"
|
|
assert "prefers-reduced-motion" in source, f"{direction}: reduced-motion missing"
|
|
assert "http://" not in source and "https://" not in source, f"{direction}: external dependency"
|
|
desktop = previews / desktop_name
|
|
mobile = previews / mobile_name
|
|
assert png_size(desktop) == (1280, 1100), f"{desktop}: wrong dimensions"
|
|
assert png_size(mobile) == (390, 844), f"{mobile}: wrong dimensions"
|
|
records.append({
|
|
"direction": direction,
|
|
"coded_slice_sha256": sha256(html),
|
|
"concept_sha256": sha256(concept),
|
|
"desktop_sha256": sha256(desktop),
|
|
"mobile_sha256": sha256(mobile),
|
|
})
|
|
gallery = previews / "comparison.png"
|
|
assert gallery.is_file(), gallery
|
|
width, height = png_size(gallery)
|
|
assert width >= 1500 and height >= 1000, "comparison preview is not full-size"
|
|
print(json.dumps({
|
|
"status": "pass",
|
|
"representative_screen": "dual-entry-shared-lab",
|
|
"directions": records,
|
|
"comparison": {"sha256": sha256(gallery), "size": [width, height]},
|
|
}, ensure_ascii=False, sort_keys=True))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|