<?php /* ========================================================= Heist Board Installer — PHP 5.2+ SAFE Creates a full corkboard “plan” viewer system Run once, then delete this file. ========================================================= */ error_reporting(E_ALL); ini_set('display_errors', 1); $root = dirname(__FILE__) . '/heist-board'; $assets = $root . '/plan-assets'; @mkdir($assets, 0777, true); function write_file($path, $content) { $f = fopen($path, 'w'); fwrite($f, $content); fclose($f); } /* ---------------- plan-board.php ---------------- */ $plan_board = '<?php $dir = __DIR__; $files = scandir($dir); $pieces = array(); foreach ($files as $file) { if (!preg_match("/\\.(php|html)$/i", $file)) continue; if ($file === "plan-board.php") continue; $base = pathinfo($file, PATHINFO_FILENAME); $img = ""; $exts = array("png","jpg","jpeg","webp"); foreach ($exts as $e) { if (file_exists($dir . "/" . $base . "." . $e)) { $img = $base . "." . $e; break; } } $title = $base; $data = @file_get_contents($dir . "/" . $file); if ($data && preg_match("/<title>(.*?)<\\/title>/is", $data, $m)) { $title = trim($m[1]); } $pieces[] = array( "file" => $file, "title" => $title, "size" => round(filesize($dir . "/" . $file) / 1024, 1) . " KB", "date" => date("Y-m-d", filemtime($dir . "/" . $file)), "image" => $img ); } ?> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>The Plan</title> plan-assets/board.css </head> <body> <div id="board"> <svg id="strings"></svg> <?php foreach ($pieces as $i => $p) { ?> <div class="piece" style="--i:<?php echo $i; ?>"> <?php if ($p["image"]) { ?> <?php echo htmlspecialchars($p[ ?>"> <?php } ?> <div class="label"> <strong><?php echo htmlspecialchars($p["title"]); ?></strong><br> <?php echo htmlspecialchars($p["file"]); ?><br> <?php echo $p["size"]; ?><br> <?php echo $p["date"]; ?> </div> </div> <?php } ?> </div> plan-assets/board.jsscript> </body> </html>'; write_file($root . '/plan-board.php', $plan_board); /* ---------------- CSS ---------------- */ $css = 'body { margin: 0; background: #2b1d12; font-family: Courier, monospace; } #board { position: relative; width: 100vw; height: 100vh; background: url("cork.jpg") repeat; } .piece { position: absolute; top: calc(10% + (var(--i) * 12%)); left: calc(10% + (var(--i) * 15%)); background: #f6f1e7; padding: 10px; box-shadow: 0 8px 20px rgba(0,0,0,.4); } .piece img { max-width: 220px; display: block; margin-bottom: 6px; } .label { font-size: 12px; }'; write_file($assets . '/board.css', $css); /* ---------------- JS ---------------- */ $js = 'var pieces = document.getElementsByClassName("piece"); var svg = document.getElementById("strings"); for (var i = 0; i < pieces.length - 1; i++) { var a = pieces[i].getBoundingClientRect(); var b = pieces[i + 1].getBoundingClientRect(); var line = document.createElementNS("http://www.w3.org/2000/svg", "line"); line.setAttribute("x1", a.left + a.width / 2); line.setAttribute("y1", a.top + a.height / 2); line.setAttribute("x2", b.left + b.width / 2); line.setAttribute("y2", b.top + b.height / 2); line.setAttribute("stroke", "#b30000"); line.setAttribute("stroke-width", "2"); svg.appendChild(line); }'; write_file($assets . '/board.js', $js); /* ---------------- Image placeholders ---------------- */ write_file($assets . '/cork.jpg.txt', "cork.jpg 2048x2048 Seamless cork texture Warm brown tones"); write_file($assets . '/pin.png.txt', "pin.png 128x128 Transparent push pin graphic"); write_file($assets . '/string.svg.txt', "string.svg Red thread texture Optional"); write_file($assets . '/top-banner.jpg.txt', "top-banner.jpg 1920x400 Paper or taped photo banner"); echo "<h2>✅ Heist Board Installed</h2> <p>Open <code>heist-board/plan-board.php</code></p> <p>Delete this installer after use.</p>"; 
