Public Access
Add four Steins;Gate pages; shuffle the page rotation hourly
Divergence meter (Nixie tubes, world lines and clock), a D-mail sent through the Phone Microwave using the panel's Message text, the Future Gadget Lab inventory with live sensors, and a world line chart of today's solar power. Original pixel art in tools/steins_sprites.py; the sprite tool is shared between themes and Sprite, sprite(), polar() and arc() move to el512_pages.h. HomeData gains the message and a 24 h solar history in 15-minute slots. The rotation now walks all pages in a random order that is reshuffled every hour (Still Alive stays out, Now playing is skipped when idle). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e9b91c5628
commit
1e8a9a5958
11 files changed
+1057
-76
No files matched your search
+17
-21
@@ -285,44 +285,39 @@ SPRITES["MEGUMIN_BLINK"] = list(SPRITES["MEGUMIN"])
|
||||
SPRITES["MEGUMIN_BLINK"][17] = SPRITES["MEGUMIN"][17][:8] + ".." + SPRITES["MEGUMIN"][17][10:]
|
||||
|
||||
|
||||
def write_header(path):
|
||||
def write_header(path, sprites=SPRITES, title="KonoSuba", tool="konosuba_sprites.py", namespace="konosuba"):
|
||||
out = [
|
||||
"// Pixel art for the KonoSuba pages, generated by tools/konosuba_sprites.py;",
|
||||
f"// Pixel art for the {title} pages, generated by tools/{tool};",
|
||||
"// edit the art there. Original 1-bit fan art, '#' = lit pixel.",
|
||||
"#pragma once",
|
||||
"",
|
||||
"#include <stdint.h>",
|
||||
'#include "el512_pages.h" // Sprite',
|
||||
"",
|
||||
"namespace esphome::el512::konosuba {",
|
||||
"",
|
||||
"struct Sprite {",
|
||||
" uint8_t w, h;",
|
||||
" const char *const *rows;",
|
||||
"};",
|
||||
f"namespace esphome::el512::{namespace} {{",
|
||||
"",
|
||||
]
|
||||
for name, rows in SPRITES.items():
|
||||
for name, rows in sprites.items():
|
||||
out.append(f"static const char *const {name}_ROWS[] = {{")
|
||||
out += [f' "{r}",' for r in rows]
|
||||
out.append("};")
|
||||
out.append(f"static constexpr Sprite {name}{{{len(rows[0])}, {len(rows)}, {name}_ROWS}};")
|
||||
out.append("")
|
||||
out.append("} // namespace esphome::el512::konosuba")
|
||||
out.append(f"}} // namespace esphome::el512::{namespace}")
|
||||
path.write_text("\n".join(out) + "\n", encoding="utf-8")
|
||||
|
||||
|
||||
def write_preview(path, scale=6):
|
||||
def write_preview(path, sprites=SPRITES, scale=6):
|
||||
from PIL import Image, ImageDraw
|
||||
|
||||
pad = 4
|
||||
names = list(SPRITES)
|
||||
width = sum(len(SPRITES[n][0]) + pad for n in names) * scale
|
||||
height = (max(len(r) for r in SPRITES.values()) + pad) * scale + 14
|
||||
names = list(sprites)
|
||||
width = sum(len(sprites[n][0]) + pad for n in names) * scale
|
||||
height = (max(len(r) for r in sprites.values()) + pad) * scale + 14
|
||||
img = Image.new("RGB", (width, height), (20, 12, 0))
|
||||
draw = ImageDraw.Draw(img)
|
||||
x = 0
|
||||
for name in names:
|
||||
rows = SPRITES[name]
|
||||
rows = sprites[name]
|
||||
draw.text((x + 2, 2), name, fill=(120, 80, 0))
|
||||
for y, row in enumerate(rows):
|
||||
for cx, ch in enumerate(row):
|
||||
@@ -333,16 +328,17 @@ def write_preview(path, scale=6):
|
||||
img.save(path)
|
||||
|
||||
|
||||
def main():
|
||||
def main(sprites=SPRITES, title="KonoSuba", tool="konosuba_sprites.py", namespace="konosuba", doc=__doc__):
|
||||
"""Command line for a sprite file: writes the header, optionally a preview."""
|
||||
root = Path(__file__).resolve().parent.parent
|
||||
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
ap.add_argument("--out", type=Path, default=root / "components/el512/konosuba_sprites.h")
|
||||
ap = argparse.ArgumentParser(description=doc, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
ap.add_argument("--out", type=Path, default=root / f"components/el512/{namespace}_sprites.h")
|
||||
ap.add_argument("--preview", type=Path, help="also write a magnified PNG of all sprites")
|
||||
args = ap.parse_args()
|
||||
write_header(args.out)
|
||||
write_header(args.out, sprites, title, tool, namespace)
|
||||
print(f"wrote {args.out}")
|
||||
if args.preview:
|
||||
write_preview(args.preview)
|
||||
write_preview(args.preview, sprites)
|
||||
print(f"wrote {args.preview}")
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Pixel art for the Steins;Gate pages (components/el512/steins.cpp).
|
||||
|
||||
Original 1-bit fan art: '#' is a lit pixel. Writes
|
||||
components/el512/steins_sprites.h and, with --preview, a magnified PNG.
|
||||
|
||||
python tools/steins_sprites.py
|
||||
python tools/steins_sprites.py --preview sprites.png
|
||||
"""
|
||||
|
||||
from konosuba_sprites import main, padded
|
||||
|
||||
SPRITES = {
|
||||
# Okabe in his lab coat, and with the coat flaring out.
|
||||
"OKABE_A": [
|
||||
"......#######.........",
|
||||
"....##########.#......",
|
||||
"...############.......",
|
||||
"..#############.#.....",
|
||||
"..##.#.#.##.####......",
|
||||
"..#.........###.......",
|
||||
"..#..##..##..#........",
|
||||
"..#...........#.......",
|
||||
"..#.....#.....#.......",
|
||||
"...#..#####..#........",
|
||||
"....#.......#.........",
|
||||
".....#######..........",
|
||||
"...###.....###........",
|
||||
"..##..#...#..##.......",
|
||||
".##....#.#....##......",
|
||||
".#.#....#....#.#......",
|
||||
".#.#....#....#.#......",
|
||||
".#..#...#...#..#......",
|
||||
"#...#...#...#...#.....",
|
||||
"#...#...#...#...#.....",
|
||||
"#..#....#....#..#.....",
|
||||
"#..#....#....#..#.....",
|
||||
"##.#....#....#.##.....",
|
||||
"##.#....#....#.##.....",
|
||||
"...#....#....#........",
|
||||
"...#...###...#........",
|
||||
"...#...#.#...#........",
|
||||
"..#....#.#....#.......",
|
||||
"..#....#.#....#.......",
|
||||
".#.....#.#.....#......",
|
||||
".#.....#.#.....#......",
|
||||
"#......#.#......#.....",
|
||||
"########.########.....",
|
||||
".......#.#............",
|
||||
".......#.#............",
|
||||
"......##.##...........",
|
||||
],
|
||||
"OKABE_B": [
|
||||
"......#######.........",
|
||||
"....##########.#......",
|
||||
"...############.......",
|
||||
"..#############.#.....",
|
||||
"..##.#.#.##.####......",
|
||||
"..#.........###.......",
|
||||
"..#..##..##..#........",
|
||||
"..#...........#.......",
|
||||
"..#.....#.....#.......",
|
||||
"...#..#####..#........",
|
||||
"....#.......#.........",
|
||||
".....#######..........",
|
||||
"...###.....###........",
|
||||
"..##..#...#..##.......",
|
||||
".##....#.#....##......",
|
||||
".#.#....#....#.##.....",
|
||||
".#.#....#....#.#.#....",
|
||||
".#..#...#...#..#..#...",
|
||||
"#...#...#...#...#..#..",
|
||||
"#...#...#...#...#...#.",
|
||||
"#..#....#....#..#....#",
|
||||
"#..#....#....#..#....#",
|
||||
"##.#....#....#.##....#",
|
||||
"##.#....#....#......#.",
|
||||
"...#....#....#......#.",
|
||||
"...#...###...#.....#..",
|
||||
"...#...#.#...#.....#..",
|
||||
"..#....#.#....#...#...",
|
||||
"..#....#.#....#...#...",
|
||||
".#.....#.#.....#.#....",
|
||||
".#.....#.#.....##.....",
|
||||
"#......#.#......#.....",
|
||||
"########.########.....",
|
||||
".......#.#............",
|
||||
".......#.#............",
|
||||
"......##.##...........",
|
||||
],
|
||||
# Kurisu: long hair, shirt and tie, belt.
|
||||
"KURISU": [
|
||||
".....######.......",
|
||||
"...##########.....",
|
||||
"..############....",
|
||||
"..##.#.##.#.##....",
|
||||
"..#..........#....",
|
||||
"..#..##..##..#....",
|
||||
"..#..........#....",
|
||||
"..#....#.....#....",
|
||||
"..##..###...##....",
|
||||
"..###......###....",
|
||||
"..#.##....##.#....",
|
||||
"..#..######..#....",
|
||||
"..#.#..#..#..#....",
|
||||
"..##..###..#.#....",
|
||||
"..#....#....##....",
|
||||
".##...###...###...",
|
||||
".#.#...#...#..#...",
|
||||
".#.#.......#..#...",
|
||||
".#..#.....#...#...",
|
||||
".#..#######...#...",
|
||||
"....#.....#.......",
|
||||
"....#.....#.......",
|
||||
"....##...##.......",
|
||||
".....#...#........",
|
||||
".....#...#........",
|
||||
".....#...#........",
|
||||
".....#...#........",
|
||||
"....##...##.......",
|
||||
],
|
||||
# Upa, upright and squashed mid-bounce.
|
||||
"UPA_A": [
|
||||
"..#........#..",
|
||||
"..##......##..",
|
||||
"..#.######.#..",
|
||||
".#..........#.",
|
||||
"#...#....#...#",
|
||||
"#............#",
|
||||
"#.....##.....#",
|
||||
".#..........#.",
|
||||
"..##########..",
|
||||
],
|
||||
"UPA_B": [
|
||||
"..............",
|
||||
"...#......#...",
|
||||
"..##.####.##..",
|
||||
".#..........#.",
|
||||
"#...#....#...#",
|
||||
"#.....##.....#",
|
||||
"##..........##",
|
||||
".############.",
|
||||
"..............",
|
||||
],
|
||||
# The lab's favourite fizzy drink.
|
||||
"CAN": [
|
||||
"..######..",
|
||||
".#......#.",
|
||||
"##########",
|
||||
"#........#",
|
||||
"#.######.#",
|
||||
"#.#....#.#",
|
||||
"#.#.##.#.#",
|
||||
"#.#....#.#",
|
||||
"#.######.#",
|
||||
"#........#",
|
||||
"#........#",
|
||||
"##########",
|
||||
".########.",
|
||||
],
|
||||
}
|
||||
|
||||
for _name in SPRITES:
|
||||
SPRITES[_name] = padded(SPRITES[_name])
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(SPRITES, "Steins;Gate", "steins_sprites.py", "steins", __doc__)
|
||||
Reference in new issue
Block a user