Why I Made WebWeb

Published: 01/05/2026

I made WebWeb because I got tired of writing the same HTML again and again. I already had a small personal website, but every time I wanted to add a new page or change the structure, I had to go back into raw HTML and repeat myself. It worked, but it felt boring. It also felt like the website was controlling me instead of me controlling the website.

So I did the obvious thing and made my own static website generator in C++. Because apparently instead of just using something normal, I had to make my own tiny language that turns into HTML.

View my website Back to articles

The idea behind WebWeb

WebWeb started as a simple experiment. I wanted to write something like this:

[h1]
Hello from WebWeb

This page was generated from my own format.

and have it turn into normal HTML.

<h1>Hello from WebWeb</h1>
<p>This page was generated from my own format.</p>

That was the whole beginning. A tag starts a block, the text inside gets collected, and then [end] tells the generator to turn that block into HTML. It is not magic. It is just a tiny parser with enough structure to be useful.

WebWeb is not trying to replace HTML. It is just trying to make my own website easier and more fun to maintain.

Why not just use an existing static site generator

I could have used an existing tool. There are many good ones. But I wanted to understand the process myself. I wanted to know what happens between a custom text format and the final HTML file. I also wanted a generator that thinks the way I think.

Most tools are made for everyone. WebWeb is made for me first. That means the syntax can be small, direct, and a bit strange if I want it to be. If I want cards, buttons, includes, themes, and classes, I can add them exactly how I want.

Also, it is just more satisfying. When the page appears in the browser and I know my own C++ program generated it, that feels good.

What WebWeb is in this version

At this point, WebWeb can generate full pages, use reusable components, create navigation bars, add footers, apply themes, copy assets, build multiple pages, and support custom classes. It is still small, but it is already enough to build this website.


This page was made with WebWeb

This entire page was written in WebWeb itself. That means this blog post is not a normal HTML file that I hand wrote. It is a .webweb file that gets compiled back into HTML by the generator.

That is the best test for a tool like this. If WebWeb can explain WebWeb while using WebWeb, then it is doing its job.

Unfortunately, at this date WebWeb is not open source. It will be soon though. I want to clean it up first before I throw it onto GitHub and let people witness the crimes.


The basic parser

The parser is based on a very simple state. It reads the file line by line. If it sees an opening tag, it remembers what kind of block it is inside. If it sees normal text, it stores it. If it sees [end], it converts the stored text into HTML.

while (std::getline(input, rawLine)) {
    std::string line = removeCarriageReturn(rawLine);
    std::string tagLine = trim(line);

    if (currentBlock.type != Type::NONE) {
        if (tagLine == "[end]") {
            addHtml(
                currentBlock.type,
                currentContent,
                currentBlock.className,
                currentDirectory,
                includeDepth
            );

            currentBlock = BlockInfo{};
            currentContent.clear();
        }
        else {
            currentContent += line;
            currentContent += '\n';
        }

        continue;
    }

    BlockInfo opening = parseOpeningTag(tagLine);

    if (opening.type != Type::NONE) {
        currentBlock = opening;
        currentContent.clear();
    }
}

This is the part that made the whole thing click for me. The generator does not need to understand everything at once. It only needs to understand what block it is currently reading.


Opening tags and classes

Later I wanted to write things like [para warning] or [section hero]. So the parser had to understand that a tag can have a name and optional classes.

struct BlockInfo {
    Type type = Type::NONE;
    std::string className;
};

So this:

[para warning]
This is important.

turns into this:

<p class="warning">This is important.</p>

That one change made the language feel much more useful. Now I could have normal paragraphs, warning paragraphs, hero sections, project cards, and anything else that only needs a class.


Variables

Variables were added because I did not want to type the same things everywhere. My name, the site name, and the base path are used across pages, so WebWeb supports a [var] block.

[var]
siteName = Ataerk Yıldırım
author = Ataerk
base = ../

Then I can write:

[para]
Made with WebWeb by $author.

and it becomes normal text with the value inserted. I also added the longer syntax for cases where the variable touches other text.

${base}resume.html

That matters because $baseresume would be read as one variable name. The braces make it clear where the variable ends.


Includes

Includes are one of the most useful features. I did not want to paste the same navigation bar and footer into every page. So now a page can include reusable WebWeb files.

[include]
../components/site_style.webweb
../components/nav.webweb

The included file is parsed as if it was part of the page. That means variables still work, navigation works, and shared styles work. This is what makes WebWeb feel like a real static website generator instead of just a converter.


Themes and styles

At first, I added raw CSS. Then I realised that was not really WebWeb anymore. It was just CSS inside a different file. So I changed it to custom style commands.

[style]
background = #121416
text = #E6E1D7
h1.color = #7DD3C7
h2.color = #D8B56D
card.radius = 16px

The generator translates those into CSS. This means I can keep the page styling simple and readable from WebWeb itself.

There are also themes. A theme is basically a preset style. I can use a dark theme, a light theme, a terminal theme, or a paper theme, then override the bits I want.

[theme]
dark

Cards and buttons

Cards were added because my website needs project previews and article previews. Writing the full HTML for a card every time would get annoying very quickly.

WebWeb

A small static website generator written in C++ that turns .webweb files into HTML.

Language: C++

Status: Private for now

Coming soon

The card above is generated from this kind of structure:

[card project-card]
title = WebWeb
text = A small static website generator written in C++.
language = C++
status = Private for now
link = #
linkText = Coming soon

Buttons work in the same way. They are just links with a button class, but WebWeb makes them nicer to write.

Primary button Secondary button

Navigation and footer

The navigation bar is just a WebWeb block too. It is simple key value text that turns into links.

[nav main-nav]
HOME = ${base}index.html
RESUME = ${base}resume.html
GAMES = ${base}games.html
TECH = ${base}tech.html

The footer works the same way. It is small, but it means every page can end consistently.

[footer subtle]
Made with WebWeb by $author.

Sections

Sections let me group content. This is useful for hero areas, article intros, and layout blocks.

[section hero]
[h1]
My title

My intro text.

This gives me a real HTML section with optional classes, while still keeping the WebWeb file readable.


Images and copied assets

WebWeb also supports images. The old syntax was simple, but I later added key value image options so I could control size, radius, display, and other useful bits.

WebWeb preview image

The image above uses the asset folder system. When the generator builds the site, it can copy static files from the input folder into the output folder. That means images, game files, PDFs, and other assets can survive the build.


Multiple page generation

The generator can build one file, but it can also build the whole website.

generator file index.webweb
generator build

The build command searches for .webweb files, skips component files, generates HTML pages, and copies static folders. This was the point where WebWeb stopped being a tiny experiment and started becoming an actual website tool.

  1. Write the page in WebWeb
  2. Include shared components
  3. Compile the page into HTML
  4. Copy the assets
  5. Open the result in the browser

What features this page uses

This page is basically a showcase of the current WebWeb version. It uses variables, output names, metadata, includes, themes, custom style rules, classes, sections, headings, paragraphs, quotes, code blocks, unordered lists, ordered lists, images, cards, navigation, footer, buttons, links, horizontal rules, asset paths, and it is intended to be generated as part of a multiple page website.


Why I like this project

I like WebWeb because it is small enough for me to understand completely, but useful enough to actually replace parts of my website workflow. It is not some massive framework. It is just my own little tool that does exactly what I need.

It also gave me a better understanding of parsing, file generation, project structure, and how static websites are built. The best part is that every time I want a new feature, I can just add it. If I want blog indexes later, I can add that. If I want RSS generation, I can add that. If I want better inline formatting, I can add that too.

That is the main reason I made WebWeb. I wanted my website to feel like mine all the way down to the tool that builds it.

It is private for now. It will be open source soon, once I clean it up and make the code less cursed.


My GitHub Back home