DevTools
Traquez les problèmes de layout, de hit-testing, de rendu et de performance avec un overlay d’une ligne, un panneau autonome et une Console structurée et bornée.
Inspecteur dans la fenêtre
En développement, attachez l’overlay à votre racine. Au survol, il entoure le rect du nœud d’un cadre en pointillés et affiche sa taille et le nom du composant. L’overlay est pass-through — il n’intercepte ni les clics ni le défilement — et le survol ne déclenche que des mises à jour au niveau du dessin, jamais de relayout.
fn mountUi(cx: *ui.Cx, scope: *ui.Scope) anyerror!*ui.Node {
const root = try mountProductUi(cx, scope);
// Development only: hover highlight with size + component name.
_ = try ui.devtools.overlay.attach(cx, scope, root, .{});
return root;
}L’état de l’overlay vit sur le scope que vous passez ; quand ce Scope est libéré, l’overlay disparaît avec lui. Utilisez-le dans la fenêtre du produit pour savoir « qui occupe cet espace ? » ; utilisez le panneau pour un diagnostic complet. Les deux lisent l’état réel de Node / Cx — aucun modèle miroir à maintenir pour le débogage.
Diagnostic par symptôme
hit_behavior du nœud touchésetText / setTextContent ? Ces API comparent et marquent elles-mêmes sizing / render dirtynode.style directement ne marque rien comme dirty ; utilisez node.setStyle(alloc, .width, v), qui choisit le bon niveau de dirty pour chaque champLe panneau DevTools
Pour les vues complètes Elements, Components, Console et Performance, utilisez ui.devtools.mountPanel(cx, target, opts). Le panneau a son propre Cx et observe un Cx target distinct ; en général, on le place dans sa propre fenêtre avec MultiWindowApp pour qu’il ne masque jamais l’UI du produit. Le target doit rester vivant tant que le panneau est utilisé.
const std = @import("std");
const ui = @import("ui");
const zenit_app = @import("zenit_app");
// mountProductUi: your app's ordinary mount function (see above).
var g_target_cx: ?*ui.Cx = null;
fn mountDevTools(cx: *ui.Cx, scope: *ui.Scope) anyerror!*ui.Node {
_ = scope;
const target = g_target_cx orelse return error.TargetNotReady;
return ui.devtools.mountPanel(cx, target, .{ .title = "My App DevTools" });
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
var application = zenit_app.MultiWindowApp.init(gpa.allocator(), .{});
defer application.deinit();
const product = try application.createWindowWith(.{
.window = .{ .width = 900, .height = 640, .title = "My App" },
}, mountProductUi);
g_target_cx = product.cx;
const tools = try application.createWindowWith(.{
.window = .{ .width = 760, .height = 560, .title = "DevTools" },
}, mountDevTools);
_ = ui.devtools.setViewMode(tools.cx, "performance"); // optional start tab
try application.run();
}C’est ainsi qu’est structuré zig build devtools-probe dans le dépôt. ui.devtools expose aussi setViewMode, setTreeFilter, setConsoleFilter et consorts, pour que les sondes et les tests E2E pilotent le panneau par programme.
Quatre vues, six onglets de détail
Une ligne Elements / Components sélectionnée, passez de Layout, Style, State, Events, Render à Trace. Certaines valeurs de Style sont modifiables en direct ; Render / Trace montrent pourquoi un nœud est devenu dirty et ses événements récents. La recherche dans l’arbre porte sur les tags, les #id et les noms de composant. Avec ui.devtools.source_link configuré, les lignes de composant peuvent ouvrir leur définition dans votre éditeur.
Journalisation Console
Chaque ui.Cx possède une Console thread-safe et bornée. Un seul appel peut écrire dans le terminal et conserver un événement structuré pour DevTools et le harness E2E ; l’historique capturé avant l’ouverture du panneau s’affiche aussi.
const log = cx.console();
log.info("application ready", .{});
log.scoped("network").warn("retry {d}", .{attempt});
// Plain level methods don't record a call site; writeAt does.
log.writeAt(.err, @src(), "save failed: {s}", .{@errorName(err)});Les niveaux sont debug, log, info, warn et err. Les équivalents de la console du navigateur sont aussi là : group / groupEnd, count, time / timeEnd, assert, trace, inspect et table.
Les méthodes de niveau simples n’enregistrent pas le site d’appel. Pour cliquer sur une ligne de log et arriver dans votre éditeur, utilisez writeAt(level, @src(), …) et définissez la racine des sources et la commande d’éditeur avec ui.devtools.source_link.configure (par défaut : code --goto).
Configurer la capture
const app = try zenit_app.App.init(allocator, .{
.console = .{
.terminal_level = .info, // null disables the terminal sink
.capture_level = .debug, // null disables in-memory capture
.max_entries = 10_000,
.max_bytes = 8 * 1024 * 1024,
.max_entry_bytes = 64 * 1024,
},
});Sans console explicite, zenit_app choisit des valeurs par défaut selon le mode de build :
Debug.debug.debugReleaseSafe.info.infoReleaseFast / ReleaseSmall.warnnull (désactivée)La Console reprend la partie capture et consultation de la console du navigateur ; ce n’est pas un REPL Zig / JavaScript. Les groups sont pour l’instant indentés mais non repliables, et table se rabat sur du texte. L’API complète, les règles de threads et de durée de vie et des exemples de harness se trouvent dans docs/CONSOLE.md du dépôt.
Performance : inactif ou bloqué
La vue Performance ne se fige pas sur « les N dernières frames rendues ». Elle observe le target en continu par buckets de 100 ms de temps réel — 64 au total, soit une fenêtre glissante d’environ 6.4 s — et calcule les FPS comme la moyenne des 10 derniers buckets (environ 1 s). Quand le target ne produit aucune frame pendant plus de 0.7 s, l’affichage indique FPS: 0 — idle (not rendering) : le framework saute délibérément des frames pour économiser l’énergie, il n’est pas bloqué à 0 FPS.
Points d’entrée des tests
zig build test-headless
zig build test-ui
zig build test-render
zig build hello-buttonAvant la publication
- ✓
Désactivez l’UI de débogage. Retirez l’overlay d’inspection, ou conditionnez-le à une configuration de debug.
- ✓
Vérifiez la saisie dans une vraie fenêtre. Clavier, IME, presse-papiers et VoiceOver.
- ✓
Passez les contrôles de build. Les steps de test headless, UI et render.
- ✓
Vérifiez la politique de Console. Le niveau terminal et la capture en Release sont ceux voulus, et les logs ne contiennent aucune donnée sensible.
- ✓
Figez les versions. Verrouillez la révision de zenit et notez la version de Zig ciblée.



