Compare commits
14 Commits
17fce21e28
...
548bdcb6a4
Author | SHA1 | Date |
---|---|---|
ktyl | 548bdcb6a4 | |
ktyl | e2a452914e | |
ktyl | 797ab70d71 | |
ktyl | b8c3974807 | |
ktyl | b67863f972 | |
ktyl | 9b39147c87 | |
ktyl | bffbb0f371 | |
ktyl | db3eb3221c | |
ktyl | 0d4bdebac9 | |
ktyl | ea39f8a5a8 | |
ktyl | ecbc5a24c4 | |
ktyl | d0e08324e8 | |
ktyl | 371758485e | |
ktyl | d10a3f19c3 |
2
blog
|
@ -1 +1 @@
|
||||||
Subproject commit 30dd1e7e01c6348324a3fef001b3a2fabfc05788
|
Subproject commit 5a1de185c30b8a1ef3400fe161fcc8f12fbacaa0
|
12
makefile
|
@ -15,6 +15,9 @@ BLOG_BUILD_DIR = $(BLOG_BASE_DIR)out/html/
|
||||||
BLOG_OUT_DIR = $(OUT_DIR)/blog
|
BLOG_OUT_DIR = $(OUT_DIR)/blog
|
||||||
BLOG_INDEX = $(BLOG_BUILD_DIR)/index.html
|
BLOG_INDEX = $(BLOG_BUILD_DIR)/index.html
|
||||||
|
|
||||||
|
GARDEN_BASE_DIR = $(SRC_DIR)/garden/
|
||||||
|
GARDEN_BUILD_DIR = $(GARDEN_BASE_DIR)html
|
||||||
|
|
||||||
PAGES = $(shell find $(ROOT_DIR) -wholename "$(ROOT_DIR)*.html")
|
PAGES = $(shell find $(ROOT_DIR) -wholename "$(ROOT_DIR)*.html")
|
||||||
STYLES = $(shell find $(ROOT_DIR) -wholename "$(ROOT_DIR)*.css")
|
STYLES = $(shell find $(ROOT_DIR) -wholename "$(ROOT_DIR)*.css")
|
||||||
IMAGES = $(shell find $(IMG_DIR) -wholename "$(IMG_DIR)/*.png")
|
IMAGES = $(shell find $(IMG_DIR) -wholename "$(IMG_DIR)/*.png")
|
||||||
|
@ -26,7 +29,8 @@ HTML_TARGETS = $(PAGES:$(ROOT_DIR)/%.html=$(OUT_DIR)/%.html)
|
||||||
CSS_TARGETS = $(STYLES:$(ROOT_DIR)/%.css=$(OUT_DIR)/%.css)
|
CSS_TARGETS = $(STYLES:$(ROOT_DIR)/%.css=$(OUT_DIR)/%.css)
|
||||||
PNG_TARGETS = $(IMG_DIR)/%.png=$(OUT_DIR)/%.png
|
PNG_TARGETS = $(IMG_DIR)/%.png=$(OUT_DIR)/%.png
|
||||||
|
|
||||||
all: html blog | $(OUT_DIR)
|
all: html blog garden | $(OUT_DIR)
|
||||||
|
cp -r src/garden/html $(OUT_DIR)/garden
|
||||||
|
|
||||||
html: $(HTML_TARGETS) $(CSS_TARGETS) | $(OUT_DIR)
|
html: $(HTML_TARGETS) $(CSS_TARGETS) | $(OUT_DIR)
|
||||||
cp $(IMG_DIR)/*.png $(OUT_DIR)/
|
cp $(IMG_DIR)/*.png $(OUT_DIR)/
|
||||||
|
@ -62,8 +66,12 @@ blog: $(HTML_INCLUDES) $(CSS_TARGETS)
|
||||||
cp $(CSS_TARGETS) `dirname $$page` ; \
|
cp $(CSS_TARGETS) `dirname $$page` ; \
|
||||||
done
|
done
|
||||||
|
|
||||||
|
garden:
|
||||||
|
make --directory $(GARDEN_BASE_DIR) site
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
make --directory $(GARDEN_BASE_DIR) clean
|
||||||
make --directory $(BLOG_BASE_DIR) clean
|
make --directory $(BLOG_BASE_DIR) clean
|
||||||
rm -rf $(OUT_DIR)
|
rm -rf $(OUT_DIR)
|
||||||
|
|
||||||
.PHONY: blog
|
.PHONY: blog garden
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
*.html
|
|
@ -0,0 +1,22 @@
|
||||||
|
py = feed.py books.py
|
||||||
|
md = rss.md book-collecting.md gardens.md
|
||||||
|
html = $(md:%.md=%.html)
|
||||||
|
|
||||||
|
site: Makefile $(md) $(py)
|
||||||
|
mkdir html
|
||||||
|
python md2html.py $(md)
|
||||||
|
cp $(html) $(py) Makefile html
|
||||||
|
|
||||||
|
clean-html:
|
||||||
|
rm -r html
|
||||||
|
|
||||||
|
.PHONY: clean-html
|
||||||
|
|
||||||
|
feed:
|
||||||
|
python feed.py `pwd`
|
||||||
|
|
||||||
|
rss: feed
|
||||||
|
|
||||||
|
clean: clean-html
|
||||||
|
|
||||||
|
.PHONY: feed clean
|
|
@ -0,0 +1,106 @@
|
||||||
|
how do you define a book collection?
|
||||||
|
my book collection is the set of all books.
|
||||||
|
|
||||||
|
i prefer physical books to e-readers.
|
||||||
|
unfortunately i have quite a few these days.
|
||||||
|
|
||||||
|
i want to read them all eventually!
|
||||||
|
i also tend to live in quite small places
|
||||||
|
and i want to be able to move city easily!
|
||||||
|
|
||||||
|
so here's my system for organising my physical book collection.
|
||||||
|
|
||||||
|
i want to:
|
||||||
|
* read books i already have
|
||||||
|
* read as many different books as possible
|
||||||
|
* minimise physical storage requirements
|
||||||
|
* keep track of books i've read
|
||||||
|
* gather books i don't already have
|
||||||
|
|
||||||
|
constraints
|
||||||
|
* i don't know for sure what book i will want to read next
|
||||||
|
|
||||||
|
for every book in the world
|
||||||
|
* i either have or have not read it
|
||||||
|
* i have access to it or i don't
|
||||||
|
|
||||||
|
so i sort my book collection with 4 categories
|
||||||
|
|
||||||
|
*-------------------*-----------------------*
|
||||||
|
| | |
|
||||||
|
| unread | read |
|
||||||
|
| have | have |
|
||||||
|
| | |
|
||||||
|
| 37º2 le matin | L'Homme des Jeux |
|
||||||
|
| | |
|
||||||
|
*-------------------*-----------------------*
|
||||||
|
| | |
|
||||||
|
| unread | read |
|
||||||
|
| haven't | haven't |
|
||||||
|
| | |
|
||||||
|
| Das Kapital | Frankisstein |
|
||||||
|
| | |
|
||||||
|
*-------------------*-----------------------*
|
||||||
|
|
||||||
|
i can then begin to optimise my collection.
|
||||||
|
|
||||||
|
* i do not have this book, and i have read it.
|
||||||
|
* i have this book, but i have not read it.
|
||||||
|
* i have this book, and i have read it.
|
||||||
|
* i do not have this book, but i have not read it.
|
||||||
|
|
||||||
|
the books i am most interested in having nearby are unread ones, as i would like to read as many different books as possible.
|
||||||
|
|
||||||
|
books i have already read i don't need nearby anymore.
|
||||||
|
i might pass it on, or store it somewhere with less of a premium on space.
|
||||||
|
i could also attempt to track where it is!
|
||||||
|
|
||||||
|
based on my requirements and my categories, i create four lists for the books
|
||||||
|
|
||||||
|
* ready
|
||||||
|
* all done
|
||||||
|
* read and gone
|
||||||
|
* hunted
|
||||||
|
|
||||||
|
that looks like a decent start to the system, so i suppose now i'll start collecting!
|
||||||
|
|
||||||
|
so i'll use markdown lists in the format
|
||||||
|
|
||||||
|
```
|
||||||
|
* [x] author - title # reading
|
||||||
|
* [ ] author - title # nearby
|
||||||
|
```
|
||||||
|
when collecting music i use artist - year - name
|
||||||
|
however, publication year is an extra step that will slow data entry, so won't use this to start with - i have a lot of books
|
||||||
|
|
||||||
|
i realised i had a gpt-4 sub and that it could look at pictures now so i gave it a go
|
||||||
|
i fed it some photos and some formatting preferences and i got out perfect markdown lists
|
||||||
|
|
||||||
|
```
|
||||||
|
- [ ] Doctorow, Cory - Walkaway
|
||||||
|
- [ ] Ferreira, Pedro G. - The Perfect Theory
|
||||||
|
- [ ] Hadfield, Chris - An Astronaut's Guide to Life on Earth
|
||||||
|
- [ ] Heinlein, Robert A. - Beyond This Horizon
|
||||||
|
```
|
||||||
|
|
||||||
|
books are lovely are great to look at, but the mishmash of fonts and presentation are a nightmare for indexing.
|
||||||
|
now we have some good and lovely metadata :)
|
||||||
|
this is an imperfect method, as the only way i can check it is still by combing through the physical books manually
|
||||||
|
but it does let me target my combing after identifying problems in the index
|
||||||
|
and in the meantime gives us a bunch of data to play with
|
||||||
|
|
||||||
|
markdown lists also allow me to mark some items in a list
|
||||||
|
this is looks flexible, so i think in my 'ready' list i will mark which book(s) i am currently reading
|
||||||
|
|
||||||
|
```
|
||||||
|
- [ ] Doctorow, Cory - Walkaway
|
||||||
|
- [ ] Ferreira, Pedro G. - The Perfect Theory
|
||||||
|
- [ ] Hadfield, Chris - An Astronaut's Guide to Life on Earth
|
||||||
|
- [ ] Heinlein, Robert A. - Beyond This Horizon
|
||||||
|
```
|
||||||
|
|
||||||
|
the other lists i will leave unmarked for now, until i think of something to do with them.
|
||||||
|
|
||||||
|
as for doing things with them, i wrote a [python script](#) which processes the data in the now-populated all-done and ready lists to yield some interesting (?) and fun (?) results?
|
||||||
|
|
||||||
|
[example output](#)
|
|
@ -0,0 +1,118 @@
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
def print_usage():
|
||||||
|
print(f"usage: python {sys.argv[0]} DIR")
|
||||||
|
print(f"")
|
||||||
|
print(f"\tDIR\tdirectory containing markdown lists in files.")
|
||||||
|
|
||||||
|
|
||||||
|
if len(sys.argv) != 2:
|
||||||
|
print_usage()
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
base_path = os.path.abspath(sys.argv[1])
|
||||||
|
ready_list_name = "ready.md"
|
||||||
|
completed_lists = ["2023.md", "2022.md", "202x.md"]
|
||||||
|
|
||||||
|
def get_path(list_name : str) -> str:
|
||||||
|
return os.path.join(base_path, list_name)
|
||||||
|
|
||||||
|
|
||||||
|
def get_matches(list_name : str) -> list[re.Match]:
|
||||||
|
# Matches a markdown list item
|
||||||
|
entry_pattern = re.compile(r"^[*-] \[([ *x])\] (.+) - (.+)")
|
||||||
|
|
||||||
|
matches = []
|
||||||
|
with open(get_path(list_name)) as f:
|
||||||
|
matches = [entry_pattern.match(l) for l in f.readlines()]
|
||||||
|
return [m for m in matches if m is not None]
|
||||||
|
|
||||||
|
|
||||||
|
class Book:
|
||||||
|
def __init__(self, match : re.Pattern):
|
||||||
|
self.mark = match.group(1) != " "
|
||||||
|
self.author = match.group(2)
|
||||||
|
self.title = match.group(3)
|
||||||
|
|
||||||
|
def is_metadata_complete(self):
|
||||||
|
if not self.title or not self.author:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if self.title == "???" or self.author == "???":
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_list(list_name : str, filter_partial_metadata = True) -> []:
|
||||||
|
books = [Book(m) for m in get_matches(list_name)]
|
||||||
|
|
||||||
|
if filter_partial_metadata:
|
||||||
|
books = [b for b in books if b.is_metadata_complete()]
|
||||||
|
|
||||||
|
return books
|
||||||
|
|
||||||
|
|
||||||
|
def print_title(title : str, books : list[str]):
|
||||||
|
print(f"# {title} ({len(books)})\n")
|
||||||
|
|
||||||
|
|
||||||
|
def print_section(title : str, books : list[str]):
|
||||||
|
print_title(title, books)
|
||||||
|
longest_title = max([len(b.title) for b in books])
|
||||||
|
title_column_width = longest_title + 2
|
||||||
|
|
||||||
|
for book in books:
|
||||||
|
row = [book.title, book.author]
|
||||||
|
format_str = "- {: <" + str(title_column_width) + "} {: <20}"
|
||||||
|
print(format_str.format(*row))
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
def print_in_progress():
|
||||||
|
books = [b for b in Book.get_list(ready_list_name, False) if b.mark]
|
||||||
|
print_section("in progress", books)
|
||||||
|
|
||||||
|
|
||||||
|
def print_completed():
|
||||||
|
|
||||||
|
completed_books = []
|
||||||
|
summaries = []
|
||||||
|
|
||||||
|
for completed_list in completed_lists:
|
||||||
|
books = [b for b in Book.get_list(completed_list)]
|
||||||
|
year = completed_list.split(".")[0]
|
||||||
|
completed_books += books
|
||||||
|
summaries.append(f"{year} - {len(books)}")
|
||||||
|
|
||||||
|
print_title("completed", completed_books)
|
||||||
|
|
||||||
|
for s in summaries:
|
||||||
|
print(s)
|
||||||
|
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
def print_available():
|
||||||
|
books = []
|
||||||
|
for completed_list in completed_lists:
|
||||||
|
books += [b for b in Book.get_list(completed_list) if b.mark]
|
||||||
|
print_section("available", books)
|
||||||
|
|
||||||
|
|
||||||
|
def print_partial_metadata():
|
||||||
|
books = Book.get_list(ready_list_name, False)
|
||||||
|
|
||||||
|
for completed_list in completed_lists:
|
||||||
|
books += Book.get_list(completed_list, False)
|
||||||
|
|
||||||
|
books = [b for b in books if not b.is_metadata_complete()]
|
||||||
|
|
||||||
|
print_section("metadata incomplete", books)
|
||||||
|
|
||||||
|
print_in_progress()
|
||||||
|
print_completed()
|
||||||
|
print_available()
|
||||||
|
print_partial_metadata()
|
|
@ -0,0 +1,63 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import markdown
|
||||||
|
import pathlib
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
|
||||||
|
def print_usage():
|
||||||
|
print("\nusage: python feed.py ROOT\n")
|
||||||
|
print("\n")
|
||||||
|
print("\t\ROOT\tbase folder")
|
||||||
|
|
||||||
|
# check args for at most one file paths
|
||||||
|
if len(sys.argv) > 2:
|
||||||
|
print_usage()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
base_folder = sys.argv[1] if len(sys.argv) == 2 else os.getcwd()
|
||||||
|
print(base_folder)
|
||||||
|
|
||||||
|
def get_paths() -> [str]:
|
||||||
|
return [x for x in glob.glob(f"{base_folder}/*.md")]
|
||||||
|
|
||||||
|
def get_text(path):
|
||||||
|
with open(path) as f:
|
||||||
|
return f.read()
|
||||||
|
|
||||||
|
#def to_html(md : str) -> str:
|
||||||
|
# return markdown.markdown(md, extensions=["fenced_code"])
|
||||||
|
|
||||||
|
def get_title(md):
|
||||||
|
m = re.compile(r"^# (.+)\n").match(md)
|
||||||
|
if m is not None:
|
||||||
|
return m.groups(1)[0]
|
||||||
|
|
||||||
|
# truncated first line of file for auto-title
|
||||||
|
return md.splitlines()[0][0:30]
|
||||||
|
|
||||||
|
def get_entry(path):
|
||||||
|
return get_title(get_text(path))
|
||||||
|
|
||||||
|
def get_entries() -> [str]:
|
||||||
|
entries = [get_entry(p) for p in get_paths()]
|
||||||
|
return "\n\n".join(entries)
|
||||||
|
|
||||||
|
def get_header() -> str:
|
||||||
|
return """<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
|
||||||
|
<channel>
|
||||||
|
<title></title>
|
||||||
|
<link>https://ktyl.dev/garden</link>
|
||||||
|
<description></description>
|
||||||
|
<atom:link href="https://ktyl.dev/garden/feed.xml" rel="self" type="application/rss+xml"/>
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_footer() -> str:
|
||||||
|
return "\n</channel></rss>"
|
||||||
|
|
||||||
|
print(get_header())
|
||||||
|
print(get_entries())
|
||||||
|
print(get_footer())
|
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
python feed.py `pwd`
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
|
||||||
|
<channel>
|
||||||
|
<title></title>
|
||||||
|
<link>https://ktyl.dev/garden</link>
|
||||||
|
<description></description>
|
||||||
|
<atom:link href="https://ktyl.dev/garden/feed.xml" rel="self" type="application/rss+xml"/>
|
||||||
|
|
||||||
|
Digital Gardens
|
||||||
|
|
||||||
|
RSS
|
||||||
|
|
||||||
|
</channel></rss>
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Digital Gardens
|
||||||
|
|
||||||
|
* Obsidian
|
||||||
|
* Notion
|
||||||
|
* Git
|
|
@ -0,0 +1,32 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import markdown
|
||||||
|
|
||||||
|
def print_usage():
|
||||||
|
print(f"usage: python {sys.argv[0]} PATHS")
|
||||||
|
print("")
|
||||||
|
print("\t\PATHS\tpaths of input markdown files")
|
||||||
|
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print_usage()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
paths = sys.argv[1:]
|
||||||
|
|
||||||
|
bad_paths = [p for p in paths if not p.endswith(".md")]
|
||||||
|
if len(bad_paths) != 0:
|
||||||
|
for p in bad_paths:
|
||||||
|
print(f"Not a markdown file: {p}")
|
||||||
|
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
def write_html(src : str):
|
||||||
|
with open(src) as md:
|
||||||
|
dest = src.replace(".md", ".html")
|
||||||
|
with open(dest, "w") as html:
|
||||||
|
print(f"{src} -> {dest}")
|
||||||
|
html.write(markdown.markdown(md.read()))
|
||||||
|
|
||||||
|
for p in paths:
|
||||||
|
write_html(p)
|
|
@ -0,0 +1,35 @@
|
||||||
|
# RSS
|
||||||
|
|
||||||
|
Really Simple Syndication (RSS) is an ancient file format for communicating updates over the Web, and my personal favourite.
|
||||||
|
|
||||||
|
* [It's Time for an RSS Revival](https://www.wired.com/story/rss-readers-feedly-inoreader-old-reader/)
|
||||||
|
|
||||||
|
### Stubs:
|
||||||
|
|
||||||
|
* my curated feeds
|
||||||
|
* reader applications
|
||||||
|
|
||||||
|
## Technical Simplicity
|
||||||
|
|
||||||
|
From a technical perspective, like [Gemini](gemini://gemini.circumlunar.space) [\(HTTP\)](https://gemini.circumlunar.space/) it's grokkable with a couple good reads of the specification.
|
||||||
|
I wrote [a simple generator](https://ktyl.dev/blog/2022/6/3/rss.md)] for my blog posts, and am now working on [a simpler one](./feed.py) for the garden.
|
||||||
|
To start with, I'd like to generate it as simply as possible, from just a directory structure, but I can already see I'd like to do more with it.
|
||||||
|
|
||||||
|
I work predominantly in [Git](https://git-scm.com/) repositories, which, like a directory, or a garden, is tree-based.
|
||||||
|
My blog's feed has a chronological hierarchy, but at present it's based on manually creating and naming folders.
|
||||||
|
It's also very much a _published_ format, rather than a living one.
|
||||||
|
This is silly!
|
||||||
|
Instead, I'd like to structure my feed around a Git repository, as I think it'd be a much better descriptor of activity.
|
||||||
|
|
||||||
|
## Managing YouTube Subscriptions
|
||||||
|
|
||||||
|
There are many reasons to avoid the YouTube homepage, such as recommended videos or the accursed Shorts.
|
||||||
|
YouTube publishes channel-specific RSS feeds, making it totally possible to circumvent its subscription system entirely - including having to make an account - and keep track of channels one enjoys with RSS feeds instead.
|
||||||
|
Get a channel's ID:
|
||||||
|
|
||||||
|
1. Go to the channel's page
|
||||||
|
2. Go to the About section
|
||||||
|
3. Share icon under Stats block
|
||||||
|
4. Copy channel ID
|
||||||
|
|
||||||
|
The channel's feed is available at `https://www.youtube.com/feeds/videos.xml?channel_id=CHANNEL_ID_HERE`.
|
|
@ -2,4 +2,5 @@
|
||||||
<li><a href="/about.html">about</a></li>
|
<li><a href="/about.html">about</a></li>
|
||||||
<li><a href="/blog.html">blog</a></li>
|
<li><a href="/blog.html">blog</a></li>
|
||||||
<li><a href="/gallery.html">gallery</a></li>
|
<li><a href="/gallery.html">gallery</a></li>
|
||||||
|
<li><a href="/garden/index.html">garden</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8"/>
|
||||||
|
<link rel="stylesheet" href="styles.css" />
|
||||||
|
</head>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="centre">
|
||||||
|
<img id="portrait" src="img/stargazer.png"></img>
|
||||||
|
<div id="text-box"></div>
|
||||||
|
<a id="button" href="#" onclick="advance()">start</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
<script src="main.js"></script>
|
After Width: | Height: | Size: 235 KiB |
After Width: | Height: | Size: 169 KiB |
After Width: | Height: | Size: 94 KiB |
After Width: | Height: | Size: 251 KiB |
After Width: | Height: | Size: 106 KiB |
After Width: | Height: | Size: 155 KiB |
After Width: | Height: | Size: 135 KiB |
After Width: | Height: | Size: 107 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 47 KiB |
After Width: | Height: | Size: 174 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 109 KiB |
After Width: | Height: | Size: 164 KiB |
After Width: | Height: | Size: 79 KiB |
After Width: | Height: | Size: 255 KiB |
After Width: | Height: | Size: 98 KiB |
After Width: | Height: | Size: 133 KiB |
After Width: | Height: | Size: 198 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 237 KiB |
After Width: | Height: | Size: 134 KiB |
After Width: | Height: | Size: 149 KiB |
After Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 132 KiB |
After Width: | Height: | Size: 120 KiB |
After Width: | Height: | Size: 146 KiB |
After Width: | Height: | Size: 374 KiB |
After Width: | Height: | Size: 55 KiB |
After Width: | Height: | Size: 139 KiB |
After Width: | Height: | Size: 138 KiB |
After Width: | Height: | Size: 229 KiB |
After Width: | Height: | Size: 163 KiB |
After Width: | Height: | Size: 173 KiB |
After Width: | Height: | Size: 90 KiB |
After Width: | Height: | Size: 190 KiB |
After Width: | Height: | Size: 170 KiB |
After Width: | Height: | Size: 134 KiB |
After Width: | Height: | Size: 273 KiB |
After Width: | Height: | Size: 151 KiB |
After Width: | Height: | Size: 473 KiB |
After Width: | Height: | Size: 142 KiB |
After Width: | Height: | Size: 151 KiB |
After Width: | Height: | Size: 196 KiB |
After Width: | Height: | Size: 136 KiB |
After Width: | Height: | Size: 69 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 284 KiB |
After Width: | Height: | Size: 288 KiB |
After Width: | Height: | Size: 186 KiB |
After Width: | Height: | Size: 127 KiB |
After Width: | Height: | Size: 119 KiB |
After Width: | Height: | Size: 482 KiB |
After Width: | Height: | Size: 96 KiB |
After Width: | Height: | Size: 112 KiB |
After Width: | Height: | Size: 348 KiB |
After Width: | Height: | Size: 137 KiB |
After Width: | Height: | Size: 64 KiB |
After Width: | Height: | Size: 64 KiB |
After Width: | Height: | Size: 209 KiB |
After Width: | Height: | Size: 114 KiB |
After Width: | Height: | Size: 79 KiB |
After Width: | Height: | Size: 226 KiB |
After Width: | Height: | Size: 220 KiB |
After Width: | Height: | Size: 164 KiB |
After Width: | Height: | Size: 110 KiB |
After Width: | Height: | Size: 102 KiB |
After Width: | Height: | Size: 114 KiB |
After Width: | Height: | Size: 236 KiB |
After Width: | Height: | Size: 242 KiB |
After Width: | Height: | Size: 290 KiB |
After Width: | Height: | Size: 410 KiB |
After Width: | Height: | Size: 139 KiB |
After Width: | Height: | Size: 177 KiB |
|
@ -0,0 +1,62 @@
|
||||||
|
let idx = 0
|
||||||
|
|
||||||
|
let frames = [
|
||||||
|
"hello! you're just in time!", "img/yay.png", null,
|
||||||
|
"this was starting to get ridiculous.", "img/you-shouldnt-be-doing-that.png", null,
|
||||||
|
"there are books EVERYWWHERE", "img/scared.png", null,
|
||||||
|
"and more keep coming!", "img/oshit.png", null,
|
||||||
|
"we've got to do something about it before the deadline!", "img/determined.png", null,
|
||||||
|
|
||||||
|
"hey, could you sort the books for me?", "img/books-messy.png", "stack books by size",
|
||||||
|
|
||||||
|
"yes, i can you've finished STACKING them,", "img/books-size.png", null,
|
||||||
|
"but that's hardly FINISHED, is it?", "img/books-size.png", null,
|
||||||
|
"i mean sure, if you want to be a pedant about it they're sort of ordered by size,", "img/nonplussed.png", null,
|
||||||
|
"but they're still just piled up in the same place, what's that supposed to change?", "img/coffee.png", null,
|
||||||
|
|
||||||
|
"why don't you try again?", "img/books-size.png", "push stack over",
|
||||||
|
"", "img/books-messy.png", "order books by colour",
|
||||||
|
"", "img/books-colour.png", null,
|
||||||
|
|
||||||
|
"no, colours won't work either.", "img/dreamer0.png", null,
|
||||||
|
"why?", "img/blast.png", null,
|
||||||
|
"simple, i don't do colours.", "img/grin.png", null,
|
||||||
|
"it's nothing personal, they're just not for me, you know?", "img/glad-you-asked.png", "restart"
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
function setText(text) {
|
||||||
|
document.getElementById('text-box').innerHTML = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setImage(path) {
|
||||||
|
document.getElementById('portrait').src = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setButtonText(text) {
|
||||||
|
console.log(text);
|
||||||
|
if (text == null)
|
||||||
|
{
|
||||||
|
text = "next";
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('button').innerHTML = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
function advance() {
|
||||||
|
const stride = 3;
|
||||||
|
|
||||||
|
if (idx >= frames.length) {
|
||||||
|
idx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let text = frames[idx];
|
||||||
|
let img = frames[idx + 1];
|
||||||
|
let buttonText = frames[idx + 2];
|
||||||
|
|
||||||
|
setText(text);
|
||||||
|
setButtonText(buttonText);
|
||||||
|
setImage(img);
|
||||||
|
|
||||||
|
idx += stride;
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
img {
|
||||||
|
max-height: 70vh;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.centre {
|
||||||
|
margin: auto;
|
||||||
|
padding: 0;
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#button {
|
||||||
|
font-size: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#text-box {
|
||||||
|
width 100%;
|
||||||
|
height: 4em;
|
||||||
|
}
|
||||||
|
|