Repository navigation
Releases: dyike/keel
Release list
v0.4.0
Desktop builds without cgo, platform accessibility, paint-only frames, and a testable app.
Desktop targets now build and run with CGO_ENABLED=0.
- macOS: CoreText glyph rasterization (
ui/theme), OpenGL, Cocoa initialization, Metal, the headless Metal context and the window itself (gio/app) drive AppKit and Metal through purego instead of cgo. The macOS window logic is shared over plain handles between the two bindings. - Linux: EGL, xkbcommon, Vulkan, X11 and Wayland windows all load without cgo, so the Linux desktop path builds and runs with
CGO_ENABLED=0. A newlinux-cgo-freeCI job covers it. - cgo stays the default where it already worked;
-tags puregoorCGO_ENABLED=0selects the new bindings. No.c,.mor.hfiles were added.
Accessibility reaches all three desktop platforms.
ui/windowexposes Keel windows to macOS accessibility (AppKit), Linux AT-SPI and Windows UI Automation, including scroll areas and what is scrolled out of view. Keel's elements are built from the semantic tree, so a window reports what it draws rather than a parallel description.- The semantic node that holds keyboard focus is marked, reported to VoiceOver, AT-SPI and UI Automation, and assistive technology can move keyboard focus with
giofocusing a semantic node from any goroutine. gio/appexposes the semantic tree and accepts synthesized input; a newdocs/accessibility.mdcovers the model.
Applications can be tested in memory.
window.OpenHeadlessopens a window in memory with no native window and noMain: it lists elements askeel-mcpreports them, finds them by visible text, clicks, types, presses keys, scrolls, resizes and takes screenshots, and closing it never quits the process.- The new
ui/window/windowtestpackage wraps it fortesting.TB(app.Click("Save"),app.Want("Hello, Ada!"));keel newnow writes such a test and a CI workflow. keel runkeeps application state across reloads, so editing a view no longer resets navigation.
Rendering and CPU.
ImageOp.PaintQuads(PaintTintedQuadson Metal) draws a glyph run as one operation instead of seven per glyph; a 3,200-glyph benchmark went from 0.99 to 0.52 ms a frame with byte-identical pixels. Keel's CoreText atlas batches consecutive masks on one page.el.Context.AnimatingAmbientticks ambient indicators (spinners, indeterminate progress, skeleton shimmer) at a shared 30 Hz instead of every display frame: the gallery's Button page went from 27-29% to about 18% CPU. Transitions, scrolling and input keep full frame rate; reduced motion requests nothing.- Large immutable Metal buffers are pooled, Tab targets are collected only when Tab is pressed, and node state is cached per frame.
- Frames that only advance paint-time animation are repainted, and
gio/inputreports pending input.
CLI.
-hexits 0 without an error line;keel versionnames the commit for source builds;keel doctorand generated projects agree on Go 1.26.1.keel new -langgenerates English by default (zh-CNfor Chinese); unknown values are refused.
Validation: gofmt, vet, all module tests, go test -race on ui/ and internal/, the Gio and go-text patch tests, the offline component check, CGO_ENABLED=0 GOOS=windows go build ./..., and cgo-free builds of the whole module on macOS. The Linux no-cgo path runs in its new CI job. The macOS real-window tests could not run on the release machine: with the screen locked (CGSSessionScreenIsLocked), windows never receive a new drawable, and v0.3.8 fails them the same way there. Run KEEL_DESKTOP=1 go test -run RealWindows ./ui/window on an unlocked machine before relying on window-level behavior.
本版是 0.4.0:macOS 与 Linux 桌面都能在 CGO_ENABLED=0 下构建和运行;三个桌面平台都接入了无障碍(AppKit、AT-SPI、UI Automation),键盘焦点可读可改;新增 window.OpenHeadless 与 ui/window/windowtest,应用视图可在内存中测试,keel new 会生带测试和 CI 的项目;ImageOp.PaintQuads 把一段字形绘制合成一次操作,环境指示器按共享 30 Hz 刷新。macOS 真窗口测试因发版机器处于锁屏状态无法运行,v0.3.8 在同机同样失败,请在解锁的机器上补跑。
Compare: v0.3.8...v0.4.0
v0.3.8
Redraw macOS windows during native resize and present glass frames in the transaction.
ui/windowsetslayerContentsRedrawDuringViewResizeandtopLeftlayer contents placement on the NSView, plus a non-scaling, top-leftcontentsGravityon its layer (chosen forcontentsAreFlipped). AppKit now redraws each step of an animated resize instead of scaling cached contents, so text no longer stretches while an ordinary or frosted-glass window is resized. The configuration is dispatched once per window with retained handles, so neither the window goroutine nor the frame lock waits for AppKit.- The glass renderer enables
presentsWithTransactiononly for a frame whose size changed and presents it insideWindow.Runon the main thread, so new bounds and pixels become visible together; GPU scheduling stays off the main thread. Stable-size frames, including recovery from idle drawable trimming and fixed-size scrolling, stay asynchronous. TestRealWindowsResizedrives 60 Gio size requests, 60 center-preserving native frame changes and 4 native zoom/restore transitions for both ordinary and frosted-glass windows, then checks the view and layer policies, full-resolution drawables, synchronous presents only while resizing, 60 scroll steps without them, and zero idle frames and CPU after trimming. The fix adds no cgo and no Gio patch.
Validation: gofmt, vet, module tests, the offline component check, CGO_ENABLED=0 GOOS=windows go build ./..., and KEEL_DESKTOP=1 go test -run RealWindows ./ui/window on macOS.
本版修正 macOS 窗口缩放:AppKit 在动画缩放的每一步重绘视图,不再拉伸缓存画面,普通窗口和磨砂玻璃窗口里的文字不再变形;玻璃窗口只在尺寸变化的帧里于主线程事务中提交,尺寸不变的帧保持异步。修复位于 ui/window,没有新增 cgo,也没有修改 Gio。
Compare: v0.3.7...v0.3.8
v0.3.7
Add experimental declarative animation primitives.
ui/motionprovides frame-time driven animation values: physics springs, tweens and cubic-bezier easing, keyframes and repeat modes, inertia, stagger, presence, color mixing and range mapping. Sampling usesel.Context.Now; only unsettled values callContext.Animating, so a settled application stays event-driven, and reduced motion jumps directly to the declared target.Transformis paint-only, so layout and automation bounds stay unchanged.LayoutGroupperforms position-only FLIP forDivelements in one scroll coordinate space.PointerGlowdraws a cursor-origin glow and ripple driven by pointer movement, andConfettikeeps an uncapped reusable particle slice, emitting and updating without allocating once capacity is available; both ownDecorate.Transform,PointerGlow,ConfettiandLayoutGroupreplace an element's existingDecoratecallback; wrap an element if it must also use another decoration. The API is experimental and may change.- The module depends on
ui/el,ui/core,ui/themeand Gio, never onui/kitorui/window, and is listed in theinternal/depstable as opt-in for heavy dependencies.examples/motion(go run ./examples/motion -section effects) demonstrates the pointer effects and an order confetti burst.
Validation: gofmt, vet, module tests, go test -race ./ui/motion, the offline component check from a clean checkout, and CGO_ENABLED=0 GOOS=windows go build ./....
本版新增实验性的声明式动效基础能力 ui/motion:弹簧、补间、缓动、关键帧、惯性与交错,只作用于绘制的变换、FLIP 布局组、指针光晕/波纹和彩纸,并附 examples/motion 示例。API 尚不稳定。
Compare: v0.3.6...v0.3.7
v0.3.6
Debounce idle GPU reclamation, pool small Metal stores, and add shared images.
gio/app(macOS, iOS): idle GPU reclamation is debounced.gpu.Idleruns 250 ms after the window last presented a frame, and on macOSgpu.Trimplus the drawable shrink run after 1 s. The timer is set once and moved, not recreated per frame, so a window redrawn by externalInvalidatecalls no longer marks textures volatile and rebuilds GPU state every frame (textureSetVolatilealone was about 12% of Mirage's CPU samples). Other contexts still callgpu.Idledirectly.gio/gpu/internal/metal: Go-memory stores of buffers up to 4 KiB, the onesset*Bytesbuilds every rebuilt path from, are pooled by power-of-two class, at most 256 per class and emptied byTrim. A 60 Hz session allocated megabytes of them a second.gio/op/paint,gio/gpu,gio/internal/dirty:NewSharedImageOp(src, mu)is a mutable image its owner writes outside the frame. The renderer takesmuonly while readingsrc(texture creation, or the upload of changed areas once the version moved), and unchanged images never take it. A remote desktop client can draw tiles cut from its decoder framebuffer withSubImageinstead of copying them (about 60 MB for a 5K screen).maximumDrawableCountstays at 3:TestMetalResizeWindowstalled in 3 of 3 runs with 2.
All three patches are listed in third_party/README.md and carry their own tests.
Validation: gofmt, vet, module tests, the offline component check and CGO_ENABLED=0 GOOS=windows go build ./... from a clean checkout. TestEveryModuleIsListed reads untracked draft modules in the gitignored work/ directory and passes without it.
本版让空闲 GPU 回收改为防抖、池化 Metal 的小 buffer 存储,并新增可跨帧写入的共享图像。三个补丁都带自己的测试,记录在 third_party/README.md。
Compare: v0.3.5...v0.3.6
v0.3.5
Cut surface and mutable-image uploads, and add custom Info.plist keys.
paint.NewSurfaceOpdraws the current picture of apaint.Surfacewithout copying it; Metal wraps each new IOSurface in a texture throughnewTextureWithDescriptor:iosurface:plane:. A 4K video frame no longer takes a swizzle, a copy into tiles and an upload. Devices without the extension draw a transparent pixel.paint.NewMutableImageOpkeeps one texture per image and uploads only the areas changed since the texture's version, or the whole image when the texture fell further behind. Tinted textures re-tint the changed area only.paint.FilterLinearNoMipmapsamples without a mip chain for images drawn near their native size and skips the Metal CPU mipmap path. A 2880x1800 remote desktop screen repainted 30 times a second went from ~450 MB to ~324 MB footprint, live Go heap from 104 MB to 43 MB and GCs from 67 to 11 a minute.macos.info_plistandios.info_plistinkeel.jsonadd keys to the generated Info.plist, such asNSLocalNetworkUsageDescription. Values may be JSON strings, booleans, numbers, arrays and objects; keys Keel derives from other fields are reserved and rejected by name.- Password inputs center the mask vertically in single-line boxes taller than the line, across faces, text sizes and pixel scales.
Only Metal ran the surface and mutable-image paths in a real window. Both patches are listed in upstream-patches.md.
Validation: gofmt, vet and module tests from a clean checkout, CGO_ENABLED=0 GOOS=windows go build ./..., cgo-free native/cmd build, and the offline component check. One local run reported TestEveryModuleIsListed; it read untracked draft modules in the gitignored work/ directory and passes in a clean checkout.
本版让画面走 IOSurface 纹理、可变图像只上传变化区域,并支持在 keel.json 里补充 Info.plist 键,同时修正密码框遮罩垂直居中。Surface 和可变图像两条路径只在 Metal 真窗口中验证过。
Compare: v0.3.4...v0.3.5
v0.3.4
Fix macOS glass composition, launcher focus and idle rendering memory.
- Preserve native glass behind transparent Gio content and activate accessory windows when raised.
- Support accessory macOS app bundles through
macos.accessory. - Trim idle Metal scratch resources and spare full-size drawables while preserving the presented frame, full-resolution rendering and triple buffering.
- Reuse bundled macOS icons instead of retaining a duplicate runtime PNG.
- Add real-window coverage for material composition, focus, close/reopen, idle recovery, resize and minimize.
Validation: module tests and vet, native glass/focus regression checks, and downstream Void integration. Measured idle memory improvements and remaining resize peaks are documented in rendering-memory.md.
CI limitations: the Windows native menu test still fails its existing HBITMAP assertion. The main-branch race job exceeded the 5-second wall-clock limit in TestTableThreeHundredThousandRows (5.65s); it did not report a data race. Both tests are unchanged by this release. Cross-compilation, distribution and Wayland checks passed.
本版修复 macOS 毛玻璃合成、启动器焦点和闲置渲染资源回收,并复用应用包内图标。保留全分辨率渲染和三缓冲;闲置内存下降不代表窗口缩放峰值已消除。包含 PR #41、#42。
Compare: v0.3.3...v0.3.4
v0.3.3
v0.3.2
Font and glyph memory
- Prepare macOS fonts from native metadata and share immutable CoreText sources instead of eagerly parsing a second set of Go font tables.
- Carry exact native font and glyph identities into rasterization; preserve file/collection identities and Go fallback behavior for unsupported font paths.
- Render monochrome glyphs through alpha masks and Metal R8 textures. Bound colored/vector glyph caches and release resources when shapers become unreachable.
- Bound sparse coverage atlas growth and resolve wrapped bidirectional text using CoreText line order.
Targeted cache measurements: CPU glyph page capacity 32 MiB → 8 MiB; a 256-pixel GPU glyph page including mipmaps 352 KiB → 96 KiB. These measurements describe individual resources, not total application memory.
Validation includes full Go tests/vet, native font and bidi checks, pixel comparisons between mask and RGBA rendering, real macOS window updates, cross-platform compilation, and external module archive builds.
Known existing CI issue: the Windows native menu bitmap lifetime test fails in both this version and v0.3.1. The affected Windows menu code is unchanged; Windows amd64/arm64 compilation passes. See baseline CI.
PR: #39
v0.3.1
Cut retained allocations in icon rendering and font index decoding.
kit now reuses immutable icon render callbacks instead of rebuilding them, and the font scanner deduplicates glyph coverage while decoding the index. Both changes ship with allocation and decode benchmarks plus regression tests.
PR: #38
v0.3.0
Cuts per-frame and startup allocations across paint, GPU and text, and
tightens element lifetimes: elements now reuse frame nodes, so a node may
not outlive its element (breaking; see docs/el.md), icon variants and leased
glyph scratch are reused, path-space stroke outlines and frame nodes are
retained, startup font initialization allocates less, markdown follows theme
fonts, and empty carets stay clear of placeholder ink. Triple-buffered
drawable presentation is restored after the drawable-count experiment. The
font startup and stroke allocation measurements are recorded in the testing
notes.
Breaking: elements reuse frame nodes with checked lifetimes
(9c7e0c9).