#!/usr/bin/env python3 # ═════════════════════════════════════════════════════════════════════════════ # PLAYER COMPUTER — Byte Identical (16/32) # by Gene Kogan · 2026 · https://genekogan.com/player_computer/byte_identical # # A film renders itself on its own terminal and plays its git hash as the melody. # # This single file IS the piece: it draws every frame, synthesizes every sound, # and muxes them into the final video with ffmpeg. No other project files are # needed. You (or your agent) are invited to make a VARIATION of it: # # Generate a variation of this music video using only code. # Start from https://genekogan.com/player_computer/code/byte_identical.py.txt # # The original render (for reference, yours should differ): # video: https://genekogan.com/player_computer/media/byte_identical.mp4 # cover: https://genekogan.com/player_computer/media/byte_identical.jpg # # Requirements: python3, numpy, pillow, and ffmpeg on PATH. # pip install numpy "pillow<13" # Speech/vocals (in pieces that have them) use the macOS `say` command; on # other platforms swap in espeak-ng / any TTS at the say_wav()/speak() calls, # or mute those lines. git provenance stamps degrade gracefully outside a repo. # Run: python3 byte_identical.py (writes frames/, audio/, and the final mp4 # next to the script; writes ~8 GB of frames, # takes 5-15 min on a modern machine) # ═════════════════════════════════════════════════════════════════════════════ """ player_computer_final — "BYTE IDENTICAL" (./spiral 10) Return to: the crypto turn (Brain Drops 2021, the covenant era) and poop's own first law. On a protocol show, the deepest thing this studio can say about provenance is what it already practices: same inputs, byte-identical output. The mp4 is one crystallization; render.py is the work. So the film is a terminal rendering the film. The screen shows this render's own source scrolling by (the file reads itself), the frame counter, the seed, the git sha — and a preview window that contains the terminal that contains the preview, droste-deep. Section by section the camera commits to the preview and pushes in; each landing is the same terminal one level down. The git sha is not just displayed: its seven hex characters are mapped to scale degrees and ARE the melody, and its bits are the kick pattern. Then, mid- liturgy: nondeterminism detected — one pixel, red channel, off by one. Cosmic radiation. It happens more than anyone admits. Render again. Composition: engine : pure-function frame loop (droste recursion inside the frame, zoom-commit camera) + audio-first content: tts-voices (Zarvox liturgy / Whisper doubt / Bad News alarm) x effects-post (CRT: scanlines, phosphor, flicker) x a hash-driven groove (sha bits -> kick pattern, sha hex -> melody) Final-curation cut (player_computer): recomposed from the 108 s ./spiral original down to ~1 minute — one liturgy rule per commit instead of two, the "change one character" tangent dropped, "Impossible." dropped, boot / sha-solo / re-render / endcard holds shortened. The arc (boot -> liturgy droste commits -> sha reveal+solo -> cosmic-ray alarm -> re-render -> byte identical -> "I remember the pixel" -> provenance endcard) is intact. FINAL CUT (player_computer_final): * Native 1920x1080. The film is authored in 1280x720 *terminal units*; S = H/720 turns them into pixels at rasterisation time (ScaledDraw proxy, fonts scaled once in font()). The droste is a ratio — PREV/W is unchanged — so the zoom-commit math is the same fix, at a different density. Scanlines and grain are generated on the 720-row authoring grid and NEAREST-blown-up so the CRT stock stays the same size on screen. * NOTHING is stripped. The frame counter, the seed readout, the provenance panel, the render bar, the log tail: on this piece the renderer talking IS the fiction. That is the whole idea. * Title flash: the boot sequence already lands on B Y T E I D E N T I C A L; the show now boots under it, "PLAYER COMPUTER" typed as the machine's own banner line, and the boot beat is lengthened to give it ~2s. Run from repo root: python3 renders/player_computer_final/byte_identical/render.py --sheet python3 renders/player_computer_final/byte_identical/render.py --jobs 3 """ import argparse, datetime, math, os, random, subprocess, wave from pathlib import Path import numpy as np from PIL import Image, ImageDraw, ImageFont, ImageFilter NAME = "byte_identical" TITLE = "BYTE IDENTICAL" # ── delivery scale ─────────────────────────────────────────────────────────── # Everything below is authored in *terminal units*: a 1280x720 screen. AW/AH # are those units; W/H are real delivery pixels; S = H/AH is the one number the # whole look scales by. Coordinates stay in terminal units and the ScaledDraw # proxy multiplies them at rasterisation time; font() scales sizes once, so # nothing is scaled twice. The droste depends only on the RATIO PREV/AW, which # is untouched — the zoom-commit composite is the same arithmetic, denser. AW, AH = 1280, 720 W, H, FPS = 1920, 1080, 30 S = H / AH PU = max(2, int(round(S))) # "one pixel" of the terminal, in real px def P(v): return int(round(v * S)) def B(r): return r * S def _sxy(v, s): if isinstance(v, (list, tuple)): return [_sxy(u, s) for u in v] return v * s class ScaledDraw: """ImageDraw proxy: geometry in terminal units, pixels out. Only the first positional arg (xy) and the `width` kwarg are touched — arc/chord/pieslice take angles positionally and those must pass through untouched.""" __slots__ = ("_d", "_s") _GEOM = frozenset(("line", "rectangle", "rounded_rectangle", "ellipse", "polygon", "arc", "chord", "pieslice", "point", "text")) def __init__(self, d, s): self._d, self._s = d, s def __getattr__(self, name): f = getattr(self._d, name) if name not in self._GEOM: return f s = self._s def wrapped(xy, *a, **kw): w = kw.get("width") if w is not None: kw["width"] = max(2, int(round(w * s))) return f(_sxy(xy, s), *a, **kw) return wrapped def mkdraw(im): d = ImageDraw.Draw(im) return d if S == 1.0 else ScaledDraw(d, S) OUT = Path(__file__).parent FRAMES = OUT / "frames"; FRAMES.mkdir(exist_ok=True) AUD = OUT / "audio"; AUD.mkdir(exist_ok=True) ROOT = Path(__file__).resolve().parent # standalone: was repo root (used for git provenance) FONTS = ROOT / "fonts" SR = 44100 GAP = 0.34 VOICES = {"lit": ("Zarvox", 156), "doubt": ("Whisper", 126), "alarm": ("Bad News", 142)} NAMES = {"lit": "THE LITURGIST", "doubt": "THE DOUBT", "alarm": "MONITOR"} SUBCOL = {"lit": (140, 255, 190), "doubt": (180, 210, 255), "alarm": (255, 150, 140)} # the sha of the repo at build time — displayed, stamped, and PLAYED try: SHA = subprocess.check_output(["git", "rev-parse", "--short", "HEAD"], cwd=ROOT).decode().strip() except Exception: SHA = "0ff1ine" SHA7 = (SHA + "0000000")[:7] # this file reads itself for the scroll SELF_LINES = Path(__file__).read_text().splitlines() # zoom: beats tagged z start a fresh full view and commit into the preview # (named SCRIPT, not S — S is the delivery scale factor above) SCRIPT = [ {"speaker": None, "text": "", "dur": 3.8, "boot": True}, {"speaker": "lit", "z": 1, "text": "Rule five. Same inputs, byte identical output, forever."}, {"speaker": "doubt", "z": 2, "text": "If you render me again, am I the same film?"}, {"speaker": "lit", "z": 2, "text": "Rule eleven. Provenance is stamped in: git hash, timestamp."}, {"speaker": "doubt", "z": 3, "text": "The timestamp changes. So I am almost the same film. The almost is where I live."}, {"speaker": "lit", "z": 3, "sha_reveal": True, "text": "The git hash: seven characters. They are the melody you are hearing."}, {"speaker": None, "text": "", "dur": 4.2, "sha_solo": True}, {"speaker": "alarm", "alarm": True, "text": "Nondeterminism detected. One pixel, off by one."}, {"speaker": "lit", "alarm": True, "text": "Cosmic radiation. A bit flipped in transit. It happens more than anyone admits."}, {"speaker": "doubt", "alarm": True, "text": "So the universe is also an author."}, {"speaker": "lit", "rerender": True, "text": "Render again."}, {"speaker": None, "text": "", "dur": 3.2, "rerender": True}, {"speaker": "lit", "z": 4, "text": "Byte identical. As I said."}, {"speaker": "doubt", "z": 4, "text": "As you said. And yet, I remember the pixel."}, {"speaker": None, "text": "", "dur": 5.0, "endcard": True}, ] # ════════════════════════════════════════════════════════════════════════════ # ── portable font resolution (cross-platform; replaces the repo-only lookup) ── import warnings as _warnings _FONT_ALIASES = { "Menlo.ttc": ["Menlo.ttc", "DejaVuSansMono.ttf", "consola.ttf", "LiberationMono-Regular.ttf"], "Georgia.ttf": ["Georgia.ttf", "georgia.ttf", "DejaVuSerif.ttf", "LiberationSerif-Regular.ttf"], "Georgia Bold.ttf": ["Georgia Bold.ttf", "georgiab.ttf", "DejaVuSerif-Bold.ttf", "LiberationSerif-Bold.ttf"], "Georgia Italic.ttf": ["Georgia Italic.ttf", "georgiai.ttf", "DejaVuSerif-Italic.ttf", "LiberationSerif-Italic.ttf"], "Impact.ttf": ["Impact.ttf", "impact.ttf", "Anton-Regular.ttf", "DejaVuSans-Bold.ttf"], "Helvetica.ttc": ["Helvetica.ttc", "arial.ttf", "Arial.ttf", "DejaVuSans.ttf", "LiberationSans-Regular.ttf"], } def _font_dirs(): here = Path(__file__).resolve() dirs = [here.parent / "fonts"] + [p / "fonts" for p in list(here.parents)[1:4]] try: home = Path.home() except Exception: home = None dirs += [Path("/System/Library/Fonts"), Path("/System/Library/Fonts/Supplemental"), Path("/Library/Fonts"), Path("C:/Windows/Fonts"), Path("/usr/share/fonts"), Path("/usr/local/share/fonts")] if home: dirs += [home / "Library/Fonts", home / ".fonts", home / ".local/share/fonts"] return dirs _FONT_DIRS = _font_dirs() _FF = {} def _find_font(name): """Path of a usable font file for `name`, or None. Cached per name.""" if name in _FF: return _FF[name] found = None for cand in _FONT_ALIASES.get(name, [name]): for d in _FONT_DIRS: if not d.is_dir(): continue p = d / cand if p.is_file(): found = p; break try: found = next(iter(d.rglob(cand)), None) except OSError: found = None if found: break if found: break if found is None: _warnings.warn(f"font {name} not found in fonts/ or system font dirs; " f"using Pillow default (layout will differ)") _FF[name] = found return found def _load_font(p, size): """ImageFont for path `p` (from _find_font) at `size`; Pillow default if p is None.""" if p is None: try: return ImageFont.load_default(size=int(size)) except TypeError: return ImageFont.load_default() return ImageFont.truetype(str(p), size) _FC = {} def font(size, bold=False): key = (size, bold) if key in _FC: return _FC[key] _FC[key] = _load_font(_find_font("Menlo.ttc"), max(1, P(size))) return _FC[key] def gfont(kind, size): key = (kind, size) if key in _FC: return _FC[key] fp = {"bold": _find_font("Georgia Bold.ttf"), "ital": _find_font("Georgia Italic.ttf")}[kind] _FC[key] = _load_font(fp, max(1, P(size))) return _FC[key] GREEN = (120, 235, 160) DGREEN = (50, 110, 75) AMBER = (235, 195, 110) RED = (240, 110, 100) BG = (8, 12, 10) PREV = (704, 84, 1216, 372) # the preview window rect — exactly 16:9 PREVP = tuple(P(v) for v in PREV) # …in real pixels, for the paste/zoom math # round 2: the frame went 14:9 -> 16:9. The preview rect is re-cut to the # NEW aspect (512x288) so the droste recursion nests without distortion, and # the right column is re-laid at the wider right margin instead of stretched. def draw_terminal(t, beat, bt01, depth, alarm_amt, pixel_on, rerender_f): """One level of the droste. depth 0 = innermost (static).""" img = Image.new("RGB", (W, H), BG) d = mkdraw(img) if depth == 0: for k in range(40): rng = random.Random(k + int(t * 8)) x, y = rng.randint(0, AW), rng.randint(0, AH) d.rectangle([(x, y), (x + 1, y + 1)], fill=DGREEN) d.text((AW // 2 - 60, AH // 2 - 10), "· deeper ·", font=font(18), fill=DGREEN) return img # top bar d.rectangle([(0, 0), (AW, 44)], fill=(14, 22, 17)) d.text((20, 12), "poop renderer v5 — provenance liturgy", font=font(17), fill=GREEN) frame_no = int(t * FPS) d.text((900, 12), f"frame {frame_no:05d} seed {7000 + frame_no}", font=font(15), fill=AMBER) blink = int(t * 2) % 2 == 0 d.text((1204, 12), "REC" if blink else " ", font=font(15), fill=RED) # left: the source, scrolling — this file, reading itself y0 = 64 start = int(t * 2.2) % max(1, len(SELF_LINES) - 30) for k in range(26): ln = SELF_LINES[(start + k) % len(SELF_LINES)][:72] col = DGREEN if any(w in ln for w in ("def ", "class ", "import ")): col = GREEN if "SHA" in ln or "seed" in ln.lower(): col = AMBER if depth >= 2: d.text((24, y0 + k * 22), ln, font=font(14), fill=col) else: d.rectangle([(24, y0 + k * 22 + 5), (24 + min(660, 9 * len(ln)), y0 + k * 22 + 12)], fill=col) # line numbers gutter for k in range(26): if depth >= 2: d.text((2, y0 + k * 22), f"{(start + k) % len(SELF_LINES):4d}", font=font(11), fill=(40, 70, 52)) # right: preview window (the recursion) d.rectangle([(PREV[0] - 4, PREV[1] - 24), (PREV[2] + 4, PREV[3] + 4)], outline=DGREEN, width=2) d.text((PREV[0] + 4, PREV[1] - 21), "PREVIEW — live", font=font(13), fill=GREEN) inner = draw_terminal(t, beat, bt01, depth - 1, alarm_amt, pixel_on, rerender_f) inner = inner.resize((PREVP[2] - PREVP[0], PREVP[3] - PREVP[1]), Image.BILINEAR) img.paste(inner, (PREVP[0], PREVP[1])) d = mkdraw(img) # the rogue pixel + magnifier if pixel_on: px, py = PREV[0] + 287, PREV[1] + 143 d.rectangle([(px, py), (px + 1, py + 1)], fill=(255, 40, 40)) mr = 44 mx, my = px + 90, py + 80 d.ellipse([(mx - mr, my - mr), (mx + mr, my + mr)], outline=RED, width=3) d.line([(px + 4, py + 4), (mx - mr * .7, my - mr * .7)], fill=RED, width=2) d.rectangle([(mx - 5, my - 5), (mx + 5, my + 5)], fill=(255, 40, 40)) d.text((mx - 40, my + mr + 6), "0xFF0000?!", font=font(13), fill=RED) # right-mid: provenance block py0 = 392 d.rectangle([(704, py0), (1216, py0 + 160)], outline=DGREEN, width=2) d.text((708, py0 + 10), "PROVENANCE", font=font(14), fill=GREEN) rows = [("generator", "renders/player_computer_final/byte_identical/render.py"), ("git", SHA7 + " (also: the melody)"), ("size", f"{W}x{H} @ {FPS}fps · 16:9"), ("law", "same inputs -> byte-identical output")] for k, (a, b) in enumerate(rows): d.text((708, py0 + 38 + k * 26), f"{a:>9}:", font=font(14), fill=DGREEN) d.text((792, py0 + 38 + k * 26), b[:50], font=font(14), fill=AMBER if a == "git" else GREEN) # sha as giant glyphs when revealed / soloing if beat.get("sha_reveal") or beat.get("sha_solo"): hot = int(t * 3.2) % 7 for k, ch in enumerate(SHA7): col = (255, 240, 170) if k == hot else AMBER d.text((757 + k * 58, py0 + 116), ch, font=font(44), fill=col) if k == hot: d.rectangle([(755 + k * 58, py0 + 164), (799 + k * 58, py0 + 168)], fill=col) # bottom: progress + log by0 = 600 d.text((24, by0 - 6), "render", font=font(14), fill=DGREEN) d.rectangle([(100, by0 - 4), (1216, by0 + 14)], outline=DGREEN, width=2) if rerender_f is not None: pf = rerender_f lab = "re-rendering…" else: pf = (t / 64.0) % 1.0 lab = "rendering" d.rectangle([(102, by0 - 2), (102 + int(1112 * pf), by0 + 12)], fill=(40, 140, 90)) d.text((104 + int(1112 * pf), by0 - 6), "█" if blink else " ", font=font(14), fill=GREEN) logs = ["frame ok · frame ok · frame ok", f"sha {SHA7} verified", "audio: hash-beat locked", "no networks were consulted"] for k, lg in enumerate(logs): d.text((24, by0 + 30 + k * 20), "> " + lg, font=font(13), fill=(60, 130, 92) if k else GREEN) d.text((24, by0 + 30 + 4 * 20), "> _" if blink else ">", font=font(13), fill=GREEN) # alarm wash if alarm_amt > 0: ov = Image.new("RGB", (W, H), (120, 20, 16)) img = Image.blend(img, ov, alarm_amt * .28) d = mkdraw(img) if int(t * 3) % 2 == 0: d.rectangle([(0, 44), (AW, 78)], fill=(90, 16, 12)) d.text((AW // 2 - 200, 50), "! NONDETERMINISM DETECTED !", font=font(20), fill=(255, 200, 190)) return img def crt(img, i, glow=True): a = np.asarray(img).astype(np.float32) # phosphor glow if glow: g = np.asarray(img.filter(ImageFilter.GaussianBlur(B(2)))).astype(np.float32) a = np.clip(a * .82 + g * .34, 0, 255) # scanlines. The period is 3 *terminal* rows — mapping delivery rows back # through S keeps the CRT stock the same coarseness at any resolution. if S == 1.0: a[::3, :, :] *= .78 else: a[(np.arange(H) / S).astype(int) % 3 == 0, :, :] *= .78 # slight vertical roll flicker a *= (0.965 + 0.035 * math.sin(i * .37)) # vignette yy, xx = np.mgrid[0:H, 0:W] nx = (xx - W / 2) / (W / 2); ny = (yy - H / 2) / (H / 2) rr = np.sqrt(nx ** 2 + ny ** 2) / 1.42 a *= np.clip(1.0 - 0.5 * rr ** 2.1, 0, 1)[..., None] rng = np.random.RandomState(7000 + i) if S == 1.0: a += rng.normal(0, 2.6, a.shape) else: # grain is a look, not a resolution: authored on the 720-row grid and # blown up nearest-neighbour so a speck covers the same screen area gn = rng.normal(0, 2.6, (AH, AW, 3)) * 8.0 + 128.0 gi = Image.fromarray(np.clip(gn, 0, 255).astype(np.uint8)) a += (np.asarray(gi.resize((W, H), Image.NEAREST), np.float32) - 128.0) / 8.0 return Image.fromarray(np.clip(a, 0, 255).astype(np.uint8)) # ════════════════════════════════════════════════════════════════════════════ # AUDIO — the sha plays itself # ════════════════════════════════════════════════════════════════════════════ # ── portable TTS ───────────────────────────────────────────────────────────── # Voice tiers: macOS `say` (the canonical voices) -> espeak-ng / espeak -> # Windows SAPI -> timed silence (chars/wpm heuristic). This piece's timeline # is duration-driven (build_timeline reads each clip's real length), so on a # different engine the film re-times itself at runtime — a different # performance of the same score, by design. The silence tier must still write # a wav at `out` so dur_of()/load_wav() work; delete audio/l_*.wav (or run # --retts) to re-voice once an engine is available. # Force a tier with POOP_TTS=say|espeak|sapi|none. def _tts_lang(voice): v = str(voice) if "Spanish" in v: return "es-mx" if "Mexico" in v else "es" if "Portuguese" in v: return "pt-br" if "Brazil" in v else "pt" if "English (UK)" in v: return "en-gb" return "en-us" def _tts_engine(): import shutil, platform want = os.environ.get("POOP_TTS", "").strip().lower() if want: return want if shutil.which("say"): return "say" if shutil.which("espeak-ng") or shutil.which("espeak"): return "espeak" if platform.system() == "Windows": return "sapi" return "none" def tts(voice, rate, text, out): import shutil, sys, base64 eng = _tts_engine() tmp = out.with_suffix(".tts.wav") try: if eng == "say": aiff = out.with_suffix(".aiff") subprocess.run(["say", "-v", voice, "-r", str(rate), "-o", str(aiff), text], check=True) subprocess.run(["ffmpeg", "-y", "-i", str(aiff), "-ar", str(SR), "-ac", "1", str(out)], check=True, capture_output=True) aiff.unlink(missing_ok=True) return if eng == "espeak": exe = shutil.which("espeak-ng") or shutil.which("espeak") or "espeak-ng" subprocess.run([exe, "-v", _tts_lang(voice), "-s", str(int(rate)), "-w", str(tmp), str(text)], check=True) elif eng == "sapi": r = max(-10, min(10, round((int(rate) - 175) / 25))) esc = str(text).replace("'", "''") ps = ("Add-Type -AssemblyName System.Speech;" "$s=New-Object System.Speech.Synthesis.SpeechSynthesizer;" f"$s.Rate={r};$s.SetOutputToWaveFile('{tmp}');" f"$s.Speak('{esc}');$s.Dispose()") enc = base64.b64encode(ps.encode("utf-16-le")).decode() subprocess.run(["powershell", "-NoProfile", "-EncodedCommand", enc], check=True) else: raise RuntimeError("no speech engine") subprocess.run(["ffmpeg", "-y", "-i", str(tmp), "-ar", str(SR), "-ac", "1", str(out)], check=True, capture_output=True) return except Exception as e: dur = max(0.6, len(str(text)) / (max(60, int(rate)) * 5.0 / 60.0)) print(f'[tts] {eng}: {e} — timed silence ({dur:.2f}s): ' f'"{str(text)[:48]}" (delete audio/l_*.wav to re-voice later)', file=sys.stderr) with wave.open(str(out), "wb") as wf: wf.setnchannels(1); wf.setsampwidth(2); wf.setframerate(SR) wf.writeframes(b"\x00\x00" * int(dur * SR)) finally: tmp.unlink(missing_ok=True) def dur_of(p): r = subprocess.run(["ffprobe", "-v", "quiet", "-show_entries", "format=duration", "-of", "csv=p=0", str(p)], capture_output=True, text=True) try: return float(r.stdout.strip()) except Exception: return 1.0 def load_wav(p): with wave.open(str(p), "r") as wf: return np.frombuffer(wf.readframes(wf.getnframes()), dtype=np.int16).astype(np.float64) / 32768.0 def build_timeline(force_tts=False): beats, t = [], 0.0 for i, b in enumerate(SCRIPT): rec = dict(b); rec["idx"] = i if not b.get("text"): d = b.get("dur", 1.2) rec.update(start=t, dur=d, wav=None) beats.append(rec); t += d continue voice, rate = VOICES[b["speaker"]] wav = AUD / f"l_{i:03d}.wav" if force_tts or not wav.exists(): tts(voice, rate, b["text"], wav) d = dur_of(wav) rec.update(start=t, dur=d, wav=str(wav)) beats.append(rec) t += d + GAP return beats, t + 1.0 def music_bed(total, beats, t_solo, t_alarm, t_rerender): n = int(SR * total) m = np.zeros(n) BPM = 112.0; spb = 60 / BPM # sha -> patterns hexv = [int(c, 16) if c in "0123456789abcdef" else 7 for c in SHA7] bits = [] for v in hexv: bits += [(v >> k) & 1 for k in (3, 2, 1, 0)] penta = [220.0, 261.63, 293.66, 329.63, 392.0] scale16 = [penta[k % 5] * (2 ** (k // 5)) for k in range(16)] nbeats = int(total / spb) for b in range(nbeats): t0 = b * spb alarm = t_alarm <= t0 < t_rerender # kick from sha bits if bits[b % len(bits)] and not alarm: ln = int(.26 * SR); lt = np.arange(ln) / SR f = 110 * np.exp(-lt * 26) + 44 m[int(t0 * SR):int(t0 * SR) + ln] += .5 * np.sin(2 * np.pi * np.cumsum(f) / SR)[:min(ln, n - int(t0 * SR))] * np.exp(-lt * 9)[:min(ln, n - int(t0 * SR))] # tick pos = int((t0 + spb / 2 * 1.06) * SR) ln = int(.04 * SR) if pos + ln < n: lt = np.arange(ln) / SR m[pos:pos + ln] += (.09 if not alarm else .05) * np.sin(2 * np.pi * (2400 if not alarm else 1200) * lt) * np.exp(-lt * 240) # sha melody: one hex char per beat ch = hexv[b % 7] f0 = scale16[ch] solo = t_solo <= t0 < t_solo + 4.3 vol = .16 if solo else .07 if alarm: vol = .03 ln = int(.6 * SR) pos = int(t0 * SR) if pos + 100 < n: ln = min(ln, n - pos) lt = np.arange(ln) / SR mod = np.sin(2 * np.pi * f0 * 2.01 * lt) * (1.8 if solo else 1.1) * np.exp(-lt * 5) m[pos:pos + ln] += vol * np.exp(-lt * (3 if solo else 5)) * np.sin(2 * np.pi * f0 * lt + mod) # alarm drone # alarm section: dissonant beating pair a0, a1 = int(t_alarm * SR), int(t_rerender * SR) if a1 > a0: lt = np.arange(a1 - a0) / SR env = np.clip(lt / .8, 0, 1) m[a0:a1] += .07 * env * (np.sin(2 * np.pi * 138 * lt) + np.sin(2 * np.pi * 141.3 * lt)) # sub floor throughout tt = np.arange(n) / SR m += .04 * np.sin(2 * np.pi * 55 * tt) * (0.7 + 0.3 * np.sin(2 * np.pi * .08 * tt)) return m def duck_envelope(total, beats, depth=0.6, pad=0.16): cr = 400 n = int(total * cr) e = np.zeros(n) for b in beats: if not b.get("wav"): continue a = max(0, int((b["start"] - pad) * cr)); z = min(n, int((b["start"] + b["dur"] + pad) * cr)) e[a:z] = 1.0 kk = np.ones(int(.22 * cr)) / int(.22 * cr) e = np.clip(np.convolve(e, kk, mode="same"), 0, 1) return np.interp(np.arange(int(total * SR)) / SR, np.arange(n) / cr, e) * depth def build_audio(beats, total, marks): t_solo, t_alarm, t_rer = marks n = int(SR * total) mix = np.zeros(n) bed = music_bed(total, beats, t_solo, t_alarm, t_rer) duck = duck_envelope(total, beats) mix += bed[:n] * (1.0 - duck[:n]) for b in beats: if not b.get("wav"): continue v = load_wav(Path(b["wav"])) si = int(b["start"] * SR); ei = min(si + len(v), n) if ei > si: mix[si:ei] += v[:ei - si] * 0.98 pk = np.max(np.abs(mix)) if pk > 0: mix = mix / pk * 0.93 out = AUD / "final.wav" with wave.open(str(out), "w") as wf: wf.setnchannels(1); wf.setsampwidth(2); wf.setframerate(SR) wf.writeframes((np.clip(mix, -1, 1) * 32767).astype(" P(AW - 140): lines.append(cur); cur = w else: cur = (cur + " " + w).strip() if cur: lines.append(cur) y0 = AH - 34 - 33 * len(lines) nm = NAMES.get(who, "") for k, ln in enumerate(([nm] if nm else []) + lines): ff = font(15) if k == 0 and nm else f col = (255, 214, 90) if (k == 0 and nm) else SUBCOL.get(who, (235, 235, 235)) x = AW // 2 - int(txt_w(d, ln, ff) / S) // 2 yy = y0 - 26 + k * 0 if (k == 0 and nm) else y0 + 33 * (k - (1 if nm else 0)) if k == 0 and nm: yy = y0 - 26 for dx, dy in ((-2, 0), (2, 0), (0, -2), (0, 2)): d.text((x + dx, yy + dy), ln, font=ff, fill=(0, 0, 0)) d.text((x, yy), ln, font=ff, fill=col) def render_endcard(t): img = Image.new("RGB", (W, H), BG) d = mkdraw(img) lines = [ "generator: renders/player_computer_final/byte_identical/render.py", f"git: {SHA7}", "law: same inputs -> byte-identical output", "", "the mp4 is one crystallization.", "the code is the work.", "", "PLAYER COMPUTER — ./spiral, ten of ten returns", ] for k, ln in enumerate(lines): if t < k * .5: break col = GREEN if k < 3 else (AMBER if k in (4, 5) else DGREEN) f = font(20) if k < 3 else (gfont("ital", 28) if k in (4, 5) else font(15)) x = AW // 2 - int(txt_w(d, ln, f) / S) // 2 d.text((x, 200 + k * 48), ln, font=f, fill=col) return img def zoom_rect(f): """Interpolate full frame -> preview rect, in REAL pixels. f in 0..1. Unchanged arithmetic — PREVP/W is the same ratio PREV/AW always was.""" x0 = PREVP[0] * f; y0 = PREVP[1] * f x1 = W + (PREVP[2] - W) * f; y1 = H + (PREVP[3] - H) * f return (x0, y0, x1, y1) _G = {} def init_worker(beats, total, marks): _G["beats"], _G["total"], _G["marks"] = beats, total, marks def render_frame(i): beats, total = _G["beats"], _G["total"] t_solo, t_alarm, t_rer = _G["marks"] t = i / FPS sb = state_beat(beats, t) if sb.get("endcard"): return i, crt(render_endcard(t - sb["start"]), i) bt01 = min(1.0, max(0.0, (t - sb["start"]) / max(1e-6, sb["dur"]))) alarm_amt = 1.0 if sb.get("alarm") else 0.0 pixel_on = bool(sb.get("alarm")) rer_f = bt01 if sb.get("rerender") else None depth = 3 term = draw_terminal(t, sb, bt01, depth, alarm_amt, pixel_on, rer_f) # zoom-commit: within a z-section, push from full view into the preview. # The droste is self-similar, so the native-res version of the preview's # content is this very frame: composite the push as (subpixel crop of the # outer) + (this frame pasted into the preview's screen-space rect). The # ease runs to a true 1.0, where the paste covers the frame exactly — the # landing IS the next section's view, crisp and pixel-aligned, no snap. z = sb.get("z") if z is not None: # zoom spans the whole z-section (may cover 2 beats with same z) zbeats = [b for b in beats if b.get("z") == z] z0 = min(b["start"] for b in zbeats) z1 = max(b["start"] + b["dur"] for b in zbeats) zf = min(1.0, max(0.0, (t - z0) / max(1e-6, z1 - z0))) zf = zf * zf * (3 - 2 * zf) # ease, commit fully if zf >= 1.0: pass # landed: full view, native res elif zf > 0.0: rect = zoom_rect(zf) rw, rh = rect[2] - rect[0], rect[3] - rect[1] # outer ring: subpixel-accurate crop+scale (no int truncation drift) outer = term.transform( (W, H), Image.AFFINE, (rw / W, 0.0, rect[0], 0.0, rh / H, rect[1]), resample=Image.BILINEAR) # inner: this same frame, scaled to the preview's on-screen rect # (always <= full size, so it only ever downscales — stays crisp) kx, ky = W / rw, H / rh sx0 = (PREVP[0] - rect[0]) * kx sy0 = (PREVP[1] - rect[1]) * ky iw = max(1, round((PREVP[2] - PREVP[0]) * kx)) ih = max(1, round((PREVP[3] - PREVP[1]) * ky)) inner = term.resize((iw, ih), Image.LANCZOS) outer.paste(inner, (round(sx0), round(sy0))) term = outer if sb.get("boot"): # boot: dark with text typing on img = Image.new("RGB", (W, H), BG) d = mkdraw(img) boot_lines = ["poop bios v5.0", "checking fonts… ok", "checking determinism… ok", f"git {SHA7} … ok", "no network devices found (by design)", "loading PLAYER COMPUTER … ok", "starting liturgy…"] nshow = int(bt01 * 14) for k, ln in enumerate(boot_lines[:nshow]): d.text((60, 68 + k * 34), "> " + ln, font=font(20), fill=GREEN) # the title, typed on one character-cell at a time, then the show name if nshow > len(boot_lines): ty = 68 + len(boot_lines) * 34 + 26 full = "B Y T E I D E N T I C A L" reveal = min(1.0, (bt01 - len(boot_lines) / 14.0) * 5.5) d.text((60, ty), full[:max(1, int(len(full) * reveal))], font=font(34), fill=AMBER) if reveal >= 1.0: # the machine names the show it is booting into blk = int(bt01 * 14) % 2 == 0 d.text((60, ty + 52), "P L A Y E R C O M P U T E R", font=font(20), fill=GREEN) d.text((60, ty + 84), "> _" if blk else ">", font=font(20), fill=GREEN) term = img img = crt(term, i, glow=True) spk = speaking_beat(beats, t) if spk and spk.get("text"): d2 = ImageDraw.Draw(img) draw_subs(d2, spk["text"], spk.get("speaker")) return i, img # ════════════════════════════════════════════════════════════════════════════ def contact_sheet(beats, total): n = int(total * FPS) picks = [int(k * (n - 1) / 31) for k in range(32)] cols = 8 rows = (len(picks) + cols - 1) // cols tw, th = 280, 180 sheet = Image.new("RGB", (cols * tw, rows * (th + 22)), (12, 12, 16)) sd = ImageDraw.Draw(sheet) for k, idx in enumerate(picks): _, im = render_frame(idx) im = im.resize((tw, th), Image.LANCZOS) cx, cy = (k % cols) * tw, (k // cols) * (th + 22) sheet.paste(im, (cx, cy)) sd.text((cx + 4, cy + th + 3), f"f{idx} t={idx/FPS:.1f}s", font=font(12), fill=(200, 200, 210)) p = OUT / "contact_sheet.png" sheet.save(p) print(f"contact sheet -> {p}") def main(): ap = argparse.ArgumentParser() ap.add_argument("--sheet", action="store_true") ap.add_argument("--mux-only", action="store_true") ap.add_argument("--force", action="store_true") ap.add_argument("--retts", action="store_true") ap.add_argument("--jobs", type=int, default=max(1, os.cpu_count() - 3)) a = ap.parse_args() print(f"[1/4] voices… (sha = {SHA7})") beats, total = build_timeline(force_tts=a.retts) n = int(total * FPS) t_solo = next(b["start"] for b in beats if b.get("sha_solo")) t_alarm = next(b["start"] for b in beats if b.get("alarm")) t_rer = next(b["start"] for b in beats if b.get("rerender")) marks = (t_solo, t_alarm, t_rer) print(f" {len(beats)} beats · {total:.1f}s · {n} frames @ {FPS}fps") init_worker(beats, total, marks) if a.sheet: contact_sheet(beats, total); return print("[2/4] audio…") wav = AUD / "final.wav" if not a.mux_only or not wav.exists(): wav = build_audio(beats, total, marks) if not a.mux_only: want = set(range(n)) if a.force else \ {i for i in range(n) if not (FRAMES / f"f{i:05d}.png").exists()} todo = sorted(want) print(f"[3/4] frames… {len(todo)}/{n} on {a.jobs} workers") if todo: import multiprocessing as mp ctx = mp.get_context("fork") with ctx.Pool(a.jobs, initializer=init_worker, initargs=(beats, total, marks)) as pool: done = 0 for idx, img in pool.imap_unordered(render_frame, todo, chunksize=8): img.save(FRAMES / f"f{idx:05d}.png") done += 1 if done % 300 == 0: print(f" {done}/{len(todo)}") print("[4/4] mux…") out = OUT / f"{NAME}.mp4" subprocess.run(["ffmpeg", "-y", "-framerate", str(FPS), "-i", str(FRAMES / "f%05d.png"), "-i", str(wav), "-c:v", "libx264", "-preset", "medium", "-crf", "19", "-pix_fmt", "yuv420p", "-c:a", "aac", "-b:a", "192k", "-shortest", "-movflags", "+faststart", "-metadata", "generator=renders/player_computer_final/byte_identical/render.py", "-metadata", f"title=player_computer_final — {TITLE}", "-metadata", "artist=poop / player_computer_final", "-metadata", f"comment=git {SHA7}; the sha is the melody", str(out)], check=True, capture_output=True) try: br = subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"], cwd=ROOT).decode().strip() except Exception: br = "unknown" (OUT / "PROVENANCE.txt").write_text( f"generator: renders/player_computer_final/byte_identical/render.py\n" f"git: {SHA7} branch: {br}\n" f"timestamp: {datetime.datetime.now().astimezone().isoformat()}\n" f"duration: {total:.2f}s fps: {FPS} size: {W}x{H} (16:9, native)\n" f"the sha is the melody: hex->pentatonic degrees, bits->kick pattern\n" f"droste: 3 levels; the preview contains the terminal containing the preview\n" f"voices: " + " ".join(f"{k}={v[0]}@{v[1]}" for k, v in VOICES.items()) + "\n") print(f"DONE {out} ({total:.1f}s)") if __name__ == "__main__": main()