Making a |[custom] blog
One optional, but useful, part of any project is recording the process.


I have always tried to do this, with varying amounts of success, and varying amounts of effort, and with varying medians, with my most recent median being discord.

Since discord is not a place designed to be used for blogs, it lacks a lot of aspects I would want for a blog, things like:
 *
A lack of any good way to insert media throughout a message.
 *
A very limiting file size for anything uploaded.
 *
No way of adding colored text.
 *
Very limited formatting.
 *
No way to embed live code.
 *
No good way to share posts.
 *
No guarantee that the posts wouldn't be removed.
And no way to change any of this.
So I decided to make my own blog
But this comes with a lot of challenges too:
 *
How am I going to model this blog?
 *
What do I want the process of creating a post to look like?
 *
What all do I want a post to be capable of?
 *
Whats going to tie all the posts together?
 *
Have I fed my cat yet?
 *
How am I going to publish this blog?

Some of there questions have easy answers:
 *
What do I want the process of creating a post to look like? I want to write text as markup in a text file, putting links to media in the text as needed, and just putting all the media and text in a folder and having it automatically generate a post.
 *
Whats going to tie all the posts together? A home page with previews of each post that can be clicked to open them.
 *
Have I fed my cat yet? Yes, though she says otherwise.
 *
How am I going to publish this blog? I can just push to github, then use Vercel to host the site.

Starting off I wanted to use a new design for project: processing all the posts on my local machine, then only publishing the translated files, seeing as this needs file manipulation to do (since all the files for the finished website would be generated by other code), and I am most familiar with JS, node seemed like the logical choice for a base.

Time to start: I make a script to scan all the files in a specific folder for posts, processing them all slightly to format them for html, putting them together in a folder, and pushing them to github...

I had forgot an important step: before I can have posts I need a home page to get to the posts from.
But I wanted this page to look nice, and not just be an empty page of links, so I looked around for inspiration, and I found this:
factorioBlog.pngAnd look at it: a nice title section, a consistent color scheme, inline images, and (not shown) videos!
But more importantly, the background, it ties the post together without making it feel like it consumes all the screen space, plus with an already semi vertical design making this site work on mobile will be much easier.

Now that I had a layout I needed a background, for the factorio example a factory in the background is in theme, but for my blog the topic changes, I can't just have an image of a finished project (or I could but I don't like the idea of that), I wanted something relevant to all my projects.

But what do all my projects have in common?
Programming.
I knew what I wanted:
Live backgrounds
What is a live background? For my use cases a live background is any background that is not pre generated, but is instead has a small program running to generate the background live.

Planning: what power did I want to give these backgrounds? How do I want to structure them? And how do I want to theme them?

Next I created a simple system to create live backgrounds thats answers these questions:
 *
Each background is a js module.
 *
The backgrounds render on a canvas element set behind all the websites content.
 *
Each background exports a start and a stop function.
 *
Each background grabs the canvas and context each time it's start function is ran.
 *
A central script schedules starting and stopping each background, as well as mixing them to ensure each one gets the appropriate screen time.

And while this was nice, the system had its problems:
 *
Since each background was in charge of keeping a loop, when I ended one background and started a new one, sometimes the old background would run one more loop.
 *
It had too much repeated code for each background.
 *
With each background grabbing the canvas and context every time they start, it could sometimes lead to bugs where one background would have the context when another background tried to use it.

While this isn't a lot of bugs, it really killed the polished feel I wanted, with small bugs happening frequently, so I needed a new system:
 *
Each background is still a js module.
 *
The backgrounds still render on a background canvas.
 *
Each background exports a start, update, and a stop function.
 *
Each background is given the canvas and context through its exposed functions.
 *
Instead of a background creating its own loop, the central script is in charge of updating the background each frame.

With just these small changes, the backgrounds ran smoothly, with no issues with them running when they shouldn't.
They were done.

Want to see more?
|[click to open]


Some other features I added include:

 *
When changing backgrounds, the canvas blurs and fades out, to remove any jarring changes.
 *
The scripts for the backgrounds are not loaded until they are needed, this can speed up the loading of the website there are large backgrounds (or a large number of backgrounds).
 *
Backgrounds changing the size and complexity to run fast on mobile devices
 *
Live backgrounds used in posts can be shared with the home page's backgrounds.
 *
A few live backgrounds with a consistent theme.

-------------------------

Now that I had backgrounds and website structure, it was time for the hard part:
Making the markup

But what is markup?

Markup is the way I can write with text with formatting, it's how I can do this
When I used discord there were a few different ways to write markup, there was *italic*, **bold**, ***bold italic***, ~~strikethrough~~, or ``code``.

But that style can cause problems, sometimes when sending text not designed for discords formatting there would be unwanted markup, and there was no good to remember what markup does what, so I needed my own style: and I like the "tags" method: where my markup is broken into two types, text and tag groups: "|[tag1 tag2 tag3] and text", this way I can have whatever I want to be tags as tags, without having to worry about using symbols or patterns used in the regular text.

The only thing I have to worry about is what symbols to use to open and close a group of tags, and since I wanted something visually compact, I decided on |[ to open and ] to close, with the only restriction on the tags being that they cannot contain either the opening or closing symbols.

Time for an example:
|[align center size large]Before |[color #0f0]green|[color] it was boring
Would become:
Before green it was boring

How does it work?

 1
The markup file (which is just stored as plaintext) is read and turned into one long string, removing any line breaks.
 2
The string is split by at each "|[" unless the symbol directly after is a "|" (so to write "|[", I would write "|[|").
 3
Each slice of the string is split at the first "]".
 4
Each slice within a |[] gets split at each " ", resulting in an array of each word inside the tag group.
 5
The array of arrays gets flattened, resulting in an array of items that are each either an array of tags, or a string.
 6
The items are looped through, if the item is a string, a styled span element gets pushed to the html with the text of the item, otherwise each tag is looped through, applying its effects.
 7
The finished html is returned, with the default styles, any needed scripts, and the translated markup inside.

Now for my favorite feature of the markup:


This means I can run arbitrary js code anywhere throughout the posts, with each of them able to create a canvas or other html elements for rendering or inputting.

And arbitrary code means I can change any aspect of the website, like adding the flickering text above, , or text that changes the background color when clicked? And so much more

(Of course there are
many other small steps in translating markup, and many other features with it, but if I explained every aspect of the code this post would be far too long, however if you are interested in what tags I have created, I have included all the ones I have created at the time of writing this post below)
|[click to open]
the tags are below, items in the first column are the keywords, items in the second column are values to be used.
a !-> in the second column indicates the action that happens if non of the other options are there

values in the second column with a [] signify that you put a value there (but don't include the [])

values in the second column with a ?[] signify that the value is optional


 *
color: -> sets the text color to the most efficient hex value that represents prop 1
 * *
#[rgb] -> each range is in the value 0-f in base 16
 * *
#[rgba]
 * *
#[rrggbb]
 * *
#[rrggbbaa]
 * *
rgb([r],[g],[b]) -> each value is in the range 0-255
 * *
rgb([r],[g],[b],[a])
 * *
rgba([r],[g],[b])
 * *
rgba([r],[g],[b],[a])
 * *
!-> sets color to the default color
 *
italic: -> sets whether text will be italic
 * *
on | true
 * *
off | false
 * *
!-> toggles italics
 *
bold: -> sets whether text will be bold
 * *
on | true
 * *
off | false
 * *
!-> toggles bold text
 *
space: -> adds [number] spaces using ' ' after
 * *
[number]
 * *
!-> defaults to 1
 *
tabs: -> adds [number] spaces * tabSize (defaults to 3) after
 * *
[number]
 * *
!-> defaults to 1
 *
break: -> used to make new lines
 * *
[number] -> creates a break and then inserts a blank line of [number] lines in height
 * *
!-> just adds <br>
 *
size: -> sets the text size
 * *
xx-small | x-small | smaller | small | medium | large | larger | x-large | xx-large -> uses the default sizes
 * *
[number] -> (viewport width + viewport height) / 2 * [number], [number] is in the range [number] >= 0.02
 * *
!-> sets size to the default size
 *
code: -> sets whether text will be code using <code></code>
 * *
on | true
 * *
off | false
 * *
!-> toggles code text
 *
align: -> sets which direction text should align (changing align triggers a break)
 * *
left | center | right
 * *
!-> sets align to the default align
 *
reset:
 * *
[property] -> sets [property] to the default [property]
 * *
!-> resets the full style to the default style
 *
default: -> changes the default used for many tags, but does not change the default retrospectively
 * *
global -> sets the global default, this is the default used to generate the local (the default always used) default, also sets the local default
 * *
!-> sets the default style to the current style
 *
fold: -> creates foldable content, with all content until the fold close being inside (fold triggers a break)
 * *
open | close -> starts a fold that is open | closed at start
 * *
!-> closes a fold
 *
image: -> embeds an image in the next line
 * *
[name] [size] -> size is relative to the div, so a size of 1 would fill the space, or a size of .5 could fit two images side by side
 * *
[name] !-> defaults to 1
 *
showMarkup: -> sets whether the markup tags will be hidden (defaults to false)
 * *
on | true
 * *
off | false
 * *
!-> toggles
 *
COMMENT: -> "comments" out the line, must be alone in the tag bracket, and the first thing in the line: |[COMMENT]
 *
video: -> embeds a video in the next line
 * *
[name] [size] -> size is relative to the div, so a size of 1 would fill the space, or a size of .5 could fit two videos side by side
 * *
[name] !-> defaults to 1
 *
strike: -> sets whether text will have strikethrough
 * *
on | true
 * *
off | false
 * *
!-> toggles strikethrough
 *
script: -> embeds a piece of live code
 * *
[path] -> where to find the script

-------------------------

At this point I could be done, the website is fully functional, it supports a rich markup, and it has the theme I was wanting.
But why stop there?

There's always stuff to add...


Link previews
|[click to open]

What do I mean by link previews? I mean the nice attachment that sometimes appears when you paste a link.

exampleLinkPreview.png
Turns out there a few main ways of creating these previews:
Theres the normal meta name="title" and meta name="description" elements.
But theres also the Open Graph Protocol which supports:
 *
og:title
 *
og:type eg: article
 *
og:url
 *
og:description
 *
og:image
And Twitter's X's protocol which supports:
 *
twitter:card
 *
twitter:type eg: article
 *
twitter:url
 *
twitter:description
 *
twitter:image
Unfortunately there is no one clear method to be supported on all platforms, so I just used all of the above methods at once.

Now the problem of what to display, the title, type, url, description, and card are clear, I already have these defined for the previews on the home page, but what to use for the image wasn't clear, I needed something to portray the post and the site.

...Or I could not add a new requirement to each post to have a preview image, instead just taking an image of the post for the preview. But getting that image is harder, I had no good way to turn the website's files into an image except rendering it in a browser...

I could just render it with a browser and take a screenshot, I just have to do so automatically every time the post changes.
Since the previews are static, I can create them before I publish the site, eg I can get the screenshots using node.
Before I can do that, I need to define the steps:
 1
Create a server for the website so a browser can "visit" it.
 2
Open a browser I can control.
 3
Navigate to the page.
 4
Screenshot the page and save it to the websites folder.
 5
Close the browser.
 6
Kill the server.
And since I am using node, finding the tools to do this was surprisingly simple, I can use the express module for the server, and the puppeteer module to do all the browser stuff.

Since I don't have to worry about unknown file changes while the server is up, the rest of the screenshotting process went smoothly, with the only other real problem being speed: opening a server, then a browser, then a page, screenshotting, and closing it all for a single screenshot takes longer than the entirety of my program before (up to around 1 second from 1/10 of a second), I managed to optimize it a lot though, only screenshotting if the content changed, reusing the same server / browser for every screenshot, and only opening the server / browser if a new screenshot is needed.

It was worth it in the end, now I have nice link previews too:

linkPreview.png
-------------------------
Live post previews
|[click to open]

One of the biggest annoyances in writing a post now is the time between writing some markup and seeing the results, I have to save the file, run the website file generation program, launch a server for the files, and navigate to the server from a browser to see any change.

No, what I wanted was to see the resulting page with every single change.

But fixing this was actually surprisingly easy, all I have to do it make a local server to serve the website's files, inject a websocket into every page to listen for reload messages, and have the server send a message any time a file it's watching changes.[break break]And that's what I did, and now whenever I change the text of a post the site automatically updates with the new post, with full markup support.
-------------------------

Now there are a lot more features I want to add, comments, a downloadable app, vscode support for highlighting, a markup editor with a gui, etc, but I've spent too long on this post and have other things to work on.
That's it for todays post, thanks for reading!
Return to top