first commit

This commit is contained in:
Mossfet 2023-03-17 22:35:59 +00:00
commit b1b4c040d3
61 changed files with 1726 additions and 0 deletions

5
README.md Normal file
View File

@ -0,0 +1,5 @@
# Mossfet's website website
This is my new and improved website, with vaguely the same content as the old one, but a better SSG (Hugo instead of my botched do-it-yourself makefile and perl solution)
Everything here is available under the AGPL 3.0, or, at your option, any later version. The content (AKA everything in a markdown file) is also available under the Creative Commons Attribution-ShareAlike 4.0 International License (CC BY-SA 4.0).

6
archetypes/default.md Normal file
View File

@ -0,0 +1,6 @@
---
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true
---

23
config.toml Normal file
View File

@ -0,0 +1,23 @@
baseURL = 'https://mossfet.xyz'
languageCode = 'en-gb'
title = "Mossfet's site"
theme = "sitetheme"
copyright = 'CC-BY-SA 4.0'
[author]
name = 'Mossfet'
email = 'root@mossfet.xyz'
[mediaTypes]
[mediaTypes."text/gemini"]
suffixes = ['gmi']
[outputFormats]
[outputFormats.GEMINI]
name = "GEMINI"
isPlainText = true
isHTML = false
mediaType = "text/gemini"
protocol = "gemini://"
permalinkable = true
[outputs]
home = ["HTML", "RSS", "GEMINI"]
section = ["HTML", "GEMINI"]
page = ["HTML", "GEMINI"]

31
content/_index.md Normal file
View File

@ -0,0 +1,31 @@
---
pronouns: She/her or vi/vim
name: Mossfet
location: UK
fedi: "@mossfet@solarpunk.moe"
---
# Mossfet's site
My name is Mossfet. I'm a computer science student living in the UK. I am autistic and trans.
I have a special interest in computer science/general computing topics, and like Rust, Linux, and C.
I'm a (social?) anarchist. I like free software, free culture, and [permacomputing](https://permacomputing.net/Principles/).
I'm working on a game with some friends! It will be released under a free license and is made with the Godot game engine.
#### Current Projects/areas of focus
* Information security
* GNOME
* Permacomputing
* Reverse proxies (NGINX+Apache)
* Indie web
* Distributed systems (DHTs, etc)
#### Other interests
* Evangelion
* Persona
* History of Anarchism
* Emulation (and other things that make Nintendo sad)

5
content/about/_index.md Normal file
View File

@ -0,0 +1,5 @@
## Mossfet
* Pronouns: She/her or vi/vim
* Location: UK
* Fedi: [@mossfet@solarpunk.moe](https://solarpunk.moe/@mossfet)

3
content/blog/_index.md Normal file
View File

@ -0,0 +1,3 @@
# Blog
I sometimes rant about computers here. I might talk about politics as well.

96
content/blog/life.md Normal file
View File

@ -0,0 +1,96 @@
---
title: Creating a GTK4 Game of Life Application
author: Mossfet
date: 2023-02-14T16:50:00+01:00
lastmod: 2023-02-14T16:50:00+01:00
draft: true
---
In A-Level computer science, one of the tasks we're marked on is a "Non-Examined Assessment" (NEA). This is a small project, in which we think of and design a program, establish stakeholders and success criteria, implement the program and its tests, and finally judge our final program based on success criteria. For my NEA, I had decided to write a GNOME app for Conway's Game of Life.
For those unfamiliar with Game of Life, it's a "zero-player game" created by a Mathematician called John Conway in 1970. It takes place in an infinite 2D board in which each cell can be "alive" or "dead". The state of the board for one turn deterministically shapes the state for the next, in the following way:
* A live cell with less than two live neighbours (orthogonal or diagonal) dies, as if by starvation
* A live cell with more than three live neighbours dies, as if by overpopulation
* A dead cell with exactly three live neighbours comes to life, as if by reproduction.
This can create fun patterns. The "game" is turing complete, so users have created entire computers with Life. They've even created computers that can run Game of Life!
The program I wrote was divided into two parts - a Rust library, which implemented the core logic and was cross-platform, and a GNOME app, which used GTK and was intended for Linux.
Most of this writeup is adopted from my original NEA writeup
## Beginning
My initial problem was the issue of storing a grid of infinite size in a program. While the size is infinite, the game will only ever have a finite number of live cells, making a hashset an ideal data structure for representing this. A hashset is a hashmap that does not store any value associated with each key, only whether an entry for a given key exists. I can use a tuple of integers as the hashset, giving it a grid size with 2^128 cells. My user will not be reaching the end of this, I think. (Rust has a bigint library, but I wasn't convinced that coordinates of this size were necessary, as no user would realistically reach the edge).
The `Game` struct contains a few fields. `primary_board` contains a `HashSet` representing the current state of the board. `initial_state` is another `HashSet` representing the earliest tracked change to the board. This is done to implement reverting the board state. `count` counts the number of iterations taken since `initial_state`.
When advancing to the next turn, each eligible cell has its neighbours counted up and applied to the game's rules. It doesn't make sense to check every cell (which is impossible on an infinite board), but thankfully only live cells and their neighbours have the capacity to change state. A "check set" is created, containing each live cell on the board and its neighbours. The set is then collected into a Vector and is split into chunks, with one chunk per core on the machine. A thread is then spawned for each chunk, which is tasked with determining the next state of each cell in its chunk. Once all threads have been completed, the secondary board is cleared and is extended with the values of each thread's results. The primary and secondary boards are then swapped.
The board implements Rust's `Iterator` trait (interface), allowing for lazily evaluated iteration over the game at each turn. While this is not used in the UI code, it can be useful for anyone seeking to use the library in their own project.
## Reverting the board
For reverting the board, the game keeps track of its `initial_state` and a `count` - the nuber of turns since the initial state. To revert a turn, the board reverts to the initial state and advances `count - 1` times. This is not performant at high `count`s, and cannot track before the last manual change (like the player clicking on a tile to flip its state manually), but is relatively simple to implement.
## GUI
The game logic is implemented as a Rust library to be included in other projects. For this reason, it makes sense to implement the GUI in Rust as well. Unfortunately, Rust's default GTK bindings are quite difficult for me to use, as Rust's OOP system is quite different from GObjects, the cross-langauge OOP system that GTK uses. For example, GObjects has both inheritence and polymorphism, whereas Rust does not, opting for extensive use of "traits" (which are analogous to Java interfaces). This makes the GTK bindings cumbersome and full of unintuitive macros. This had stumped me for a while before I discovered Relm4, a Rust library for creating UIs that used gtk-rs as a backend but provided a much more intuitive API.
## Relm4
Relm4 is based on "models", representations of application state, their representations in GTK, and the messages passed between them. The main model for the Game of Life GUI has several messages that it can receive from UI elements - advance the board, revert the board, flip at a coordinate, etc.
Although GTK is not web-based, it uses CSS to style itself. The GNOME project provides the libadwaita library and stylesheets to enforce a consistent and clean look across their apps, which I opted to use. The program opens onto a single window, containing a headerbar with controls for the grid and a grid in the center of the screen.
The grid uses another useful concept that Relm4 has - factories. A factory is a collection of elements that each contain the data for a UI element. Adding an item to the collection (in my case, an item being a struct containing a coordinate and whether a cell is live) is sufficient to add it to the grid.
Two buttons on the left and right of the top bar send advance and revert messages to the app model, while the middle "play" button is a component with its own model, which, upon being clicked, toggles the "running" boolean through the toggle message. When the play button model receives a message, it checks if it is running, and if it is, spawns a thread that sends the advance message to the main model, waits 1 second, then sends a "pass" message to its own model (think of it as a form of recursion). The pass message contains the id of the thread it is called from. The model also contains the ID of the currently running thread, which is compared and does not spawn a thread if the ID does not match. This is to avoid a scenario where the user presses the play button twice in half a second, which ends up spawning two instances of the threads recursing at once. Now, only the most recently spawned will be allowed to continue.
To add cells to the factory, the app model requests a "view" from the game of life library - a list of all live cells between a top-left and bottom-right coordinate. The model then iterates through all coordinates between these two, adds it with the live value set to false if it is not in the view, and to true if it is. The model performs this synchronisation every time it receives a message.
## File access
There are several file formats that board states in game of life can be encoded in. The most popular are "plaintext" and "RLE". RLE uses a form of run-length encoding, which I opted not to use to avoid unnecessary complexity. The other, plaintext, sees each line in the file represent a row on the board, with "." representing a dead cell and "O" representing a live cell. An older format, Life 1.05, uses "\*" as a live cell. My game of life library supports both, and can generate a new game from them. This allows me to load pretty much whatever pattern I want from the internet and test it, which is helpful.
Relm4 provides a widget to allow file selection using the OS's native UI, giving me a path to feed into my reader function. This file selection also works on Flatpaks' sandboxing. Rather than giving the program universal file access, it has to open a dialog controlled by the OS for the user to select a file that they consent to the program accessing.
## Performance and optimisation
Implementing file loading allowed me to conduct more thorough benchmarks. Particularly, I was interested in how the performance of my system would manage with patterns whose live cell counts dramatically increase over time. Space fillers are a type of pattern that expand to fill the grid as quickly as possible. I downloaded a plaintext file for a spacefiller and tried to benchmark how quickly it would slow down. Sadly, the slowdowns were quite quick, with performance dropping off after 60 turns or so. It didn't reach a speed lower than the UI advanced it either way, but I still found it unsatisfactory. Reaching 150 turns took about 5.8 seconds, and I wanted to lower this.
Looking at the `advance_board` function, there were a few places I could see room for improvement. Rather than use a double buffer, with secondary board being drained and filled with the new values, I simplified it by removing the secondary board and simply initialising a new board each update, which lowered memory requirements. I experimented with changing the form of each thread's results from a `HashSet` to a vector, but this had no major effect. The system finds out how many threads it should split itself into by calling the `available_parallelism` function, which queries the system for a core count. This was being done every advance in my current implementation, which the documentation for the function warns against. I moved the call into the board's new function and stored it in the game struct itself, which improved it by about 0.2 seconds. Removing unnecessary prints in my code vastly improved performance. Still, only around 5.2 seconds for 150 iterations on the spacefiller.
I looked for other, more efficient algorithms for life and one that stood out to me was HashLife. HashLife is notable firstly because it's much faster, but also because it does not calculate the board turn-by-turn. It is able to look ahead and calculate several turns at once, which allows for a variety of optimisations. Sadly, the ability to traverse multiple turns does not make sense for my program, and the algorithm is also notoriously complex to implement, and would require me to implement several data structures I'm unfamiliar with, as well as my own garbage collector.
I had also been reccomended using SIMD for further improvements, but I was very unfamiliar with SIMD concepts and wasn't confident in implementing it. I explored simplifying the boolean logic for the neighbour counts, but I found it to have no benefit for performance and decrease readability. I also tried a parallel iteration library called rayon, which allowed me to abstract away the process of chunking and mapping each hashset, which was faster, but I wanted to try to do the game logic with as few libraries as possible.
The Rust Performance Book's section of hashing details that the default hasher used in `HashMap`s and `HashSet`s is relatively safe, but slow. However, it is possible to provide a custom hasher. The book details the rustc-hash crate (a crate is a Rust library), which provides a custom hasher that is considerably faster at the cost of a higher collision rate. Applying this to my board gave a moderate speedup (about 0.6s) with no apparent logic errors. It also mentions the nohash_hasher crate, which is able to use integers as keys verbatim, without hashing. I wanted to see if I could do something similar with my key, a tuple of `isize`s (an isize is a signed integer with size dependent on the architecture). Sadly, no implementation I could provide was faster than rustc-hash, so I didn't pursue it further, but it did give me some useful knowledge of Rust's `Hash` and `Hasher` traits (interfaces).
## Testing
The library has a number of integration tests. These ensure that the rules of Life are followed in the program's simulation. These tests typically involve taking established patterns like the R-Pentomino, advancing them a couple turns, and checking them against a result I took from another simulator. The Linux UI automated testing scene is not well-established, and the application has no tests for ITs UI. Rust's extensive use of static analysis allows many things that would otherwise have been tested for to be caught as compile-time, such as type errors, memory unsafety, and race conditions (Rust is famously impossible to get memory unsafety without an explicit unsafe keyword).
## Packaging
So far, if a user wanted to install the application, they would have to install the Rust toolchain (compiler, package manager, etc), install the necessary GTK development libraries, and compile my program from source, a long and performance-intensive process. This may be acceptable for some users, but most are not willing to install GTK libraries and the Rust toolchain.
Fortunately, Relm4 provides a template for building applications into Flatpaks. After integrating the necessary build files and installing runtimes, it becomes possible to build a full Flatpak for my application. Not only does this make my application very easy to install (Flatpak installation is well-documented on almost all Linux systems), but it also provides users a degree of security assurance - for example, Flatpaks do not have file access by default outside of a file picker that the user controls and the application cannot tamper with. This was not a design goal, but is nice to have.
## Documentation
Rust has a built-in documentation system, in which code and appropriate comments are compiled into an HTML page containing documentation for any given type, module, or library. This allows me to document any given function by writing a comment directly above it. My documentation coverage mainly covers the Rust library.
## hardware requirements
As this is a GNOME app, it is only runnable on a Linux system, or through WSL2, which needs some technical knowledge to set up. Installing from source requires Rust and several GTK development libraries, which are readily available through most Linux package managers, while Flatpaks make installation significantly easier. Flatpaks can also be installed through Crostini, making the application available on ChromeOS (with some elbow grease). The application is not available for macOS, Android, and iOS. It is untested for Linux phones but should run (though presently the user would not be able to scroll).
It is a lightweight app, with low hardware requirements. The speed at which the board advances is slow enough that the cost of computing the next term is negligable. It will struggle on very low-spec systems due to the requirements of GTK, but works well on my budget Chromebook.
## What's next?
I have a few further goals with which I intend to extend the program after the NEA is complete:
* I want to ensure that the program works on mobile Linux devices
* I want to modify the logic library to allow for custom rulesets.
* I'd quite like a presets menu to select preset patterns for the board.

40
content/blog/metaballs.md Normal file
View File

@ -0,0 +1,40 @@
---
title: "Metaballs"
author: Mossfet
date: 2022-05-17T17:57:00+01:00
lastmod: 2022-05-24T21:58:00+01:00
draft: false
---
### 1: TIC-80
A few months ago, I stumbled across the concept of 'metaballs' on YouTube. I was already trying to work on a semi-successful 3D graphics project on the [TIC-80](https://tic80.com/), a fantasy console similar to the Pico-8, so when I gave up on that, I decided to try my hand at writing them there as well.
You can find the result [here](https://tic80.com/play?cart=2784)
It didn't go horribly, but I was pretty dissatisfied with the performance and the limitation to a few colour bands. The TIC-80's standard library is tiny, and doesn't seem to have any support for hardware acceleration or multithreading. The most efficient way I could find was essentially to run the calculation on every pixel in sequence on every frame. Combined with the inherent limitations of an interpreted language being run in a browser and it ran at around 10fps for three balls on my admittedly low-power Chromebook, and that's taking into account the low resolution of the TIC-80 - 240 by 136. If this were scaled up to something like 1080p it would probably run around 60 times slower. So I tried again
### 2: Godot
About a week ago, I decided to rewrite in in Godot. I ran a shader on it that did the calculations per-pixel, and instead of set colour bands I was able to make a gradient. I'm not entirely sure whether I prefer the bands or the gradient, but I'm glad I was able to try both. More importantly, it was able to run at 1080p at 60 frames per second, so the performance was more than satisfactory for me. I haven't published the code because frankly it's not that interesting, thought if you want it for whatever reason, message me.
I'm currently working on a game in Godot, so I'm glad to take all the excuses to learn new concepts in it as I can get.
### 3: OpenGL
I had done [an OpenGL course](https://learnopengl.com/) around a year ago, and wanted to have a go at Metaballs on there as well. As the code for this project is largely based on the OpenGL course, it is written in C++ and uses the GLFW library. I followed the course up to drawing a triangle, but instead focused on making two triangles that form a rectangle that covers the whole screen (I am told that this is how game developers usually apply a shader to the whole screen). The shader was very similar to the one done in Godot but had some very cursed code that attempted to convert between the coordinate system that the ball uses (-1.0, -1.0 for the top-left, 1.0, 1.0 for the top right), and normal pixel coordinates.
I could refactor it into something better but frankly I am tired and have a short attention span.
```C
// This is not happy code
return (500.0 * ball.z / (pow(abs(gl_FragCoord.x - (0.5 + ball.x / 2) * 1920.0), 2) + pow(abs(gl_FragCoord.y - (0.5 + ball.y / 2) * 1080.0), 2)));
```
All in all the code took me around four straight hours to write. Sadly, as the laptop it was written on has now died due to a faulty charging port (might see about repairing it in future), the program is lost. I didn't get a chance to benchmark it, either. If I do manage to fix it, I will back up the program and benchmark it against the Vulkan implementation.
### 4: Vulkan
This was probably a mistake. Being a much more complex to use graphics API than OpenGL, it was far more verbose to complete. Like OpenGL, I followed [a course](https://vulkan-tutorial.com/) to set up the boilerplate I needed (and introduce me to Vulkan's various concepts). I have to say, I'm pretty proud of it. Like the original TIC-80 project (though I'm not sure if that's what actually ended up on the site), it features randomly placed metaballs, something missing on both the Godot and OpenGL implementation. I also experimented with balls with negative 'size', if size is even the correct term here, and the results were very fun. You can ask for either purely positive metaballs or negative metaballs as well with a command-line option. While I was unable to get the validation layer for a proper FPS count compiled on my Chromebook, I was able to use Mangohud to measure the program's FPS. The results were mixed, with 60 FPS on the default resolution (800x600), and around 30 FPS when fullscreened (1336x768) on my Chromebook.
### 5: What's next?
I have a few ideas for where I want to go with this project. The obvious one is leave it here. With Vulkan, I've gone about as 'low-level' as I'm willing to go. I might return to [the interpreter tutorial I was working on](http://craftinginterpreters.com/), and I'll obviously continue working on this site. Some other options are DirectX (thought I'm not sure how that would work, as I don't own a Windows computer), and Unreal Engine (again, Windows only makes it a bit awkward since I don't own a Windows computer).

13
content/blog/newsite.md Normal file
View File

@ -0,0 +1,13 @@
---
title: "Reworking the site frontend"
author: Mossfet
date: 2022-08-31T12:29:17+01:00
lastmod: 2022-08-31T12:29:17+01:00
draft: false
---
My previous website implementation left much to be desired. It was difficult to debug, implemented with a maze of makefiles, bizarre perl commands, and creative uses of pandoc. While it was a pretty useful exercise in pandoc and make, it wasn't really a sustainable solution. I had heard about Hugo from YouTube, and was already planning to use it to implement a friend's blog, so figured this would be good practise.
The only main downside I can think of is it means I'll have to put my plans of porting this site to Gemini will have to be put on hold. I've heard that there are ways of doing Gemini output on Hugo, but I don't want to focus on this while I'm still finding my feet.
I'm still using the same very simple rocket.rs backend, with some minor tweaks.

View File

@ -0,0 +1,25 @@
---
title: Hosting my website
author: Mossfet
date: 2023-02-14T09:45:00+01:00
lastmod: 2023-02-14T12:01:00+01:00
draft: false
---
It's been a while since I originally created the website, but didn't get the chance to host it on real hardware until now.
When I initially set up my site, I had been planning on running it on a Raspberry Pi 4. If you've tried to get hold of a Pi 4 in the last three years, you'll know why that's not gonna work. I still have plans for getting my own SBC (specifically waiting for the Star64 to release), but in the mean time I found a different solution.
## Enter: A shitty broken Chromebook
A while ago, my parents bought me an Acer Chromebook 14 for school. It's a horrible thing, has broken and needed repair four times, is no longer supported for software updates, and looks ugly. It's my favourite laptop. Before it's most recent breakage, I had been running Fedora Linux off it for my schoolwork, with mixed results. Sadly, the LCD was broken after my bag fell off a desk, so it was no longer usable as a laptop.
What about as a server?
As I mentioned, the laptop (and most Chromebooks) can run Linux, so I figured that it could probably run webserver software as well as any other Linux box. I took the screen out to save power, disconnected the battery to stop it from being worn out, and installed NixOS on it. The nice thing about a Chromebook is it's pretty low wattage - the battery advertises 45 Watt-hours, which divided by the Chromebook's advertised 12-hour battery life gives 3.75 Watts, on average. I imagine (hope?) that it would be even lower for NixOS and without an LCD connected.
I'm not currently running my rocket.rs backend, instead running Apache httpd, configured through NixOS. This allows me to set up ACME "fairly easily" (big thanks to the NixOS Matrix channel for giving me a hand). I'm still on my home network, so dynamic IP is a problem. Thankfully, my DNS provider has a dynamic DNS protocol, and I found a shell script that can update it [here](https://nextnet.top/content/using-gandi-livedns-dynamic-dns-server).
![The laptop running a webserver](/images/blog/laptopserver.jpg)
I may migrate this to a different system when the Star64 arrives - I'm expecting an Ox64 at the same time, which could be perfect for a tiny task like this. I also intend to automate updating the website with git - currently I have to ssh into the machine and pull every time I want to update the website. I expect Gitlab could help me out here.

21
content/blog/site.md Normal file
View File

@ -0,0 +1,21 @@
---
title: I made a website
author: Mossfet
date: 2022-05-17T17:56:00+01:00
lastmod: 2022-05-21T19:30:00+01:00
draft: false
---
***Note: This is outdated. I have rewritten the site with Hugo, and the solution described here was never hosted***
I made a website! And a blog! It remains to be seen how much I'll use it, but I'll at least make a post on how I made it
The site uses a very convoluted static site generator I wrote with makefiles and pandoc, the source of which can be found in the header of my website, along with that of the rest of this site (not that I would recommend using it. This was a very stupid idea kept going by sunk cost and pride). While the site's main pages are currently written in HTML and inserted into a template with pandoc (I may explore rewriting the main contents of the site in markdown), the blog posts are written in markdown and also converted using pandoc. Commonly shared elements like headers and footers are done with Pandoc templates.
I had initially used markdown instead of pandoc to convert the blog pages to HTML, and used Perl's regular expressions to find-and-replace markers I had placed in templates with content, but frankly this was a stupid idea.
The backend is written in Rust, with [rocket.rs](https://rocket.rs). I didn't particularly have the need for performance that Rust provides, but I like Rust and I like the way that Rocket works. It's a very simple implementation, with routes for the index, 404 page, and anything in the static/web/ and static/atom/ directories.
I eventually plan to add Gemini support as well, with rewrites of the main pages and the same blog posts being converted to Gemtext as well at HTML, but this will take some additional work as it is not supported in Pandoc.
The blog pages are also made into an Atom feed, also generated with pandoc.

6
content/links/_index.md Normal file
View File

@ -0,0 +1,6 @@
# Links
You can find my Fedi account at [@mossfet@solarpunk.moe](https://solarpunk.moe/@mossfet)
My code forge is [here](git.solarpunk.moe/mossfet)
You can message me on Fedi for my Matrix or whatever else you want to contact me on.

View File

@ -0,0 +1,29 @@
{{ $content := .RawContent -}}
{{ $content := $content | replaceRE `#### ` "### " -}}
{{ $content := $content | replaceRE `\n- (.+?)` "\n* $1" -}}
{{ $content := $content | replaceRE `\n(\d+). (.+?)` "\n* $2" -}}
{{ $content := $content | replaceRE `\[\^(.+?)\]:?` "" -}}
{{ $content := $content | replaceRE `<br/??>` "\n" -}}
{{ $content := $content | replaceRE `<a .*href="(.+?)".*>(.+?)</a>` "[$2]($1)" -}}
{{ $content := $content | replaceRE `\sgemini://(\S*)` " [gemini://$1](gemini://$1)" -}}
{{ $content := $content | replaceRE "([^`])<.*?>([^`])" "$1$2" -}}
{{ $content := $content | replaceRE `\n\n!\[.*\]\((.+?) \"(.+?)\"\)` "\n\n=> $1 Image: $2" -}}
{{ $content := $content | replaceRE `\n\n!\[.*]\((.+?)\)` "\n\n=> $1 Embedded Image: $1" -}}
{{ $links := findRE `\n=> ` $content }}{{ $scratch.Set "ref" (add (len $links) 1) }}
{{ $refs := findRE `\[.+?\]\(.+?\)` $content }}
{{ $scratch.Set "content" $content }}{{ range $refs }}{{ $ref := $scratch.Get "ref" }}{{ $contentInLoop := $scratch.Get "content" }}{{ $url := (printf "%s #%d" . $ref) }}{{ $contentInLoop := replace $contentInLoop . $url -}}{{ $scratch.Set "content" $contentInLoop }}{{ $scratch.Set "ref" (add $ref 1) }}{{ end }}{{ $content := $scratch.Get "content" | replaceRE `\[(.+?)\]\((.+?)\) #(\d+)` "$1 [$3]" -}}
{{ $content | safeHTML }}
# {{ if $refs }}
## References
{{ $scratch.Set "ref" (add (len $links) 1) }}{{ range $refs }}{{ $ref := $scratch.Get "ref" }}{{ $url := (printf "%s #%d" . $ref) }}
=> {{ $url | replaceRE `\[(.+?)\]\((.+?)\) #(\d+)` "$2 [$3] $1 ($2)" -}}
{{ $scratch.Set "ref" (add $ref 1) }}{{ end}}
{{ $related := first 3 (where (where .Site.RegularPages.ByDate.Reverse ".Params.tags" "intersect" .Params.tags) "Permalink" "!=" .Permalink) }}
{{ if $related }}
## Related articles
{{ range $related }}
=> {{ replace .RelPermalink "/gemini" "" 1}} {{ .Title }}: {{ .Params.Subtitle }}{{ end }}{{ end }}{{ end }}
=> / Back to the Index
=> {{ .Site.BaseURL }}/{{ replace (replace .RelPermalink "/gemini" "" 1) "index.gmi" "" }} View this article on the WWW

34
layouts/_default/list.gmi Normal file
View File

@ -0,0 +1,34 @@
{{ $scratch := newScratch -}}
{{ $content := .RawContent -}}
{{ $content := $content | replaceRE `#### ` "### " -}}
{{ $content := $content | replaceRE `\n- (.+?)` "\n* $1" -}}
{{ $content := $content | replaceRE `\n(\d+). (.+?)` "\n* $2" -}}
{{ $content := $content | replaceRE `\[\^(.+?)\]:?` "" -}}
{{ $content := $content | replaceRE `<br/??>` "\n" -}}
{{ $content := $content | replaceRE `<a .*href="(.+?)".*>(.+?)</a>` "[$2]($1)" -}}
{{ $content := $content | replaceRE `\sgemini://(\S*)` " [gemini://$1](gemini://$1)" -}}
{{ $content := $content | replaceRE "([^`])<.*?>([^`])" "$1$2" -}}
{{ $content := $content | replaceRE `\n\n!\[.*\]\((.+?) \"(.+?)\"\)` "\n\n=> $1 Image: $2" -}}
{{ $content := $content | replaceRE `\n\n!\[.*]\((.+?)\)` "\n\n=> $1 Embedded Image: $1" -}}
{{ $links := findRE `\n=> ` $content }}{{ $scratch.Set "ref" (add (len $links) 1) -}}
{{ $refs := findRE `\[.+?\]\(.+?\)` $content -}}
{{ $scratch.Set "content" $content }}{{ range $refs }}{{ $ref := $scratch.Get "ref" }}{{ $contentInLoop := $scratch.Get "content" }}{{ $url := (printf "%s #%d" . $ref) }}{{ $contentInLoop := replace $contentInLoop . $url -}}{{ $scratch.Set "content" $contentInLoop }}{{ $scratch.Set "ref" (add $ref 1) }}{{ end }}{{ $content := $scratch.Get "content" | replaceRE `\[(.+?)\]\((.+?)\) #(\d+)` "$1 [$3]" -}}
{{ $content | safeHTML -}}
{{ range .Pages }}
=> {{ .Permalink }} {{.Title}}
{{ end }}
{{ if $refs }}
## References
{{ $scratch.Set "ref" (add (len $links) 1) }}{{ range $refs }}{{ $ref := $scratch.Get "ref" }}{{ $url := (printf "%s #%d" . $ref) }}
=> {{ $url | replaceRE `\[(.+?)\]\((.+?)\) #(\d+)` "$2 [$3] $1 ($2)" -}}
{{ $scratch.Set "ref" (add $ref 1) -}}
{{ end -}}
{{ $related := first 3 (where (where .Site.RegularPages.ByDate.Reverse ".Params.tags" "intersect" .Params.tags) "Permalink" "!=" .Permalink) -}}
{{ if $related }}
## Related articles
{{ range $related }}
=> {{ replace .RelPermalink "/gemini" "" 1}} {{ .Title }}: {{ .Params.Subtitle }}{{ end }}{{ end }}{{ end -}}
=> / Back to the Index
=> {{ .Site.BaseURL }}/{{ replace (replace .RelPermalink "/gemini" "" 1) "index.gmi" "" }} View this article on the WWW

View File

@ -0,0 +1,32 @@
# {{ .Title }}{{ $scratch := newScratch }}
{{ $content := .RawContent -}}
{{ $content := $content | replaceRE `#### ` "### " -}}
{{ $content := $content | replaceRE `\n- (.+?)` "\n* $1" -}}
{{ $content := $content | replaceRE `\n(\d+). (.+?)` "\n* $2" -}}
{{ $content := $content | replaceRE `\[\^(.+?)\]:?` "" -}}
{{ $content := $content | replaceRE `<br/??>` "\n" -}}
{{ $content := $content | replaceRE `<a .*href="(.+?)".*>(.+?)</a>` "[$2]($1)" -}}
{{ $content := $content | replaceRE `\sgemini://(\S*)` " [gemini://$1](gemini://$1)" -}}
{{ $content := $content | replaceRE "([^`])<.*?>([^`])" "$1$2" -}}
{{ $content := $content | replaceRE `\n\n!\[.*\]\((.+?) \"(.+?)\"\)` "\n\n=> $1 Image: $2" -}}
{{ $content := $content | replaceRE `\n\n!\[.*]\((.+?)\)` "\n\n=> $1 Embedded Image: $1" -}}
{{ $links := findRE `\n=> ` $content }}{{ $scratch.Set "ref" (add (len $links) 1) -}}
{{ $refs := findRE `\[.+?\]\(.+?\)` $content -}}
{{ $scratch.Set "content" $content }}{{ range $refs }}{{ $ref := $scratch.Get "ref" }}{{ $contentInLoop := $scratch.Get "content" }}{{ $url := (printf "%s #%d" . $ref) }}{{ $contentInLoop := replace $contentInLoop . $url -}}{{ $scratch.Set "content" $contentInLoop }}{{ $scratch.Set "ref" (add $ref 1) }}{{ end }}{{ $content := $scratch.Get "content" | replaceRE `\[(.+?)\]\((.+?)\) #(\d+)` "$1 [$3]" -}}
{{- $content | safeHTML -}}
{{ if $refs }}
## References
{{ $scratch.Set "ref" (add (len $links) 1) }}{{ range $refs }}{{ $ref := $scratch.Get "ref" }}{{ $url := (printf "%s #%d" . $ref) }}
=> {{ $url | replaceRE `\[(.+?)\]\((.+?)\) #(\d+)` "$2 [$3] $1 ($2)" -}}
{{ $scratch.Set "ref" (add $ref 1) -}}
{{ end -}}
{{ $related := first 3 (where (where .Site.RegularPages.ByDate.Reverse ".Params.tags" "intersect" .Params.tags) "Permalink" "!=" .Permalink) -}}
{{ if $related }}
## Related articles
{{ range $related }}
=> {{ replace .RelPermalink "/gemini" "" 1}} {{ .Title }}: {{ .Params.Subtitle }}{{ end }}{{ end }}{{ end }}
=> / Back to the Index
=> {{ .Site.BaseURL }}/{{ replace (replace .RelPermalink "/gemini" "" 1) "index.gmi" "" }} View this article on the WWW

34
layouts/index.gmi Normal file
View File

@ -0,0 +1,34 @@
{{ $scratch := newScratch -}}
{{ $content := .RawContent -}}
{{ $content := $content | replaceRE `#### ` "### " -}}
{{ $content := $content | replaceRE `\n- (.+?)` "\n* $1" -}}
{{ $content := $content | replaceRE `\n(\d+). (.+?)` "\n* $2" -}}
{{ $content := $content | replaceRE `\[\^(.+?)\]:?` "" -}}
{{ $content := $content | replaceRE `<br/??>` "\n" -}}
{{ $content := $content | replaceRE `<a .*href="(.+?)".*>(.+?)</a>` "[$2]($1)" -}}
{{ $content := $content | replaceRE `\sgemini://(\S*)` " [gemini://$1](gemini://$1)" -}}
{{ $content := $content | replaceRE "([^`])<.*?>([^`])" "$1$2" -}}
{{ $content := $content | replaceRE `\n\n!\[.*\]\((.+?) \"(.+?)\"\)` "\n\n=> $1 Image: $2" -}}
{{ $content := $content | replaceRE `\n\n!\[.*]\((.+?)\)` "\n\n=> $1 Embedded Image: $1" -}}
{{ $links := findRE `\n=> ` $content }}{{ $scratch.Set "ref" (add (len $links) 1) -}}
{{ $refs := findRE `\[.+?\]\(.+?\)` $content -}}
{{ $scratch.Set "content" $content }}{{ range $refs }}{{ $ref := $scratch.Get "ref" }}{{ $contentInLoop := $scratch.Get "content" }}{{ $url := (printf "%s #%d" . $ref) }}{{ $contentInLoop := replace $contentInLoop . $url -}}{{ $scratch.Set "content" $contentInLoop }}{{ $scratch.Set "ref" (add $ref 1) }}{{ end }}{{ $content := $scratch.Get "content" | replaceRE `\[(.+?)\]\((.+?)\) #(\d+)` "$1 [$3]" -}}
{{- $content | safeHTML -}}
{{ if $refs }}
## References
{{ $scratch.Set "ref" (add (len $links) 1) }}{{ range $refs }}{{ $ref := $scratch.Get "ref" }}{{ $url := (printf "%s #%d" . $ref) }}
=> {{ $url | replaceRE `\[(.+?)\]\((.+?)\) #(\d+)` "$2 [$3] $1 ($2)" -}}
{{ $scratch.Set "ref" (add $ref 1) -}}
{{ end -}}
{{ $related := first 3 (where (where .Site.RegularPages.ByDate.Reverse ".Params.tags" "intersect" .Params.tags) "Permalink" "!=" .Permalink) -}}
{{ if $related }}
## Related articles
{{ range $related }}
=> {{ replace .RelPermalink "/gemini" "" 1}} {{ .Title }}: {{ .Params.Subtitle }}{{ end }}{{ end }}{{ end }}
=> {{ .Site.BaseURL }}/{{ replace (replace .RelPermalink "/gemini" "" 1) "index.gmi" "" }} View this article on the WWW
=> {{ replace .Site.BaseURL "https://" "gemini://" }}/blog Blog
=> {{ replace .Site.BaseURL "https://" "gemini://" }}/links Links
=> https://git.solarpunk.moe/mossfet/site Source

1
layouts/links/baseof.gmi Normal file
View File

@ -0,0 +1 @@
{{ .RawContent }}

2
layouts/links/index.gmi Normal file
View File

@ -0,0 +1,2 @@
## hi
{{ .RawContent }}

37
public/404.html Normal file
View File

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html lang="en"><link rel="stylesheet" href="/css/style.css" type="text/css" media="all" />
<body>
<div style="margin: 2%"><header>
<nav class="navbar">
<a href="/index.xml"><img src="/images/feed.svg" style="height: 20px; width: 20px; float: left;" alt="RSS Feed"></a>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/blog">Blog</a></li>
<li><a href="/links">Links</a></li>
<li><a href="https://git.solarpunk.moe/mossfet.site">Source</a></li>
</ul>
</nav>
</header>
<main id="main">
<div>
<h2>Oops!</h2>
<p>Looks like this page doesn't exist, or it does exist and I've broken something. (Error 404)</p>
<a href="/">Why don't you go home?</a>
</div>
</main>
<footer class="footer">
<div>
This site (frontend and backend) is licensed under the <a href="https://www.gnu.org/licenses/agpl-3.0.en.html">AGPLv3</a> or later, with images and text also available under the <a href="https://creativecommons.org/licenses/by-sa/4.0/legalcode">CC-BY-SA 4.0</a>, at your discretion.
</div>
<hr>
<div class="webring"><a href="https://fediring.net/previous?host=mossfet.xyz" title="Previous Webring site">Previous</a> <a href="https://fediring.net">Fediring</a> <a href="https://fediring.net/next?host=mossfet.xyz" title="Next webring site">Next</a></div>
</footer>
</div>
</body>
</html>

12
public/about/index.gmi Normal file
View File

@ -0,0 +1,12 @@
## Mossfet
* Pronouns: She/her or vi/vim
* Location: UK
* Fedi: @mossfet@solarpunk.moe [1]
## References
=> https://solarpunk.moe/@mossfet [1] @mossfet@solarpunk.moe (https://solarpunk.moe/@mossfet)=> / Back to the Index
=> https://mossfet.xyz//about/ View this article on the WWW

46
public/about/index.html Normal file
View File

@ -0,0 +1,46 @@
<!DOCTYPE html>
<html lang="en"><link rel="alternate" type="text/gemini" href="gemini://mossfet.xyz/about/index.gmi" title="Mossfet's site" />
<link rel="stylesheet" href="/css/style.css" type="text/css" media="all" />
<body>
<div style="margin: 2%"><header>
<nav class="navbar">
<a href="/index.xml"><img src="/images/feed.svg" style="height: 20px; width: 20px; float: left;" alt="RSS Feed"></a>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/blog">Blog</a></li>
<li><a href="/links">Links</a></li>
<li><a href="https://git.solarpunk.moe/mossfet.site">Source</a></li>
</ul>
</nav>
</header>
<div class = "container border">
<div class = "section">
<div class = "content">
<h1 class="title"></h1>
<h2 id="mossfet">Mossfet</h2>
<ul>
<li>Pronouns: She/her or vi/vim</li>
<li>Location: UK</li>
<li>Fedi: <a href="https://solarpunk.moe/@mossfet">@mossfet@solarpunk.moe</a></li>
</ul>
</div>
</div>
</div>
<footer class="footer">
<div>
This site (frontend and backend) is licensed under the <a href="https://www.gnu.org/licenses/agpl-3.0.en.html">AGPLv3</a> or later, with images and text also available under the <a href="https://creativecommons.org/licenses/by-sa/4.0/legalcode">CC-BY-SA 4.0</a>, at your discretion.
</div>
<hr>
<div class="webring"><a href="https://fediring.net/previous?host=mossfet.xyz" title="Previous Webring site">Previous</a> <a href="https://fediring.net">Fediring</a> <a href="https://fediring.net/next?host=mossfet.xyz" title="Next webring site">Next</a></div>
</footer>
</div>
</body>
</html>

15
public/blog/index.gmi Normal file
View File

@ -0,0 +1,15 @@
# Blog
I sometimes rant about computers here. I might talk about politics as well.
=> gemini://mossfet.xyz/blog/serverhost/index.gmi Hosting my website
=> gemini://mossfet.xyz/blog/newsite/index.gmi Reworking the site frontend
=> gemini://mossfet.xyz/blog/metaballs/index.gmi Metaballs
=> gemini://mossfet.xyz/blog/site/index.gmi I made a website
=> / Back to the Index
=> https://mossfet.xyz//blog/ View this article on the WWW

58
public/blog/index.html Normal file
View File

@ -0,0 +1,58 @@
<!DOCTYPE html>
<html lang="en"><link rel="alternate" type="text/gemini" href="gemini://mossfet.xyz/blog/index.gmi" title="Mossfet's site" />
<link rel="stylesheet" href="/css/style.css" type="text/css" media="all" />
<body>
<div style="margin: 2%"><header>
<nav class="navbar">
<a href="/index.xml"><img src="/images/feed.svg" style="height: 20px; width: 20px; float: left;" alt="RSS Feed"></a>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/blog">Blog</a></li>
<li><a href="/links">Links</a></li>
<li><a href="https://git.solarpunk.moe/mossfet.site">Source</a></li>
</ul>
</nav>
</header>
<div class = "container border">
<div class = "section">
<div class = "content">
<h1 class="title"></h1>
<h1 id="blog">Blog</h1>
<p>I sometimes rant about computers here. I might talk about politics as well.</p>
<ul>
<li><a href="https://mossfet.xyz/blog/serverhost/">Hosting my website (2/14/23)</a></li>
</ul>
<ul>
<li><a href="https://mossfet.xyz/blog/newsite/">Reworking the site frontend (8/31/22)</a></li>
</ul>
<ul>
<li><a href="https://mossfet.xyz/blog/metaballs/">Metaballs (5/17/22)</a></li>
</ul>
<ul>
<li><a href="https://mossfet.xyz/blog/site/">I made a website (5/17/22)</a></li>
</ul>
</div>
</div>
</div>
<footer class="footer">
<div>
This site (frontend and backend) is licensed under the <a href="https://www.gnu.org/licenses/agpl-3.0.en.html">AGPLv3</a> or later, with images and text also available under the <a href="https://creativecommons.org/licenses/by-sa/4.0/legalcode">CC-BY-SA 4.0</a>, at your discretion.
</div>
<hr>
<div class="webring"><a href="https://fediring.net/previous?host=mossfet.xyz" title="Previous Webring site">Previous</a> <a href="https://fediring.net">Fediring</a> <a href="https://fediring.net/next?host=mossfet.xyz" title="Next webring site">Next</a></div>
</footer>
</div>
</body>
</html>

View File

@ -0,0 +1,46 @@
# Metaballs
### 1: TIC-80
A few months ago, I stumbled across the concept of 'metaballs' on YouTube. I was already trying to work on a semi-successful 3D graphics project on the TIC-80 [1], a fantasy console similar to the Pico-8, so when I gave up on that, I decided to try my hand at writing them there as well.
You can find the result here [2]
It didn't go horribly, but I was pretty dissatisfied with the performance and the limitation to a few colour bands. The TIC-80's standard library is tiny, and doesn't seem to have any support for hardware acceleration or multithreading. The most efficient way I could find was essentially to run the calculation on every pixel in sequence on every frame. Combined with the inherent limitations of an interpreted language being run in a browser and it ran at around 10fps for three balls on my admittedly low-power Chromebook, and that's taking into account the low resolution of the TIC-80 - 240 by 136. If this were scaled up to something like 1080p it would probably run around 60 times slower. So I tried again
### 2: Godot
About a week ago, I decided to rewrite in in Godot. I ran a shader on it that did the calculations per-pixel, and instead of set colour bands I was able to make a gradient. I'm not entirely sure whether I prefer the bands or the gradient, but I'm glad I was able to try both. More importantly, it was able to run at 1080p at 60 frames per second, so the performance was more than satisfactory for me. I haven't published the code because frankly it's not that interesting, thought if you want it for whatever reason, message me.
I'm currently working on a game in Godot, so I'm glad to take all the excuses to learn new concepts in it as I can get.
### 3: OpenGL
I had done an OpenGL course [3] around a year ago, and wanted to have a go at Metaballs on there as well. As the code for this project is largely based on the OpenGL course, it is written in C++ and uses the GLFW library. I followed the course up to drawing a triangle, but instead focused on making two triangles that form a rectangle that covers the whole screen (I am told that this is how game developers usually apply a shader to the whole screen). The shader was very similar to the one done in Godot but had some very cursed code that attempted to convert between the coordinate system that the ball uses (-1.0, -1.0 for the top-left, 1.0, 1.0 for the top right), and normal pixel coordinates.
I could refactor it into something better but frankly I am tired and have a short attention span.
```C
// This is not happy code
return (500.0 * ball.z / (pow(abs(gl_FragCoord.x - (0.5 + ball.x / 2) * 1920.0), 2) + pow(abs(gl_FragCoord.y - (0.5 + ball.y / 2) * 1080.0), 2)));
```
All in all the code took me around four straight hours to write. Sadly, as the laptop it was written on has now died due to a faulty charging port (might see about repairing it in future), the program is lost. I didn't get a chance to benchmark it, either. If I do manage to fix it, I will back up the program and benchmark it against the Vulkan implementation.
### 4: Vulkan
This was probably a mistake. Being a much more complex to use graphics API than OpenGL, it was far more verbose to complete. Like OpenGL, I followed a course [4] to set up the boilerplate I needed (and introduce me to Vulkan's various concepts). I have to say, I'm pretty proud of it. Like the original TIC-80 project (though I'm not sure if that's what actually ended up on the site), it features randomly placed metaballs, something missing on both the Godot and OpenGL implementation. I also experimented with balls with negative 'size', if size is even the correct term here, and the results were very fun. You can ask for either purely positive metaballs or negative metaballs as well with a command-line option. While I was unable to get the validation layer for a proper FPS count compiled on my Chromebook, I was able to use Mangohud to measure the program's FPS. The results were mixed, with 60 FPS on the default resolution (800x600), and around 30 FPS when fullscreened (1336x768) on my Chromebook.
### 5: What's next?
I have a few ideas for where I want to go with this project. The obvious one is leave it here. With Vulkan, I've gone about as 'low-level' as I'm willing to go. I might return to the interpreter tutorial I was working on [5], and I'll obviously continue working on this site. Some other options are DirectX (thought I'm not sure how that would work, as I don't own a Windows computer), and Unreal Engine (again, Windows only makes it a bit awkward since I don't own a Windows computer).
## References
=> https://tic80.com/ [1] TIC-80 (https://tic80.com/)
=> https://tic80.com/play?cart=2784 [2] here (https://tic80.com/play?cart=2784)
=> https://learnopengl.com/ [3] an OpenGL course (https://learnopengl.com/)
=> https://vulkan-tutorial.com/ [4] a course (https://vulkan-tutorial.com/)
=> http://craftinginterpreters.com/ [5] the interpreter tutorial I was working on (http://craftinginterpreters.com/)
=> / Back to the Index
=> https://mossfet.xyz//blog/metaballs/ View this article on the WWW

View File

@ -0,0 +1,91 @@
<!DOCTYPE html>
<html lang="en"><link rel="alternate" type="text/gemini" href="gemini://mossfet.xyz/blog/metaballs/index.gmi" title="Mossfet's site" />
<link rel="stylesheet" href="/css/style.css" type="text/css" media="all" />
<body>
<div style="margin: 2%"><header>
<nav class="navbar">
<a href="/index.xml"><img src="/images/feed.svg" style="height: 20px; width: 20px; float: left;" alt="RSS Feed"></a>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/blog">Blog</a></li>
<li><a href="/links">Links</a></li>
<li><a href="https://git.solarpunk.moe/mossfet.site">Source</a></li>
</ul>
</nav>
</header>
<section class="section border">
<nav class="ring">
<div class="ring-prev">
<a href="https://mossfet.xyz/blog/site/">Previous post - I made a website</a>
</div>
<div class="ring-next">
<a href="https://mossfet.xyz/blog/newsite/">Next post - Reworking the site frontend</a>
</div>
</nav>
<hr>
<article>
<div class="blog-header">
<h1 class="blog-title">Metaballs</h1>
<h5>Written May 17, 2022</h5>
<h5>Last modifed May 24, 2022</h5>
<h5>Written by Mossfet</h5>
</div>
<div class="blog-content">
<h3 id="1-tic-80">1: TIC-80</h3>
<p>A few months ago, I stumbled across the concept of &lsquo;metaballs&rsquo; on YouTube. I was already trying to work on a semi-successful 3D graphics project on the <a href="https://tic80.com/">TIC-80</a>, a fantasy console similar to the Pico-8, so when I gave up on that, I decided to try my hand at writing them there as well.</p>
<p>You can find the result <a href="https://tic80.com/play?cart=2784">here</a></p>
<p>It didn&rsquo;t go horribly, but I was pretty dissatisfied with the performance and the limitation to a few colour bands. The TIC-80&rsquo;s standard library is tiny, and doesn&rsquo;t seem to have any support for hardware acceleration or multithreading. The most efficient way I could find was essentially to run the calculation on every pixel in sequence on every frame. Combined with the inherent limitations of an interpreted language being run in a browser and it ran at around 10fps for three balls on my admittedly low-power Chromebook, and that&rsquo;s taking into account the low resolution of the TIC-80 - 240 by 136. If this were scaled up to something like 1080p it would probably run around 60 times slower. So I tried again</p>
<h3 id="2-godot">2: Godot</h3>
<p>About a week ago, I decided to rewrite in in Godot. I ran a shader on it that did the calculations per-pixel, and instead of set colour bands I was able to make a gradient. I&rsquo;m not entirely sure whether I prefer the bands or the gradient, but I&rsquo;m glad I was able to try both. More importantly, it was able to run at 1080p at 60 frames per second, so the performance was more than satisfactory for me. I haven&rsquo;t published the code because frankly it&rsquo;s not that interesting, thought if you want it for whatever reason, message me.</p>
<p>I&rsquo;m currently working on a game in Godot, so I&rsquo;m glad to take all the excuses to learn new concepts in it as I can get.</p>
<h3 id="3-opengl">3: OpenGL</h3>
<p>I had done <a href="https://learnopengl.com/">an OpenGL course</a> around a year ago, and wanted to have a go at Metaballs on there as well. As the code for this project is largely based on the OpenGL course, it is written in C++ and uses the GLFW library. I followed the course up to drawing a triangle, but instead focused on making two triangles that form a rectangle that covers the whole screen (I am told that this is how game developers usually apply a shader to the whole screen). The shader was very similar to the one done in Godot but had some very cursed code that attempted to convert between the coordinate system that the ball uses (-1.0, -1.0 for the top-left, 1.0, 1.0 for the top right), and normal pixel coordinates.
I could refactor it into something better but frankly I am tired and have a short attention span.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-C" data-lang="C"><span style="display:flex;"><span><span style="color:#75715e">// This is not happy code
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">return</span> (<span style="color:#ae81ff">500.0</span> <span style="color:#f92672">*</span> ball.z <span style="color:#f92672">/</span> (<span style="color:#a6e22e">pow</span>(<span style="color:#a6e22e">abs</span>(gl_FragCoord.x <span style="color:#f92672">-</span> (<span style="color:#ae81ff">0.5</span> <span style="color:#f92672">+</span> ball.x <span style="color:#f92672">/</span> <span style="color:#ae81ff">2</span>) <span style="color:#f92672">*</span> <span style="color:#ae81ff">1920.0</span>), <span style="color:#ae81ff">2</span>) <span style="color:#f92672">+</span> <span style="color:#a6e22e">pow</span>(<span style="color:#a6e22e">abs</span>(gl_FragCoord.y <span style="color:#f92672">-</span> (<span style="color:#ae81ff">0.5</span> <span style="color:#f92672">+</span> ball.y <span style="color:#f92672">/</span> <span style="color:#ae81ff">2</span>) <span style="color:#f92672">*</span> <span style="color:#ae81ff">1080.0</span>), <span style="color:#ae81ff">2</span>)));
</span></span></code></pre></div><p>All in all the code took me around four straight hours to write. Sadly, as the laptop it was written on has now died due to a faulty charging port (might see about repairing it in future), the program is lost. I didn&rsquo;t get a chance to benchmark it, either. If I do manage to fix it, I will back up the program and benchmark it against the Vulkan implementation.</p>
<h3 id="4-vulkan">4: Vulkan</h3>
<p>This was probably a mistake. Being a much more complex to use graphics API than OpenGL, it was far more verbose to complete. Like OpenGL, I followed <a href="https://vulkan-tutorial.com/">a course</a> to set up the boilerplate I needed (and introduce me to Vulkan&rsquo;s various concepts). I have to say, I&rsquo;m pretty proud of it. Like the original TIC-80 project (though I&rsquo;m not sure if that&rsquo;s what actually ended up on the site), it features randomly placed metaballs, something missing on both the Godot and OpenGL implementation. I also experimented with balls with negative &lsquo;size&rsquo;, if size is even the correct term here, and the results were very fun. You can ask for either purely positive metaballs or negative metaballs as well with a command-line option. While I was unable to get the validation layer for a proper FPS count compiled on my Chromebook, I was able to use Mangohud to measure the program&rsquo;s FPS. The results were mixed, with 60 FPS on the default resolution (800x600), and around 30 FPS when fullscreened (1336x768) on my Chromebook.</p>
<h3 id="5-whats-next">5: What&rsquo;s next?</h3>
<p>I have a few ideas for where I want to go with this project. The obvious one is leave it here. With Vulkan, I&rsquo;ve gone about as &rsquo;low-level&rsquo; as I&rsquo;m willing to go. I might return to <a href="http://craftinginterpreters.com/">the interpreter tutorial I was working on</a>, and I&rsquo;ll obviously continue working on this site. Some other options are DirectX (thought I&rsquo;m not sure how that would work, as I don&rsquo;t own a Windows computer), and Unreal Engine (again, Windows only makes it a bit awkward since I don&rsquo;t own a Windows computer).</p>
</div>
</article>
<hr>
<nav class="ring">
<div class="ring-prev">
<a href="https://mossfet.xyz/blog/site/">Previous post - I made a website</a>
</div>
<div class="ring-next">
<a href="https://mossfet.xyz/blog/newsite/">Next post - Reworking the site frontend</a>
</div>
</nav>
</section>
<footer class="footer">
<div>
This site (frontend and backend) is licensed under the <a href="https://www.gnu.org/licenses/agpl-3.0.en.html">AGPLv3</a> or later, with images and text also available under the <a href="https://creativecommons.org/licenses/by-sa/4.0/legalcode">CC-BY-SA 4.0</a>, at your discretion.
</div>
<hr>
<div class="webring"><a href="https://fediring.net/previous?host=mossfet.xyz" title="Previous Webring site">Previous</a> <a href="https://fediring.net">Fediring</a> <a href="https://fediring.net/next?host=mossfet.xyz" title="Next webring site">Next</a></div>
</footer>
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
# Reworking the site frontend
My previous website implementation left much to be desired. It was difficult to debug, implemented with a maze of makefiles, bizarre perl commands, and creative uses of pandoc. While it was a pretty useful exercise in pandoc and make, it wasn't really a sustainable solution. I had heard about Hugo from YouTube, and was already planning to use it to implement a friend's blog, so figured this would be good practise.
The only main downside I can think of is it means I'll have to put my plans of porting this site to Gemini will have to be put on hold. I've heard that there are ways of doing Gemini output on Hugo, but I don't want to focus on this while I'm still finding my feet.
I'm still using the same very simple rocket.rs backend, with some minor tweaks.
=> / Back to the Index
=> https://mossfet.xyz//blog/newsite/ View this article on the WWW

View File

@ -0,0 +1,77 @@
<!DOCTYPE html>
<html lang="en"><link rel="alternate" type="text/gemini" href="gemini://mossfet.xyz/blog/newsite/index.gmi" title="Mossfet's site" />
<link rel="stylesheet" href="/css/style.css" type="text/css" media="all" />
<body>
<div style="margin: 2%"><header>
<nav class="navbar">
<a href="/index.xml"><img src="/images/feed.svg" style="height: 20px; width: 20px; float: left;" alt="RSS Feed"></a>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/blog">Blog</a></li>
<li><a href="/links">Links</a></li>
<li><a href="https://git.solarpunk.moe/mossfet.site">Source</a></li>
</ul>
</nav>
</header>
<section class="section border">
<nav class="ring">
<div class="ring-prev">
<a href="https://mossfet.xyz/blog/metaballs/">Previous post - Metaballs</a>
</div>
<div class="ring-next">
<a href="https://mossfet.xyz/blog/serverhost/">Next post - Hosting my website</a>
</div>
</nav>
<hr>
<article>
<div class="blog-header">
<h1 class="blog-title">Reworking the site frontend</h1>
<h5>Written August 31, 2022</h5>
<h5>Last modifed August 31, 2022</h5>
<h5>Written by Mossfet</h5>
</div>
<div class="blog-content">
<p>My previous website implementation left much to be desired. It was difficult to debug, implemented with a maze of makefiles, bizarre perl commands, and creative uses of pandoc. While it was a pretty useful exercise in pandoc and make, it wasn&rsquo;t really a sustainable solution. I had heard about Hugo from YouTube, and was already planning to use it to implement a friend&rsquo;s blog, so figured this would be good practise.</p>
<p>The only main downside I can think of is it means I&rsquo;ll have to put my plans of porting this site to Gemini will have to be put on hold. I&rsquo;ve heard that there are ways of doing Gemini output on Hugo, but I don&rsquo;t want to focus on this while I&rsquo;m still finding my feet.</p>
<p>I&rsquo;m still using the same very simple rocket.rs backend, with some minor tweaks.</p>
</div>
</article>
<hr>
<nav class="ring">
<div class="ring-prev">
<a href="https://mossfet.xyz/blog/metaballs/">Previous post - Metaballs</a>
</div>
<div class="ring-next">
<a href="https://mossfet.xyz/blog/serverhost/">Next post - Hosting my website</a>
</div>
</nav>
</section>
<footer class="footer">
<div>
This site (frontend and backend) is licensed under the <a href="https://www.gnu.org/licenses/agpl-3.0.en.html">AGPLv3</a> or later, with images and text also available under the <a href="https://creativecommons.org/licenses/by-sa/4.0/legalcode">CC-BY-SA 4.0</a>, at your discretion.
</div>
<hr>
<div class="webring"><a href="https://fediring.net/previous?host=mossfet.xyz" title="Previous Webring site">Previous</a> <a href="https://fediring.net">Fediring</a> <a href="https://fediring.net/next?host=mossfet.xyz" title="Next webring site">Next</a></div>
</footer>
</div>
</body>
</html>

View File

@ -0,0 +1,27 @@
# Hosting my website
It's been a while since I originally created the website, but didn't get the chance to host it on real hardware until now.
When I initially set up my site, I had been planning on running it on a Raspberry Pi 4. If you've tried to get hold of a Pi 4 in the last three years, you'll know why that's not gonna work. I still have plans for getting my own SBC (specifically waiting for the Star64 to release), but in the mean time I found a different solution.
## Enter: A shitty broken Chromebook
A while ago, my parents bought me an Acer Chromebook 14 for school. It's a horrible thing, has broken and needed repair four times, is no longer supported for software updates, and looks ugly. It's my favourite laptop. Before it's most recent breakage, I had been running Fedora Linux off it for my schoolwork, with mixed results. Sadly, the LCD was broken after my bag fell off a desk, so it was no longer usable as a laptop.
What about as a server?
As I mentioned, the laptop (and most Chromebooks) can run Linux, so I figured that it could probably run webserver software as well as any other Linux box. I took the screen out to save power, disconnected the battery to stop it from being worn out, and installed NixOS on it. The nice thing about a Chromebook is it's pretty low wattage - the battery advertises 45 Watt-hours, which divided by the Chromebook's advertised 12-hour battery life gives 3.75 Watts, on average. I imagine (hope?) that it would be even lower for NixOS and without an LCD connected.
I'm not currently running my rocket.rs backend, instead running Apache httpd, configured through NixOS. This allows me to set up ACME "fairly easily" (big thanks to the NixOS Matrix channel for giving me a hand). I'm still on my home network, so dynamic IP is a problem. Thankfully, my DNS provider has a dynamic DNS protocol, and I found a shell script that can update it here [2].
=> /images/blog/laptopserver.jpg Embedded Image: /images/blog/laptopserver.jpg
I may migrate this to a different system when the Star64 arrives - I'm expecting an Ox64 at the same time, which could be perfect for a tiny task like this. I also intend to automate updating the website with git - currently I have to ssh into the machine and pull every time I want to update the website. I expect Gitlab could help me out here.
## References
=> https://nextnet.top/content/using-gandi-livedns-dynamic-dns-server [2] here (https://nextnet.top/content/using-gandi-livedns-dynamic-dns-server)
=> / Back to the Index
=> https://mossfet.xyz//blog/serverhost/ View this article on the WWW

View File

@ -0,0 +1,79 @@
<!DOCTYPE html>
<html lang="en"><link rel="alternate" type="text/gemini" href="gemini://mossfet.xyz/blog/serverhost/index.gmi" title="Mossfet's site" />
<link rel="stylesheet" href="/css/style.css" type="text/css" media="all" />
<body>
<div style="margin: 2%"><header>
<nav class="navbar">
<a href="/index.xml"><img src="/images/feed.svg" style="height: 20px; width: 20px; float: left;" alt="RSS Feed"></a>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/blog">Blog</a></li>
<li><a href="/links">Links</a></li>
<li><a href="https://git.solarpunk.moe/mossfet.site">Source</a></li>
</ul>
</nav>
</header>
<section class="section border">
<nav class="ring">
<div class="ring-prev">
<a href="https://mossfet.xyz/blog/newsite/">Previous post - Reworking the site frontend</a>
</div>
<div class="ring-next">
</div>
</nav>
<hr>
<article>
<div class="blog-header">
<h1 class="blog-title">Hosting my website</h1>
<h5>Written February 14, 2023</h5>
<h5>Last modifed February 14, 2023</h5>
<h5>Written by Mossfet</h5>
</div>
<div class="blog-content">
<p>It&rsquo;s been a while since I originally created the website, but didn&rsquo;t get the chance to host it on real hardware until now.</p>
<p>When I initially set up my site, I had been planning on running it on a Raspberry Pi 4. If you&rsquo;ve tried to get hold of a Pi 4 in the last three years, you&rsquo;ll know why that&rsquo;s not gonna work. I still have plans for getting my own SBC (specifically waiting for the Star64 to release), but in the mean time I found a different solution.</p>
<h2 id="enter-a-shitty-broken-chromebook">Enter: A shitty broken Chromebook</h2>
<p>A while ago, my parents bought me an Acer Chromebook 14 for school. It&rsquo;s a horrible thing, has broken and needed repair four times, is no longer supported for software updates, and looks ugly. It&rsquo;s my favourite laptop. Before it&rsquo;s most recent breakage, I had been running Fedora Linux off it for my schoolwork, with mixed results. Sadly, the LCD was broken after my bag fell off a desk, so it was no longer usable as a laptop.</p>
<p>What about as a server?</p>
<p>As I mentioned, the laptop (and most Chromebooks) can run Linux, so I figured that it could probably run webserver software as well as any other Linux box. I took the screen out to save power, disconnected the battery to stop it from being worn out, and installed NixOS on it. The nice thing about a Chromebook is it&rsquo;s pretty low wattage - the battery advertises 45 Watt-hours, which divided by the Chromebook&rsquo;s advertised 12-hour battery life gives 3.75 Watts, on average. I imagine (hope?) that it would be even lower for NixOS and without an LCD connected.</p>
<p>I&rsquo;m not currently running my rocket.rs backend, instead running Apache httpd, configured through NixOS. This allows me to set up ACME &ldquo;fairly easily&rdquo; (big thanks to the NixOS Matrix channel for giving me a hand). I&rsquo;m still on my home network, so dynamic IP is a problem. Thankfully, my DNS provider has a dynamic DNS protocol, and I found a shell script that can update it <a href="https://nextnet.top/content/using-gandi-livedns-dynamic-dns-server">here</a>.</p>
<p><img src="/images/blog/laptopserver.jpg" alt="The laptop running a webserver"></p>
<p>I may migrate this to a different system when the Star64 arrives - I&rsquo;m expecting an Ox64 at the same time, which could be perfect for a tiny task like this. I also intend to automate updating the website with git - currently I have to ssh into the machine and pull every time I want to update the website. I expect Gitlab could help me out here.</p>
</div>
</article>
<hr>
<nav class="ring">
<div class="ring-prev">
<a href="https://mossfet.xyz/blog/newsite/">Previous post - Reworking the site frontend</a>
</div>
<div class="ring-next">
</div>
</nav>
</section>
<footer class="footer">
<div>
This site (frontend and backend) is licensed under the <a href="https://www.gnu.org/licenses/agpl-3.0.en.html">AGPLv3</a> or later, with images and text also available under the <a href="https://creativecommons.org/licenses/by-sa/4.0/legalcode">CC-BY-SA 4.0</a>, at your discretion.
</div>
<hr>
<div class="webring"><a href="https://fediring.net/previous?host=mossfet.xyz" title="Previous Webring site">Previous</a> <a href="https://fediring.net">Fediring</a> <a href="https://fediring.net/next?host=mossfet.xyz" title="Next webring site">Next</a></div>
</footer>
</div>
</body>
</html>

View File

@ -0,0 +1,23 @@
# I made a website
***Note: This is outdated. I have rewritten the site with Hugo, and the solution described here was never hosted***
I made a website! And a blog! It remains to be seen how much I'll use it, but I'll at least make a post on how I made it
The site uses a very convoluted static site generator I wrote with makefiles and pandoc, the source of which can be found in the header of my website, along with that of the rest of this site (not that I would recommend using it. This was a very stupid idea kept going by sunk cost and pride). While the site's main pages are currently written in HTML and inserted into a template with pandoc (I may explore rewriting the main contents of the site in markdown), the blog posts are written in markdown and also converted using pandoc. Commonly shared elements like headers and footers are done with Pandoc templates.
I had initially used markdown instead of pandoc to convert the blog pages to HTML, and used Perl's regular expressions to find-and-replace markers I had placed in templates with content, but frankly this was a stupid idea.
The backend is written in Rust, with rocket.rs [1]. I didn't particularly have the need for performance that Rust provides, but I like Rust and I like the way that Rocket works. It's a very simple implementation, with routes for the index, 404 page, and anything in the static/web/ and static/atom/ directories.
I eventually plan to add Gemini support as well, with rewrites of the main pages and the same blog posts being converted to Gemtext as well at HTML, but this will take some additional work as it is not supported in Pandoc.
The blog pages are also made into an Atom feed, also generated with pandoc.
## References
=> https://rocket.rs [1] rocket.rs (https://rocket.rs)
=> / Back to the Index
=> https://mossfet.xyz//blog/site/ View this article on the WWW

View File

@ -0,0 +1,77 @@
<!DOCTYPE html>
<html lang="en"><link rel="alternate" type="text/gemini" href="gemini://mossfet.xyz/blog/site/index.gmi" title="Mossfet's site" />
<link rel="stylesheet" href="/css/style.css" type="text/css" media="all" />
<body>
<div style="margin: 2%"><header>
<nav class="navbar">
<a href="/index.xml"><img src="/images/feed.svg" style="height: 20px; width: 20px; float: left;" alt="RSS Feed"></a>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/blog">Blog</a></li>
<li><a href="/links">Links</a></li>
<li><a href="https://git.solarpunk.moe/mossfet.site">Source</a></li>
</ul>
</nav>
</header>
<section class="section border">
<nav class="ring">
<div class="ring-prev">
</div>
<div class="ring-next">
<a href="https://mossfet.xyz/blog/metaballs/">Next post - Metaballs</a>
</div>
</nav>
<hr>
<article>
<div class="blog-header">
<h1 class="blog-title">I made a website</h1>
<h5>Written May 17, 2022</h5>
<h5>Last modifed May 21, 2022</h5>
<h5>Written by Mossfet</h5>
</div>
<div class="blog-content">
<p><em><strong>Note: This is outdated. I have rewritten the site with Hugo, and the solution described here was never hosted</strong></em></p>
<p>I made a website! And a blog! It remains to be seen how much I&rsquo;ll use it, but I&rsquo;ll at least make a post on how I made it</p>
<p>The site uses a very convoluted static site generator I wrote with makefiles and pandoc, the source of which can be found in the header of my website, along with that of the rest of this site (not that I would recommend using it. This was a very stupid idea kept going by sunk cost and pride). While the site&rsquo;s main pages are currently written in HTML and inserted into a template with pandoc (I may explore rewriting the main contents of the site in markdown), the blog posts are written in markdown and also converted using pandoc. Commonly shared elements like headers and footers are done with Pandoc templates.</p>
<p>I had initially used markdown instead of pandoc to convert the blog pages to HTML, and used Perl&rsquo;s regular expressions to find-and-replace markers I had placed in templates with content, but frankly this was a stupid idea.</p>
<p>The backend is written in Rust, with <a href="https://rocket.rs">rocket.rs</a>. I didn&rsquo;t particularly have the need for performance that Rust provides, but I like Rust and I like the way that Rocket works. It&rsquo;s a very simple implementation, with routes for the index, 404 page, and anything in the static/web/ and static/atom/ directories.</p>
<p>I eventually plan to add Gemini support as well, with rewrites of the main pages and the same blog posts being converted to Gemtext as well at HTML, but this will take some additional work as it is not supported in Pandoc.</p>
<p>The blog pages are also made into an Atom feed, also generated with pandoc.</p>
</div>
</article>
<hr>
<nav class="ring">
<div class="ring-prev">
</div>
<div class="ring-next">
<a href="https://mossfet.xyz/blog/metaballs/">Next post - Metaballs</a>
</div>
</nav>
</section>
<footer class="footer">
<div>
This site (frontend and backend) is licensed under the <a href="https://www.gnu.org/licenses/agpl-3.0.en.html">AGPLv3</a> or later, with images and text also available under the <a href="https://creativecommons.org/licenses/by-sa/4.0/legalcode">CC-BY-SA 4.0</a>, at your discretion.
</div>
<hr>
<div class="webring"><a href="https://fediring.net/previous?host=mossfet.xyz" title="Previous Webring site">Previous</a> <a href="https://fediring.net">Fediring</a> <a href="https://fediring.net/next?host=mossfet.xyz" title="Next webring site">Next</a></div>
</footer>
</div>
</body>
</html>

View File

@ -0,0 +1,40 @@
<!DOCTYPE html>
<html lang="en"><link rel="alternate" type="application/rss+xml" href="https://mossfet.xyz/categories/index.xml" title="Mossfet's site" />
<link rel="stylesheet" href="/css/style.css" type="text/css" media="all" />
<body>
<div style="margin: 2%"><header>
<nav class="navbar">
<a href="/index.xml"><img src="/images/feed.svg" style="height: 20px; width: 20px; float: left;" alt="RSS Feed"></a>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/blog">Blog</a></li>
<li><a href="/links">Links</a></li>
<li><a href="https://git.solarpunk.moe/mossfet.site">Source</a></li>
</ul>
</nav>
</header>
<div class = "container border">
<div class = "section">
<div class = "content">
<h1 class="title">Categories</h1>
</div>
</div>
</div>
<footer class="footer">
<div>
This site (frontend and backend) is licensed under the <a href="https://www.gnu.org/licenses/agpl-3.0.en.html">AGPLv3</a> or later, with images and text also available under the <a href="https://creativecommons.org/licenses/by-sa/4.0/legalcode">CC-BY-SA 4.0</a>, at your discretion.
</div>
<hr>
<div class="webring"><a href="https://fediring.net/previous?host=mossfet.xyz" title="Previous Webring site">Previous</a> <a href="https://fediring.net">Fediring</a> <a href="https://fediring.net/next?host=mossfet.xyz" title="Next webring site">Next</a></div>
</footer>
</div>
</body>
</html>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Categories on Mossfet&#39;s site</title>
<link>https://mossfet.xyz/categories/</link>
<description>Recent content in Categories on Mossfet&#39;s site</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-gb</language>
<managingEditor>root@mossfet.xyz (Mossfet)</managingEditor>
<webMaster>root@mossfet.xyz (Mossfet)</webMaster>
<copyright>CC-BY-SA 4.0</copyright><atom:link href="https://mossfet.xyz/categories/index.xml" rel="self" type="application/rss+xml" />
</channel>
</rss>

88
public/css/style.css Normal file
View File

@ -0,0 +1,88 @@
.navbar ul {
display: flex;
justify-content: space-evenly;
padding: 0px;
}
.navbar li {
list-style-type: none;
margin-left: 5px;
margin-right: 5px;
font-size: 20px;
}
a {
color: black;
text-decoration: underline;
}
.border {
border: 2px solid black;
padding: 10px;
margin-bottom: 20px;
}
.footer {
text-align: center;
}
.ring {
display: flex;
justify-content: space-between;
}
.ring-next {
margin-right: 10px;
}
.blog-title {
font-size: 3em;
}
.blog-header {
text-align: center;
}
.blog-content img {
max-width: 60%;
height: auto;
margin-left: auto;
margin-right: auto;
display: block;
}
.homepage-wrapper {
display: flex;
}
.homepage-content {
flex-grow: 1;
}
.homepage-column {
min-width: 200px;
width: 300px;
flex-grow: 1;
margin-left: 20px;
}
.homepage-column ul {
overflow-wrap: break-word;
}
@media screen and (max-width: 600px) {
.homepage-column {
width: 100%;
margin-left: 0px;
margin-bottom: 20px;
}
.homepage-wrapper {
flex-wrap: wrap-reverse;
}
}
.webring {
display: flex;
justify-content: space-evenly;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

1
public/images/feed.svg Normal file
View File

@ -0,0 +1 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>RSS</title><path d="M19.199 24C19.199 13.467 10.533 4.8 0 4.8V0c13.165 0 24 10.835 24 24h-4.801zM3.291 17.415c1.814 0 3.293 1.479 3.293 3.295 0 1.813-1.485 3.29-3.301 3.29C1.47 24 0 22.526 0 20.71s1.475-3.294 3.291-3.295zM15.909 24h-4.665c0-6.169-5.075-11.245-11.244-11.245V8.09c8.727 0 15.909 7.184 15.909 15.91z"/></svg>

After

Width:  |  Height:  |  Size: 400 B

35
public/index.gmi Normal file
View File

@ -0,0 +1,35 @@
# Mossfet's site
My name is Mossfet. I'm a computer science student living in the UK. I am autistic and trans.
I have a special interest in computer science/general computing topics, and like Rust, Linux, and C.
I'm a (social?) anarchist. I like free software, free culture, and permacomputing [1].
I'm working on a game with some friends! It will be released under a free license and is made with the Godot game engine.
### Current Projects/areas of focus
* Information security
* GNOME
* Permacomputing
* Reverse proxies (NGINX+Apache)
* Indie web
* Distributed systems (DHTs, etc)
### Other interests
* Evangelion
* Persona
* History of Anarchism
* Emulation (and other things that make Nintendo sad)
## References
=> https://permacomputing.net/Principles/ [1] permacomputing (https://permacomputing.net/Principles/)
=> https://mossfet.xyz// View this article on the WWW
=> gemini://mossfet.xyz/blog Blog
=> gemini://mossfet.xyz/links Links
=> https://git.solarpunk.moe/mossfet/site Source

70
public/index.html Normal file
View File

@ -0,0 +1,70 @@
<!DOCTYPE html>
<html lang="en"><link rel="alternate" type="application/rss+xml" href="https://mossfet.xyz/index.xml" title="Mossfet's site" />
<link rel="alternate" type="text/gemini" href="gemini://mossfet.xyz/index.gmi" title="Mossfet's site" />
<link rel="stylesheet" href="/css/style.css" type="text/css" media="all" />
<body>
<div style="margin: 2%"><header>
<nav class="navbar">
<a href="/index.xml"><img src="/images/feed.svg" style="height: 20px; width: 20px; float: left;" alt="RSS Feed"></a>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/blog">Blog</a></li>
<li><a href="/links">Links</a></li>
<li><a href="https://git.solarpunk.moe/mossfet.site">Source</a></li>
</ul>
</nav>
</header>
<div class="homepage-wrapper">
<div class="border homepage-content">
<h1 id="mossfets-site">Mossfet&rsquo;s site</h1>
<p>My name is Mossfet. I&rsquo;m a computer science student living in the UK. I am autistic and trans.</p>
<p>I have a special interest in computer science/general computing topics, and like Rust, Linux, and C.</p>
<p>I&rsquo;m a (social?) anarchist. I like free software, free culture, and <a href="https://permacomputing.net/Principles/">permacomputing</a>.</p>
<p>I&rsquo;m working on a game with some friends! It will be released under a free license and is made with the Godot game engine.</p>
<h4 id="current-projectsareas-of-focus">Current Projects/areas of focus</h4>
<ul>
<li>Information security</li>
<li>GNOME</li>
<li>Permacomputing</li>
<li>Reverse proxies (NGINX+Apache)</li>
<li>Indie web</li>
<li>Distributed systems (DHTs, etc)</li>
</ul>
<h4 id="other-interests">Other interests</h4>
<ul>
<li>Evangelion</li>
<li>Persona</li>
<li>History of Anarchism</li>
<li>Emulation (and other things that make Nintendo sad)</li>
</ul>
</div>
<div class="border homepage-column">
<h2 id="mossfet">Mossfet</h2>
<ul>
<li>Pronouns: She/her or vi/vim</li>
<li>Location: UK</li>
<li>Fedi: <a href="https://solarpunk.moe/@mossfet">@mossfet@solarpunk.moe</a></li>
</ul>
</div>
</div>
<footer class="footer">
<div>
This site (frontend and backend) is licensed under the <a href="https://www.gnu.org/licenses/agpl-3.0.en.html">AGPLv3</a> or later, with images and text also available under the <a href="https://creativecommons.org/licenses/by-sa/4.0/legalcode">CC-BY-SA 4.0</a>, at your discretion.
</div>
<hr>
<div class="webring"><a href="https://fediring.net/previous?host=mossfet.xyz" title="Previous Webring site">Previous</a> <a href="https://fediring.net">Fediring</a> <a href="https://fediring.net/next?host=mossfet.xyz" title="Next webring site">Next</a></div>
</footer>
</div>
</body>
</html>

55
public/index.xml Normal file
View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Mossfet&#39;s site</title>
<link>https://mossfet.xyz/</link>
<description>Recent content on Mossfet&#39;s site</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-gb</language>
<managingEditor>root@mossfet.xyz (Mossfet)</managingEditor>
<webMaster>root@mossfet.xyz (Mossfet)</webMaster>
<copyright>CC-BY-SA 4.0</copyright>
<lastBuildDate>Tue, 14 Feb 2023 09:45:00 +0100</lastBuildDate><atom:link href="https://mossfet.xyz/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Hosting my website</title>
<link>https://mossfet.xyz/blog/serverhost/</link>
<pubDate>Tue, 14 Feb 2023 09:45:00 +0100</pubDate>
<author>root@mossfet.xyz (Mossfet)</author>
<guid>https://mossfet.xyz/blog/serverhost/</guid>
<description>It&amp;rsquo;s been a while since I originally created the website, but didn&amp;rsquo;t get the chance to host it on real hardware until now.
When I initially set up my site, I had been planning on running it on a Raspberry Pi 4. If you&amp;rsquo;ve tried to get hold of a Pi 4 in the last three years, you&amp;rsquo;ll know why that&amp;rsquo;s not gonna work. I still have plans for getting my own SBC (specifically waiting for the Star64 to release), but in the mean time I found a different solution.</description>
</item>
<item>
<title>Reworking the site frontend</title>
<link>https://mossfet.xyz/blog/newsite/</link>
<pubDate>Wed, 31 Aug 2022 12:29:17 +0100</pubDate>
<author>root@mossfet.xyz (Mossfet)</author>
<guid>https://mossfet.xyz/blog/newsite/</guid>
<description>My previous website implementation left much to be desired. It was difficult to debug, implemented with a maze of makefiles, bizarre perl commands, and creative uses of pandoc. While it was a pretty useful exercise in pandoc and make, it wasn&amp;rsquo;t really a sustainable solution. I had heard about Hugo from YouTube, and was already planning to use it to implement a friend&amp;rsquo;s blog, so figured this would be good practise.</description>
</item>
<item>
<title>Metaballs</title>
<link>https://mossfet.xyz/blog/metaballs/</link>
<pubDate>Tue, 17 May 2022 17:57:00 +0100</pubDate>
<author>root@mossfet.xyz (Mossfet)</author>
<guid>https://mossfet.xyz/blog/metaballs/</guid>
<description>1: TIC-80 A few months ago, I stumbled across the concept of &amp;lsquo;metaballs&amp;rsquo; on YouTube. I was already trying to work on a semi-successful 3D graphics project on the TIC-80, a fantasy console similar to the Pico-8, so when I gave up on that, I decided to try my hand at writing them there as well.
You can find the result here
It didn&amp;rsquo;t go horribly, but I was pretty dissatisfied with the performance and the limitation to a few colour bands.</description>
</item>
<item>
<title>I made a website</title>
<link>https://mossfet.xyz/blog/site/</link>
<pubDate>Tue, 17 May 2022 17:56:00 +0100</pubDate>
<author>root@mossfet.xyz (Mossfet)</author>
<guid>https://mossfet.xyz/blog/site/</guid>
<description>Note: This is outdated. I have rewritten the site with Hugo, and the solution described here was never hosted
I made a website! And a blog! It remains to be seen how much I&amp;rsquo;ll use it, but I&amp;rsquo;ll at least make a post on how I made it
The site uses a very convoluted static site generator I wrote with makefiles and pandoc, the source of which can be found in the header of my website, along with that of the rest of this site (not that I would recommend using it.</description>
</item>
</channel>
</rss>

14
public/links/index.gmi Normal file
View File

@ -0,0 +1,14 @@
# Links
You can find my Fedi account at @mossfet@solarpunk.moe [1]
My code forge is here [2]
You can message me on Fedi for my Matrix or whatever else you want to contact me on.
## References
=> https://solarpunk.moe/@mossfet [1] @mossfet@solarpunk.moe (https://solarpunk.moe/@mossfet)
=> git.solarpunk.moe/mossfet [2] here (git.solarpunk.moe/mossfet)=> / Back to the Index
=> https://mossfet.xyz//links/ View this article on the WWW

44
public/links/index.html Normal file
View File

@ -0,0 +1,44 @@
<!DOCTYPE html>
<html lang="en"><link rel="alternate" type="text/gemini" href="gemini://mossfet.xyz/links/index.gmi" title="Mossfet's site" />
<link rel="stylesheet" href="/css/style.css" type="text/css" media="all" />
<body>
<div style="margin: 2%"><header>
<nav class="navbar">
<a href="/index.xml"><img src="/images/feed.svg" style="height: 20px; width: 20px; float: left;" alt="RSS Feed"></a>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/blog">Blog</a></li>
<li><a href="/links">Links</a></li>
<li><a href="https://git.solarpunk.moe/mossfet.site">Source</a></li>
</ul>
</nav>
</header>
<div class = "container border">
<div class = "section">
<div class = "content">
<h1 class="title"></h1>
<h1 id="links">Links</h1>
<p>You can find my Fedi account at <a href="https://solarpunk.moe/@mossfet">@mossfet@solarpunk.moe</a>
My code forge is <a href="git.solarpunk.moe/mossfet">here</a></p>
<p>You can message me on Fedi for my Matrix or whatever else you want to contact me on.</p>
</div>
</div>
</div>
<footer class="footer">
<div>
This site (frontend and backend) is licensed under the <a href="https://www.gnu.org/licenses/agpl-3.0.en.html">AGPLv3</a> or later, with images and text also available under the <a href="https://creativecommons.org/licenses/by-sa/4.0/legalcode">CC-BY-SA 4.0</a>, at your discretion.
</div>
<hr>
<div class="webring"><a href="https://fediring.net/previous?host=mossfet.xyz" title="Previous Webring site">Previous</a> <a href="https://fediring.net">Fediring</a> <a href="https://fediring.net/next?host=mossfet.xyz" title="Next webring site">Next</a></div>
</footer>
</div>
</body>
</html>

34
public/sitemap.xml Normal file
View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xhtml="http://www.w3.org/1999/xhtml">
<url>
<loc>https://mossfet.xyz/</loc>
<lastmod>2023-02-14T12:01:00+01:00</lastmod>
</url><url>
<loc>https://mossfet.xyz/blog/</loc>
<lastmod>2023-02-14T12:01:00+01:00</lastmod>
<priority>0</priority>
</url><url>
<loc>https://mossfet.xyz/blog/serverhost/</loc>
<lastmod>2023-02-14T12:01:00+01:00</lastmod>
</url><url>
<loc>https://mossfet.xyz/blog/newsite/</loc>
<lastmod>2022-08-31T12:29:17+01:00</lastmod>
</url><url>
<loc>https://mossfet.xyz/blog/metaballs/</loc>
<lastmod>2022-05-24T21:58:00+01:00</lastmod>
</url><url>
<loc>https://mossfet.xyz/blog/site/</loc>
<lastmod>2022-05-21T19:30:00+01:00</lastmod>
</url><url>
<loc>https://mossfet.xyz/about/</loc>
<priority>0</priority>
</url><url>
<loc>https://mossfet.xyz/links/</loc>
<priority>0</priority>
</url><url>
<loc>https://mossfet.xyz/categories/</loc>
</url><url>
<loc>https://mossfet.xyz/tags/</loc>
</url>
</urlset>

40
public/tags/index.html Normal file
View File

@ -0,0 +1,40 @@
<!DOCTYPE html>
<html lang="en"><link rel="alternate" type="application/rss+xml" href="https://mossfet.xyz/tags/index.xml" title="Mossfet's site" />
<link rel="stylesheet" href="/css/style.css" type="text/css" media="all" />
<body>
<div style="margin: 2%"><header>
<nav class="navbar">
<a href="/index.xml"><img src="/images/feed.svg" style="height: 20px; width: 20px; float: left;" alt="RSS Feed"></a>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/blog">Blog</a></li>
<li><a href="/links">Links</a></li>
<li><a href="https://git.solarpunk.moe/mossfet.site">Source</a></li>
</ul>
</nav>
</header>
<div class = "container border">
<div class = "section">
<div class = "content">
<h1 class="title">Tags</h1>
</div>
</div>
</div>
<footer class="footer">
<div>
This site (frontend and backend) is licensed under the <a href="https://www.gnu.org/licenses/agpl-3.0.en.html">AGPLv3</a> or later, with images and text also available under the <a href="https://creativecommons.org/licenses/by-sa/4.0/legalcode">CC-BY-SA 4.0</a>, at your discretion.
</div>
<hr>
<div class="webring"><a href="https://fediring.net/previous?host=mossfet.xyz" title="Previous Webring site">Previous</a> <a href="https://fediring.net">Fediring</a> <a href="https://fediring.net/next?host=mossfet.xyz" title="Next webring site">Next</a></div>
</footer>
</div>
</body>
</html>

13
public/tags/index.xml Normal file
View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Tags on Mossfet&#39;s site</title>
<link>https://mossfet.xyz/tags/</link>
<description>Recent content in Tags on Mossfet&#39;s site</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-gb</language>
<managingEditor>root@mossfet.xyz (Mossfet)</managingEditor>
<webMaster>root@mossfet.xyz (Mossfet)</webMaster>
<copyright>CC-BY-SA 4.0</copyright><atom:link href="https://mossfet.xyz/tags/index.xml" rel="self" type="application/rss+xml" />
</channel>
</rss>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

1
static/images/feed.svg Normal file
View File

@ -0,0 +1 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>RSS</title><path d="M19.199 24C19.199 13.467 10.533 4.8 0 4.8V0c13.165 0 24 10.835 24 24h-4.801zM3.291 17.415c1.814 0 3.293 1.479 3.293 3.295 0 1.813-1.485 3.29-3.301 3.29C1.47 24 0 22.526 0 20.71s1.475-3.294 3.291-3.295zM15.909 24h-4.665c0-6.169-5.075-11.245-11.244-11.245V8.09c8.727 0 15.909 7.184 15.909 15.91z"/></svg>

After

Width:  |  Height:  |  Size: 400 B

20
themes/sitetheme/LICENSE Normal file
View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2022 YOUR_NAME_HERE
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,2 @@
+++
+++

View File

@ -0,0 +1,9 @@
{{ define "main"}}
<main id="main">
<div>
<h2>Oops!</h2>
<p>Looks like this page doesn't exist, or it does exist and I've broken something. (Error 404)</p>
<a href="/">Why don't you go home?</a>
</div>
</main>
{{ end }}

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="{{.Site.Language.Lang}}">
{{- partial "head.html" . -}}
<body>
<div style="margin: 2%">
{{- partial "header.html" . -}}
{{- block "main" . }}{{- end }}
{{- partial "footer.html" . -}}
</div>
</body>
</html>

View File

@ -0,0 +1,15 @@
{{ define "main" }}
<div class = "container border">
<div class = "section">
<div class = "content">
<h1 class="title">{{ .Title }}</h1>
{{ .Content }}
{{ range .Pages }}
<ul>
<li><a href="{{ .Permalink }}">{{ .Title }} ({{ .Date | time.Format ":date_short" }})</a></li>
</ul>
{{ end }}
</div>
</div>
</div>
{{ end }}

View File

@ -0,0 +1,21 @@
{{ define "main" }}
<section class="section border">
{{ partial "ring.html" . }}
<hr>
<article>
<div class="blog-header">
<h1 class="blog-title">{{ .Title }}</h1>
{{ with .PublishDate }}
<h5>Written {{ $.PublishDate.Format "January 2, 2006" }}</h5>
{{ end }}
<h5>Last modifed {{ .Lastmod.Format "January 2, 2006" }}</h5>
<h5>Written by {{ .Params.author }}</h5>
</div>
<div class="blog-content">
{{ .Content }}
</div>
</article>
<hr>
{{ partial "ring.html" . }}
</section>
{{ end }}

View File

@ -0,0 +1,30 @@
# {{ .Title }}{{ $scratch := newScratch }}
{{ $content := .RawContent -}}
{{ $content := $content | replaceRE `#### ` "### " -}}
{{ $content := $content | replaceRE `\n- (.+?)` "\n* $1" -}}
{{ $content := $content | replaceRE `\n(\d+). (.+?)` "\n* $2" -}}
{{ $content := $content | replaceRE `\[\^(.+?)\]:?` "" -}}
{{ $content := $content | replaceRE `<br/??>` "\n" -}}
{{ $content := $content | replaceRE `<a .*href="(.+?)".*>(.+?)</a>` "[$2]($1)" -}}
{{ $content := $content | replaceRE `\sgemini://(\S*)` " [gemini://$1](gemini://$1)" -}}
{{ $content := $content | replaceRE "([^`])<.*?>([^`])" "$1$2" -}}
{{ $content := $content | replaceRE `\n\n!\[.*\]\((.+?) \"(.+?)\"\)` "\n\n=> $1 Image: $2" -}}
{{ $content := $content | replaceRE `\n\n!\[.*]\((.+?)\)` "\n\n=> $1 Embedded Image: $1" -}}
{{ $links := findRE `\n=> ` $content }}{{ $scratch.Set "ref" (add (len $links) 1) }}
{{ $refs := findRE `\[.+?\]\(.+?\)` $content }}
{{ $scratch.Set "content" $content }}{{ range $refs }}{{ $ref := $scratch.Get "ref" }}{{ $contentInLoop := $scratch.Get "content" }}{{ $url := (printf "%s #%d" . $ref) }}{{ $contentInLoop := replace $contentInLoop . $url -}}{{ $scratch.Set "content" $contentInLoop }}{{ $scratch.Set "ref" (add $ref 1) }}{{ end }}{{ $content := $scratch.Get "content" | replaceRE `\[(.+?)\]\((.+?)\) #(\d+)` "$1 [$3]" -}}
{{ $content | safeHTML }}
# {{ if $refs }}
## References
{{ $scratch.Set "ref" (add (len $links) 1) }}{{ range $refs }}{{ $ref := $scratch.Get "ref" }}{{ $url := (printf "%s #%d" . $ref) }}
=> {{ $url | replaceRE `\[(.+?)\]\((.+?)\) #(\d+)` "$2 [$3] $1 ($2)" -}}
{{ $scratch.Set "ref" (add $ref 1) }}{{ end}}
{{ $related := first 3 (where (where .Site.RegularPages.ByDate.Reverse ".Params.tags" "intersect" .Params.tags) "Permalink" "!=" .Permalink) }}
{{ if $related }}
## Related articles
{{ range $related }}
=> {{ replace .RelPermalink "/gemini" "" 1}} {{ .Title }}: {{ .Params.Subtitle }}{{ end }}{{ end }}{{ end }}
=> / Back to the Index
=> {{ .Site.BaseURL }}/{{ replace (replace .RelPermalink "/gemini" "" 1) "index.gmi" "" }} View this article on the WWW

View File

@ -0,0 +1,18 @@
{{ define "main" }}
<div class="homepage-wrapper">
<div class="border homepage-content">
{{ .Content }}
</div>
<div class="border homepage-column">
<!--<h2> {{ .Params.name }}</h2>
<ul>
<li>Pronouns: {{ .Params.pronouns}}</li>
<li>Location: {{ .Params.location}}</li>
<li>Fedi handle: {{.Params.fedi}}</li>
</ul>-->
{{ with .Site.GetPage "/about" }}
{{ .Content }}
{{ end }}
</div>
</div>
{{ end }}

View File

@ -0,0 +1,11 @@
<footer class="footer">
<div>
This site (frontend and backend) is licensed under the <a href="https://www.gnu.org/licenses/agpl-3.0.en.html">AGPLv3</a> or later, with images and text also available under the <a href="https://creativecommons.org/licenses/by-sa/4.0/legalcode">CC-BY-SA 4.0</a>, at your discretion.
</div>
<hr>
<!--FEED-->
<!--<a href="/index.xml"><img src="/images/feed.svg" style="height: 30px; width: 30px; float: left; margin-left: 3%" alt="RSS Feed"></a>-->
<!--WEBRING-->
{{ $url := urls.Parse .Site.BaseURL }}
<div class="webring"><a href="https://fediring.net/previous?host={{ $url.Host }}" title="Previous Webring site">Previous</a> <a href="https://fediring.net">Fediring</a> <a href="https://fediring.net/next?host={{ $url.Host }}" title="Next webring site">Next</a></div>
</footer>

View File

@ -0,0 +1,4 @@
{{ range .AlternativeOutputFormats -}}
{{ printf `<link rel="%s" type="%s" href="%s" title="%s" />` .Rel .MediaType.Type .Permalink $.Site.Title | safeHTML }}
{{ end -}}
<link rel="stylesheet" href="/css/style.css" type="text/css" media="all" />

View File

@ -0,0 +1,12 @@
<header>
<nav class="navbar">
<!--FEED-->
<a href="/index.xml"><img src="/images/feed.svg" style="height: 20px; width: 20px; float: left;" alt="RSS Feed"></a>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/blog">Blog</a></li>
<li><a href="/links">Links</a></li>
<li><a href="https://git.solarpunk.moe/mossfet.site">Source</a></li>
</ul>
</nav>
</header>

View File

@ -0,0 +1,12 @@
<nav class="ring">
<div class="ring-prev">
{{ if .PrevInSection }}
<a href="{{ .PrevInSection.Permalink }}">Previous post - {{ .PrevInSection.Title }}</a>
{{ end }}
</div>
<div class="ring-next">
{{ if .NextInSection }}
<a href="{{ .NextInSection.Permalink }}">Next post - {{ .NextInSection.Title }}</a>
{{ end }}
</div>
</nav>

View File

@ -0,0 +1,88 @@
.navbar ul {
display: flex;
justify-content: space-evenly;
padding: 0px;
}
.navbar li {
list-style-type: none;
margin-left: 5px;
margin-right: 5px;
font-size: 20px;
}
a {
color: black;
text-decoration: underline;
}
.border {
border: 2px solid black;
padding: 10px;
margin-bottom: 20px;
}
.footer {
text-align: center;
}
.ring {
display: flex;
justify-content: space-between;
}
.ring-next {
margin-right: 10px;
}
.blog-title {
font-size: 3em;
}
.blog-header {
text-align: center;
}
.blog-content img {
max-width: 60%;
height: auto;
margin-left: auto;
margin-right: auto;
display: block;
}
.homepage-wrapper {
display: flex;
}
.homepage-content {
flex-grow: 1;
}
.homepage-column {
min-width: 200px;
width: 300px;
flex-grow: 1;
margin-left: 20px;
}
.homepage-column ul {
overflow-wrap: break-word;
}
@media screen and (max-width: 600px) {
.homepage-column {
width: 100%;
margin-left: 0px;
margin-bottom: 20px;
}
.homepage-wrapper {
flex-wrap: wrap-reverse;
}
}
.webring {
display: flex;
justify-content: space-evenly;
}

View File

@ -0,0 +1,19 @@
# theme.toml template for a Hugo theme
# See https://github.com/gohugoio/hugoThemes#themetoml for an example
name = "Sitetheme"
license = "GPLv3"
description = ""
tags = []
features = []
min_version = "0.41.0"
[author]
name = "Mossfet"
homepage = "mossfet.xyz"
# If porting an existing theme
[original]
name = ""
homepage = ""
repo = ""