add a markdown template and styling for tables
This commit is contained in:
parent
00fc46587a
commit
ed9413532e
1
Pipfile
1
Pipfile
@ -5,6 +5,7 @@ name = "pypi"
|
|||||||
|
|
||||||
[packages]
|
[packages]
|
||||||
jinja2 = "*"
|
jinja2 = "*"
|
||||||
|
markdown = "*"
|
||||||
|
|
||||||
[dev-packages]
|
[dev-packages]
|
||||||
|
|
||||||
|
|||||||
21
articles/article.template.md
Normal file
21
articles/article.template.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<!-- see generate.ignore.py for how this is used with .article.md files! -->
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
{% block head %}
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>{% block title %}Writings by Shoofle{% endblock %}</title>
|
||||||
|
<script src="/static/jquery.min.js" type="text/javascript"></script>
|
||||||
|
<link href="/static/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css">
|
||||||
|
<link href="/static/bootstrap/css/bootstrap-responsive.css" rel="stylesheet" type="text/css">
|
||||||
|
<link href="/static/shoofle.css" rel="stylesheet" type="text/css">
|
||||||
|
{% endblock %}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{% block body -%}
|
||||||
|
<article>
|
||||||
|
{{ contents }}
|
||||||
|
</article>
|
||||||
|
{%- endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
8
articles/forest.article.html
Normal file
8
articles/forest.article.html
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<article>
|
||||||
|
<p>I think there's an interesting conceptual link between wikis and MUDs. Specifically, MUDs that allow you to build the map from within the game. The world of a MUD and the pages of a wiki form a graph of connected pages the user can move between and edit. I think that's neat.</p>
|
||||||
|
<p>I spent some time in an early relationship out of college playing around in a MUD called <a href="https://en.wikipedia.org/wiki/LambdaMOO">LambdaMOO</a>. It's built around an object-oriented programming paradigm and users have a tremendous freedom to script and reshape the world from within. I had a lot of fun building a city, and then scripting an NPC to wander around the city recording things for export.</p>
|
||||||
|
<p>LambdaMOO has its own scripting language which is closely tied with the natural language parsing of the MUD-style interface. Its functions are all "verbs" which can be (generally) called through syntax like the classic "take lantern from chest" interface, and the natural-language-first design of the script really stuck with me. I have always found myself wondering what else its design insights could be applied to.</p>
|
||||||
|
<p>Wikis are really cool, and I think we're all familiar with them. I've always been interested in how wikis kind of fulfill the original dream of hypertext, of documents with easy-to-traverse links between them. And I think it's fascinating how wikis (with their reading and clicking on links and writing new pages) correspond to MUDs (with their looking and traveling and digging new rooms) and it's always been sitting in the back of my head wondering "could those be combined?"</p>
|
||||||
|
<p>So I'm embarking on the project of writing my very first wiki software. Please set aside for a moment the fact that I'm once again building the tools for creative work rather than doing the creative work itself.</p>
|
||||||
|
<p>I'm planning on doing this with react and libSQL, at least to start. Let's go!</p>
|
||||||
|
</article>
|
||||||
@ -1,6 +1,5 @@
|
|||||||
<article>
|
<article>
|
||||||
<h1 id="an-asynchronous-assembly-adventure-on-the-game-boy-" class="title">an asynchronous assembly adventure, on the game boy!</h1>
|
<h1 id="an-asynchronous-assembly-adventure-on-the-game-boy-" class="title">an asynchronous assembly adventure, on the game boy!</h1>
|
||||||
<p><strong>By:</strong> Shoofle</p>
|
|
||||||
<p>As a preface: This article assumes some familiarity with assembly, or a willingness to pick it up on the fly. The super ultra quick crash course on game boy sm83 assembly is this: </p>
|
<p>As a preface: This article assumes some familiarity with assembly, or a willingness to pick it up on the fly. The super ultra quick crash course on game boy sm83 assembly is this: </p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>ld a, b</code> means "copy the value from register <code>b</code> into register <code>a</code>" (note the order!)</li>
|
<li><code>ld a, b</code> means "copy the value from register <code>b</code> into register <code>a</code>" (note the order!)</li>
|
||||||
@ -505,5 +504,4 @@ def ASYNC_STACK_FUNCTION = ASYNC_STACK_EARLY_RETURN - <span class="hljs-number">
|
|||||||
</ul>
|
</ul>
|
||||||
<p>And finally, some disclaimers and warnings:</p>
|
<p>And finally, some disclaimers and warnings:</p>
|
||||||
<p>Variable names have been changed to protect the innocent. There's some layers of indirection I've skipped, such as the interrupt vector jumping into a specified RAM address edited for configurable interrupts. This could have been avoided if I had known about the <code>jp hl</code> instruction, but it's probably faster. Concurrent access to RAM is the same headache as in modern code, which has caused some truly perplexing bugs - there's a very small chance that a context switch will happen between writing the first byte of an important memory address and the second byte, which can wreak havoc. I found it was usually sufficient to temporarily disable interrupts to make operations atomic - surround a memory access with <code>di</code> and <code>ei</code> to turn interrupts on and off, and they'll get handled afterwards if they happened in between. I am not an expert. In fact I know shockingly little about the conventional wisdom. This does not constitute legal or medical advice.</p>
|
<p>Variable names have been changed to protect the innocent. There's some layers of indirection I've skipped, such as the interrupt vector jumping into a specified RAM address edited for configurable interrupts. This could have been avoided if I had known about the <code>jp hl</code> instruction, but it's probably faster. Concurrent access to RAM is the same headache as in modern code, which has caused some truly perplexing bugs - there's a very small chance that a context switch will happen between writing the first byte of an important memory address and the second byte, which can wreak havoc. I found it was usually sufficient to temporarily disable interrupts to make operations atomic - surround a memory access with <code>di</code> and <code>ei</code> to turn interrupts on and off, and they'll get handled afterwards if they happened in between. I am not an expert. In fact I know shockingly little about the conventional wisdom. This does not constitute legal or medical advice.</p>
|
||||||
<p><em>I can be reached as "shoofle" wherever the internet is sold - most frequently these days i'm on <a href="https://beach.city/@shoofle">the fediverse as @shoofle@beach.city</a>, or on <a href="https://bsky.app/profile/shoofle.bsky.social">bluesky as shoofle.bsky.social</a>, or on <a href="https://ada-adorable.tumblr.com">tumblr as ada-adorable</a>. Gimme a holler if you read this!</em></p>
|
|
||||||
</article>
|
</article>
|
||||||
|
|||||||
80
articles/lcdt/notes.article.md
Normal file
80
articles/lcdt/notes.article.md
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
## tarot deck for the game boy!
|
||||||
|
|
||||||
|
for the last year, i've been working on a tarot deck for the nintendo game boy.
|
||||||
|
|
||||||
|
it's a full 78 card deck of pixel art illustrations. the major arcana are fully animated and shaded, and the minor arcana are in a silhouette style. the cartridge also shows you a few meanings for each card, including reversed cards, and allows you to shuffle the deck and perform readings, with a small library of spreads to choose from. it also supports the game boy printer, allowing you to print out the cards so you can hold on to them!
|
||||||
|
## the beginning
|
||||||
|
|
||||||
|
it's been a journey to make this. i had the idea sometime, in the year before i started work, that it would be funny to make a tarot deck for the game boy. i had a vision that it could help you do readings, index the meanings of cards, and let you print them out on the game boy printer. i have a love of "useful" software, especially when it's on something like a game console. it's so silly! i love the idea of being able to accomplish something with a computer, rather than just sinking time into it and getting experiences out. and who (aside from nintendo) doesn't love some retro homebrew software?
|
||||||
|
|
||||||
|
i've done a lot of projects for a long time. i'm a project-oriented person. i love arts and crafts. but most of my projects tend to get far enough that i can show them to a friend and say "hey, look at this!" and it's just finished enough that you can get what i'm going for. i get things to the proof-of-concept stage. but as i've been slowly angling towards going back into the professional sector, and thinking about building my portfolio, i thought maybe i should try to get things to more of a finished stage - so i can show them to a stranger and the stranger will really get what i'm trying to accomplish. this year my goal has been to actually finish and polish things.
|
||||||
|
|
||||||
|
so when i started looking into one of my old obsessions (the nintendo game boy) this year, the tarot project seemed like a natural fit. i'd exercise my art skills, i'd learn a new programming environment and language, and i'd produce something cool that would impress people. initially i thought it would take me a month or two.
|
||||||
|
|
||||||
|
## drawing in aseprite and coding in rgbds-live
|
||||||
|
|
||||||
|
it was smooth sailing early on. the whole project was built inside [rgbds-live](https://gbdev.io/rgbds-live/), a web interface to the venerable rgbds toolchain for game boy homebrew. i didn't know assembly, but i'm a dab hand at picking things up. i started poking at it, moving things around, and before long i had started on the work of building my standard framework of screens, bookkeeping functions, update and draw calls, and so on.
|
||||||
|
|
||||||
|
i also found [an export script](https://github.com/redboyrave/Aseprite-GB-Exporter/tree/main) for pixel art software Aseprite which could be readily modified for my purposes. i built a tool for generating and editing lists of points for animation data, i built some python functions for manipulating data in asm formats, and all around i was having a ball.
|
||||||
|
|
||||||
|
and i started drawing cards.
|
||||||
|
|
||||||
|
i can say i've gotten a lot better at art over this project. some of the early versions of card art were cringe-inducing, and i've still got a list of changes i'd make if i had infinite time. but when i started i think i didn't really comprehend in my soul how many cards are in a tarot deck. doing a series of 22 careful illustrations, including animation, which has to be programmed in assembly, was just. i can't overstate how much work it was. and then later i would make the ludicrous decision to *increase* that to 78.
|
||||||
|
|
||||||
|
this deck is largely in the style of rider-waite-smith, although many of my cards deviate from the specific compositions and i eschew a lot of the esoteric details. my Death is much more stark. my Lovers was a right-out-the-gate decision and it wasn't until my consultants pointed out the strong parallel that I re-composed Devil to match. I'm particularly happy with my Chariot, which is a much more dynamic composition than rider-waite-smith, and i think communicates its ideas of power and control and speed quite well. I chose to replace Judgment with The Meteor (as in "that killed the dinosaurs", or other apocalyptic scenarios), both to give a little bit of abstracting flair, and to better pull together the final five cards as an Astral Sequence. if you look you will notice that the positions of the astral bodies in focus descend over their course towards the center.
|
||||||
|
|
||||||
|
The World is really my piece de resistance; as on the main title screen, I have once again opted to make some pseudo-3d graphics, for the heck of it. getting its animation to form an illusion of a curved shape was complex, given the limited facilities for arithmetic operations. once again data tables are my friend! it's achieved with a matrix of bit flag values that control how far to move each component of the world map for each zone it can be in, so it moves slowly at the edges, and quickly in the middle.
|
||||||
|
|
||||||
|
speaking of the main title screen, it was one of the earliest things I actually built. it's stored as a list of 255 y/x/size pairs, precalculated by a python script; every frame it simply draws three cards at three points in that list. unfortunately the code for drawing the cards is horrendous; i may go back and clean it up.
|
||||||
|
|
||||||
|
over the course of this project i've gone from having no experience with assembly to having a lot. i understand a lot of things now. i've become adept at using subroutine calls and jump tables, computing offsets into arrays, building simple data structures, using the assembler to define static data layouts in ram, and i've even built a system that uses the game boy's interrupts to allow parallel execution of code; i detailed this adventure in [the advent async article].
|
||||||
|
|
||||||
|
i really enjoy assembly programming now, although i'd certainly prefer something higher level if i were going to make anything this big (or larger) again. i describe assembly as writing code while simultaneously solving a puzzle, because you don't have variables to work with, there's such limits on what values you can compute with, you have limited space to worry about, and so on. it's great fun, but of course quite limiting!
|
||||||
|
|
||||||
|
i'm permanently indebted to the fine folks who made rgbds-live, which executes the rgbds toolchain and provides a web interface to it with a live emulator and some debugging facilities. i certainly could have made this with just the basic rgbds tools, writing build scripts myself and such, but it was so easy to simply work in the browser with the emulator live next to the code... and i only ran into issues once or twice with extreme edge cases.
|
||||||
|
|
||||||
|
for my code i decided to use the stack almost exclusively as a call stack, and not for passing data, and never reset it from its starting location of high HRAM. this was a silly decision, and meant i wasn't using some features of the processor, but what's done is done. using it only as a call stack meant it stayed short - never more than 16 or so bytes, i think - and meant i could pack two stacks into the space when i eventually branched for having parallel code. i think it is customary to pass extra arguments on the stack as well? but i essentially always pass arguments in registers, with a few that use static memory locations to hold important values. this wouldn't work if i ever thought that two calls to a function might collide, but happily i simply guarantee it doesn't. packing all the arguments into the available registers sometimes required me to make questionable decisions - for example, my metatile sprite drawing routine (allocates sprites corresponding to a grid of tiles) takes the height and width tile counts in the high and low nibbles of the same register. this means i can't draw sprites something larger than 16x16 tiles, but i can just avoid doing that. there aren't that many sprites available anyway!
|
||||||
|
|
||||||
|
one of the moonshot ideas in this project was to have it interface with the game boy printer, a forgotten peripheral which allowed players to print out victory certificates and other images on thermal paper. this project never would have existed without the dedicated and thorough game boy development community, which has meticulously documented the behavior of the printer. even with their help, though, debugging serial communication and an opaque black box device was a challenge! and that's setting aside the question of actually doing graphical manipulation on the images. the printing code takes the tiles drawn to the screen, scales them by two, and simulates in software the sprites being drawn over them (including replacing palette values all around as necessary!), and then sends them 16 lines at a time to the printer, waiting for an OK signal between each batch. writing this - and interfacing it with my already-substantial UI code on two different screens - was a beast! i'm proud to say that it all works, though, and i have shitty receipt paper printouts of my art littering my desk.
|
||||||
|
|
||||||
|
the game boy has a native 64kb available to it, divided into a number of segments. at minimum, a rom can hold 32kb of data, which are directly accessed in the lower half of the memory space. however! with memory mapper chips, you can expand that, which is good, because i quickly ran out of room. the way this functions is whenever you write a byte to a special set of addresses in the rom, it will swap in a different "bank" of 16 kb in the second half of the rom space. so memory addresses 0-16k always hold the base of the rom, and addresses 16k-32k can be swapped for any of a large number of replacements (maximum size depending on the chip). this ended up being a little bit of a headache when i started swapping contexts, and is one of the weak spots of my parallel computation engine - it doesn't track that as part of the context to swap! in any case, it largely didn't impede me, because most of my actual game code was stored in the base 16k, and (mostly) only card data and sound were stored in the banked memory. fitting 5-8 cards into each bank meant we still ended up with a fair number, and i believe the final size of the rom is now 128kb. not the 4mb maximum, but certainly chunky as gameboy cartridges go!
|
||||||
|
|
||||||
|
the cards are stored in their own `.inc` files and apportioned into banks by `CardLibrary.inc`. that card library file also holds the list of spreads with descriptions, and the definitive store of card addresses, an array of three-byte tuples of the card's address plus which bank they need loaded. all of this is used by the `CardHelper.inc` functions which encapsulate a lot of the guts of manipulating cards, initializing card animation states, drawing cards, updating cards, and so on.
|
||||||
|
|
||||||
|
one of the sillier "mistakes" i made in this project was that i didn't notice, until very late, that there is in fact a `jp hl` instruction for a jump to a register. so instead i populated a list of dummy functions in work ram, each of the form `Handle: call $00; ret`. since these are in work memory, they can be directly changed, by editing their raw bytes, to point them at something new. then you simply jump to the static `Handle` address, and it will call whatever function you specified. if i had known about `jp hl` this kind of indirection wouldn't be needed, but alas! i took the hard way for no reason. one thing that has me kicking myself here is that i could have used a lot more jump tables if i had known how to implement them. as it is i only use the technique a few times.
|
||||||
|
|
||||||
|
i wrote a snazzy little implementation of a pseudorandom number generator! `Random.inc` holds a linear feedback shift register, which can be processed one bit at a time, or one byte at a time, and which is used for, well, random number generation. it's sorta a shame that i didn't end up actually needing it more than a tiny bit!
|
||||||
|
|
||||||
|
oh in the beginning of this section i mentioned my standard layout of scenes and helper functions. this is simple. in all sorts of different situations i end up writing the same code to deal with a multi-state application: somewhere there is a global variable holding what the present "scene" is. a "scene" or "screen" refers to a structure holding pointers to functions corresponding to initialization, frame update, frame draw, and optionally teardown. then there's a helper function to change what the active scene is, and then the game's main loop gets to do its own bookkeeping and setting up application-level variables (such as a delta time, or checking and compiling input states) and then call "current scene's update function", or "current scene's draw function", at the appropriate times. this lets you separate the universal behavior of how the update loop needs to behave from separately encapsulated per-screen variables and behaviors. it's worked pretty well for me. this cartridge has five screens: displaying a card while doing a reading, displaying a card while browsing, the shuffle interface, the spread selecting interface, and the main screen.
|
||||||
|
|
||||||
|
i'm really proud of doing 3d graphics on the game boy. have i mentioned that it doesn't have a multiply instruction? it doesn't have a multiply instruction. it doesn't even have modulo! wild.
|
||||||
|
|
||||||
|
|
||||||
|
## tooling
|
||||||
|
|
||||||
|
i worked primarily in rgbds-live, but i did accrue some extra tooling. i wrote several python functions i could use in the REPL to manipulate strings of data and generate values i wanted. aseprite was the name of the game for drawing pixel art. it's the best art program i know for pushing pixels, and i was able to get an export script working, which i'd also like to distribute widely. that export script renders the tiles (of an aseprite tilemap layer) into the appropriate bitplaned 2bpp format the game boy uses, and outputs them as hex literals in an array along with an array of indices describing the map itself. I rewrote it a bit to make it output compatible assembly data instead of C-style arrays, and add an offset value so you can load the tile data at whatever point in vram you like.
|
||||||
|
|
||||||
|
working in aseprite wasn't too bad. i certainly think it would have been a much worse experience in other programs! it has a few idiosyncracies like problems with generating dithered gradients, but i really can't complain. it did the job admirably.
|
||||||
|
|
||||||
|
I went through several options for adding music, which is still in progress. originally i was planning to compose my own. in the end i gave up on that; i believe someday i may learn music better, but at the moment it's one of the few things i consider beyond me. i went through a number of options for format, though, ranging from lsdj, to writing my own playback engine for a bespoke tracker format, to specially formatted schism tracker files, to the carillon editor (whose `.sav` file can be imported as a binary blob by your assembly, and indexed into to call functions for start, update, and pause!), to hugetracker (the standard for gameboy composition these days), back to writing my own, then to a hybrid approach, and finally i gave up. i'm using hugetracker, now, which requires a relatively small import and will do all the hard stuff for me, and a friend graciously offered to compose the music for me.
|
||||||
|
|
||||||
|
one of the things that i'm the most unhappy with about the overall state of this project is the use of disorganized `.inc` files. I have had trouble getting rgbds-live to work kindly with subdirectories, and i don't know how to configure it to build multiple .asm files into a single final project, so i have opted to simply not do that. so everything is in a massive tree of `.inc` files, there's a single `main.asm` file which is the entry point, and it's all in one directory, including 78 files for each card.
|
||||||
|
## the late: long slog, motivation, the experience
|
||||||
|
|
||||||
|
like i wrote earlier, one of the motivations for this project was to get better at finishing things, rather than just letting my projects linger in a half-finished state for eternity. i'm trying to get this done, not just play around until i get bored! so managing my motivation and enthusiasm levels was a huge part of this project's story. i'm deeply indebted to my husband for keeping me honest about working hours - they are strict in the face of my puppy dog eyes when i want to keep working after they get out of their job for the day. when they're out of work, i'm not allowed to work. i've been treating this as my job, but trying to make that a healthy thing instead of an anxiety-and-burnout-inducing thing. and i'm proud that i've managed consistent work on this for a year! there was one break for a couple of months after june when i wasn't feeling it, and it's been a little spotty as i wrap up loose ends and check things off my to-do list, but all in all i think i've done really well at sticking to my goals.
|
||||||
|
|
||||||
|
in particular this was a test of my art skills. i've always been a little bit of an artist, but this is far beyond the scope of anything i've done before; normally i just doodle and sketch, but liquid crystal dreams tarot required i make 78 finished illustrations (daunting), in pixel art (unfamiliar), with animations for some (never really done that). that was a lot! i'm really proud of myself, though, for just taking it a bit at a time. that's a struggle, given my tendency to catastrophize and drag myself down. i had to exercise nonjudgmental attitudes towards myself, avoiding the despair i'm inclined to feel when my art doesn't measure up to my quality standards. it was tough! in the end i'm really proud of what i made, even if it's not quite as good as i wanted.
|
||||||
|
|
||||||
|
when i started i was so used to sketching that i thought of my pixel art in terms of lines delineating shapes. but now, having drawn a lot more, i see how much pixel art is more like painting, with which i'm unfamiliar: you block out shapes, you don't draw their edges. you can still see traces of this sketchy approach in the early cards, before it gave way to the painterly style that i think works better.
|
||||||
|
|
||||||
|
i suppose if i wanted to put into words the core mysterious goal of this project, it's that i want to make something that wows people, even if they're not my friends. i've made so many things that my friends love and are impressed by, but which don't hold up to the scrutiny of an "impartial" observer; it's a part of my philosophy that i don't usually worry about that kind of thing. i keep working on things for me and my friends, and say screw the observer, that's too high of a standard to keep! and this has served me well. it's part of how i engage in so many arts and activities, to discard concern for how the outside world would see me and drag me down.
|
||||||
|
|
||||||
|
liquid crystal dreams has been an exercise in making something that can impress people even if they're not already on my side. i want something i can sell to people outside my friends and family, that people will see and *want*. that's the goal i'm striving to reach.
|
||||||
|
## finishing: publishing and packaging?
|
||||||
|
|
||||||
|
of course, you can't sell something without concern to the marketing, right? so i've been dipping my toes into the matter of publishing too. this has involved figuring out how to write cartridges, how to package and sell things, shipping costs, graphic design of marketing materials, writing copy (hi, that's what i'm doing right now! you're reading it!), and generally making everything ancillary needed for the process of getting a product out there and making sure people actually see and want and get it. i wrote an article about my parallel execution library that i'm proud of. i'm planning to write an essay about tarot cards and their meanings (which may become a companion book). i need to start writing a manual - and that's going to require gathering and formatting samples of the interface and art from the program itself! i'm gathering screenshots and recordings of art that i want to share to pique peoples' interest. marketing is a lot of work. normally it's work i eschew - i don't believe in letting the "outside world" influence me, and i make what i want to make, not what a nebulous populace wants! i don't want to sell my work, i want to make work that stands on its own and accomplishes its goal! but this is a project that really requires it, and it's a natural extension of this project, so i'm dipping my toes in. i might even make a kickstarter!
|
||||||
|
|
||||||
|
as for the particulars, i'm planning to sell the cartridges through homebrew factory, a possible deck of cards through the game crafter, and i got some stickers made from diecutstickers.com. i'm still looking for a printer for manuals at this time.
|
||||||
|
## final thoughts
|
||||||
|
|
||||||
|
this has been a lot of fun. i'm proud of it.
|
||||||
@ -3,6 +3,7 @@ import os
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import shutil
|
import shutil
|
||||||
import argparse
|
import argparse
|
||||||
|
import markdown
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument("-i", "--input", type=Path, help="source materials")
|
parser.add_argument("-i", "--input", type=Path, help="source materials")
|
||||||
@ -23,20 +24,21 @@ env = Environment(
|
|||||||
# article template is used for all .article.html files
|
# article template is used for all .article.html files
|
||||||
article_template = env.get_template("articles/article.template.html")
|
article_template = env.get_template("articles/article.template.html")
|
||||||
|
|
||||||
|
md = markdown.Markdown(extensions=["tables"])
|
||||||
|
|
||||||
|
template_for_markdown = env.get_template("articles/article.template.md")
|
||||||
|
|
||||||
for path_to_source in source.glob("**/*"):
|
for path_to_source in source.glob("**/*"):
|
||||||
rel_path = path_to_source.relative_to(source)
|
rel_path = path_to_source.relative_to(source)
|
||||||
path_to_output = finals / rel_path
|
path_to_output = finals / rel_path
|
||||||
|
|
||||||
if ".ignore" in str(rel_path):
|
if ".ignore" in str(rel_path): continue
|
||||||
continue
|
if ".git" in str(rel_path): continue
|
||||||
if ".git" in str(rel_path):
|
|
||||||
continue
|
|
||||||
|
|
||||||
if path_to_source.is_dir():
|
if path_to_source.is_dir(): pass
|
||||||
pass
|
|
||||||
|
|
||||||
elif ".article.html" in str(path_to_source):
|
elif ".article.html" in str(path_to_source):
|
||||||
# all .article.html files are transformed into a folder of the same name and then rendered with the template at index.html
|
# all .article.html files are transformed into a folder of the same name and then rendered with the at index.html
|
||||||
|
|
||||||
folder_name = path_to_output.parent / path_to_output.name.replace(".article.html","")
|
folder_name = path_to_output.parent / path_to_output.name.replace(".article.html","")
|
||||||
os.makedirs(folder_name, exist_ok=True) # make the folder /var/www/shoofle.net/articles/circle_script
|
os.makedirs(folder_name, exist_ok=True) # make the folder /var/www/shoofle.net/articles/circle_script
|
||||||
@ -46,15 +48,33 @@ for path_to_source in source.glob("**/*"):
|
|||||||
with open(path_to_output, "w") as output_file:
|
with open(path_to_output, "w") as output_file:
|
||||||
output_file.write(article_template.render(title="Article", target=str(rel_path)))
|
output_file.write(article_template.render(title="Article", target=str(rel_path)))
|
||||||
|
|
||||||
|
|
||||||
|
elif ".article.md" in str(path_to_source):
|
||||||
|
# all .article.md files are rendered, then the same thing done as for article.html files
|
||||||
|
|
||||||
|
text = f"something must have gone wrong in the parsing of {path_to_source} for you to see this"
|
||||||
|
with open(path_to_source, "r") as input_file:
|
||||||
|
text = input_file.read()
|
||||||
|
|
||||||
|
html_source = md.convert(text)
|
||||||
|
|
||||||
|
folder_name = path_to_output.parent / path_to_output.name.replace(".article.md", "")
|
||||||
|
os.makedirs(folder_name, exist_ok=True)
|
||||||
|
|
||||||
|
path_to_output = folder_name / "index.html"
|
||||||
|
|
||||||
|
with open(path_to_output, "w") as output_file:
|
||||||
|
output_file.write(template_for_markdown.render(title="Article", contents=html_source))
|
||||||
|
|
||||||
elif ".renderme" in str(path_to_source):
|
elif ".renderme" in str(path_to_source):
|
||||||
path_to_output = path_to_output.parent / path_to_output.name.replace(".renderme","")
|
path_to_output = path_to_output.parent / path_to_output.name.replace(".renderme","")
|
||||||
with open(path_to_output, "w") as output_file:
|
with open(path_to_output, "w") as output_file:
|
||||||
os.makedirs(path_to_output.parent, exist_ok=True)
|
os.makedirs(path_to_output.parent, exist_ok=True)
|
||||||
output_file.write(env.get_template(rel_path).render())
|
output_file.write(env.get_template(rel_path).render())
|
||||||
|
|
||||||
elif ".template.html" in str(path_to_source):
|
elif ".template.html" in str(path_to_source): pass
|
||||||
pass
|
elif ".template.md" in str(path_to_source): pass
|
||||||
|
|
||||||
else:
|
else:
|
||||||
os.makedirs(path_to_output.parent, exist_ok=True)
|
os.makedirs(path_to_output.parent, exist_ok=True)
|
||||||
shutil.copy(path_to_source, path_to_output)
|
shutil.copy(path_to_source, path_to_output)
|
||||||
|
|||||||
14
index.html
14
index.html
@ -18,32 +18,38 @@
|
|||||||
<div class="span8">
|
<div class="span8">
|
||||||
<div class="row-fluid">
|
<div class="row-fluid">
|
||||||
<div class="span4">
|
<div class="span4">
|
||||||
<div class="small_project art">
|
<div class="small_project coding">
|
||||||
<p class="description"><a href="articles/lcdt/async/">LCDT: Async Assembly Adventure</a></p>
|
<p class="description"><a href="articles/lcdt/async/">LCDT: Async Assembly Adventure</a></p>
|
||||||
<p class="name">I wrote about developing asynchronous execution in assembly on the nintendo game boy.</p>
|
<p class="name">I wrote about developing asynchronous execution in assembly on the nintendo game boy.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="span4">
|
||||||
|
<div class="small_project game">
|
||||||
|
<p class="description"><a href="articles/forest">The Forest</a></p>
|
||||||
|
<p class="name">The Forest, a MUD with wiki characteristics.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="span4">
|
<div class="span4">
|
||||||
<div class="small_project web">
|
<div class="small_project web">
|
||||||
<p class="description">The shoofle.net constellation!</p>
|
<p class="description">The shoofle.net constellation!</p>
|
||||||
<p class="name"> I run a gitea server on <a href="https://git.shoofle.net">git.shoofle.net</a> and this server at <a href="https://shoofle.net">shoofle.net</a>.</p>
|
<p class="name"> I run a gitea server on <a href="https://git.shoofle.net">git.shoofle.net</a> and this server at <a href="https://shoofle.net">shoofle.net</a>.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row-fluid">
|
||||||
<div class="span4">
|
<div class="span4">
|
||||||
<div class="small_project art">
|
<div class="small_project art">
|
||||||
<p class="description"><a href="articles/circle-script/">Circle Script</a></p>
|
<p class="description"><a href="articles/circle-script/">Circle Script</a></p>
|
||||||
<p class="name">I created an artsy phonetic writing system for making intricate circles.</p>
|
<p class="name">I created an artsy phonetic writing system for making intricate circles.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="row-fluid">
|
|
||||||
<div class="span4">
|
<div class="span4">
|
||||||
<div class="small_project game">
|
<div class="small_project game">
|
||||||
<p class="description"><a href="articles/atelier-phoebe">Atelier Phoebe</a></p>
|
<p class="description"><a href="articles/atelier-phoebe">Atelier Phoebe</a></p>
|
||||||
<p class="name">An Atelier fangame made for the <a href="https://www.lexaloffle.com/pico-8.php">Pico-8</a>.</p>
|
<p class="name">An Atelier fangame made for the <a href="https://www.lexaloffle.com/pico-8.php">Pico-8</a>.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="span6">
|
<div class="span4">
|
||||||
<div class="small_project game">
|
<div class="small_project game">
|
||||||
<p class="description"><a href="articles/mindjail-engine">A 2D Physics-Based Game Engine in Python with OpenGL</a></p>
|
<p class="description"><a href="articles/mindjail-engine">A 2D Physics-Based Game Engine in Python with OpenGL</a></p>
|
||||||
<p class="name">The Mindjail Engine, my hand-crafted 2D game engine!</p>
|
<p class="name">The Mindjail Engine, my hand-crafted 2D game engine!</p>
|
||||||
|
|||||||
BIN
static/WHA.epub
BIN
static/WHA.epub
Binary file not shown.
@ -62,6 +62,20 @@ figcaption {
|
|||||||
|
|
||||||
.file-tree, .file-tree ul { list-style: none; }
|
.file-tree, .file-tree ul { list-style: none; }
|
||||||
|
|
||||||
|
/* default styling for tables: 1em corner-radius on the whole table, plus 1px solid black between them? */
|
||||||
|
table {
|
||||||
|
border-collapse: separate;
|
||||||
|
border: 1px solid black;
|
||||||
|
border-radius: 1em;
|
||||||
|
border-spacing: 0;
|
||||||
|
max-width: 70%;
|
||||||
|
}
|
||||||
|
table td { padding: 0.5em 1.5em 0.5em 1.5em; }
|
||||||
|
thead th { border-bottom: 1px solid black; }
|
||||||
|
tr td { border-bottom: 1px solid black; }
|
||||||
|
tr:last-child td { border-bottom: none; }
|
||||||
|
td { border-right: 1px solid black; }
|
||||||
|
td:last-child { border-right: none; }
|
||||||
|
|
||||||
/* background and color coding to differentiate URLs and filepaths from surrounding text. */
|
/* background and color coding to differentiate URLs and filepaths from surrounding text. */
|
||||||
.filename, .url {
|
.filename, .url {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user