Add Still Alive photo; keep spaces between split lyric pieces

The source page splits some lines into several spans; a browser renders the
whitespace between them as a space, which the importer dropped ("becausewe").
It now adds that space. Regenerated imported.h.

Add a photo of the demo on the panel to the README.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mangavalkandClaude Opus 5.5 committed 2026-10-18 19:29:16 +02:00
1 parent 7e738b951b
commit 410885de24
4 files changed
+33 -27

No files matched your search

+2
View File
@@ -91,6 +91,8 @@ pio device monitor
## Still Alive demo ## Still Alive demo
![Still Alive demo running on the EL512.256-H](docs/images/still_alive.jpg)
A recreation of Portal's ending: timed song text typed into a console on the A recreation of Portal's ending: timed song text typed into a console on the
left, credits scrolling top right, ASCII art bottom right. The text, timing, art left, credits scrolling top right, ASCII art bottom right. The text, timing, art
and credits in `src/still_alive/imported.h` come from and credits in `src/still_alive/imported.h` come from
Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

+26 -26
View File
@@ -389,16 +389,16 @@ static const LyricStep LYRICS[] = {
{18130, 2710, STEP_NEWLINE, ART_KEEP, "my satisfaction."}, {18130, 2710, STEP_NEWLINE, ART_KEEP, "my satisfaction."},
{22970, 1760, STEP_NEWLINE, 1, "Aperture Science"}, {22970, 1760, STEP_NEWLINE, 1, "Aperture Science"},
{26830, 1570, STEP_NEWLINE, ART_KEEP, "We do what we must"}, {26830, 1570, STEP_NEWLINE, ART_KEEP, "We do what we must"},
{28600, 750, 0, ART_KEEP, "because"}, {28600, 750, 0, ART_KEEP, "because "},
{29550, 710, STEP_NEWLINE, ART_KEEP, "we can."}, {29550, 710, STEP_NEWLINE, ART_KEEP, "we can."},
{31930, 1550, 0, ART_KEEP, "For the good"}, {31930, 1550, 0, ART_KEEP, "For the good "},
{33480, 1530, STEP_NEWLINE, ART_KEEP, "of all of us."}, {33480, 1530, STEP_NEWLINE, ART_KEEP, "of all of us."},
{35289, 1741, STEP_NEWLINE, 6, "Except the ones who are dead."}, {35289, 1741, STEP_NEWLINE, 6, "Except the ones who are dead."},
{37030, 400, STEP_NEWLINE, ART_KEEP, ""}, {37030, 400, STEP_NEWLINE, ART_KEEP, ""},
{37430, 1858, STEP_NEWLINE, 1, "But there's no sense crying"}, {37430, 1858, STEP_NEWLINE, 1, "But there's no sense crying"},
{39298, 1782, STEP_NEWLINE, ART_KEEP, "over every mistake."}, {39298, 1782, STEP_NEWLINE, ART_KEEP, "over every mistake."},
{41280, 1985, STEP_NEWLINE, ART_KEEP, "You just keep on trying"}, {41280, 1985, STEP_NEWLINE, ART_KEEP, "You just keep on trying"},
{43275, 1366, 0, ART_KEEP, "till you run out of"}, {43275, 1366, 0, ART_KEEP, "till you run out of "},
{44641, 400, STEP_NEWLINE, ART_KEEP, "cake."}, {44641, 400, STEP_NEWLINE, ART_KEEP, "cake."},
{45227, 1970, STEP_NEWLINE, 5, "And the Science gets done."}, {45227, 1970, STEP_NEWLINE, 5, "And the Science gets done."},
{47197, 1970, STEP_NEWLINE, ART_KEEP, "And you make a neat gun."}, {47197, 1970, STEP_NEWLINE, ART_KEEP, "And you make a neat gun."},
@@ -410,22 +410,22 @@ static const LyricStep LYRICS[] = {
{55477, 0, STEP_NEWLINE, ART_KEEP, ""}, {55477, 0, STEP_NEWLINE, ART_KEEP, ""},
{58487, 0, STEP_NEWLINE, ART_KEEP, ""}, {58487, 0, STEP_NEWLINE, ART_KEEP, ""},
{58547, 1917, STEP_NEWLINE, ART_KEEP, "I'm not even angry."}, {58547, 1917, STEP_NEWLINE, ART_KEEP, "I'm not even angry."},
{62832, 697, 0, ART_KEEP, "I'm being"}, {62832, 697, 0, ART_KEEP, "I'm being "},
{63529, 650, 0, ART_KEEP, "so"}, {63529, 650, 0, ART_KEEP, "so "},
{64179, 906, 0, ART_KEEP, "sincere"}, {64179, 906, 0, ART_KEEP, "sincere "},
{65085, 1115, STEP_NEWLINE, ART_KEEP, "right now."}, {65085, 1115, STEP_NEWLINE, ART_KEEP, "right now."},
{67825, 650, 0, ART_KEEP, "Even"}, {67825, 650, 0, ART_KEEP, "Even "},
{68475, 1347, 0, ART_KEEP, "though you"}, {68475, 1347, 0, ART_KEEP, "though you "},
{69822, 488, 0, 8, "broke"}, {69822, 488, 0, 8, "broke "},
{70310, 998, STEP_NEWLINE, ART_KEEP, "my heart."}, {70310, 998, STEP_NEWLINE, ART_KEEP, "my heart."},
{71308, 325, 0, ART_KEEP, "And"}, {71308, 325, 0, ART_KEEP, "And "},
{71633, 488, 0, ART_KEEP, "killed"}, {71633, 488, 0, ART_KEEP, "killed "},
{72121, 557, STEP_NEWLINE, ART_KEEP, "me."}, {72121, 557, STEP_NEWLINE, ART_KEEP, "me."},
{74678, 1649, STEP_NEWLINE, 3, "And tore me to pieces."}, {74678, 1649, STEP_NEWLINE, 3, "And tore me to pieces."},
{78649, 1440, 0, ART_KEEP, "And threw every piece"}, {78649, 1440, 0, ART_KEEP, "And threw every piece "},
{80091, 580, 0, ART_KEEP, "into"}, {80091, 580, 0, ART_KEEP, "into "},
{81066, 882, STEP_NEWLINE, 11, "a fire."}, {81066, 882, STEP_NEWLINE, 11, "a fire."},
{83597, 1400, 0, ART_KEEP, "As they burned"}, {83597, 1400, 0, ART_KEEP, "As they burned "},
{84997, 1509, STEP_NEWLINE, ART_KEEP, "it hurt because"}, {84997, 1509, STEP_NEWLINE, ART_KEEP, "it hurt because"},
{86831, 1625, STEP_NEWLINE, 9, "I was so happy for you!"}, {86831, 1625, STEP_NEWLINE, 9, "I was so happy for you!"},
{88897, 2067, STEP_NEWLINE, ART_KEEP, "Now these points of data"}, {88897, 2067, STEP_NEWLINE, ART_KEEP, "Now these points of data"},
@@ -435,7 +435,7 @@ static const LyricStep LYRICS[] = {
{96884, 2113, STEP_NEWLINE, 3, "So I'm GLaD. I got burned."}, {96884, 2113, STEP_NEWLINE, 3, "So I'm GLaD. I got burned."},
{98997, 2020, STEP_NEWLINE, 5, "Think of all the things we learned"}, {98997, 2020, STEP_NEWLINE, 5, "Think of all the things we learned"},
{101017, 1556, STEP_NEWLINE, 1, "for the people who are"}, {101017, 1556, STEP_NEWLINE, 1, "for the people who are"},
{102573, 395, 0, ART_KEEP, "still"}, {102573, 395, 0, ART_KEEP, "still "},
{102968, 1440, STEP_NEWLINE, ART_KEEP, "alive."}, {102968, 1440, STEP_NEWLINE, ART_KEEP, "alive."},
{106008, 0, STEP_CLEAR, ART_KEEP, ""}, {106008, 0, STEP_CLEAR, ART_KEEP, ""},
{106008, 450, STEP_NEWLINE, ART_KEEP, "Forms FORM-55551-6:"}, {106008, 450, STEP_NEWLINE, ART_KEEP, "Forms FORM-55551-6:"},
@@ -443,22 +443,22 @@ static const LyricStep LYRICS[] = {
{107768, 0, STEP_NEWLINE, ART_KEEP, ""}, {107768, 0, STEP_NEWLINE, ART_KEEP, ""},
{108428, 2200, STEP_NEWLINE, ART_KEEP, "One last thing:"}, {108428, 2200, STEP_NEWLINE, ART_KEEP, "One last thing:"},
{110628, 0, STEP_NEWLINE, ART_KEEP, ""}, {110628, 0, STEP_NEWLINE, ART_KEEP, ""},
{110678, 1324, 0, ART_KEEP, "Go ahead and leave"}, {110678, 1324, 0, ART_KEEP, "Go ahead and leave "},
{112002, 627, STEP_NEWLINE, ART_KEEP, "me."}, {112002, 627, STEP_NEWLINE, ART_KEEP, "me."},
{114417, 534, 0, ART_KEEP, "I think"}, {114417, 534, 0, ART_KEEP, "I think "},
{114951, 1184, 0, ART_KEEP, "I prefer"}, {114951, 1184, 0, ART_KEEP, "I prefer "},
{116135, 1022, 0, ART_KEEP, "to stay"}, {116135, 1022, 0, ART_KEEP, "to stay "},
{117157, 232, 0, ART_KEEP, "in"}, {117157, 232, 0, ART_KEEP, "in"},
{117389, 882, STEP_NEWLINE, ART_KEEP, "side."}, {117389, 882, STEP_NEWLINE, ART_KEEP, "side."},
{119701, 511, 0, ART_KEEP, "May"}, {119701, 511, 0, ART_KEEP, "May"},
{120212, 2972, STEP_NEWLINE, ART_KEEP, "be you'll find someone else"}, {120212, 2972, STEP_NEWLINE, ART_KEEP, "be you'll find someone else"},
{123184, 1254, STEP_NEWLINE, ART_KEEP, "to help you."}, {123184, 1254, STEP_NEWLINE, ART_KEEP, "to help you."},
{126690, 511, 0, ART_KEEP, "Maybe"}, {126690, 511, 0, ART_KEEP, "Maybe "},
{127201, 325, 0, 7, "Black"}, {127201, 325, 0, 7, "Black "},
{127526, 998, 0, ART_KEEP, "Mesa"}, {127526, 998, 0, ART_KEEP, "Mesa"},
{128524, 2183, STEP_NEWLINE, ART_KEEP, "..."}, {128524, 2183, STEP_NEWLINE, ART_KEEP, "..."},
{130707, 1440, 0, ART_KEEP, "THAT WAS A JOKE."}, {130707, 1440, 0, ART_KEEP, "THAT WAS A JOKE. "},
{133168, 279, 0, ART_KEEP, "FAT"}, {133168, 279, 0, ART_KEEP, "FAT "},
{133447, 859, STEP_NEWLINE, ART_KEEP, "CHANCE."}, {133447, 859, STEP_NEWLINE, ART_KEEP, "CHANCE."},
{135699, 1486, 0, ART_KEEP, "Anyway"}, {135699, 1486, 0, ART_KEEP, "Anyway"},
{137185, 1765, STEP_NEWLINE, 2, ", this cake is great."}, {137185, 1765, STEP_NEWLINE, 2, ", this cake is great."},
@@ -470,7 +470,7 @@ static const LyricStep LYRICS[] = {
{149167, 2043, STEP_NEWLINE, 5, "I've experiments to run."}, {149167, 2043, STEP_NEWLINE, 5, "I've experiments to run."},
{151210, 2020, STEP_NEWLINE, 3, "There is research to be done."}, {151210, 2020, STEP_NEWLINE, 3, "There is research to be done."},
{153230, 1625, STEP_NEWLINE, 1, "On the people who are"}, {153230, 1625, STEP_NEWLINE, 1, "On the people who are"},
{154855, 348, 0, ART_KEEP, "still"}, {154855, 348, 0, ART_KEEP, "still "},
{155203, 1440, STEP_NEWLINE, ART_KEEP, "alive."}, {155203, 1440, STEP_NEWLINE, ART_KEEP, "alive."},
{156843, 0, STEP_CLEAR, ART_KEEP, ""}, {156843, 0, STEP_CLEAR, ART_KEEP, ""},
{156953, 0, STEP_NEWLINE, ART_KEEP, ""}, {156953, 0, STEP_NEWLINE, ART_KEEP, ""},
@@ -532,8 +532,8 @@ static const LyricStep LYRICS[] = {
{283939, 0, STEP_NEWLINE, ART_KEEP, ""}, {283939, 0, STEP_NEWLINE, ART_KEEP, ""},
{284939, 5000, STEP_NEWLINE, ART_KEEP, "// Getting Faster and Faster //"}, {284939, 5000, STEP_NEWLINE, ART_KEEP, "// Getting Faster and Faster //"},
{290939, 2000, STEP_NEWLINE, ART_KEEP, "... I just said this is a simple game."}, {290939, 2000, STEP_NEWLINE, ART_KEEP, "... I just said this is a simple game."},
{293439, 500, 0, ART_KEEP, "Actually,"}, {293439, 500, 0, ART_KEEP, "Actually, "},
{294939, 3500, 0, ART_KEEP, "THIS IS NOT A GAME."}, {294939, 3500, 0, ART_KEEP, "THIS IS NOT A GAME. "},
}; };
static constexpr size_t LYRIC_COUNT = sizeof(LYRICS) / sizeof(LYRICS[0]); static constexpr size_t LYRIC_COUNT = sizeof(LYRICS) / sizeof(LYRICS[0]);
+5 -1
View File
@@ -96,7 +96,9 @@ def parse_steps(page, art_ids):
end = screens[i + 1].start() if i + 1 < len(screens) else len(page) end = screens[i + 1].start() if i + 1 < len(screens) else len(page)
body = page[screen.end():end] body = page[screen.end():end]
steps.append((base, len(steps), 0, "STEP_CLEAR", "ART_KEEP", "")) steps.append((base, len(steps), 0, "STEP_CLEAR", "ART_KEEP", ""))
for tag in re.finditer(r"<(span|br)\b[^>]*>", body): # Group 2 is the whitespace after the element: a browser renders it as one
# space between spans on the same line ("because" + "we can").
for tag in re.finditer(r"<(span|br)\b[^>]*>(?:</span>)?(\s*)", body):
t = tag.group(0) t = tag.group(0)
if tag.group(1) == "br": if tag.group(1) == "br":
offset = attr(t, "data-show-offset") offset = attr(t, "data-show-offset")
@@ -107,6 +109,8 @@ def parse_steps(page, art_ids):
if text is None or attr(t, "data-start") is None: if text is None or attr(t, "data-start") is None:
continue continue
flags = "STEP_NEWLINE" if attr(t, "data-append-br") == "true" else "0" flags = "STEP_NEWLINE" if attr(t, "data-append-br") == "true" else "0"
if flags == "0" and tag.group(2) and not text.endswith(" "):
text += " "
art = attr(t, "data-asciiart") art = attr(t, "data-asciiart")
art_id = "ART_KEEP" if art is None else ("ART_NONE" if art == "clear" else str(art_ids.get(art, 0))) art_id = "ART_KEEP" if art is None else ("ART_NONE" if art == "clear" else str(art_ids.get(art, 0)))
steps.append((base + int(attr(t, "data-start")), len(steps), steps.append((base + int(attr(t, "data-start")), len(steps),