Skip to main content

Pragtical v3.13.0 Release

· 8 min read
Jefferson Gonzalez
Contributor of Pragtical

Pragtical v3.13.0 is out with the first native audio API and built-in audio player, another round of renderer backend improvements, faster multi-cursor editing, better project/file searching, and a larger set of settings and editor workflow refinements.

Rendering Since 3.12.0​

Version 3.12.0 introduced the modular renderer stack and the SDL GPU backend. The work since then has mostly been about making that stack less experimental and easier to live with day to day.

SDL GPU text now blends subpixel glyphs correctly on light backgrounds, avoiding the colored edge artifacts that came from collapsing LCD coverage into a single alpha value. SDL GPU also handles collapsed polygon geometry as an empty draw instead of aborting when subpixel paths flatten into coincident or collinear points.

Fractional scaling was reworked for both SDL GPU and SDLRenderer. Window targets now stay in physical-pixel coordinates while Lua remains responsible for visual UI scaling. Input coordinates, touch positions, hit testing and IME placement use the same translation path, which fixes doubled SDLRenderer output and mismatched SDLGPU pointer coordinates on fractional-scale displays.

Windows surface rendering also got a frame-pacing fix. On Windows, Pragtical now requests SDL's accelerated framebuffer before creating window surfaces and wires surface backend vsync through SDL's surface API. That keeps the conservative surface backend feeling better when Auto FPS follows the display refresh rate.

The renderer internals were also reorganized under src/renderer, with concrete backends under src/renderer/backend and generated shader headers under src/renderer/shaders. That does not change the UI directly, but it makes the native side easier to navigate as the backend work continues.

Renderer Selection​

The renderer can now be selected from Settings, instead of only through the PRAGTICAL_RENDERER environment variable or build option.

The new Core > Graphics setting writes the preferred backend into USERDIR/renderer, or removes it when setting it to Default, the renderer is read during startup so a full restart is required on each change. Explicit PRAGTICAL_RENDERER will override the UI configured renderer.

This is a small UI change with a large practical effect, users can easily try:

  • Surface,
  • SDL GPU
  • SDLRenderer

without rebuilding or keeping wrapper scripts around.

renderer selection

Audio API And Player​

Pragtical now has a native audio API. Plugins can play music and sound effects, stream files, reuse decoded sounds, generate PCM, record from input devices, group mixer tracks, loop, fade, query durations, and optionally capture samples for visualizations.

The built-in Audio Player uses that API directly. It can open audio files from the treeview, file picker, or drag and drop without treating them as text. It can scan music directories recursively, filter the playlist, seek, change volume, repeat or shuffle tracks, and restore the playlist with the workspace without starting playback automatically.

audio player

Builds can use system SDL3_mixer or the bundled static fallback, with FLAC, MP3, Vorbis and Opus support. macOS builds include the required audio framework dependencies and microphone permission metadata.

The following video shows an experimental slop game being developed with AI inside Pragtical, used as a practical stress test for the new audio API and the renderer system.

Large multi-cursor edits are much faster now. The document code avoids repeated selection splices and full cursor sanitization for common single-line edits, keeps one selection snapshot per undo group, and preserves large edit groups under the existing undo limit. The benchmark used during development moved operations that previously took hundreds or thousands of milliseconds down into single-digit or low double-digit timings.

File searching was also tightened. Worker cleanup now closes Lua states and channels when changing projects or exiting, and cancelled searches no longer leave workers or queues behind. Find File avoids repeated queue shifting and reuses previous matches while typing. On a large project used for testing, the initial scan dropped from 38 seconds to 4 seconds, and broad filtering queries fell from about one second to roughly 70-130 ms.

Project Search results can now open in splits. A match can be opened normally or in a reusable side pane, including from Ctrl-click and the result context menu. The pane is reused while its original layout leaf survives, which keeps split search workflows predictable without adding another widget API. Thanks to Amer for suggesting this feature.

project search split

Settings And Editor Workflow​

Settings now supports WidgetList-backed values, which is used for plugin and transition enable/disable lists. Code folding can also be enabled or disabled by language name or extension (thanks to bananakid for the suggestion!).

plugins list

codefold languages

Untitled documents can carry extension hints. That gives new files syntax highlighting, descriptive tab names, Save As suggestions, active-document inheritance, and workspace restore behavior without assigning a real filename (thanks to ShalokShalom for the suggestion!).

new file settings

Markdown highlighting also recognizes more code block language identifiers and frontmatter formats, along with extra Markdown syntax such as task checkboxes, inline metadata and wikilinks (thanks to Vinfall for implementing these enhancements).

Syntax plugins can now mark tokenizer rules with first_line = true. This is useful for formats that only allow a region to start at the top of a document, such as Markdown frontmatter. The rule may still continue and close on later lines, it just cannot open again halfway through the file.

syntax.add {
name = "Markdown",
files = { "%.md$", "%.markdown$" },
patterns = {
{
pattern = { "^%-%-%-%s*\n", "^%-%-%-%s*$" },
type = "string",
syntax = ".yaml",
first_line = true
},
-- other markdown rules...
}
}

Before

markdown before

After

markdown after

Stability Fixes​

This release also fixes repeated prompts in two common cases. Declining an autoreload prompt now refreshes the recorded file metadata, so the same external change does not ask again on every poll. Changing projects now cleans up discarded dirty documents before restarting, so the same edits are not prompted again after the user already agreed to discard them.

Trailing whitespace error markers now replace the regular dot marker instead of overlapping it. Context menu divider normalization was tightened so filtered menus do not leave duplicate or orphaned separators behind. Diff views now support wrapping while keeping both panes and their diff gaps aligned.

Build And Packaging​

Windows builds now embed VERSIONINFO metadata in pragtical.exe, including the project publisher, product name, description and Meson release version (thanks also to bananakid for guiding this improvement).

PGO profile collection was fixed for Clang CI builds, optional SDL_image codec include paths were corrected, mbedTLS was updated to v4.1.1, the widget and plugins subprojects were refreshed, and the release metadata now points at 3.13.0. Thanks to everybody who reported issues, suggestions and opened pull requests!

Downloads on GitHub.

Changes Log​

New Features​

  • Add audio support and built-in player (#601)

  • Add persistent renderer selection in settings (#608)

  • Add WidgetList support to settings UI (#591)

  • Add codefold toggle support by language (#592)

  • Add extension hints for new files (#596)

  • Open project search results in splits (#594)

  • Add first-line-only tokenizer rules (#606)

Enhancements​

  • Improve thread cleanup and file searches (#611)

  • Improve multi-cursor performance (#597)

  • Support wrapping in diff views (#593)

  • Support more Markdown syntax and code block languages (#605)

  • Add Windows EXE version information (#604)

Fixes​

  • Fix repeated prompts when changing projects (#612)

  • Fix repeated autoreload prompts after declining (#610)

  • Fix SDL GPU crashes on collapsed polygons (#603)

  • Fix overlapping trailing whitespace markers (#599)

  • Fix Windows surface frame pacing (#589)

  • Fix conditional context menu dividers (#586)

  • Fix SDL GPU and SDLRenderer fractional scaling (#584)

  • Fix PGO training cleanup and locked-node failure (#600)

Build System​

  • Update mbedTLS subproject to v4.1.1 (#595)

  • Update widgets to include WidgetList support (#590)

  • Update widget scaling fix (d3f9e11a)

  • Fix SDL_image optional codec include paths (#598)

  • Fix Clang PGO profile collection in CI (e86b40f9)

  • Update plugins subproject (854a9489)