htmw

HTMW > Change Log

Change Logs

HTMW vT.6

Added HTTP include, global include path, nested `no` directive support, `$#` template body sequence, etc.

Jan. 22, 2026

While working on Blurple (an internal high-performance HTMW + PHP framework, released in December 2025), I added several new useful features.

First of all, HTTP Include: you can now include files over HTTP.

<@include_once <https://i.example.com/lib/file.htmw>>

To enable HTTP includes, you must use the -N flag. This feature is disabled by default.

htmw index -N

Note: if the -N flag is set, some features will be disabled by default for safety reasons. To re-enable them, use the --unsafe flag.

htmw index -N --unsafe

WARNING! Use the --unsafe flag only if you fully trust all included HTTP sources. This feature can potentially be exploited to inject malicious templates that may lead to RCE.

You can now define global include paths using the -I<path> flag.

<@include_once <file.htmw>>

To compile it:

htmw index -I./include

The <@no> directive (used to prevent content from being rendered) now supports nesting. As a result, the <@no> and <@comment> directives now behave differently. Previously, <@no> did not support nesting: rendering would resume at the first </@no>, regardless of how many <@no> directives were nested inside.

<@no>
    <@no>
        [not rendered]
    </@no>
    [still not rendered]
</@no>

In previous versions, there was no way to place text immediately after a value inside a template body, because the compiler would treat that text as part of the variable name. To solve this, I introduced the $# sequence (also called the void sequence), which renders no characters and allows values and text to be separated correctly.

Before:

<@template time(seconds="3.14")>
<p>
    time: $seconds s
</p>
</@template>
time: 3.14 s

Now:

<@template time(seconds="3.14")>
<p>
    time: $seconds$#s
</p>
</@template>
time: 3.14s

Another small syntax improvement: templates without parameters no longer require parentheses ().

<@template test>
<p>
    test
</p>
</@template>

Plus a few bug fixes.


WMGR v0.1.0

The new project manager for HTMW apps

Aug. 26, 2025

I'm excited to announce that over the past 3-4 days I've been working on a side project designed to simplify Web development with HTMW!

To create a new project, run wmgr new <name>. The program will generate a folder with the given name and the following file structure:

<project folder>
┣━╸src
  ┣━╸config.htmw
  ┣━╸header.htmw
  ┣━╸index.htmw
  ┗━╸style.css
┣━╸out
┣━╸assets
┣━╸dependencies
┣━╸build.sh or build.bat
┗━╸make.txt

Each folder serves a specific purpose:

  • src — source files (HTMW, CSS, JS, JSON, XML, etc.)
  • assets — media such as images, videos, fonts...
  • dependencies — external HTMW libraries
  • out — read-only folder where the compiled project is exported

The out folder can be zipped and uploaded directly to your web server if your project is a complete website.

Finally, the make.txt file stores project information. By running wmgr make inside your project folder, WMGR will generate a build script (build.sh or build.bat, depending on your platform).


HTMW vT.5

Enhanced arguments and native tag notation added

Aug. 15, 2025

This release introduces two big improvements: enhanced argument handling and native tag notation.

You can now pass strings with escape sequences and evaluated, multi-type Lua expressions as arguments.

New argument notations (only for HTMW-defined tags):

<test x=`hello\nworld!`>
<test x={2 + 2}>

In the first example, the value is wrapped with backticks (`) and supports escape sequences (e.g. \n → newline). In the second, the argument is evaluated as a Lua expression. The result is a number (4), but you can also pass arrays, tables, and any Lua type.

Another new feature is the native tag notation. By prefixing a tag name with # (e.g. <#div>), the compiler will force the use of the native HTML element, even if a template with the same name exists.

Example:

<@template div() {}>|this is a template|</@template>

<div>hello world!</div> <!-- template -->
<#div>hello world!</#div> <!-- native html -->
Output:
|this is a template|
<div>hello world!</div>


HTMW vT.4

Added no text and no inner

Aug. 9, 2025

Previously, if you created an HTMW library file with multiple template definitions, then included it in a webpage file and compiled, the output would contain unnecessary whitespace and new lines (often at the top).

This happened because we typically add new lines between template directives. A common workaround was to remove all spacing between definitions, but that made the code less readable.

Starting from version vT.4, we can keep our code readable while fixing the spacing issue using the new <@ntxt> directive. This feature also allows writing text or notes without any special notation and without rendering them, while keeping all directives functional.

Usage example:

<@ntxt>

    junk text or notes
    <@template test0() {}>test0</@template>

    junk text or notes
    <@template test1() {}>test1</@template>

    junk text or notes
    junk text or notes
    <@template test2() {}>test2</@template>

    junk text or notes

</@ntxt>

rendered text
<test0/>
<test1/>
<test2/>
Output:
rendered text
test0
test1
test2

Another new feature is the ability to tell the compiler that a widget has no inner elements without using the "slash at the end" notation, by adding the ninner keyword.

Usage example:

<@template ninner test() {}>works!</@template>

<test/> <!-- classic notation -->

<test> <!-- no need for slashes; the compiler already knows there's no inner element -->

I also fixed a bug that caused symbols inside default template argument strings to have unexpected behaviors


HTMW vT.3

Added support for nullable and default template arguments

Aug. 7, 2025

Previously, all templates and widgets required explicitly specifying input arguments every single time. This added unnecessary complexity and forced developers to provide parameters that were neither important nor meant to be required.

Starting from version vT.3, arguments can be nullable and have a default value. This means developers no longer need to specify them every time, and no error will be thrown if they're omitted.

To mark an argument as nullable in the template definition directive, add a ? next to the argument name.
To assign a default value to a template argument, place an = followed by the value string after the argument name (after the ? if it's marked as nullable).

Usage example

<!-- `x` is nullable with a default value, `y` is nullable and `z` has a default value -->
<@template test(x?="29", y?, z="default") {}>
<p>
    <b>x:</b> $x<br>
    <b>y:</b> $y<br>
    <b>z:</b> $z
</p>
</@template>

<test/>
<!-- x: nil, y: nil, z: default -->

<test x z/>
<!-- x: 29, y: nil, z: default -->

<test x="32" y z="qwerty"/>
<!-- x: 32, y: (empty string), z: qwerty -->


HTMW vT.2

Test version 0.2

Jul. 30, 2025

Added local and global includes with <@include ...> and <@include_once ...> directives


HTMW vT.1

Test version 0.1

Jul. 25, 2025

You can create and use templates.