---
title: "DevTools — zenit Zig UI Doku"
description: "Finden Sie Layout-, Hit-Testing-, Rendering- und Performance-Probleme mit einem einzeiligen Overlay, einem eigenständigen Panel und einer begrenzten…"
url: https://zenit.z.express/de/docs/advanced/devtools
language: de
alternate_en: https://zenit.z.express/docs/advanced/devtools.md
alternate_zh: https://zenit.z.express/zh/docs/advanced/devtools.md
alternate_es: https://zenit.z.express/es/docs/advanced/devtools.md
alternate_ja: https://zenit.z.express/ja/docs/advanced/devtools.md
alternate_ko: https://zenit.z.express/ko/docs/advanced/devtools.md
alternate_fr: https://zenit.z.express/fr/docs/advanced/devtools.md
project: zenit v0.1.0-alpha (Zig 0.15.2, macOS)
source: https://github.com/version-next/zenit
---

# DevTools

Finden Sie Layout-, Hit-Testing-, Rendering- und Performance-Probleme mit einem einzeiligen Overlay, einem eigenständigen Panel und einer begrenzten, strukturierten Console.

## Inspektor im Fenster

Hängen Sie das Overlay während der Entwicklung an Ihre Wurzel. Beim Hover umrandet es das Rect des Knotens gestrichelt und zeigt Größe und Komponentennamen. Das Overlay ist pass-through – es fängt weder Klicks noch Scrollen ab –, und Hover löst nur Updates auf Paint-Ebene aus, niemals ein Relayout.

`main.zig`

```zig
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;
}
```

Der Zustand des Overlays hängt am übergebenen `scope`; wird dieser Scope freigegeben, verschwindet auch das Overlay. Nutzen Sie es im Produktfenster, um zu klären „Wer belegt diesen Platz?“; für die vollständige Diagnose nehmen Sie das Panel. Beide lesen den echten Node-/Cx-Zustand – kein Spiegelmodell, das Sie fürs Debugging pflegen müssten.

## Diagnose nach Symptom

| Symptom | Zuerst prüfen |
| --- | --- |
| Inhalt falsch ausgerichtet | Rect, Padding, Gap und Direction des Elternknotens (Elements → Layout) |
| Leere Bereiche sind anklickbar | Größe und `hit_behavior` des getroffenen Knotens |
| Textdaten geändert, Anzeige nicht | Haben Sie TextProps-Felder geändert, ohne `setText` / `setTextContent` aufzurufen? Diese APIs vergleichen selbst und markieren sizing / render dirty |
| Layout ignoriert neue Breite | Eine direkte Zuweisung an `node.style` markiert nichts als dirty; verwenden Sie `node.setStyle(alloc, .width, v)`, das pro Feld die richtige Dirty-Stufe wählt |
| Wird mit der Zeit langsamer | Wiederholte Mounts, nicht mit ihrem Scope freigegebene Effects, Allokationen pro Frame (Performance → Summary / Rebuild) |

## Das DevTools-Panel

Für die vollständigen Ansichten Elements, Components, Console und Performance verwenden Sie `ui.devtools.mountPanel(cx, target, opts)`. Das Panel hat einen eigenen Cx und beobachtet einen separaten Target-Cx; üblicherweise liegt es mit [MultiWindowApp](https://zenit.z.express/de/docs/advanced/multi-window) in einem eigenen Fenster, damit es die Produkt-UI nie verdeckt. Der Target muss am Leben bleiben, solange das Panel genutzt wird.

`main.zig`

```zig
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();
}
```

So ist `zig build devtools-probe` im Repo aufgebaut. `ui.devtools` bietet außerdem `setViewMode`, `setTreeFilter`, `setConsoleFilter` und weitere Funktionen, mit denen Probes und E2E-Tests das Panel programmatisch steuern.

[![Zenit DevTools Elements panel with a box selected and its layout details](https://zenit.z.express/media/devtools-elements.png?v=1c99ec3edc)](https://zenit.z.express/media/devtools-elements.png?v=1c99ec3edc)

Links der Live-UI-Baum; wählen Sie einen Knoten, zeigt der Layout-Tab rechts sein berechnetes Rect, Padding, Sizing und die Flex-Eigenschaften. Der Hand-Cursor im Bild ist der virtuelle Cursor des harness.

### Vier Ansichten, sechs Detail-Tabs

| Ansicht | Beantwortet |
| --- | --- |
| **Elements** | Wie sieht die echte Knotenhierarchie aus – tag / id / text, Layout und Hit-Bereich? |
| **Components** | Welche Knoten bilden Komponentengrenzen, und wo liegen ihr Zustand und ihr Owner-Scope? |
| **Console** | Welche strukturierten Logs hat der Target-Cx erfasst, und wurde etwas verdrängt oder verworfen? |
| **Performance** | Rendert der Target oder ist er idle? Was kosten Layout / Render / Cache / Interaction? |

Bei ausgewählter Elements-/Components-Zeile wechseln Sie zwischen **Layout, Style, State, Events, Render und Trace**. Einige Style-Werte lassen sich live bearbeiten; Render / Trace zeigen, warum ein Knoten dirty wurde, und seine letzten Events. Die Baumsuche findet Tags, `#id` und Komponentennamen. Mit konfiguriertem `ui.devtools.source_link` springen Komponentenzeilen direkt zur Definition in Ihrem Editor.

## Console-Logging

Jeder `ui.Cx` besitzt eine eigene threadsichere, begrenzte Console. Ein Aufruf kann ins Terminal schreiben und zugleich ein strukturiertes Event für DevTools und den E2E-harness behalten; auch vor dem Öffnen des Panels erfasste Einträge werden angezeigt.

`logging.zig`

```zig
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)});
```

Die Level sind `debug`, `log`, `info`, `warn` und `err`. Auch die Gegenstücke der Browser-Konsole sind vorhanden: `group` / `groupEnd`, `count`, `time` / `timeEnd`, `assert`, `trace`, `inspect` und `table`.

| Panel-Bereich | Zweck |
| --- | --- |
| **Clear** | Leert den Console-Speicher des Targets selbst, nicht nur die Ansicht. |
| **Filter** | Groß-/Kleinschreibung-unabhängige Suche in message und scope; kombiniert mit dem Level-Filter. |
| **Levels** | Debug / Log / Info / Warn / Error beliebig kombiniert ein- und ausschalten. |
| **Log-Liste** | Level, scope, Nachricht, group-Einrückung und optionale Quellposition; Auto-Follow pausiert, sobald Sie vom Ende wegscrollen. |
| **Statusleiste** | shown / captured / evicted / dropped – unterscheidet Filterung, Verdrängung und Verlust. |

[![Zenit DevTools Console with debug, info, warn and error entries](https://zenit.z.express/media/devtools-console.png?v=1411f611cd)](https://zenit.z.express/media/devtools-console.png?v=1411f611cd)

Die Logs landeten vor dem Öffnen des Panels im begrenzten Speicher des Target-Cx; scope, Level und Quellposition bleiben erhalten.

[![Zenit DevTools Console filtered to the network scope](https://zenit.z.express/media/devtools-console-filter.png?v=acfa3d9446)](https://zenit.z.express/media/devtools-console-filter.png?v=acfa3d9446)

Filter und Levels wirken lokal in DevTools zusammen; aus dem Speicher des Targets wird nichts entfernt.

[Video](https://zenit.z.express/media/devtools-console.mp4?v=05e8c163e3)

Eine echte Zwei-Fenster-App: Der virtuelle Cursor wechselt von Elements zu Console, fokussiert Filter und tippt network. Direkt aus dem Metal-Drawable des DevTools-Fensters aufgezeichnet.

Die einfachen Level-Methoden zeichnen keine Aufrufstelle auf. Um per Klick auf eine Logzeile im Editor zu landen, verwenden Sie `writeAt(level, @src(), …)` und setzen Quellwurzel und Editor-Befehl mit `ui.devtools.source_link.configure` (Standard: `code --goto`).

### Erfassung konfigurieren

`main.zig`

```zig
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,
    },
});
```

Ohne explizites `console` wählt `zenit_app` die Standardwerte nach Build-Modus:

| Build-Modus | Terminal | Erfassung |
| --- | --- | --- |
| `Debug` | `.debug` | `.debug` |
| `ReleaseSafe` | `.info` | `.info` |
| `ReleaseFast / ReleaseSmall` | `.warn` | `null` (aus) |

> WARNING
> 
> **Release-Builds erfassen standardmäßig nicht.** Unter ReleaseFast / ReleaseSmall sieht DevTools keinen Verlauf. Braucht ein Produktions-Build ihn, setzen Sie `capture_level` explizit – und halten Sie Tokens, Passwörter und personenbezogene Daten aus Ihren Logs heraus.

Die Console bildet die Erfassungs- und Anzeigeseite der Browser-Konsole nach; sie ist kein Zig-/JavaScript-REPL. Groups werden derzeit nur eingerückt, lassen sich aber nicht interaktiv einklappen, und `table` wird als Text ausgegeben. Vollständige API, Thread- und Lebensdauerregeln sowie harness-Beispiele stehen in `docs/CONSOLE.md` im Repo.

## Performance: idle oder hängend

Die Performance-Ansicht friert nicht auf „den letzten N gerenderten Frames“ ein. Sie beobachtet den Target fortlaufend in 100-ms-Wanduhr-Buckets – 64 davon, ein rollendes Fenster von etwa 6.4 s – und berechnet die FPS als Mittel der letzten 10 Buckets (etwa 1 s). Liefert der Target länger als 0.7 s keinen Frame, zeigt die Anzeige `FPS: 0 — idle (not rendering)`: Das Framework lässt bewusst Frames aus, um Energie zu sparen, und hängt nicht bei 0 FPS.

100MS BUCKETS

Nach dem Frame-Stopp läuft das Diagramm weiter und zeichnet Nullen auf; die Anzeige sinkt mit jedem leeren Bucket und wechselt nach 0.7 s auf idle – ein veralteter Wert wird nie als aktuell ausgegeben.

[![Zenit DevTools Performance showing FPS 0 idle (not rendering) with timing metrics](https://zenit.z.express/media/devtools-performance.png?v=41f18a12a0)](https://zenit.z.express/media/devtools-performance.png?v=41f18a12a0)

Der statische Target rendert nicht mehr; DevTools aktualisiert sich selbst mit etwa 10 Hz, damit das Diagramm weiterläuft, und die Metriken für Layout, Render, Cache, Focus und Interaction bleiben lesbar.

| Anzeige | Bedeutung |
| --- | --- |
| FPS + rollendes Diagramm | Wanduhr-Buckets; ein Bucket ohne Frames zählt 0 und wird als neutrale Grundlinie gezeichnet, nie als veralteter Wert |
| Timing | CPU-Wanduhrzeit des letzten Target-Frames: Layout, Erzeugung der Render-Befehle usw. |
| Summary / Interaction | Hit-Registry, mouse-hit, Redraw-Streak, Focus und Interaction-Rebuilds |
| Cache / Rebuild | Retained-Cache-Treffer / -Fehlschläge, Full- / Partial-Rebuilds |

## Test-Einstiegspunkte

```sh
zig build test-headless
zig build test-ui
zig build test-render
zig build hello-button
```

> WARNING
> 
> **Führen Sie zig test nicht auf interne Dateien aus.** zenit-Module importieren über Verzeichnisgrenzen hinweg; verwenden Sie daher die in `build.zig` definierten Test-Steps, sonst droht `import of file outside module path`. Die vollständige Liste steht unter [Befehle](https://zenit.z.express/de/docs/reference/commands); für Tests im echten Fenster siehe [E2E-harness](https://zenit.z.express/de/docs/advanced/e2e).

## Vor dem Release

-   **Debug-UI abschalten.** Entfernen Sie das Inspektor-Overlay oder binden Sie es an eine reine Debug-Konfiguration.
    
-   **Eingabe im echten Fenster prüfen.** Tastatur, IME, Zwischenablage und VoiceOver.
    
-   **Build-Gates ausführen.** Die Test-Steps für headless, UI und Render.
    
-   **Console-Richtlinie prüfen.** Terminal-Level und Erfassung im Release sind wie beabsichtigt, und die Logs enthalten keine sensiblen Daten.
    
-   **Versionen festschreiben.** Fixieren Sie die zenit-Revision und halten Sie die Ziel-Zig-Version fest.
