2026-09-09

https://gitlab.com/keid/meta/-/raw/main/resolvers/keid-engine-2026-09-09.yaml (GHC 9.10.3 / LTS-24.58)

Keid

The major focus was text processing and rendering: fonts moved from Evan Wallace’s SDF atlases to MSDF with proper shaping and line wrapping. The rest is mostly keeping up with the dependencies.

keid-frp-banana, keid-geometry, keid-resource-gltf and keid-sound-openal stay at their previous versions.

Dependencies

New packages:

The core of the Keid update this time:

Git pins

  • bindings-GLFW from b37d104 to pick up glfw-3.4 until it hits Hackage.

Non-git pins

  • mcp-server
  • quic/quic-simple and its entourage of tls, crypton-* and async.

Breaking

Fonts: EvanW SDF is gone

  • Removed Resource.Font.EvanW and Render.Font.EvanwSdf.* together with the pEvanwSdf pipeline. Use Resource.Font.Ktxf and Render.Font.Msdf.* with pMsdf.
  • Fonts are .ktxf bundles now, not a JSON atlas next to a KTX2 texture. Atlas generation no longer needs a browser and copy-pasting. demos/sky-playground and examples/2d/texts-and-sprites show the migration.
  • Engine.UI.Message.Input:
    • inputFontId is removed.
    • inputFont is a Ktxf.Stack now (see Ktxf.allocateStack1 and Ktxf.allocateMonoStacks) instead of a Font.Container.
    • inputLineSize and inputBreak are new fields.
  • If you built .ktxf bundles with ktx-font-0.1.x, rebuild them. ktx-font-0.2 changed the format of the bundled shaping data.

Render.Basic settings and pipelines

  • Render.Basic.Settings gained sMSAA, sAnisotropy and sLitSpec, and lost its Zero instance. Use Render.Basic.swapchainSettings swapchain instead of passing the swapchain around for antialiasing settings.
  • PipelinesF no longer has pMSAA. pSettings (the observable Settings) takes its place.
  • External.ConfigureGraphics ^ p and External.ConfigureCompute ^ p slots in HKD pipeline collections are Worker.Vars of the configuration now, not External.Processes. External pipelines use one loader for all variants.

Look of the scene

  • The AO channel of the Material texture is inverted (0 is the most occluded, 1 is fully open) and multiplicative, like the rest of the channels. Existing AO maps will render differently and will need updates.
  • Lights use the roughness-aware Fresnel function, so lit materials will look different.

Textures

  • Global.Resource.Texture.Base.Collection gained white. The indices of the textures that come after the Base ones are shifted by one.

ImGui

keid-ui-dearimgui-0.1.5.0 follows dear-imgui-2.5.0 (Dear ImGui 1.92.8), with breaking changes around the DrawList API:

  • image drops the border and tint arguments. Use imageWithBg.
  • Texture functions take ImTextureRef instead of ImTextureID. pushTextureID and popTextureID are pushTexture and popTexture now.
  • addRect, addPolyLine and pathStroke swapped some of their arguments.

Upstream

  • ktx-codec-0.1.0.0: Codec.Ktx2.Write functions take the new Ktx2 type instead of separate arguments.
  • apecs-stm-0.3: Map, Global and Unique are renamed to TMap, TGlobal and TUnique. They can now be used alongside the vanilla ones.
  • vulkan-3.26.5: the debugMessage text is a Maybe.
  • spirv-reflect-{ffi,types,yaml}-0.4: SpecializationConstant has new type_description and default_value fields.
  • geomancy-0.3.1.0: Block.sizeOf40 for Packed 3-vectors is 12 (was 16). It is a fix, but check any buffer layouts that relied on the old size.

Added

keid-core-0.1.11.1

  • Texture.fromAllocatedImage.
  • Resource.Image.Downsample.mipPyramid, the downsampler that used to live in the sky-playground demo.
    • The Image.DstImage constructor is exported.
    • Image.allocateDstMipFor.
  • Worker.merge1, merge2, merge3, merge4 and mergeT: the spawnMerge* functions with the function in the last position.
  • Worker.mergeNeq1 only publishes the result when it differs from the previous one.
  • Worker.merge1M for the times you absolutely must do some MonadUnliftIO m in reaction to the change.
  • Resource.Static.collection splices the record type and fills it with the source paths.
  • MonadTrans Bound instance.
  • External.Params, a wrapper for HKD pipeline collections that keeps the value in a Var.
  • External.bindGraphics to bind the most recent pipeline version.
  • External.spawnReflect_ keeps the loaded stages and reflection without further processing, so they can be shared.
  • Offscreen.settingsTexture and Offscreen.settingsCubemap as baselines.
  • AllocatedImage.aiName.

keid-render-basic-0.1.12.0

  • Resource.Font.Ktxf, the texture + atlas + shaping font container.
    • Text is shaped once with Ktxf.shape and placed with the pure Ktxf.place, so resizing a box doesn’t touch the fonts.
    • Long lines wrap to the box width and align per line. inputBreak picks the line breaking strategy.
  • Render.Font.Msdf.* models and the pMsdf pipeline, with pSoftmask as its SoftMask variant.
  • Specialization constants in the common Lit code, and thus in all the lit pipelines, set with sLitSpec in Settings. External pipelines react to the change in the specialization constants.
  • Settings is observable (pSettings).
  • Base{white} built-in texture.
  • Engine.UI.Message.Input derives Generic.

keid-ui-dearimgui-0.1.4.0

  • Render.ImGui.Widget, composable widgets built on top of keid-frp-banana. It brings in a whole new dependency set, but not much.

Upstream

  • ktx-codec-0.1.0.0 makes editing KTX2 files simpler: Codec.Ktx2.Ktx2, Codec.Ktx2.Read.fromFile, and lookup/insertBytes/insertNumber/insertText in Codec.Ktx.KeyValue.
  • geomancy-0.3.0.1: Lift and Serialise instances for data (opt-out with the th-lift and serialise flags).
  • dear-imgui-2.5.0: inputPassword, addFontDefaultBitmap and addFontDefaultVector.

Tools and templates

  • A new project template: stack new mygame gitlab:keid/quickstart (very WIP, see https://gitlab.com/keid/stack-templates). It comes with an apecs world scaffold, sprites, MSDF text, and keyboard and mouse events. Files put into assets/textures/ become fields of the texture Collection record.
  • weld: translate-x:N, translate-y:N and translate-z:N transforms. Unrecognized transform arguments are an error now (Unexpected transform: ...).

Demos and examples

  • demos/pbr got a dragon.
  • demos/sky-playground uses ktxf fonts and the mip downsampler from keid-core.

Fixed

  • keid-core: Specialization.packConstData for the Float->Word32 bitcast.
  • keid-core rebuilt on every file change. --version is no longer spliced by Template Haskell and prints Keid Engine <version>.
  • keid-render-basic: AO texture application in Material, see the notes in Breaking.
  • rio-0.1.25.0: warnings with newer GHC versions, and a workaround for GHC #26479.
  • spirv-reflect-ffi-0.4 and 0.4.1:
    • Windows build (size_t is bound as CSize).
    • Recursive TypeDescription/BlockVariable (buffer_reference/PhysicalStorageBuffer) used to never finish inflating.
    • The built_in sentinel (0xFFFFFFFF) decodes to Nothing.
  • spirv-reflect-types-0.4: TYPE_FLAG_REF label was aliased to ARRAY.
  • ktx-font-0.2.0.0: initialCursorDown really advances the lines downwards, and stacked marks land on the correct side of the glyph.
  • kb-text-layout-0.1.2.0: emergency line breaks no longer split a ligature or a shaping cluster.
  • kb-text-shape-0.2.1.0: fonts with non-UTF-8 name records (e.g. Mac Roman) load instead of failing.
  • demos/sky-playground: the cubemap flip in the irradiance shader.
  • Texture compression how-to: the ktx transcode examples were missing line continuations.
#26479