<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="atom.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://balaurengine.org/blog/</id>
    <title>Balaur Blog</title>
    <updated>2026-09-26T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://balaurengine.org/blog/"/>
    <subtitle>Balaur Blog</subtitle>
    <entry>
        <title type="html"><![CDATA[Themes that follow the system]]></title>
        <id>https://balaurengine.org/blog/themes-that-follow-the-system/</id>
        <link href="https://balaurengine.org/blog/themes-that-follow-the-system/"/>
        <updated>2026-09-26T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Every editor theme is a dark and a light half, the editor wears the one the system is in, and ten popular schemes ship with it.]]></summary>
        <content type="html"><![CDATA[<p>An editor theme is a pair of a dark half and a light half. The editor wears the half the system is in, and switches when the system does.</p>
<!-- -->
<p><img decoding="async" loading="lazy" alt="Four halves in the Script workspace: balaur dark, Catppuccin Latte, Gruvbox dark and Rosé Pine Dawn" src="https://balaurengine.org/assets/images/theme_pairs-f135e796c5c230cad3be2af8a496df92.webp" width="1920" height="1080" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="pairs-and-the-mode">Pairs and the mode<a href="https://balaurengine.org/blog/themes-that-follow-the-system/#pairs-and-the-mode" class="hash-link" aria-label="Direct link to Pairs and the mode" title="Direct link to Pairs and the mode" translate="no">​</a></h2>
<ul>
<li class="">A theme is a folder holding <code>dark.toml</code> and <code>light.toml</code>. <code>editor/appearance/theme</code> names the pair, <code>balaur</code> by default.</li>
<li class=""><code>editor/appearance/mode</code> is <code>system</code>, <code>dark</code> or <code>light</code>, and <code>system</code> by default. The ☾ button writes <code>dark</code> or <code>light</code>.</li>
<li class="">Duplicate writes <code>themes/balaur-custom/</code> in the editor's data folder, holding the half you wear. A half the folder lacks comes from its base.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="bundled-schemes">Bundled schemes<a href="https://balaurengine.org/blog/themes-that-follow-the-system/#bundled-schemes" class="hash-link" aria-label="Direct link to Bundled schemes" title="Direct link to Bundled schemes" translate="no">​</a></h2>
<ul>
<li class="">Solarized, Gruvbox, Catppuccin, Tokyo Night, Atom One, Rosé Pine, GitHub, Everforest, Dracula and Kanagawa ship with the editor, both halves each. The largest half is 621 bytes.</li>
<li class="">A half states the scheme's surfaces, text, accents and syntax colours, read off the scheme's own palette file. Its header names the licence and the source.</li>
<li class="">Every half reads at WCAG AA. A colour under 4.5:1 keeps its hue and moves in lightness, with the scheme's value beside it: Catppuccin Latte's keyword went from <code>#8839ef</code> to <code>#771dda</code>.</li>
<li class="">Nord has no light half, so it is not bundled.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="dark-mode-in-a-game">Dark mode in a game<a href="https://balaurengine.org/blog/themes-that-follow-the-system/#dark-mode-in-a-game" class="hash-link" aria-label="Direct link to Dark mode in a game" title="Direct link to Dark mode in a game" translate="no">​</a></h2>
<ul>
<li class=""><code>engine::dark_mode()</code> and <code>on_dark_mode_changed(bool)</code> answer on Windows, Linux, iOS and Android, as on macOS and in a browser.</li>
<li class="">Linux asks the desktop portal's <code>color-scheme</code> through the system's <code>libdbus</code>, loaded on first use and asked every two seconds.</li>
</ul>]]></content>
        <author>
            <name>Dragos</name>
            <uri>https://github.com/Ughuuu</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Drawing in the draw order]]></title>
        <id>https://balaurengine.org/blog/drawing-in-the-draw-order/</id>
        <link href="https://balaurengine.org/blog/drawing-in-the-draw-order/"/>
        <updated>2026-09-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A script's 2D drawing takes a z_index, so a shape sits among the sprites of that index instead of over the whole scene, and a picture takes a region.]]></summary>
        <content type="html"><![CDATA[<p>The <code>render.draw_*_2d</code> verbs take a trailing options table. Its <code>z_index</code> puts a shape among the nodes of that index, over them and under the next.</p>
<!-- -->
<p><img decoding="async" loading="lazy" alt="A sea at index 0, a ship at index 2, and a green circle and a white line drawn at index 1 between them; a red circle with no index draws over everything" src="data:image/webp;base64,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" width="1000" height="500" class="img_ev3q"></p>
<ul>
<li class=""><code>#{ z_index: 1 }</code> on <code>draw_circle_2d</code>, <code>draw_rect_2d</code>, <code>draw_arc_2d</code>, <code>draw_polygon_2d</code>, <code>draw_polyline_2d</code>, <code>draw_texture_2d</code>, <code>draw_line_2d</code> and <code>draw_text_2d</code> places the shape at that index. Without one it draws over the scene.</li>
<li class="">A stroke placed at an index is a mesh, so its width in pixels holds at the camera's zoom.</li>
<li class=""><code>draw_texture_2d</code> takes <code>region_origin</code> and <code>region_size</code> in the image's pixels and draws that part of it, the keys a sprite uses for its region.</li>
<li class="">A misspelt key is an error naming the keys a verb takes.</li>
<li class=""><code>balaur import</code> draws a Godot node's <code>_draw</code> at the node's <code>global_z_index</code>, and a <code>draw_texture_rect_region</code> through the region.</li>
</ul>
<div class="language-rune codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#403f53;--prism-background-color:#FBFBFB"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rune codeBlock_bY9V thin-scrollbar" style="color:#403f53;background-color:#FBFBFB"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#403f53"><span class="token namespace" style="color:rgb(12, 150, 155)">render</span><span class="token namespace punctuation" style="color:rgb(153, 76, 195)">::</span><span class="token function" style="color:rgb(153, 76, 195);font-style:italic">draw_circle_2d</span><span class="token punctuation" style="color:rgb(153, 76, 195)">(</span><span class="token operator" style="color:rgb(12, 150, 155)">-</span><span class="token number" style="color:rgb(170, 9, 130)">1.5</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(170, 9, 130)">0.0</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(170, 9, 130)">1.4</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">[</span><span class="token number" style="color:rgb(170, 9, 130)">0.2</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(170, 9, 130)">0.9</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(170, 9, 130)">0.4</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(170, 9, 130)">1.0</span><span class="token punctuation" style="color:rgb(153, 76, 195)">]</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">#{</span><span class="token plain"> z_index</span><span class="token punctuation" style="color:rgb(153, 76, 195)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(170, 9, 130)">1</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">}</span><span class="token punctuation" style="color:rgb(153, 76, 195)">)</span><span class="token punctuation" style="color:rgb(153, 76, 195)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#403f53"><span class="token plain"></span><span class="token namespace" style="color:rgb(12, 150, 155)">render</span><span class="token namespace punctuation" style="color:rgb(153, 76, 195)">::</span><span class="token function" style="color:rgb(153, 76, 195);font-style:italic">draw_texture_2d</span><span class="token punctuation" style="color:rgb(153, 76, 195)">(</span><span class="token string" style="color:rgb(72, 118, 214)">"art/blocks.png"</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> </span><span class="token operator" style="color:rgb(12, 150, 155)">-</span><span class="token number" style="color:rgb(170, 9, 130)">5.0</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(170, 9, 130)">2.2</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(170, 9, 130)">1.5</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(170, 9, 130)">1.5</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">(</span><span class="token punctuation" style="color:rgb(153, 76, 195)">)</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#403f53"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(153, 76, 195)">#{</span><span class="token plain"> region_origin</span><span class="token punctuation" style="color:rgb(153, 76, 195)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">[</span><span class="token number" style="color:rgb(170, 9, 130)">0</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(170, 9, 130)">0</span><span class="token punctuation" style="color:rgb(153, 76, 195)">]</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> region_size</span><span class="token punctuation" style="color:rgb(153, 76, 195)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">[</span><span class="token number" style="color:rgb(170, 9, 130)">16</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(170, 9, 130)">16</span><span class="token punctuation" style="color:rgb(153, 76, 195)">]</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">}</span><span class="token punctuation" style="color:rgb(153, 76, 195)">)</span><span class="token punctuation" style="color:rgb(153, 76, 195)">;</span><br></div></code></pre></div></div>]]></content>
        <author>
            <name>Dragos</name>
            <uri>https://github.com/Ughuuu</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Editor themes]]></title>
        <id>https://balaurengine.org/blog/editor-themes/</id>
        <link href="https://balaurengine.org/blog/editor-themes/"/>
        <updated>2026-09-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Editor themes built from six colours, a window that edits every token and role while the editor wears it, and a contrast check on each.]]></summary>
        <content type="html"><![CDATA[<p>The editor's look is a theme file, and the Theme window edits one while the editor wears it. A theme states a few source colours and every other token is derived from them.</p>
<!-- -->
<p><img decoding="async" loading="lazy" alt="The Theme window on its Controls page, each control role drawn as itself beside its edit chip, with the page counts down the side" src="https://balaurengine.org/assets/images/editor_themes-212c6bbe8dfabf1c3ec5db17c14136f2.webp" width="1190" height="800" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="sources-and-tokens">Sources and tokens<a href="https://balaurengine.org/blog/editor-themes/#sources-and-tokens" class="hash-link" aria-label="Direct link to Sources and tokens" title="Direct link to Sources and tokens" translate="no">​</a></h2>
<ul>
<li class="">The dark theme states six colours: <code>background</code>, <code>foreground</code>, <code>primary</code>, <code>secondary</code>, <code>warning</code> and <code>danger</code>. The other 55 of its 61 tokens are derived.</li>
<li class="">A token is <code>&lt;group&gt;_&lt;role&gt;</code>: <code>bg_panel</code>, <code>text_muted</code>, <code>primary_fill</code>, <code>text_on_primary</code>. Stating one overrides its rule.</li>
<li class="">Sizes work the same way. <code>font_size = 12</code> and <code>control_height = 24</code> give the editor's 11, 14 and 17 px text and its 20, 30 and 33 px controls.</li>
<li class="">The 106 roles live in one <code>roles.toml</code> both bundled themes share, so the dark and light files hold colours only.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="your-own-themes">Your own themes<a href="https://balaurengine.org/blog/editor-themes/#your-own-themes" class="hash-link" aria-label="Direct link to Your own themes" title="Direct link to Your own themes" translate="no">​</a></h2>
<ul>
<li class="">Duplicate writes <code>themes/dark-custom.toml</code> in the editor's data folder, holding <code>base = "dark"</code> and nothing else. The copy is worn at once.</li>
<li class="">Save writes only the keys that differ from the base, so a theme with its own primary colour is one line.</li>
<li class=""><code>editor/appearance/theme</code> lists <code>dark</code>, <code>light</code> and every file in that folder. The ☾ button writes the same setting.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-window">The window<a href="https://balaurengine.org/blog/editor-themes/#the-window" class="hash-link" aria-label="Direct link to The window" title="Direct link to The window" translate="no">​</a></h2>
<video width="1920" height="1080" loop="" muted="" playsinline="" controls="" preload="none" poster="/img/poster/theme_editor.webp" aria-label="The Theme window opened from the palette: the dark theme duplicated, its primary colour turned from blue to amber while every token derived from it follows, a chip's padding dragged from 8 to 16, and the copy saved" style="width:100%;height:auto;display:block;margin:1rem 0"><source src="/video/theme_editor.webm" type="video/webm"><source src="/video/theme_editor.mp4" type="video/mp4"></video>
<ul>
<li class="">It opens from the menu, from Settings, or from the palette.</li>
<li class="">The side lists Colors, Sizes, Text, Controls, Boxes, Layout, Kinds and Problems. A derived token reads quieter than one the theme states.</li>
<li class="">Each role is drawn as itself. Edit lists its keys: a swatch and a token for a colour, a number or a size's name for a size.</li>
<li class="">A chip row picks the role or its <code>hover</code>, <code>active</code>, <code>focus</code>, <code>disabled</code>, <code>checked</code> or <code>touch</code> table, and "add a key…" states one the base leaves out.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="contrast">Contrast<a href="https://balaurengine.org/blog/editor-themes/#contrast" class="hash-link" aria-label="Direct link to Contrast" title="Direct link to Contrast" translate="no">​</a></h2>
<ul>
<li class="">Every role's text is measured on its fill with the WCAG 2 ratio. Problems lists each pair under 4.5:1, or 3:1 for large text. Both bundled themes have none.</li>
<li class=""><code>ui::contrast(a, b)</code>, <code>ui::contrast_pairs(theme, ground)</code> and <code>ui::complete_theme(theme)</code> give a script the same numbers and tokens.</li>
</ul>
<div class="language-toml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#403f53;--prism-background-color:#FBFBFB"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-toml codeBlock_bY9V thin-scrollbar" style="color:#403f53;background-color:#FBFBFB"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#403f53"><span class="token comment" style="color:rgb(152, 159, 177);font-style:italic"># themes/dusk.toml</span><span class="token plain"></span><br></div><div class="token-line" style="color:#403f53"><span class="token plain"></span><span class="token key property" style="color:rgb(12, 150, 155)">type</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(72, 118, 214)">"widget_theme"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#403f53"><span class="token plain"></span><span class="token key property" style="color:rgb(12, 150, 155)">base</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(72, 118, 214)">"dark"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#403f53"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#403f53"><span class="token plain"></span><span class="token punctuation" style="color:rgb(153, 76, 195)">[</span><span class="token table class-name" style="color:rgb(17, 17, 17)">colors</span><span class="token punctuation" style="color:rgb(153, 76, 195)">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#403f53"><span class="token plain"></span><span class="token key property" style="color:rgb(12, 150, 155)">primary</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(72, 118, 214)">"#c8843e"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#403f53"><span class="token plain"></span><span class="token key property" style="color:rgb(12, 150, 155)">background</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(72, 118, 214)">"#221e28"</span><br></div></code></pre></div></div>]]></content>
        <author>
            <name>Dragos</name>
            <uri>https://github.com/Ughuuu</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Soft bodies]]></title>
        <id>https://balaurengine.org/blog/soft-bodies/</id>
        <link href="https://balaurengine.org/blog/soft-bodies/"/>
        <updated>2026-09-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Balaur devlog: softbody2d and softbody3d on Rapier, with cloth, rope, tearing, and a Physics panel that turns a mesh into a collider or a soft body.]]></summary>
        <content type="html"><![CDATA[<p><code>softbody2d</code> and <code>softbody3d</code> are bodies of particles held together by springs and elastic cells. Rapier simulates them on the fixed step, and the node is drawn from what it produced.</p>
<!-- -->
<p><img decoding="async" loading="lazy" alt="examples/cloth: a sheet draped over a block, and a ball tearing through a sheet pinned all round" src="https://balaurengine.org/assets/images/soft_bodies_cloth-b8d94af02306029a81ff04b93491f2fe.webp" width="1600" height="1000" class="img_ev3q"></p>
<ul>
<li class=""><code>kind</code> lays the particles out: <code>box</code>, <code>sphere</code>, <code>cloth</code>, <code>cloth_tube</code> or <code>rope</code> in 3D, and <code>grid</code>, <code>circle</code> or <code>rope</code> in 2D. A <code>mesh</code> can be filled with cells or kept as a surface.</li>
<li class=""><code>pinned_particles</code> names the particles held in place. Past <code>tear_strain</code> or <code>tear_force</code> an edge breaks, and the node's <code>on_tear</code> runs.</li>
<li class="">The material rows set a spring per constraint family, the cell model and plasticity. <code>solver = "fem"</code> switches to Rapier's implicit step.</li>
<li class="">A soft body is in the snapshot, and the digest hashes every particle's velocity.</li>
<li class="">The Physics panel lists every physics component on the selection. One click turns a mesh into a hull, convex pieces, voxels or a soft body.</li>
</ul>
<p><img decoding="async" loading="lazy" alt="The Physics panel on the disk of examples/jelly: the components it can add, and the soft body&amp;#39;s rows by group" src="https://balaurengine.org/assets/images/soft_bodies_panel-df7593579475761b8d2d9fc24b342bf6.webp" width="1600" height="900" class="img_ev3q"></p>
<p><img decoding="async" loading="lazy" alt="examples/jelly: a grid block over a peg, a disk under a box, a star, an arch and a rope bridge" src="https://balaurengine.org/assets/images/soft_bodies_jelly-bf6cd23e8a256ac87e0d266af21ba92b.webp" width="1600" height="900" class="img_ev3q"></p>
<div class="language-toml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#403f53;--prism-background-color:#FBFBFB"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-toml codeBlock_bY9V thin-scrollbar" style="color:#403f53;background-color:#FBFBFB"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#403f53"><span class="token punctuation" style="color:rgb(153, 76, 195)">[</span><span class="token table class-name" style="color:rgb(17, 17, 17)">nodes.softbody2d</span><span class="token punctuation" style="color:rgb(153, 76, 195)">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#403f53"><span class="token plain"></span><span class="token key property" style="color:rgb(12, 150, 155)">kind</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(72, 118, 214)">"circle"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#403f53"><span class="token plain"></span><span class="token key property" style="color:rgb(12, 150, 155)">radius</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(170, 9, 130)">1.0</span><span class="token plain"></span><br></div><div class="token-line" style="color:#403f53"><span class="token plain"></span><span class="token key property" style="color:rgb(12, 150, 155)">particle_count</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(170, 9, 130)">32</span><span class="token plain"></span><br></div><div class="token-line" style="color:#403f53"><span class="token plain"></span><span class="token key property" style="color:rgb(12, 150, 155)">color</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">[</span><span class="token number" style="color:rgb(170, 9, 130)">0.29</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(170, 9, 130)">0.56</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(170, 9, 130)">0.82</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(170, 9, 130)">1.0</span><span class="token punctuation" style="color:rgb(153, 76, 195)">]</span><br></div></code></pre></div></div>]]></content>
        <author>
            <name>Dragos</name>
            <uri>https://github.com/Ughuuu</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Batching]]></title>
        <id>https://balaurengine.org/blog/batching/</id>
        <link href="https://balaurengine.org/blog/batching/"/>
        <updated>2026-09-21T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Sprites, shapes and meshes that draw alike go to the GPU as one call with an instance each.]]></summary>
        <content type="html"><![CDATA[<p>Nodes that draw alike now go to the GPU as one call, with a position, a size and a tint per instance. Nothing turns it on.</p>
<!-- -->
<p><img decoding="async" loading="lazy" alt="Sixteen sprites cut from one sheet, turned, scaled, tinted and flipped apart, drawn in a single call" src="https://balaurengine.org/assets/images/batching_sprite-a758c0da4439f41f733fa0f92cc91fbe.webp" width="1600" height="1000" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-it-costs-offscreen-at-1600x1000">What it costs, offscreen at 1600x1000<a href="https://balaurengine.org/blog/batching/#what-it-costs-offscreen-at-1600x1000" class="hash-link" aria-label="Direct link to What it costs, offscreen at 1600x1000" title="Direct link to What it costs, offscreen at 1600x1000" translate="no">​</a></h2>
<table><thead><tr><th>case</th><th style="text-align:right">render CPU before</th><th style="text-align:right">after</th><th style="text-align:right">GPU before</th><th style="text-align:right">after</th></tr></thead><tbody><tr><td>5000 circles</td><td style="text-align:right">22.7 ms</td><td style="text-align:right">0.41 ms</td><td style="text-align:right">1.56 ms</td><td style="text-align:right">1.02 ms</td></tr><tr><td>2000 cuboids</td><td style="text-align:right">30.7 ms</td><td style="text-align:right">0.77 ms</td><td style="text-align:right">3.67 ms</td><td style="text-align:right">4.03 ms</td></tr><tr><td>2000 balls</td><td style="text-align:right">31.9 ms</td><td style="text-align:right">1.49 ms</td><td style="text-align:right">13.5 ms</td><td style="text-align:right">5.50 ms</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-joins-a-call">What joins a call<a href="https://balaurengine.org/blog/batching/#what-joins-a-call" class="hash-link" aria-label="Direct link to What joins a call" title="Direct link to What joins a call" translate="no">​</a></h2>
<table><thead><tr><th>kind</th><th>grouped by</th></tr></thead><tbody><tr><td>sprites</td><td>image, material</td></tr><tr><td>shapes</td><td>primitive and its size, material</td></tr><tr><td>meshes</td><td>geometry or <code>mesh</code> asset, texture, material, shadows, light layers</td></tr></tbody></table>
<ul>
<li class="">A sheet frame joins the run. The frame is a rectangle on the instance, where it used to be a private copy of the built-in quad with rewritten coordinates.</li>
<li class="">In two dimensions a run is cut along the draw order, so what covers what does not change. In three it is not, because geometry is depth-tested.</li>
</ul>
<p><img decoding="async" loading="lazy" alt="Eighteen cubes turned, scaled and tinted apart, lit and casting shadows, drawn in a single call" src="https://balaurengine.org/assets/images/batching_mesh-3b704771446475d8a3bacaeccd13c3c3.webp" width="1600" height="1000" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-keeps-a-draw-of-its-own">What keeps a draw of its own<a href="https://balaurengine.org/blog/batching/#what-keeps-a-draw-of-its-own" class="hash-link" aria-label="Direct link to What keeps a draw of its own" title="Direct link to What keeps a draw of its own" translate="no">​</a></h2>
<table><thead><tr><th>kind</th><th>why</th></tr></thead><tbody><tr><td>polygon, polyline</td><td>geometry of its own</td></tr><tr><td>own material</td><td>its own pipeline</td></tr><tr><td>skinned, morphed</td><td>deformed on its node</td></tr><tr><td><code>cloner</code>, levels of detail</td><td>already instanced, or swaps geometry</td></tr><tr><td>uneven scale</td><td>the instance's matrix goes through its normals</td></tr></tbody></table>]]></content>
        <author>
            <name>Dragos</name>
            <uri>https://github.com/Ughuuu</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Custom types for the inspector]]></title>
        <id>https://balaurengine.org/blog/custom-types-for-the-inspector/</id>
        <link href="https://balaurengine.org/blog/custom-types-for-the-inspector/"/>
        <updated>2026-09-21T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A list, a map and a record a component or a script exports, drawn a row an entry in the inspector.]]></summary>
        <content type="html"><![CDATA[<p>A property can now hold other properties. A <code>list</code> is ordered and holds one type, a <code>map</code> is keyed, and a <code>record</code> is a fixed set of named fields. The inspector draws a row per entry, each with the editor its type already had.</p>
<!-- -->
<p><img decoding="async" loading="lazy" alt="The inspector drawing a map keyed by numbers, a Wave class of two fields and a list of three numbers, each entry on its own row" src="data:image/webp;base64,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" width="380" height="400" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="declaring-one">Declaring one<a href="https://balaurengine.org/blog/custom-types-for-the-inspector/#declaring-one" class="hash-link" aria-label="Direct link to Declaring one" title="Direct link to Declaring one" translate="no">​</a></h2>
<ul>
<li class=""><code>of</code> is the spec a <code>list</code>'s entries and a <code>map</code>'s values take, and <code>fields</code> is one spec per <code>record</code> field. Each is a whole property spec, so <code>min</code>, <code>options</code>, <code>asset</code> and <code>component</code> work at any depth.</li>
<li class="">A nested spec may leave its <code>default</code> out; the type's zero is written in when the component registers, and a new entry starts there.</li>
<li class="">A <code>map</code>'s <code>key</code> is <code>"string"</code> or <code>"int"</code>. A number key is written <code>"7"</code> in the file and reaches the script as the number.</li>
<li class=""><code>strings</code> and <code>nodes</code> are gone. They were <code>list of string</code> and <code>list of node</code>, and fifteen schema lines were rewritten.</li>
</ul>
<div class="language-toml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#403f53;--prism-background-color:#FBFBFB"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-toml codeBlock_bY9V thin-scrollbar" style="color:#403f53;background-color:#FBFBFB"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#403f53"><span class="token key property" style="color:rgb(12, 150, 155)">waves</span><span class="token plain">  </span><span class="token punctuation" style="color:rgb(153, 76, 195)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">{</span><span class="token plain"> </span><span class="token key property" style="color:rgb(12, 150, 155)">type</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(72, 118, 214)">"list"</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> </span><span class="token key property" style="color:rgb(12, 150, 155)">of</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">{</span><span class="token plain"> </span><span class="token key property" style="color:rgb(12, 150, 155)">type</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(72, 118, 214)">"int"</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> </span><span class="token key property" style="color:rgb(12, 150, 155)">min</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(170, 9, 130)">0</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">}</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> </span><span class="token key property" style="color:rgb(12, 150, 155)">default</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">[</span><span class="token punctuation" style="color:rgb(153, 76, 195)">]</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#403f53"><span class="token plain"></span><span class="token key property" style="color:rgb(12, 150, 155)">spawns</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">{</span><span class="token plain"> </span><span class="token key property" style="color:rgb(12, 150, 155)">type</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(72, 118, 214)">"map"</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> </span><span class="token key property" style="color:rgb(12, 150, 155)">key</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(72, 118, 214)">"int"</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> </span><span class="token key property" style="color:rgb(12, 150, 155)">of</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">{</span><span class="token plain"> </span><span class="token key property" style="color:rgb(12, 150, 155)">type</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(72, 118, 214)">"node"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">}</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> </span><span class="token key property" style="color:rgb(12, 150, 155)">default</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">{</span><span class="token punctuation" style="color:rgb(153, 76, 195)">}</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">}</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="exporting-one-from-a-script">Exporting one from a script<a href="https://balaurengine.org/blog/custom-types-for-the-inspector/#exporting-one-from-a-script" class="hash-link" aria-label="Direct link to Exporting one from a script" title="Direct link to Exporting one from a script" translate="no">​</a></h2>
<ul>
<li class="">A bare export says what it is: <code>waves: [2, 4, 8]</code> is a list of whole numbers, and an object is a record whose fields keep their own types.</li>
<li class="">A list holds one type, and an entry of another names itself in the error.</li>
<li class="">A node path is resolved wherever the spec puts one, so a list of nodes arrives as the nodes, and a record's node field does too.</li>
<li class="">A <code>struct</code> the script declares is exported as itself: the scene writes its fields, and <code>init</code> is handed that class, methods and all. The inspector row says which class it is.</li>
</ul>
<div class="language-rune codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#403f53;--prism-background-color:#FBFBFB"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rune codeBlock_bY9V thin-scrollbar" style="color:#403f53;background-color:#FBFBFB"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#403f53"><span class="token keyword" style="color:rgb(12, 150, 155)">struct</span><span class="token plain"> </span><span class="token type-definition class-name" style="color:rgb(17, 17, 17)">Wave</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">{</span><span class="token plain"> hp</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> name </span><span class="token punctuation" style="color:rgb(153, 76, 195)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#403f53"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#403f53"><span class="token plain"></span><span class="token keyword" style="color:rgb(12, 150, 155)">pub</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(12, 150, 155)">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:rgb(153, 76, 195);font-style:italic">exports</span><span class="token punctuation" style="color:rgb(153, 76, 195)">(</span><span class="token punctuation" style="color:rgb(153, 76, 195)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#403f53"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(153, 76, 195)">#{</span><span class="token plain"> waves</span><span class="token punctuation" style="color:rgb(153, 76, 195)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">[</span><span class="token number" style="color:rgb(170, 9, 130)">2</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(170, 9, 130)">4</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(170, 9, 130)">8</span><span class="token punctuation" style="color:rgb(153, 76, 195)">]</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> wave</span><span class="token punctuation" style="color:rgb(153, 76, 195)">:</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(17, 17, 17)">Wave</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">{</span><span class="token plain"> hp</span><span class="token punctuation" style="color:rgb(153, 76, 195)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(170, 9, 130)">3</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> name</span><span class="token punctuation" style="color:rgb(153, 76, 195)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(72, 118, 214)">"grunt"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">}</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#403f53"><span class="token plain"></span><span class="token punctuation" style="color:rgb(153, 76, 195)">}</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="docs">Docs<a href="https://balaurengine.org/blog/custom-types-for-the-inspector/#docs" class="hash-link" aria-label="Direct link to Docs" title="Direct link to Docs" translate="no">​</a></h2>
<ul>
<li class=""><a class="" href="https://balaurengine.org/docs/reference/components/">Component properties</a></li>
<li class=""><a class="" href="https://balaurengine.org/docs/manual/scripting/#exported-properties">Exported script properties</a></li>
</ul>]]></content>
        <author>
            <name>Dragos</name>
            <uri>https://github.com/Ughuuu</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Modules]]></title>
        <id>https://balaurengine.org/blog/modules/</id>
        <link href="https://balaurengine.org/blog/modules/"/>
        <updated>2026-09-19T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Files under addons/<name>/ are modules any script calls by path, like the Gamend SDK.]]></summary>
        <content type="html"><![CDATA[<p>A file directly under <code>addons/&lt;name&gt;/</code> is a module every script reaches by path, with no <code>require</code>. The Gamend SDK is laid out that way: one module per server feature.</p>
<!-- -->
<p><img decoding="async" loading="lazy" alt="Completion after gamend::lobbies:: listing that module&amp;#39;s functions with their parameters" src="https://balaurengine.org/assets/images/addon_completion-7ca1bf536ce7888cb032b1a3aaa8a508.webp" width="1920" height="1080" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="modules">Modules<a href="https://balaurengine.org/blog/modules/#modules" class="hash-link" aria-label="Direct link to Modules" title="Direct link to Modules" translate="no">​</a></h2>
<ul>
<li class=""><code>addons/kit/math.rn</code> is <code>kit::math</code>. Its functions are called as <code>kit::math::double(2)</code> and its constants read as <code>kit::math::LIMIT</code>.</li>
<li class="">The constants in a <code>pub mod</code> block sit one segment deeper: <code>kit::math::colors::RED</code>.</li>
<li class="">Saving an addon file reaches every script that calls it.</li>
<li class="">Completion and hover walk the path, and show a function's parameters and its doc line.</li>
<li class="">An addon may share a name with an engine module: <code>gamend::lobbies</code> sits beside <code>gamend::login</code>.</li>
<li class="">An exported pack keeps the paths, and a project opened in the editor mounts its own addons.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-gamend-sdk">The Gamend SDK<a href="https://balaurengine.org/blog/modules/#the-gamend-sdk" class="hash-link" aria-label="Direct link to The Gamend SDK" title="Direct link to The Gamend SDK" translate="no">​</a></h2>
<ul>
<li class="">259 operations in 47 modules, one per server feature: <code>gamend::lobbies::create_lobby</code>, <code>gamend::users::get_current_user</code>.</li>
<li class="">Realtime events are grouped by channel. <code>gamend::events::lobby::MEMBER_JOINED</code> is what <code>gamend::events::decode</code> answers for a lobby's <code>user_joined</code>.</li>
</ul>
<div class="language-rune codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#403f53;--prism-background-color:#FBFBFB"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rune codeBlock_bY9V thin-scrollbar" style="color:#403f53;background-color:#FBFBFB"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#403f53"><span class="token keyword" style="color:rgb(12, 150, 155)">let</span><span class="token plain"> reply </span><span class="token operator" style="color:rgb(12, 150, 155)">=</span><span class="token plain"> </span><span class="token namespace" style="color:rgb(12, 150, 155)">task</span><span class="token namespace punctuation" style="color:rgb(153, 76, 195)">::</span><span class="token function" style="color:rgb(153, 76, 195);font-style:italic">wait</span><span class="token punctuation" style="color:rgb(153, 76, 195)">(</span><span class="token namespace" style="color:rgb(12, 150, 155)">gamend</span><span class="token namespace punctuation" style="color:rgb(153, 76, 195)">::</span><span class="token namespace" style="color:rgb(12, 150, 155)">lobbies</span><span class="token namespace punctuation" style="color:rgb(153, 76, 195)">::</span><span class="token function" style="color:rgb(153, 76, 195);font-style:italic">quick_join</span><span class="token punctuation" style="color:rgb(153, 76, 195)">(</span><span class="token plain">this</span><span class="token punctuation" style="color:rgb(153, 76, 195)">.</span><span class="token plain">node</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">#{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#403f53"><span class="token plain">    </span><span class="token string" style="color:rgb(72, 118, 214)">"title"</span><span class="token punctuation" style="color:rgb(153, 76, 195)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(72, 118, 214)">"duel"</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(72, 118, 214)">"max_users"</span><span class="token punctuation" style="color:rgb(153, 76, 195)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(170, 9, 130)">2</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#403f53"><span class="token plain"></span><span class="token punctuation" style="color:rgb(153, 76, 195)">}</span><span class="token punctuation" style="color:rgb(153, 76, 195)">)</span><span class="token punctuation" style="color:rgb(153, 76, 195)">)</span><span class="token punctuation" style="color:rgb(153, 76, 195)">.</span><span class="token keyword" style="color:rgb(12, 150, 155)">await</span><span class="token punctuation" style="color:rgb(153, 76, 195)">;</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="docs">Docs<a href="https://balaurengine.org/blog/modules/#docs" class="hash-link" aria-label="Direct link to Docs" title="Direct link to Docs" translate="no">​</a></h2>
<ul>
<li class=""><a class="" href="https://balaurengine.org/docs/manual/scripting/#script-files-as-modules">Script files as modules</a></li>
<li class=""><a class="" href="https://balaurengine.org/docs/manual/gamend/#accounts">Gamend accounts</a></li>
</ul>]]></content>
        <author>
            <name>Dragos</name>
            <uri>https://github.com/Ughuuu</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[The Gamend dock]]></title>
        <id>https://balaurengine.org/blog/gamend-dock/</id>
        <link href="https://balaurengine.org/blog/gamend-dock/"/>
        <updated>2026-09-16T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The Gamend dock: the server target, the signed-in player, the lobby, one tab per server feature, and a run's log shipped to the server.]]></summary>
        <content type="html"><![CDATA[<p>A project that carries the Gamend addon now has a Gamend tab in the editor. It shows what the played game holds on the server, and reads each server feature without a line of script.</p>
<!-- -->
<p><img decoding="async" loading="lazy" alt="The Gamend dock reading gamend.org&amp;#39;s leaderboards" src="https://balaurengine.org/assets/images/gamend_dock-f0a80ccc7a525943d5c0a319967c49ce.webp" width="1202" height="704" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-server">The server<a href="https://balaurengine.org/blog/gamend-dock/#the-server" class="hash-link" aria-label="Direct link to The server" title="Direct link to The server" translate="no">​</a></h2>
<ul>
<li class="">The header switches between the project's two servers, <code>[gamend] url</code> and <code>local_url</code>.</li>
<li class="">The choice is kept in the editor's own settings, so an exported game always talks to <code>url</code>.</li>
<li class="">A new project starts on <code>https://gamend.org</code>.</li>
<li class="">Open and Admin go to the server and to its admin site.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-player">The player<a href="https://balaurengine.org/blog/gamend-dock/#the-player" class="hash-link" aria-label="Direct link to The player" title="Direct link to The player" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" alt="The User tab signed in to a local Gamend" src="https://balaurengine.org/assets/images/gamend_user-b75495a70d2a45dd658fc8af9fee1b05.webp" width="1202" height="704" class="img_ev3q"></p>
<ul>
<li class="">The User tab shows the session, both tokens masked behind show and copy, and when the access token expires.</li>
<li class="">A session kept by an earlier run can be read while signed out, restored or forgotten.</li>
<li class="">The editor uses the game's own user data folder and device id, so a device sign-in from the dock is the game's account.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="one-tab-per-feature">One tab per feature<a href="https://balaurengine.org/blog/gamend-dock/#one-tab-per-feature" class="hash-link" aria-label="Direct link to One tab per feature" title="Direct link to One tab per feature" translate="no">​</a></h2>
<ul>
<li class="">Leaderboards, Quests, Economy, Friends, Chat, Parties, Groups, Tournaments, Matchmaking, Notifications, Payments, Hooks and Users list their <code>GET</code> endpoints as trees.</li>
<li class="">The Lobby tab follows the lobby the game joined, and reads it again when a message lands on its topic.</li>
<li class="">Activity lists every call and socket message, opens each to its arguments and reply, and filters to errors.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="shipping-the-log">Shipping the log<a href="https://balaurengine.org/blog/gamend-dock/#shipping-the-log" class="hash-link" aria-label="Direct link to Shipping the log" title="Direct link to Shipping the log" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" alt="The Logs tab while the game plays" src="https://balaurengine.org/assets/images/gamend_logs-0fda395b0106586d20bf978100980df7.webp" width="1202" height="704" class="img_ev3q"></p>
<ul>
<li class="">Nothing is sent unless the game puts <code>addons/gamend/log_sink.rn</code> on a long-lived node.</li>
<li class="">The sink reads <code>log::since</code> and collects what the server's policy asks for.</li>
<li class="">A batch goes at 50 lines, every 10 seconds, and at once on an error.</li>
<li class="">Unsent lines wait in a save slot for the next launch.</li>
<li class="">Every call, the socket and each batch carry <code>gamend::run_id()</code>, so the server files a run's lines together.</li>
<li class="">The Logs tab shows the newest lines and flushes on demand.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="docs">Docs<a href="https://balaurengine.org/blog/gamend-dock/#docs" class="hash-link" aria-label="Direct link to Docs" title="Direct link to Docs" translate="no">​</a></h2>
<ul>
<li class=""><a class="" href="https://balaurengine.org/docs/manual/gamend/#the-gamend-dock">The Gamend dock</a></li>
<li class=""><a class="" href="https://balaurengine.org/docs/manual/gamend/#client-logs">Client logs</a></li>
<li class=""><a class="" href="https://balaurengine.org/docs/manual/editor/#extending-the-editor">Extending the editor</a></li>
</ul>]]></content>
        <author>
            <name>Dragos</name>
            <uri>https://github.com/Ughuuu</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Project manager]]></title>
        <id>https://balaurengine.org/blog/project-manager/</id>
        <link href="https://balaurengine.org/blog/project-manager/"/>
        <updated>2026-09-15T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Project manager: project list, examples, and the engine versions.]]></summary>
        <content type="html"><![CDATA[<p>When double clicking Balaur Engine, the Project manager will now show up. You can view here your projects, the examples and manage the engine versions.</p>
<!-- -->
<p><img decoding="async" loading="lazy" alt="The Projects tab" src="https://balaurengine.org/assets/images/project_manager-7c84283c104362926a44cb13f34249d9.webp" width="1920" height="1080" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="projects-list">Projects list<a href="https://balaurengine.org/blog/project-manager/#projects-list" class="hash-link" aria-label="Direct link to Projects list" title="Direct link to Projects list" translate="no">​</a></h2>
<p>The project manager contains a list of all your projects, what version of the engine you used to open them and a logo.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="example">Example<a href="https://balaurengine.org/blog/project-manager/#example" class="hash-link" aria-label="Direct link to Example" title="Direct link to Example" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" alt="The Examples tab" src="https://balaurengine.org/assets/images/project_examples-53d64de350951a5fc2a2ba4666aa3388.webp" width="1920" height="1080" class="img_ev3q"></p>
<p>The default examples that the GitHub repo contains are also visible in the Examples tab. Each of them has a screenshot and a title.
Opening it downloads it into your projects and opens the copy.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="manage-engine-version">Manage Engine Version<a href="https://balaurengine.org/blog/project-manager/#manage-engine-version" class="hash-link" aria-label="Direct link to Manage Engine Version" title="Direct link to Manage Engine Version" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" alt="The Engine tab" src="https://balaurengine.org/assets/images/engine_versions-0b266d71989ca4fa1481f888d83b2300.webp" width="1920" height="1080" class="img_ev3q"></p>
<ul>
<li class="">Pick a channel: <code>alpha</code>, <code>beta</code>, <code>rc</code>, <code>stable</code> or <code>nightly</code>.</li>
<li class="">The latest version is checked whenever you open the tab.</li>
<li class="">Each release says whether it is newer or older than yours, and its button says Install or Downgrade.</li>
<li class="">An install downloads in the background with a progress bar. Restart to use it.</li>
<li class="">The macOS app downloads the release's <code>.dmg</code> instead, since it cannot replace itself.</li>
<li class="">The tab calls the same functions as <code>balaur update</code> (the cli).</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="about-balaur">About Balaur<a href="https://balaurengine.org/blog/project-manager/#about-balaur" class="hash-link" aria-label="Direct link to About Balaur" title="Direct link to About Balaur" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" alt="The About sheet" src="https://balaurengine.org/assets/images/about_balaur-33c70bbd6fea6dcf66fc71d0c157ff18.webp" width="1920" height="1080" class="img_ev3q"></p>
<ul>
<li class="">The menu under the logo has an About Balaur entry.</li>
<li class="">It shows the version, build, channel and platform, and whether your channel has a newer build.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="docs">Docs<a href="https://balaurengine.org/blog/project-manager/#docs" class="hash-link" aria-label="Direct link to Docs" title="Direct link to Docs" translate="no">​</a></h2>
<p>Read more about it here:</p>
<ul>
<li class=""><a class="" href="https://balaurengine.org/docs/manual/editor/#the-project-manager">The Project manager</a>.</li>
</ul>]]></content>
        <author>
            <name>Dragos</name>
            <uri>https://github.com/Ughuuu</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Loading screen]]></title>
        <id>https://balaurengine.org/blog/loading-screen/</id>
        <link href="https://balaurengine.org/blog/loading-screen/"/>
        <updated>2026-09-14T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Balaur devlog: added support for loading screen, with customizable time and progress bar.]]></summary>
        <content type="html"><![CDATA[<p>Added support to Balaur for loading / splash screen.
Now, while the game loads the assets and the engine itself gets ready,
a nice progress bar and an image will show for a few seconds (configurable).</p>
<!-- -->
<p><img decoding="async" loading="lazy" alt="Splash screen" src="https://balaurengine.org/assets/images/editor_splash-9882ee73867951ce5e35d638c3c8a8f6.webp" width="1920" height="1080" class="img_ev3q"></p>
<p>It is also configurable in the <code>project.toml</code> file:</p>
<div class="language-toml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#403f53;--prism-background-color:#FBFBFB"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-toml codeBlock_bY9V thin-scrollbar" style="color:#403f53;background-color:#FBFBFB"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#403f53"><span class="token punctuation" style="color:rgb(153, 76, 195)">[</span><span class="token table class-name" style="color:rgb(17, 17, 17)">application</span><span class="token punctuation" style="color:rgb(153, 76, 195)">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#403f53"><span class="token plain"></span><span class="token key property" style="color:rgb(12, 150, 155)">splash</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(72, 118, 214)">"art/logo.png"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#403f53"><span class="token plain"></span><span class="token key property" style="color:rgb(12, 150, 155)">splash_seconds</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(153, 76, 195)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(170, 9, 130)">1.5</span><br></div></code></pre></div></div>
<p>It can also be reused if needed for other parts of the game, from Rune:</p>
<div class="language-rune codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#403f53;--prism-background-color:#FBFBFB"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rune codeBlock_bY9V thin-scrollbar" style="color:#403f53;background-color:#FBFBFB"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#403f53"><span class="token namespace" style="color:rgb(12, 150, 155)">ui</span><span class="token namespace punctuation" style="color:rgb(153, 76, 195)">::</span><span class="token function" style="color:rgb(153, 76, 195);font-style:italic">set_load_progress</span><span class="token punctuation" style="color:rgb(153, 76, 195)">(</span><span class="token number" style="color:rgb(170, 9, 130)">0.4</span><span class="token punctuation" style="color:rgb(153, 76, 195)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(72, 118, 214)">"textures"</span><span class="token punctuation" style="color:rgb(153, 76, 195)">)</span><span class="token punctuation" style="color:rgb(153, 76, 195)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#403f53"><span class="token plain"></span><span class="token comment" style="color:rgb(152, 159, 177);font-style:italic">// ...</span><span class="token plain"></span><br></div><div class="token-line" style="color:#403f53"><span class="token plain"></span><span class="token namespace" style="color:rgb(12, 150, 155)">ui</span><span class="token namespace punctuation" style="color:rgb(153, 76, 195)">::</span><span class="token function" style="color:rgb(153, 76, 195);font-style:italic">finish_loading</span><span class="token punctuation" style="color:rgb(153, 76, 195)">(</span><span class="token punctuation" style="color:rgb(153, 76, 195)">)</span><span class="token punctuation" style="color:rgb(153, 76, 195)">;</span><br></div></code></pre></div></div>
<ul>
<li class=""><code>set_load_progress</code> takes a fraction and a label, and draws a bar under the
picture in the theme's primary colour.</li>
<li class=""><code>finish_loading</code> ends the loading early.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="docs">Docs<a href="https://balaurengine.org/blog/loading-screen/#docs" class="hash-link" aria-label="Direct link to Docs" title="Direct link to Docs" translate="no">​</a></h2>
<p>Read more about it here:</p>
<ul>
<li class=""><a class="" href="https://balaurengine.org/docs/manual/shipping/#splash-screen">Shipping</a>.</li>
</ul>]]></content>
        <author>
            <name>Dragos</name>
            <uri>https://github.com/Ughuuu</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Async import of assets]]></title>
        <id>https://balaurengine.org/blog/async-import-of-assets/</id>
        <link href="https://balaurengine.org/blog/async-import-of-assets/"/>
        <updated>2026-09-13T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Assets import off the main thread, reload when saved, keep stable id:// references, and read import settings from a sidecar.]]></summary>
        <content type="html"><![CDATA[<p>Importing an asset runs on its own thread, so the editor keeps drawing.</p>
<!-- -->
<p><img decoding="async" loading="lazy" alt="The editor importing two files at once, one finished and one part way through" src="https://balaurengine.org/assets/images/editor_import-10eff7616905db074418989899e2b94b.webp" width="1920" height="1080" class="img_ev3q"></p>
<ul>
<li class="">A saved texture, model, font or sound reloads, and every node built from it is rebuilt.</li>
<li class="">An <code>id://</code> reference survives a move, and a rename in the Assets dock rewrites every reference to the file.</li>
<li class=""><code>art/hero.png.import.toml</code> holds one image's import settings, and <code>[import.texture]</code> in <code>project.toml</code> is the default.</li>
<li class=""><code>filter = "nearest"</code> draws pixel art crisp.</li>
</ul>
<p><img decoding="async" loading="lazy" alt="The same 32-pixel sprite at ten times its size, filtered linearly and with nearest" src="https://balaurengine.org/assets/images/import_settings-20db1e1d038dd15f2fc6d3ded46c7dc8.webp" width="1200" height="620" class="img_ev3q"></p>
<p><img decoding="async" loading="lazy" alt="The Import tab showing filter and srgb for a selected picture" src="data:image/webp;base64,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" width="506" height="322" class="img_ev3q"></p>
<p><a class="" href="https://balaurengine.org/docs/manual/editor/#asset-imports">Asset imports</a> · <a class="" href="https://balaurengine.org/docs/manual/scenes/#import-settings">Import settings</a></p>]]></content>
        <author>
            <name>Dragos</name>
            <uri>https://github.com/Ughuuu</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Running Sponza]]></title>
        <id>https://balaurengine.org/blog/running-sponza/</id>
        <link href="https://balaurengine.org/blog/running-sponza/"/>
        <updated>2026-09-12T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Sky lighting, ambient occlusion, glass, mirrors, reflection probes and post passes, shown on Sponza.]]></summary>
        <content type="html"><![CDATA[<p>Sponza, imported by running <code>balaur import</code>. Nothing in it was
created by hand except a camera, a sun, an environment and a player.</p>
<!-- -->
<video width="1920" height="1080" loop="" muted="" playsinline="" controls="" preload="none" poster="/img/poster/sponza_walk.webp" aria-label="Sponza walking forward" style="width:100%;height:auto;display:block;margin:1rem 0"><source src="/video/sponza_walk.webm" type="video/webm"><source src="/video/sponza_walk.mp4" type="video/mp4"></video>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="surfaces">Surfaces<a href="https://balaurengine.org/blog/running-sponza/#surfaces" class="hash-link" aria-label="Direct link to Surfaces" title="Direct link to Surfaces" translate="no">​</a></h2>
<p><code>package::mesh</code> binds the sky as an environment map, the occlusion, the reflection probes,
and the scene that glass refracts.</p>
<p><img decoding="async" loading="lazy" alt="A chrome ball, a pane of glass and a mirrored floor under a sky" src="https://balaurengine.org/assets/images/3d_look_surfaces-1ba0af35fa367a7ac4126ca6205d1cdb.webp" width="1600" height="1000" class="img_ev3q"></p>
<ul>
<li class="">Image-based lighting takes the place of <code>environment.ambient</code>.</li>
<li class="">A mirror renders the scene from its own plane.</li>
<li class="">A <code>reflection_probe</code> is a box with a room captured inside.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="occlusion">Occlusion<a href="https://balaurengine.org/blog/running-sponza/#occlusion" class="hash-link" aria-label="Direct link to Occlusion" title="Direct link to Occlusion" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" alt="Two boxes on a floor, without occlusion and with it" src="https://balaurengine.org/assets/images/3d_look_occlusion-41d7b814a3b2b19366644dea2a156bf5.webp" width="1600" height="498" class="img_ev3q"></p>
<p>Every 3D material draws a geometry prepass. It then feeds the occlusion buffer.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="running-it">Running it<a href="https://balaurengine.org/blog/running-sponza/#running-it" class="hash-link" aria-label="Direct link to Running it" title="Direct link to Running it" translate="no">​</a></h2>
<p>Follow the instructions in <a href="https://github.com/balaurengine/balaur-sponza" target="_blank" rel="noopener noreferrer" class="">balaur-sponza</a>. Its scripts download the model and set up the scene after <code>balaur import</code>.</p>
<ul>
<li class="">The model is <a href="https://github.com/KhronosGroup/glTF-Sample-Assets/tree/main/Models/Sponza" target="_blank" rel="noopener noreferrer" class="">Sponza</a> from the Khronos glTF sample assets, CC BY 4.0, after the original by Frank Meinl for Crytek.</li>
</ul>]]></content>
        <author>
            <name>Dragos</name>
            <uri>https://github.com/Ughuuu</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Pause]]></title>
        <id>https://balaurengine.org/blog/pause/</id>
        <link href="https://balaurengine.org/blog/pause/"/>
        <updated>2026-09-11T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[engine.set_paused, nodes that run through a pause, a time scale, a frame cap and a tick rate.]]></summary>
        <content type="html"><![CDATA[<p><code>engine.set_paused(true)</code> holds the tree. A node set to <code>process = "always"</code>
keeps its own subtree running, which is what a pause menu is.</p>
<!-- -->
<video width="1920" height="1080" loop="" muted="" playsinline="" controls="" preload="none" poster="/img/poster/pause_states.webp" aria-label="Twelve boxes falling, frozen in mid-air when the game pauses, then falling again at a quarter speed. The heading and the marker beside it keep animating throughout" style="width:100%;height:auto;display:block;margin:1rem 0"><source src="/video/pause_states.webm" type="video/webm"><source src="/video/pause_states.mp4" type="video/mp4"></video>
<p><code>process</code> is a key on a node like <code>visible</code>, and the subtree under it
inherits the answer:</p>
<ul>
<li class=""><code>pausable</code> stops while paused. The default, and what everything above gets
from the root.</li>
<li class=""><code>always</code> runs either way. A pause menu, a loading screen, the script that
lifts the pause.</li>
<li class=""><code>when_paused</code> runs only while paused.</li>
<li class=""><code>disabled</code> never runs.</li>
<li class=""><code>inherit</code> takes the nearest ancestor's answer.</li>
</ul>
<p>That one key stops everything that ticks per node:</p>
<ul>
<li class="">Scripts, animation players, tweens, state machines and the <code>timer</code>
component.</li>
<li class="">Physics is one world and is held whole, so a body under an <code>always</code> node
stops with the rest. Godot draws the line in the same place.</li>
<li class="">Every script's <code>on_paused(bool)</code> is called when the state changes, the
scripts the pause just stopped included.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="slow-motion-and-the-frames-between-ticks">Slow motion, and the frames between ticks<a href="https://balaurengine.org/blog/pause/#slow-motion-and-the-frames-between-ticks" class="hash-link" aria-label="Direct link to Slow motion, and the frames between ticks" title="Direct link to Slow motion, and the frames between ticks" translate="no">​</a></h2>
<p><code>engine.set_time_scale(0.25)</code> multiplies wall-clock time before the
simulation is owed it. Half speed takes half the fixed steps, double takes
twice, and each step is still the same length. The cap on catch-up steps
scales with it, so fast forward is not quietly clipped. Three settings come
with it:</p>
<ul>
<li class=""><code>[window] max_fps</code> caps the loop where vsync does not.</li>
<li class=""><code>[time] tick_hz</code> replaces the built-in 60. A recording carries the rate it
was made at.</li>
<li class=""><code>[time] interpolate</code> draws bodies and <code>fixed_update</code> nodes between steps,
so they move on every frame of a 144 Hz display. Off by default: it costs
one tick of latency, which a run taking one step per frame pays for
nothing.</li>
</ul>]]></content>
        <author>
            <name>Dragos</name>
            <uri>https://github.com/Ughuuu</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Lists, trees and tables]]></title>
        <id>https://balaurengine.org/blog/lists-trees-and-tables/</id>
        <link href="https://balaurengine.org/blog/lists-trees-and-tables/"/>
        <updated>2026-09-10T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Rows in a scene: a list or tree holding many rows, a table with named columns a drag resizes, and only the rows on screen ever built.]]></summary>
        <content type="html"><![CDATA[<p>The three row kinds hold many rows now, a <code>table</code> has columns a drag resizes,
and none of them builds a row the box does not show.</p>
<!-- -->
<p><img decoding="async" loading="lazy" alt="A list with two rows picked, the same entries as a folding tree, and again as a table with named columns" src="https://balaurengine.org/assets/images/ui_rows-17fc54bf1e0e30083d31c3819c7d915b.webp" width="1800" height="800" class="img_ev3q"></p>
<ul>
<li class=""><code>multi</code> lets a <code>list</code>, <code>tree</code> or <code>table</code> hold more than one row. The
platform's command key toggles a row, shift takes the run from the last one
clicked, and <code>selection</code> is what the widget holds.</li>
<li class=""><code>on_change</code> hears the whole selection where the widget holds many, and the
row where it holds one. A widget without <code>multi</code> behaves as it always did.</li>
<li class="">A <code>table</code>'s <code>placeholder</code> names its columns, split on the separator its rows
are. A name ending in <code>&gt;</code> draws its column against the right edge, which is
what a column of numbers wants.</li>
<li class="">Each column's width is a share the seam in the header drags, held per table,
so a rebuild of the rows leaves the widths where you put them.</li>
<li class="">A row may carry an <code>#rrggbb</code> past its last cell, the way a list row carries
its own colour.</li>
<li class="">A secondary click picks the row it lands on, so a <code>context</code> menu acts on
what it opened over. A row already picked keeps the set it is in.</li>
<li class="">The <code>table</code> places its body by arithmetic now, as <code>list</code> and <code>tree</code> already
did: 2,000 rows cost a screenful. No crate was added for any of it.</li>
</ul>
<p>The editor eats it. Its Profiler and Cost docks were padding numbers into a
monospace string to fake columns, and both are <code>table</code> nodes now. The
outliner's search view moved onto the same <code>tree</code> node the unfiltered one
already used, and a right click on a row opens the node's own menu.</p>
<p>The picture above is one scene of widget nodes, with no drawing code behind
it.</p>
<p>The rest is on the <a class="" href="https://balaurengine.org/docs/roadmap/">roadmap</a>.</p>]]></content>
        <author>
            <name>Dragos</name>
            <uri>https://github.com/Ughuuu</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Mobile support]]></title>
        <id>https://balaurengine.org/blog/mobile-support/</id>
        <link href="https://balaurengine.org/blog/mobile-support/"/>
        <updated>2026-09-09T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The editor lays itself out for a desktop, a tablet or a phone.]]></summary>
        <content type="html"><![CDATA[<p>The editor lays itself out for the room it gets, and draws larger under a
finger.</p>
<!-- -->
<p><img decoding="async" loading="lazy" alt="The same editor on a desktop, a tablet and a phone" src="https://balaurengine.org/assets/images/one_editor_three_screens-25b1879538bca794c68fbb1975c14215.webp" width="2691" height="900" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="docks">Docks<a href="https://balaurengine.org/blog/mobile-support/#docks" class="hash-link" aria-label="Direct link to Docks" title="Direct link to Docks" translate="no">​</a></h2>
<ul>
<li class="">On a tablet both side docks start folded, and an open one takes half the
screen.</li>
<li class="">On a phone all three start folded, and one opens at a time.</li>
<li class="">A folded dock leaves a handle at its edge, and an open one folds back the
same way.</li>
</ul>
<p><img decoding="async" loading="lazy" alt="A phone with nothing open, then the outliner, the inspector and the output" src="https://balaurengine.org/assets/images/phone_one_panel-a22e1ce213c709f3b87419f489dac3cc.webp" width="1620" height="844" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="touch">Touch<a href="https://balaurengine.org/blog/mobile-support/#touch" class="hash-link" aria-label="Direct link to Touch" title="Direct link to Touch" translate="no">​</a></h2>
<ul>
<li class="">Under a finger the glyph, the plate and the bar grow together.</li>
<li class="">Every control is at least 44 points, and the editor's selftest fails one
under that.</li>
</ul>
<p><a class="" href="https://balaurengine.org/docs/manual/editor/">The editor</a></p>]]></content>
        <author>
            <name>Dragos</name>
            <uri>https://github.com/Ughuuu</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Menus, popups and toasts]]></title>
        <id>https://balaurengine.org/blog/menus-popups-and-toasts/</id>
        <link href="https://balaurengine.org/blog/menus-popups-and-toasts/"/>
        <updated>2026-09-08T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Menus in a scene: a bar with submenus, a context menu any widget names, chords that fire while the menu is shut, and a toast that stacks and leaves.]]></summary>
        <content type="html"><![CDATA[<p>Menus are scene nodes now. A <code>menu</code> holds rows, any widget names one as its
<code>context</code>, and a <code>toast</code> says something and leaves.</p>
<!-- -->
<p><img decoding="async" loading="lazy" alt="A menu bar with a menu open, its rows showing shortcuts and a submenu, and a toast in the corner" src="https://balaurengine.org/assets/images/ui_menus-8d05c67e25e13643f1b9c789aa28f2a4.webp" width="1600" height="960" class="img_ev3q"></p>
<ul>
<li class="">A menu bar is a <code>row</code> of <code>menu</code> nodes. A row that is itself a <code>menu</code>
opens to the side on hover, one submenu at a time, and does not shut the
menu it hangs off.</li>
<li class="">Any widget names a <code>menu</code> as its <code>context</code>. A right click opens it at the
pointer, and so does a long press, which is the same gesture on a phone.
The widget's own <code>on_click</code> stays quiet for that press.</li>
<li class=""><code>placement</code> says where a menu opens: <code>below</code>, <code>above</code>, <code>pointer</code>, or
<code>center</code>.</li>
<li class=""><code>shortcut</code> is a chord on any widget, written one way: <code>cmd+shift+s</code>,
<code>f5</code>. A menu row fires with its menu shut, and the row draws the chord
the way this platform writes it.</li>
<li class="">A <code>toast</code> is a root that stacks at its anchor, fades over its last half
second, and frees itself when its <code>duration</code> is up. A binding action puts
one up with no script at all.</li>
<li class="">A <code>dialog</code> closes on Escape and on a click on the dim, and reports that
through <code>on_change</code>.</li>
</ul>
<p>Every one of them is a property on the <code>widget</code> component, so the inspector
edits them and a scene file holds them.</p>
<p>The rest is on the <a class="" href="https://balaurengine.org/docs/roadmap/">roadmap</a>.</p>]]></content>
        <author>
            <name>Dragos</name>
            <uri>https://github.com/Ughuuu</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Links and selectable text]]></title>
        <id>https://balaurengine.org/blog/links-and-selectable-text/</id>
        <link href="https://balaurengine.org/blog/links-and-selectable-text/"/>
        <updated>2026-09-07T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Links and hints in labels, text you can select and copy, and number fields with arrows and units.]]></summary>
        <content type="html"><![CDATA[<p>Marks in a label can be clicked and hovered, a drag selects its text, and a
number in it carries units.</p>
<!-- -->
<p><img decoding="async" loading="lazy" alt="A label with a link and a hint, a selectable line, and two numbers with arrows and units" src="https://balaurengine.org/assets/images/ui_text-8b282e712caed67f4a92f21764b3fb5e.webp" width="1280" height="840" class="img_ev3q"></p>
<ul>
<li class="">A <code>[url=target]</code> span wears the theme's link colour and an underline, the
pointer over it is a hand, and a click calls <code>on_link</code> with the target.
What to do with it is the game's: a scene, a shop, a browser.</li>
<li class="">A <code>[hint=text]</code> span says something while the pointer rests on it. The
hover text belongs to the span, not to the whole label.</li>
<li class="">With <code>selectable</code>, a drag selects, the platform's copy key takes it,
double click takes a word and treble takes the block. A seed or an error
code is now something a player can send you.</li>
<li class="">A <code>drag_value</code> with <code>arrows</code> draws a step up and a step down inside its
own box, each moving by <code>step</code> within <code>min</code> and <code>max</code>, and <code>suffix</code> puts
the units after the number: <code>12 px</code>, <code>4.5 m/s</code>.</li>
</ul>
<p>Labels are still shaped by the engine's own text stack. That is what keeps
right-to-left runs in order, holds one glyph atlas behind the HUD and the
world, and measures a width a headless run agrees with.</p>]]></content>
        <author>
            <name>Dragos</name>
            <uri>https://github.com/Ughuuu</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Concave 2D colliders]]></title>
        <id>https://balaurengine.org/blog/concave-2d-colliders/</id>
        <link href="https://balaurengine.org/blog/concave-2d-colliders/"/>
        <updated>2026-09-06T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Splitting a concave polygon into multiple polygons that overlap for better physics results and stability.]]></summary>
        <content type="html"><![CDATA[<p>Now, concave polygons are split into multiple polygons that overlap for better physics results and stability.</p>
<!-- -->
<video width="1920" height="1080" loop="" muted="" playsinline="" controls="" preload="none" poster="/img/poster/concave_beam.webp" aria-label="Two tables with a beam spawned inside each, across a seam. In the plain one the beam stays wedged; in the grown one it is pushed up and clear of the top within a second" style="width:100%;height:auto;display:block;margin:1rem 0"><source src="/video/concave_beam.webm" type="video/webm"><source src="/video/concave_beam.mp4" type="video/mp4"></video>
<p>Cutting a polygon used to leave seams, where small objects could get stuck. Erin Catto's
<a href="https://box2d.org/posts/2020/04/stuck-inside/" target="_blank" rel="noopener noreferrer" class="">Stuck Inside</a> article explains about
overlaps the pieces by hand. This does it automatically.</p>
<p><code>overlap</code> is configurable, 0.9 by default (it leaves a bit of empty room). At 0 you get the plain cut.</p>
<p><img decoding="async" loading="lazy" alt="One shape at four overlap settings, and three stars showing how many pieces pile onto one point" src="https://balaurengine.org/assets/images/concave_dial_stack-d0e0c75120ff0de6902f3d73eb438739.webp" width="1597" height="984" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="performance">Performance<a href="https://balaurengine.org/blog/concave-2d-colliders/#performance" class="hash-link" aria-label="Direct link to Performance" title="Direct link to Performance" translate="no">​</a></h2>
<p>What the times look like (at build time):</p>
<table><thead><tr><th>kind</th><th>ns</th><th>result</th></tr></thead><tbody><tr><td>trimesh</td><td>118</td><td>still inside</td></tr><tr><td>convex_decomposition, overlap 0</td><td>187</td><td>still inside</td></tr><tr><td>convex_decomposition, overlap 0.9</td><td>367</td><td>out</td></tr></tbody></table>
<ul>
<li class="">A trimesh is the cheaper static collider when bodies only touch it from
outside. This kind is for dynamic bodies.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="also">Also<a href="https://balaurengine.org/blog/concave-2d-colliders/#also" class="hash-link" aria-label="Direct link to Also" title="Direct link to Also" translate="no">​</a></h2>
<ul>
<li class="">Mass comes from the ungrown pieces, so a table weighs what its area says.</li>
<li class="">A solids-mode Godot <code>CollisionPolygon2D</code> imports as this kind.</li>
<li class=""><code>geometry2d.convex_decomposition</code> hands the pieces to a script.</li>
</ul>]]></content>
        <author>
            <name>Dragos</name>
            <uri>https://github.com/Ughuuu</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Godot game converter]]></title>
        <id>https://balaurengine.org/blog/godot-game-converter/</id>
        <link href="https://balaurengine.org/blog/godot-game-converter/"/>
        <updated>2026-09-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[balaur import converts a Godot project's settings, scenes, scripts and theme.]]></summary>
        <content type="html"><![CDATA[<p><code>balaur import</code> converts a Godot project: the settings, every scene, the
scripts, the theme, and a report of what did not carry.</p>
<!-- -->
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#403f53;--prism-background-color:#FBFBFB"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#403f53;background-color:#FBFBFB"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#403f53"><span class="token plain">balaur </span><span class="token function" style="color:rgb(153, 76, 195);font-style:italic">import</span><span class="token plain"> project.godot </span><span class="token parameter variable" style="color:rgb(201, 103, 101)">--project</span><span class="token plain"> my-game</span><br></div></code></pre></div></div>
<p><img decoding="async" loading="lazy" alt="Godot on the left, the port on the right" src="https://balaurengine.org/assets/images/port_godot_balaur-86c6f5d91e62425bb4514efedd63bb20.webp" width="810" height="900" class="img_ev3q"></p>
<p>Ported: Polyglot Pirates, a shipped Godot 4.7 game. 181 scenes, 769 scripts,
a theme of 700 items. Its automation runner was ported first, so a passing
scenario proves every script it walks through.</p>
<ul>
<li class="">Each scene has one root, and an instance is that root, so a converted
node path reads the same as in Godot.</li>
<li class="">A <code>stack</code> container lays every child over the same box, as a Godot
MarginContainer does.</li>
<li class="">Theme import carries separations, icon colours and bold faces.</li>
<li class=""><code>fit</code> on a picture covers Godot's expand and stretch modes.</li>
<li class=""><code>await</code> works on a signal and on another node's method.</li>
<li class="">A <code>meta</code> component, <code>Array[Node]</code> exports, toggle buttons, and children
running <code>init</code> before their parent.</li>
<li class="">Tilemaps honour <code>z_index</code> against sprites.</li>
<li class="">A button takes the box the layout solved, not its caption's size.</li>
<li class="">macOS dark mode is read from the window.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-far-it-is">How far it is<a href="https://balaurengine.org/blog/godot-game-converter/#how-far-it-is" class="hash-link" aria-label="Direct link to How far it is" title="Direct link to How far it is" translate="no">​</a></h2>
<p>Five scenarios pass headless, and a run ends with a screenshot. The menu
matches. The gameplay screens are next.</p>]]></content>
        <author>
            <name>Dragos</name>
            <uri>https://github.com/Ughuuu</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Focus mode]]></title>
        <id>https://balaurengine.org/blog/focused-mode/</id>
        <link href="https://balaurengine.org/blog/focused-mode/"/>
        <updated>2026-09-04T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[⇧⌘\ folds the editor around the code pane, and restores the layout on exit.]]></summary>
        <content type="html"><![CDATA[<p>Focus mode gives the code pane the whole window. <code>⇧⌘\</code> folds the three docks
and the split; the file's hooks stay beside the pane. A second press restores
the layout it folded.</p>
<!-- -->
<p><img decoding="async" loading="lazy" alt="The code pane with the window to itself, the hooks list beside it, and the Focus chip lit in the top bar" src="https://balaurengine.org/assets/images/editor_focus-a03733be7713b00428b3907e88e25ae9.webp" width="1920" height="1080" class="img_ev3q"></p>
<ul>
<li class="">It folds the tree, the inspector and the bottom dock, whatever each was
showing, and the split with them. The hooks list stays.</li>
<li class="">Focus records the three docks' state and the split before folding them,
and leaving restores what was open.</li>
<li class="">Opening a panel under focus ends it: the panel stays and the record is
dropped. Leaving the code tab restores the shell.</li>
<li class="">A chip beside Split in the top bar, <code>⇧⌘\</code>, or the command palette turns
it on. With no script on the selection the chip is greyed and its tooltip
says why.</li>
</ul>]]></content>
        <author>
            <name>Dragos</name>
            <uri>https://github.com/Ughuuu</uri>
        </author>
    </entry>
</feed>