Neopoligen
Neopoligen is a free website building app. It's designed to make websites you can tinker with. It's largely a personal project, but I'm open - sourcing it for anyone else who likes to play around with different tools.
The app built this site, but it needs a little more work before it's ready for other folks to play with. Until then, you can read more about how it works below. You can also check out GitHub if you want to follow along with the development.
If you're wondering why I decided to make my own app you can check out Why I Built Neopoligen
How It Works
Files
Neopoligen sites are made from files that look like this :
-- title Welcome To Neopoligen -- p Neopoligen is a free website building app. It's designed to make websites you can tinker with. The app built this site, but it needs a little more work before it's ready for other folks to play with. Until then, you can read more about how it works below. You can also <<link|check out GitHub|https://github.com/neopoligen/neopoligen>> if you want to follow along with the development. -- metadata -- created: 2024-05-31T19:20:58-04:00 -- id: 2ikuxluk
Sections
Neopoligen files are made from sections that start with two dashes
and a name like
:
-- title
,
-- p
and
-- metadata
.
The name for each section determines what happens to the content in it.
For example, outputting a title or a set of paragraphs like above. Some
sections, like "metadata", don't do anything directly. They're used
for things like storing the IDs of a pages which are used for linking.
Another type of section is
-- list
which looks like this
:
-- list - the quick brown fox - jumps over the lazy dog
Each line that starts with a single dash becomes a new list item which turns into this output :
-
the quick brown fox
-
jumps over the lazy dog
Some of the other default sections include :
-
Blockquotes
-
Checklists
-
Code Samples
-
Footnotes 1
-
HTML, CSS, and JavaScript Embeds
-
Images
Section Attributes
Each section can have addition details called "attributes". They can do things like change a section's appearance, add alt text to images, or provide more content that can be formatted independently.
Attributes are made by adding extra lines start
with two dashes after a section. For example,
here's a
-- class
attribute that's used to make the
text in the section green.
-- p -- class: green The quick brown fox jumps over the lazy dog
This is what that looks like :
The quick brown fox jumps over the lazy dog
Custom Sections
Neopoligen works by using templates to control the output of each type of section. It comes with several default sections, but you can make as many as you want. As far as the app is concerned, there's no difference between a section/template combination you make and one the ones the come built - in.
For example, here's a new type of section called
book-to-read-example
with some attributes for the title, author, and cover image.
-- book-to-read-example -- title: The Peripheral -- author: William Gibson -- image: /neo-images/the-peripheral-cover/100w.jpg I've read a bunch of other William Gibson stuff and can't wait to get to this one!
And here's an example of what it could look like :
The Peripheral
I've read a bunch of other William Gibson stuff and can't wait to get to this one!
Spans
Neopoligen supports adding different "spans" to text inside sections. A span starts with two less than signs and ends followed by the name for the type of span then a pipe character and the contents. A closing pair of two greater than signs ends the span.
For example, here's an "em" span that makes the text inside it italics :
The <<em|quick brown>> fox
The output looks like this :
The quick brown fox
Nested Spans
Spans can be nested inside each other. For example, here's how to make text that's bold (via "strong") and underlined (via "u").
The <<strong|<<u|quick brown>>>> fox
Which outputs :
The quick brown fox
Span Attributes
Spans can have attributes as well. Attributes are separated by a pipe character like this :
The <<em|quick brown|class: green>> fox
The output looks like this :
The quick brown fox
Custom Span Functionality
Spans work off templates the same way sections do. You can make your
own with whatever functionality you want. The
tlink
span
is a good example. It takes the ID of another page on the site
and turns into into a link to that page using the page's title.
Next Page: <<tlink|2kiw8tvv>>
Which outputs this :
Next Page : TODO List
Hosting
Neopoligen uses files directly on your computer to create websites. You can preview the sites on your machine. You have to published them to a "hosting provider" to make them available to the world. Neopoligen is designed to work with a free service called GitHub Pages by default.
Details on using GitHub and other free services are a work in progress.
Tech Stuff
A few details for those interested in the more technical side of things :
-
Neopoligen is a Static Site Generator written in Rust that uses the nom parser combinator for parsing and MiniJinja for templates
-
Sites generated by the app can be hosted pretty much anywhere that offers static site hosting. The only real requirement is that the server automatically serve "index.html" files when a directory is called e.g. calling " /en/abcd1234/ " returns the file stored at " /en/abcd1234/index.html "). Every service I'm aware of has this option.
-
The original content files are stored locally on your machine. You maintain ownership and control of them. You can change hosting providers at any time without losing your content.
-
You can also keep your site name when changing hosting providers if you buy your own domain name (I'll write more about, but it's something I highly recommend if you can afford it)
-
Neopoligen is not built off from on any JavaScript frameworks and learning JavaScript is not required to create new templates or modify existing ones. (I'm building Neopoligen with the explicit goal that it's what powers my site for the next twenty years and part of the means not constantly jumping to new frameworks)
-
The name of the content file format is "Neopolitan" which uses the ".neo" file extension
-
Templates are stored in ".neoj" files. They're just like regular MiniJinja files with the exception that the delimiters have been changed from {% %}, {{ }}, and {# #} to [! !], [@ @], and [# #] because I find those easier to type and read
-
Templates are grouped together into themes. The theme for a site is determined via a config file. The default theme can be copied to a new folder and used as the starting point for making a new one
-
Each content page has a "type" which defaults to "post" and a "status" that defaults to "published". Those values can be changed for any page by setting attributes in the
-- metadata
section. The "type" and "status" are then used to determine which base template to use from the theme. (e.g. you can make templates for "post/draft", "homepage/published", etc...) -
All sections have a default template. Additional templates can be added for each section type and then used by adding a
-- template
attribute -
Custom CSS and JavaScript can be added to pages via
-- css
and-- javascript
sections. The output from those sections is added to the < head > of the document in their appropriate tags -
The default theme contains custom templates for CSS and JavaScript that show them as inline code blocks as well as adding them to the < head > of the document. This effectively provides live code for examples so you can verify your samples actually work
-
The default theme includes an HTML section that drops raw HTML directly into the output. Similar to the CSS and JavaScript sections there's a custom template to show the code in a code block as well as output it to verify code samples do what they're supposed to
-
The default theme provides for
-- head
sections. The content of those sections is inserted directly in the html < head > element of the output for things like adding script libraries -
Syntax highlighting is built - in. Highlighting can be applied to sections similar to how code blocks are used in Markdown. Highlights can also be added to inline text via spans
-
The syntax highlighting is done via classes (instead of via inline styles) so things can be controlled via stylesheets
-
The syntax highlighter adds an empty span with a specific class at the start of each line that can be used to add line number in CSS
-
A test engine for verifying the output of templates is built - in
-
Basic image optimization is built - in
-
Basic Open Graph images with the title of the page are built - in
-
Right now, the app is a command line app, but a front end built with Tauri is in progress. The goal is to make it so folks can build sites without having to learn to use the command line
-
Basic error handling and messaging is built into the app. It's not great yet, but improving it is an explicit goal. (This is based off my experience with the Rust compiler where the general vibe is if you can't figure out what you need to do based on an error message they consider that a bug)
-
I've built a basic syntax highlighter for Neopolitan via Tree-sitter for Neovim . My longer term goal is to make an LSP for both ".neo" and ".neoj" files that can be used with Neovim, VSCode, or any other app that works with LSPs
-
Pages are output to URLs based off their IDs be default. (e.g. " /en/2kiw8tvv/ "). This is done in an effort to prevent link rot by keeping the URLs the same regardless of if the content on the page changes or it's moved in the source file directory structure.
My plan is to use Neopoligen for my sites from this point forward, but if I ever do move again it will be easier to duplicate that exact structure than trying to match something with text slugs or redirects. (Over the past few decades I've used both those techniques repeatedly and I'm not interested in doing it ever again)
-
Another reason for the use of IDs is for automatic linking. You can always just link directly to the ID for a given page.
-
The default theme provides "ilink" and "tlink" spans for automatic linking to pages. The links these spans generate contain the title of the destination page in a URL friendly query string (e.g. " /en/2kiw8tvv/?todo-list "). While that's not nearly as pretty as " /todo-list " it does provide a human readable slug.
It's unclear from my research what impact using the slug in a query string has on SEO, but, frankly, I don't really care. My goal is not to make sites that most pleases the search engines. It's to make an app that makes it as easy as possible to create content. Not having to fiddle with URLs supports that goal.
-
All that said, Neopoligen supports setting up specific custom URLs by adding a
-- path
attribute to the-- metadata
section of a file.Personally, I rarely do this. I want to avoid link rot as much as possible and adding a custom URL means having to maintain it. Over the past few decades I've moved my sites enough that I've spent days worth of effort dealing with changing URLs. I've decided to opt out of that. Even for things like my "about" page. Sure, "/about" looks better than "/en/abcd1234/?about", but I doubt that's going to keep most people from clicking the link if they even think about it at all. I'd rather put my effort elsewhere.
-
The "en" in the default URL paths comes from the default language that's defined for each site in its config file. This is done to support internationalization/localization. I'm not planning to add that any time soon but want to make sure the app and, more importantly, the URLs are prepped for it.
Next Steps
That's the basics of how Neopoligen works. There's more advanced stuff like being able to nest sections, embedding JavaScript and CSS, syntax highlighting, and outputting collections of links of pages. I'm in the process of writing up how the other parts work and will post them as they're finished.
I'll be posting about progress on my Mastodon account if you're interested. You can also checkout my personal site (which is built from Neopoligen) at : alanwsmith.com
Footnotes
The default set of templates for Neopoligen provide for automatic linking of footnote numbers in the text and the footnote itself at the bottom of the page.