Gemini2024-03-28T17:39:17Zhttps://d.moonfire.us/tags/gemini/D. MoonfireCreative Commons Attribution-NonCommercial-ShareAlike 4.0 InternationalMigrated Fedran to Nitride2022-11-25T06:00:00Zhttps://d.moonfire.us/blog/2022/11/25/fedran-and-nitride/Some thoughts about migrating Fedran to Nitride.
<p>Part of my push to get <a href="/tags/flight-of-the-scions/">Flight of the Scions</a> published, I had to rewrite my website because the <a href="https://fedran.com/flight-of-the-scions/">landing page</a> couldn't get any commerical links or be updated. That meant I had two options before me, either to figure out the <a href="/tags/gatsby/">Gatsby</a> errors that caused me to stop adding new content years ago or move forward and migrate the site to <a href="/tags/nitride/">Nitride</a>.</p>
<p>Since moving forward with Nitride would benefit me in the long wrong (I could add new content) but would also set me back (not everything moved along), I decided Nitride was the best approach. So, in the middle of everything going on, I sat down and migrated the website.</p>
<h2>Appearance</h2>
<p>I went with a much different look for the site, mostly based on the CSS theme for <a href="https://d.moonfire.us/">https://d.moonfire.us/</a>, but with the “standard” green theme I use for Fedran. I also knew I would be eventually hosting it on <a href="/tags/gemini/">Gemini</a> so much of the complex layouts and multiple columns were taken away in favor of CSS Grids and linear lists. This also let me create a “dark” and “light” mode since the original Fedran site predated my evolving preference for dark mode (and the CSS to support it). As a bonus, I went through and made sure everything passed Firefox's accessibility page for AA contrast.</p>
<p>This did make the site a bit more “generic looking” but that is also where my preferences are leading too. Complex sites are pretty to use but I wanted something easier to navigate and less confusing (a frequent complaint). It also meant I got rid of those fancy buttons with the <a href="https://fedran.com/identifiers/">identifiers</a> on the left and the various keywords on the right in favor of something like:</p>
<blockquote>
<ul>
<li>Flight of the Scions (0047-00) → Kanéko • Novel (129k)</li>
<li>Sand and Ash (0100-01) → Rutejìmo • Novel (78k)</li>
<li>Sand and Blood (0100-00) → Rutejìmo • Novel (69k)</li>
<li>Sand and Bone (0100-02) → Rutejìmo • Novel (82k)</li>
</ul>
</blockquote>
<p>On the other hand, as I integrate genres and other information, the bullet list version will scale much easier and I won't struggle to layout it out in neat columns. (You can also see I integrated word counts into the listings, which is new).</p>
<h2>Migration</h2>
<p>The migration went surprisingly easy. I was originally planning on holding off fedran.com until the end, because it is my “flagship” and most complicated site, but the various styles and concepts that I was working with were too different as long as I didn't try to integrate the custom calendar or build up the time line (two features that were removed but will come back eventually). The idea for multiple category lists came from the MediaWiki version of the site. I change the format how plugins were listed on the page, but that was just to work around <a href="https://github.com/xoofx/markdig">MarkDig's</a> and <a href="https://github.com/xoofx/zio">Zio's</a> functionality. The only big problem with my wiki links which I originally had a Markdown links with no paths such as <code>[Rutejìmo]()</code> but eventually wrote a proper MarkDig extension so I could say <code>[[Rutejìmo]]</code> instead and fit with better conventions.</p>
<p>The biggest thing was the 80+ Git repositories. I had already decided to move the retrieval out of the Nitride process (as opposed to Gatsby trying to do everything), so I had those prepared in a shell script called before building. And I had already tried out some ideas when integrating my <a href="/garden/">garden</a> where a Nitride pipeline looped through the projects and called a builder on each one before gathering all the results into a single pipeline.</p>
<pre><code class="language-csharp">var entities = this.fileSystem
.EnumerateItems("/fedran/sources", SearchOption.TopDirectoryOnly)
.OrderBy(a => a.Path.ToString())
.SelectMany(this.CreateProject)
.ToList();
</code></pre>
<p>Being able to set the “/” of a project to the input files is a great feature of Zio and I use it for most projects that need to view a directory structure without worrying about where that directory is located.</p>
<p>Overall, it took two weeks.</p>
<h2>New Features</h2>
<p>There are two really cool features that I'm proud of. The first is that dead links (e.g., pages I haven't written) are not automatically turned into spans with a class. That means if a link is there, it will go to a page as opposed to having so many be missing. I think this will improve the experience a lot while still giving me the hooks to fill in the pages and eventually aim for a 100% coverage of pages.</p>
<p>The other related to the Fedran's POV coloring scheme. Every character has a different color associated with them. The entire idea was that you could identify the series by the primary colors in the cover. Well, as part of the rewrite, I switched from SASS variables to CSS variables which meant I could inject a POV-specific stylesheet on the pages so now the POV charcters pages have the same color scheme as their covers, such as <a href="https://fedran.com/sand-and-blood/">Sand and Blood</a>, <a href="https://fedran.com/rutejimo/">Rutejìmo</a>, <a href="https://fedran.com/flight-of-the-scions/">Flight of the Scions</a>, and <a href="https://fedran.com/allegro/">Allegro</a>.</p>
<p>It's a little touch but I love how the colors change based on the page. And it covers both the POV charcter's entry and all of their sources.</p>
<h2>Gemini</h2>
<p>One of the other reasons I wanted to migrate to Nitride was because I wanted to also generate Gemtext pages and create a <a href="https://gemini.circumlunar.space/">Gemini pod</a>. This is a bit of a “silly” project since I know most readers aren't going to ever be on Gemini, but the “small network” is nice and I like sticking my work out where outliers might find it.</p>
<p>Because I wrote Nitride with Gemini in mind and had already done this site, it ended up only being a few days to create something I thought was pleasing and to push it out as <a href="gemini://fedran.com/">a pod</a>. It was nice as things I've been working on for over a year just fell into place.</p>
<h2>Next Steps</h2>
<p>There are a lot of next steps when it comes to that site. I still seem to be struggling to write and programming is a nice distraction, but I really want to get my time line back, which requires me to port my custom calendar (MfGames Culture) code to C# and get the “what is every chapter or scene where this character participated in or was referenced from”.</p>
<p>Then, start to fill out the pages since I really should write up <em>Flight of the Scions</em> in the site.</p>
August in a Nutshell2022-08-27T05:00:00Zhttps://d.moonfire.us/blog/2022/08/27/august-in-a-nutshell/The last few weeks of August have been very busy, both in terms of obligations, deadlines, and events of note. Some of them are negative while others are positive, so give me a chance to tell how my month has been going.
<p>The last few weeks of August have been very busy, both in terms of obligations, deadlines, and events of note. Some of them are negative while others are positive, so give me a chance to tell how my month has been going.</p>
<h1>The Trip</h1>
<p>The month started with a trip to the <a href="/tags/cabin/">family cabin</a>. It was about ten days, mainly because Partner had things going on and was unable to attend (various reasons of their own, I don't force them to come to my family events). It ended up being ten days and fourteen hours of driving (I do not like driving long distance, period).</p>
<p>My younger brother did a lot to spruce up the cabin and he brought the results of his multi-year project: a boat he had been restoring that my father had helped build. It was cool and nice to see a slice of my childhood in the water again.</p>
<p>I didn't get on it. Not that I didn't want to, it just didn't work out. The younger cousins (my kids and his kids) were having fun with rafting and water skiing. That meant I was well suited for jumping into the water around the dock and occupying them as they took turns, helping guide the boat into position, and assisting in my kids (who don't know how to swim as well as his).</p>
<p>I still had a ball. I like visiting family, seeing my brother, and just remaining in contact since I'm really terrible at initiating conversation outside of those events.</p>
<h1>Broadband</h1>
<p>One of the projects I started in August of last year was trying to get broadband into the cabin. The city had a large-scale installation and we got free installation of fiber (about twice as fast as I have at home). It was pretty much installed a year to the week, which worked out because my company stopped providing an access point and my phone doesn't work that far north†.</p>
<p>Having that there means that there is a better chance I can have a “writing weekend” where I got up for a couple of days of writing and work since everything I do is remote. I just have to get a better monitor/keyboard set up there.</p>
<p>Still, when it comes to reducing the chaos in my life, this was something that was hanging over me as one more item in the <a href="/tags/entanglement-2021/">entanglement</a>.</p>
<p>† T-Mobile started saying “99% coverage of the population” which is a lot more accurate because 99% of <a href="https://www.worldometers.info/world-population/us-population/">329.5 million</a> is still missing out on 3.3 million people. As such, that is Verizon territory and my phone pretty much craps out the second I hit the interstate. (I won't buy non-GSM phones and Verizon screwed me over more than once because I hold onto phones for about a decade before buying a new one.)</p>
<h1>Flood Five</h1>
<p>Now, I wouldn't be mentioning the entanglement if there wasn't something that went wrong. When I came home and went into my basement office, I could smell moisture. That is rarely a good sign and something that is quickly triggering PTSD.</p>
<p>Apparently, there was a major rain while I was gone and the sump pump had died so the entire basement flooded. Every scrap of carpet, soaked drywall, and ruined boxes were laid out for me to manage. Today, I got all of the carpet and padding out and into the garage; I'm planning on getting a dumpster in late October to get rid of it along with the rotted wood from the shelves and furniture and everything else that needs to get tossed.</p>
<p>One thing I find fascinating is that of all the six floods I've had in the basement (first one didn't really count since that was the week I moved in), they have all had entire different sources:</p>
<ul>
<li>Flood Zero: Water main cracked</li>
<li>Flood One: Derecho in 2020</li>
<li>Flood Two: Cracked pipe inside the slab</li>
<li>Flood Three: Refrigerator water line snapped</li>
<li>Flood Four: Mother's Day toilet explosion</li>
<li>Flood Five: Sump pump</li>
</ul>
<p>Floods two through five have all happened in the last twelve months. The end result is that I used to have a finished basement. At this point, I think the entire thing has been gutted enough to consider it no longer finished.</p>
<p>With best estimates, I figured I'll get it back to speed in five to ten years. I'm still working in the basement, I just have everything on naked concrete.</p>
<h1>Surgery</h1>
<p>In 2020, I caught Covid. I suspect twice, once in February since I had all the symptoms and then in November where I had all the symptoms but even worse. During the first one, I coughed so hard I hurt myself but it was a minor hernia so the doctor's dismissed it (probably because I'm fat) until it became obvious that it was steadily getting worse.</p>
<p>Fast foward to July: that is when we can change our benefits at work. I switched from high-deductible to PPO and then got the doctor to look at it with something more than “well, that looks painful, so how is everything else?”</p>
<p>Next week, I get surgery to fix that and I have so much hopes that it will handle the nigh continuous pain I've been in for the last four months. Given that I'm hypersensitive to input, that has been a distraction for almost everything I do and prevented me from sleeping well.</p>
<p>Of course, I have to get through the pre-op exam, the pre-pre-op tests, the pre-op phone call, and the pre-op billing statement first.</p>
<p>This also put a knife edge on the deadline for the carpet removal from the flooding since I won't be able to pick up anything heavy for a while. Wet carpet is not… light. Nor is moving water-logged furniture.</p>
<h1>Allegro</h1>
<p>A while ago, I contributed to a fund-raiser to send some writers to Clarion. Call it a wish fulfillment since I won't be able to go myself. One of the rewards was having another author read a book (or a chance to play with an AI novel writing tool). I decided to go with the reading and that meant I needed to finish “something” before September.</p>
<p>Since I was stalled on <a href="/tags/allegro/">Allegro</a>, I committed to finishing that novel for September. Earlier this week, I got the first draft done and I'm so excited. For what is a glorified fan-fiction of <a href="https://inv.riverside.rocks/watch?v=jvipPYFebWc">Lindsey Sterling's Roundtable Rival</a> set in <a href="/tags/fedran/">Fedran</a>, I'm pretty happy with a 105k word novel coming from a four minute music video.</p>
<p>It ended up being a much different story that Lindsey's video. It ties into <a href="/tags/songbird-in-a-kitchen/">Songbird in a Kitchen</a> and the general build up of stories to Fedran's world war (it's a Phase One story). Regardless, I'm really happy with the results and I hope I can polish it up to make it my sixth published novel (<a href="/tags/second-hand-dresses/">Second-Hand Dresses</a> will be my fifth and <a href="/tags/nor-curse-be-found/">Nor Curse Be Found</a> will probably be my seventh).</p>
<h1>Flight of the Scions</h1>
<p>Before the trip, I got the “release candidate” for <a href="/tags/flight-of-the-scions/">Flight of the Scions</a> done and sent to Ingram for a print version. It came while I was at the cabin. It looks beautiful and I'm really happy how the new covers turned out.</p>
<p>I also botched the layout (missed one page of padding so everything has the wrong margins), so I need to order a new one. That also means I have another chance to look for typos. My dad sent me a bunch, I found a few, I'm just going to work on them in September because of <em>Allegro</em>.</p>
<p>I think I'm on-track for the November 8th release of <em>Flight of the Scions</em> and I'm so excited. I will have early copies at <a href="/tags/icon/">ICON</a> this year since I'll have a table in the merchant area along with Shannon Ryan's <a href="https://weirdauthor.com/merger">Merger of Evil</a>.</p>
<p>For a novel I've been working off and on for almost two decades, having this out will be both a relief and a source of constant anxiety because it doesn't have my full evolution of writing (I couldn't rewrite it one more time, I just couldn't). It also means I need to get off my rear and start writing <a href="/tags/pack-daughter/">Pack Daughter</a>, the second of four in the series.</p>
<h1>Fedran Website</h1>
<p>Of course, I want to show off since my books are available to read even before they are for sale. Unfortunately, the site generator that <a href="https://fedran.com/">https://fedran.com/</a> uses, <a href="https://www.gatsbyjs.com/">Gatsby JS</a>, proved to be too fragile for how I use it. Plus it doesn't play well with my goal of getting my site on <a href="/tags/gemini/">Gemini</a>.</p>
<p>That means I need to get it migrated over to <a href="/tags/nitride/">Nitride</a> as soon as reasonable. Until then, the site is pretty much static until I can do that. It also means I can't start posting weekly chapters for <em>Allergo</em> until that comes out (even though everyone will be able to read the entire thing).</p>
<p>I just like having that weekly post. It makes me feel good to see that steady signal. I have no clue if I'm going to try again for <a href="/blog/2021/03/17/three-hundred-weeks/">three hundred consecutive weeks</a> like before. In most regards, I just effectively took a year off from writing.</p>
<h1>September</h1>
<p>September is going to be a busy month for me. I have <em>Allegro</em> to get out, <em>Flight</em> to polish, and fix the little things that are needed to get the book out the door.</p>
MfGames.Markdown.Gemtext v1.2.12022-02-17T06:00:00Zhttps://d.moonfire.us/blog/2022/02/17/mfgames-markdown-gemtext-1.2.1/New features for MfGames.Markdown.Gemtext, tables!
<p>As part of yesterday's post, I wanted to create a table in Gemtext that I could also produce in my Markdown to HTML pipeline. However, that was one step I skipped because it was overwhelming when I first wrote. However, the need to rant and warm pushed me over the board so I implemented tables.</p>
<h1>What is MfGames.Markdown.Gemtext?</h1>
<p>Let's start with the biggest question. This is a library that uses <a href="https://github.com/xoofx/markdig">Markdig</a> to parse Markdown and output <a href="https://gemini.circumlunar.space/docs/gemtext.gmi">gemtext</a> instead of HTML. This is the limited markup format used by Gemini browsers which is kind of a low-overhead and simplified browsing.</p>
<p>The limitations of Gemtext are a big one. There are a few I struggle with, specifically a lack of italics and bolds, but it also doesn't let you have more than one link per paragraph, no Javascript, and generally is “what you see is exactly what you get”. For a writer, it fits nicely with that especially when used with a lovely client such as <a href="https://github.com/skyjake/lagrange">Lagrange</a>.</p>
<p>I wrote the library inspired by <a href="https://github.com/makeworld-the-better-one/md2gemini">md2gemini</a> which creates a “reasonable” output from Markdown which is my native writing format for novels and posts.</p>
<p>At the moment, I don't have a SSL certificate to sign the library so I can't post it on NuGet, so I have my libraries at <a href="https://www.myget.org/feed/Packages/mfgames">MyGet</a>. In specific, <a href="https://www.myget.org/feed/mfgames/package/nuget/MfGames.Markdown.Gemtext">MfGames.Markdown.Gemtext</a> gives the information for downloading and using it.</p>
<p>Note, if you want want to multiple NuGet sources, the following <code>NuGet.config</code> works well for my packages:</p>
<pre><code><?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
<add key="mfgames" value="https://www.myget.org/F/mfgames/api/v3/index.json" protocolVersion="3" />
</packageSources>
</configuration>
</code></pre>
<p>I have this checked into any project that uses them. I have… opinions about single source repositories but getting a SSL certificate isn't quite in my cards for at least half a year.</p>
<p>The source is located on <a href="https://gitlab.com/mfgames-cil/mfgames-markdown-gemtext-cil">Gitlab</a> along with ticket-tracking and the usual slew of tools.</p>
<h1>Using MfGames.Markdown.Gemtext</h1>
<p>The bulk of the code can be seen in the unit tests, but I want to work on better documentation. It's just waiting for <a href="/tags/nitride/">Nitride</a>. Until then, here are some basics.</p>
<pre><code>// using MfGames.Markdown.Gemtext;
string input = "This is input.";
string expected = "This is input.";
string actual = MarkdownGemtext.ToGemtext(input);
Assert.Equal(expected, actual);
</code></pre>
<p>This is pretty much how the base Markdig processing is done. I had to jump through a few extra hoops because of hard-coding, but overall, this is it.</p>
<p>The biggest thing is converting a paragraph with links into something Gemtext. There are a couple of formats, but my preferred (and the one I use on my <a href="gemini://d.moonfire.us/">Gemini version of this site</a>) is a table of links after the paragraph.</p>
<pre><code>var input = string.Join(
"\n",
"This is a paragraph with an [inline](https://example.com) link.",
"Here is [another](https://example.org/) link, part of the same paragraph.",
"",
"This is a second paragraph, with a different [link](https://duck.com) in it.");
string actual = MarkdownGemtext.ToGemtext(
input,
new MarkdownPipelineBuilder()
.Use(new SetBlockLinkHandling(BlockLinkHandling.ParagraphEnd))
.Build());
Console.WriteLine(actual)
/* Output is:
This is a paragraph with an inline[10] link. Here is another[11] link, part of the same paragraph.
=> https://example.com 10: https://example.com
=> https://example.org/ 11: https://example.org/
This is a second paragraph, with a different link[12] in it.
=> https://duck.com 12: https://duck.com
*/
</code></pre>
<h1>Tables</h1>
<p>Tables are not part of Gemtext. Before this version, if you passed in a table such as:</p>
<pre><code>aaa|bbb|ccc
--:|---|:-:
1|2|3
4|5|6
</code></pre>
<p>You would get everything on a single line.</p>
<pre><code>aaa|bbb|ccc --:|---|:-: 1|2|3 4|5|6
</code></pre>
<p>With this version, you can pass a table parsing that produces a normalized table based on formatting using the excellent <a href="https://www.nuget.org/packages/ConsoleTableExt">ConsoleTableEx</a> library.</p>
<pre><code>//using MfGames.Markdown.Gemtext;
//using MfGames.Markdown.Gemtext.Extensions;
MarkdownPipeline pipeline = new MarkdownPipelineBuilder()
.Use(
new GemtextPipeTableExtension(
new GemtextPipeTableOptions()
{
OmitPreformatLines = true,
ConfigureTableBuilder = (x) => x.WithFormat(ConsoleTableBuilderFormat.MarkDown),
}))
.Build();
string input = string.Join(
"\n",
"aaa|bbb|ccc",
"--:|---|:-:",
"1|2|3",
"4|5|6");
string expected = string.Join(
"\n",
"| aaa | bbb | ccc |",
"|-----|-----|-----|",
"| 1 | 2 | 3 |",
"| 4 | 5 | 6 |",
"");
string actual = MarkdownGemtext.ToGemtext(input, pipeline);
Assert.Equal(expected, actual);
</code></pre>
<p>I went with the library because I like how <code>ConsoleTableEx</code> will make sure everything is lined up. Plus, you can change the formatting to change the borders around and between the cells, different layouts, and the like. Basically, the options configured in the <code>ConfigureTableBuilder</code> lets the developer set the format instead of me deciding on a One True Way™️.</p>
<h1>What's Next</h1>
<p>I have a couple minor little things with this library, but a lot of it is based on getting Nitride cleaned up and usable. This site uses Nitride and it runs nicely, but it isn't quite ready for prime time. So, I'm taking lessons learned, refactoring that library, and hopefully get it ready for the next big site (<a href="https://mfgames.com/">https://mfgames.com/</a>).</p>
Gallium Nitride and Gemini2021-07-10T05:00:00Zhttps://d.moonfire.us/blog/2021/07/10/gallium-nitride-and-gemini/Last November, I switched my static site generator from CobblestoneJS (my homebrew Gulp-based one) to Statiq. There were a number of reasons, all of them still good but mainly to support what I want to do with fedran.com and my other sites. This weekend, I changed it to a new static site generator that I have written and hosted the site also on Gemini.
<p>Last <a href="/blog/2020/11/20/website-update/">November</a>, I switched my static site generator from CobblestoneJS (my homebrew Gulp-based one) to <a href="https://statiq.dev/">Statiq</a>. There were a number of reasons, all of them still good but mainly to support what I want to do with <a href="https://fedran.com/">fedran.com</a> and my other sites.</p>
<p>This holiday weekend, I ended up ripping out all of the Statiq and wrote another static site generator, this time in C# and using an <a href="https://en.m.wikipedia.org/wiki/Entity_component_system">Entity-Component-System</a> (ECS). I also migrated my site over to <a href="gemini://d.moonfire.us/">Gemini</a> as part of the effort.</p>
<h1>Why?</h1>
<p>I liked many of the ideas that Statiq provided:</p>
<ul>
<li>Treating the website generation as code.</li>
<li>Having pipelines with dependencies for generation.</li>
<li>Immutable objects on the pipeline.</li>
</ul>
<p>However, I found myself struggling with concepts. It just didn't sit well with me and I would spend two weeks trying to implement a feature and getting stuck. When I realized I had spent a month not fixing something that was bothering me because I didn't want to delve into the code, I knew it was time to change.</p>
<p><em>That isn't to say Statiq isn't bad. It just isn't for me. That's it.</em></p>
<p>About once a year, I get 4-7 days of “alone time” to do what I want. This year, I decided to work on a new static site generator that did work the way I work today and that I hoped would carry me over for the next five years or so.</p>
<h1>Entity-Component-Systems (ECS)</h1>
<p>One thing that Statiq did (but differently) was implemented the system as an ECS. Basically, you have a lightweight object (the “entity”) and add various components into it. Those components are what provide the features: the text content, flags to say if it is HTML or Markdown, or the path.</p>
<p>While Statiq had a number of these elements built-into the <code>Document</code> call (basically their entity), there were a lot of assumptions that didn't always fit. Likewise, <code>Statiq.Web</code> had some nice opinionated ways of handling it, including a document type (binary, text, etc), but I couldn't find an easy way to extend it.</p>
<h1>Gallium</h1>
<p>With my ECS, <code>Entity</code> is only a collection plus an integer identifier. Components can be added, removed, and replaced easily using generics to determine the type. Methods are chained together but not pseudo-English fluent (which I'm also not fond of). Entities are immutable, so all the operations return a clone of that entity with the new components added, removed, or otherwise changed. (Thanks to functional programming for some of those ideas.)</p>
<pre><code class="language-csharp">Entity entity = new();
Entity entityWithTwoComponents = entity
.Set(new Uri("https://d.moonfire.us"))
.Set<FileSystemInfo>(new FileInfo("/bob.txt"));
Entity entityWithReplacedUri = entityWithTwoComponents
.Set(new Uri("http://path-to-replace-d.moonfire.us/"));
Entity entityWithOnlyUri = entityWithReplacedUri
.Remove<FileSystemInfo>();
</code></pre>
<p>I also really like chained operations, so most of the processing looks like this:</p>
<pre><code class="language-csharp">IEnumerable<Entity> input;
var onlyHtmlOutputs = input
.OrderBy(x => x.Get<FileInfo>().FullPath)
.ForComponents<Uri>((entity, uri) => this.Uri(entity, uri))
.WhereComponents<IsHtml>();
</code></pre>
<p>The whole idea is <code>ForComponents<T1, T2, T3></code> will go through the list and for all entities that have <code>T1</code>, <code>T2</code>, and <code>T3</code>, it will do the callback, otherwise it will passs it on. Likewise <code>WhereComponents<T1></code> is basically a <code>Where</code> that says only the entities with the given components.</p>
<p>Those ideas really simplified a lot of the difficulties I had with CobblestoneJS. Overall, most of the logic “felt” right for me, so I'm really happy with the results. Plus, it is based on a far more stable package ecosystem (NuGet) and in a language I enjoy greatly (C#).</p>
<p>Also, the language uses <a href="https://autofac.org/">Autofac</a> as my preferred dependency injection of choice. I really like the library plus <a href="https://nodatime.org/">NodaTime</a> when coding, so I went with these. It's a bit opinionated, but… only a few people ever used Cobblestone, so I'm going to assume very few are going to use this.</p>
<p>Once I get it cleaned up, I'll probably call the ECS “Gallium” because my original name was “Gallium Nitride” (GaN, because it's a cool name and I like what the molecule does). The static site generator would be named Nitride.</p>
<h1>Nitride</h1>
<p>Nitride is just a multi-threaded pipeline static generator. It uses pipelines much like Statiq but based on C#'s thread control (<code>ManualReset</code>, <code>ReaderWriterLockSlim</code>).</p>
<p>The rough code looks like this:</p>
<pre><code class="language-csharp">List<Entity> list = entities
.Run(new IdentifyMarkdown())
.Run(new ParseYamlHeader<PageModel>())
.ForComponents<PageModel>(this.SetHandlebarsFromPageModel)
.Run(this.setInstantFromComponent)
.Run(this.filterOutFutureInstants)
.Run(this.createCategoryIndexes)
.Run(this.createTagIndexes)
.ToList();
</code></pre>
<p>Again, DI or direct instantiate of modules, it all works the same and really ties into using Linq and C# generics. All of the pipelines are <code>async</code> but most of the operations (<code>createTagIndexes</code>, <code>ParseYamlHeader</code>) are not. But since the pipelines are, it is easy to make something <code>await</code> without changing signatures.</p>
<p>I really like the pipelines. For my site, I have the following:</p>
<ul>
<li><code>PostsPipeline</code>: Load posts and create blog archives</li>
<li><code>PagesPipeline</code>: Load static pages.</li>
<li><code>ContentPipeline</code>: Combines <code>PostsPipeline</code> and <code>PagesPipeline</code>, creates categories/tag indexes, handle filtering out future pages.</li>
<li><code>BareHtmlPipeline</code>: Takes <code>ContentPipeline</code> and converts into bare, unstyled HTML. Also creates the RSS and Atom feeds from the bare HTML.</li>
<li><code>WebpackPipeline</code>: Runs Webpack.</li>
<li><code>StyledHtmlPipeline</code>: Takes <code>BareHtmlPipeline</code> and <code>WebpackPipeline</code> and makes it styled using handlebars.</li>
<li><code>GeminiPipeline</code>: Takes <code>ContentPipeline</code> and turns the Markdown into Gemini, applies some simple styling, and generates Gemtext pages.</li>
</ul>
<p>That's it, but I'm happy with the result because I've taken lessons learned from my previous attempts to created something that will handle Fedran's massive cross-linking and project pages, MfGames's pulling in of separate Git repositories, and also some of the more complex formatting of my new sci-fi fiction website.</p>
<h1>Gemini</h1>
<p>I like the idea of <a href="//gemini.circumlunar.space/">Gemini</a>. It is a low-overhead protocol that has almost no extra features, no cookies, and basically focused on presenting content. In my case, I really want to see all of my sites on Gemini because I think it has some significant merits, more so as I want to get away from heavily styled content written by people who like tiny fonts or don't have my color contrast issues.</p>
<p>To do that, I ended up taking inspiration from <a href="https://pypi.org/project/md2gemini/">md2gemini</a> and wrote a C# library that converts Markdown into Gemtext (Gemini's markup format inspired by Markdown). The end result is <a href="gemini://d.moonfire.us/">pretty nice</a>, I think and I'm really happy with the results.</p>
<p>Of course, it meant I had to get a virtual machine to host a Gemini server next to a HTTP one, but that was going to happen sooner or later anyways.</p>
<h1>Next Steps</h1>
<p>I write a lot libraries that I think are interesting but very few people worry about. They rise up, either I stick with them or I trail off, but they always scratch my itches. On that front, the following things are left to do:</p>
<ul>
<li>Split out Gallium more formally into <code>MfGames.Gallium</code> or <code>Gallium</code>, not sure.</li>
<li>Clean up the API for <code>Nitride</code> and make sure everything is consistent. Some of the names are a bit… off, but the functionality is good.</li>
<li>Break all the modules into separate Gitlab projects and set up CI for releasing.</li>
<li>Document everything.</li>
<li>Convert five other websites sites to use it to figure out what is missing.</li>
</ul>
<p>I haven't found the money to get a developer's signing certificate, so I'll probably just put everything up on my public <a href="https://www.myget.org/">MyGet repository</a>.</p>
Website Update2020-11-20T06:00:00Zhttps://d.moonfire.us/blog/2020/11/20/website-update/I've switched the generator used to create this website from Cobblestone to Statiq, a much different type of static site generator. With this change came a revamp of the site's appearance, one that is far less graphical than before, but it will allow for some future plans.
<p>I haven't been posting here lately. There are a number of reasons, but I'm going to have to go with the simple one: 2020. Lots of things all piling up, adding to to stress, and making just getting things difficult. Along the way, occasionally things slip to make sure other things continue.</p>
<p><a href="https://fedran.com/">Fedran</a> was one of those things. I've been working on maintaining my weekly chapters but it seems like I haven't been doing other than heads-down writing.</p>
<p>One of my favorite methods for managing stress is obsessing about a little change that quickly blossoms into a much larger epic worthy of sailing across the ocean and trying to debate some sirens. Usually this ends up with me redoing one of my websites, rewriting my accounting system, or completely revamping one of my writing tools.</p>
<p>If you can't get, I have a “type” when it comes to reducing stress.</p>
<p>In this case, it was stumbling onto <a href="https://gemini.circumlunar.space/">Gemini</a>. This is a stripped-down but still fairly capable protocol based on both Gopher and web browsing. It focused more on information but without stressing about the “pretty” part of the web. There are no themes, font choices, or a ton of links. Well, there can be links but they are one per line and clearly identified as such.</p>
<p>Gemini appeals to me. Almost everything I create is already in written form, this seems like an ideal place to hang up a pole and see what happens. Not to mention, it's just fun to find new places to explore.</p>
<p>This also happened at the time when I had butted up against limitations in <a href="https://www.gatsbyjs.com/">Gatsby</a>, which I had just spent three months rewriting Fedran. I had switched to Gatsby because of flaws I encountered in Cobblestone, my own static site generator.</p>
<p>That isn't to say, Gatsby doesn't make a beautiful sites. The trick they use to load the next page quickly was great. But it also is very heavy on the Javascript side of things which was pretty much the opposite of trying out Gemini which has no Javascript.</p>
<p>Since I rarely do things halfway, I want to migrate this site over to Gemini. This means either I stick with Cobblestone (which was already failing on me), convert it to Gatsby <em>and</em> to Gemini, or find something new.</p>
<p>Enter <a href="https://statiq.dev/">Statiq</a>. It's another static site generator that is one of my preferred languages (C#, Typescript, and apparently Rust) but it also allows for pipelines (what I liked about the Gulp-based Cobblestone) that would let me diverge the site between HTML and Gemini on the final steps while still allowing me the massive cross-referencing I use on Fedran.</p>
<p>I did consider switching Fedran, but after years of spinning wheels on redoing projects, I limit myself to one website rewrite a year. Otherwise, I would just endlessly redo my website and not actually create anything.</p>
<p>If you are reading this, then I've managed to switch over. Fortunately, <a href="http://d.moonfire.us/">http://d.moonfire.us/</a> is one of the more basic websites I have. That means I can build on it as I work toward the final boss, Fedran.</p>