# Inkscape

Ein Modell steuert Inkscape 1.4 über den Hub, um auf zwei Ebenen eine Visitenkarte zu gestalten. Inkscape ist hier die einzige Anwendung, bei der nichts zu starten ist: Der Hub führt für jedes Skript einen Python-Prozess aus. Die Seite nennt den Text, das Skript, die Antworten des Hubs und die Aufnahme.

*Eine Zeichnung, die ein Skript erzeugt hat und die in Inkscape geöffnet ist: Sie ist eine gewöhnliche SVG-Datei, deren XML-Knoten sich von Hand bearbeiten lassen.*

## Fakten

- Erprobte Version: 1.4
- Modus: `cli`

## Inkscape aktivieren

Es gibt weder eine Brücke noch ein Fenster. Der Hub sucht `/usr/bin/python3`, `/usr/bin/inkscape` und die Inkscape-Erweiterungen in `/usr/share/inkscape/extensions`. Die gesamte Vorbereitung ist ein Eintrag in `~/.config/libremodular-mcp/config.toml`, nach `libremodular-mcp init`:

```toml
[apps.inkscape]
enabled = true
```

Auf einem frischen Debian 13 braucht `import inkex` außerdem `python3-tinycss2`, das das Paket `inkscape` nicht nachzieht: `sudo apt install inkscape python3-tinycss2`.

`get_state` für `hub` listete Inkscape als verbunden im Modus `cli` auf, mit der Version, die Inkscape meldete:

**Antwort des Hubs**

```json
{
  "app": "hub",
  "app_version": "0.1.0",
  "bridge_version": null,
  "captured_at": "2026-10-21T12:47:13.608Z",
  "connected": true,
  "content_origin": "hub",
  "screenshot": null,
  "state": {
    "modules": [
      {
        "app_version": "1.4",
        "bridge_version": null,
        "connected": true,
        "mode": "cli",
        "name": "inkscape"
      }
    ]
  },
  "warnings": []
}
```


## Dem Modell gegebener Text

```text
In Inkscape, lay out a name card, A6 landscape (148 by 105 mm). Dark blue background (#1c385c), a copper circle (#c25438) in the top-left corner, the name "Alice Martin" in white and large, a thin amber line (#f2b344) under it, then the role "Sound engineer" in light grey and smaller. Put the background shapes on a layer named "Background" and the text on a layer named "Text".
```


Vor dem Schreiben rief das Modell `get_state` für `inkscape` auf. Der `state` war leer, und eine Warnung lautete `no document yet: the working document is created by the first script`.

## Geschriebenes Skript

Ein Modell, Claude Sonnet 5.5, schrieb dieses Skript nach dem Leitfaden und nach diesem Zustand. Es ist kein Skript aus den Tests des Projekts. Zwei Dinge stammen aus dem Leitfaden: Das Skript entfernt zuerst die Kindelemente der Wurzel, weil das Dokument von einem Skript zum nächsten erhalten bleibt, und es setzt `cx`, `cy` und `r` des Kreises einzeln, weil die beiden Argumente von `inkex.Circle.new`, wie der Leitfaden warnt, keinen Mittelpunkt ergeben.

**Geschriebenes Skript**

```python
import json
import os

import inkex

document = inkex.load_svg(os.environ["LMM_DOCUMENT"])
svg = document.getroot()
for child in list(svg):
    svg.remove(child)
svg.set("width", "148mm")
svg.set("height", "105mm")
svg.set("viewBox", "0 0 148 105")

background = svg.add(inkex.Layer.new("Background"))
panel = inkex.Rectangle.new(0, 0, 148, 105)
panel.style = {"fill": "#1c385c"}
background.add(panel)
disc = inkex.Circle()
disc.set("cx", "20")
disc.set("cy", "20")
disc.set("r", "9")
disc.style = {"fill": "#c25438"}
background.add(disc)
rule = inkex.Rectangle.new(20, 62, 108, 0.8)
rule.style = {"fill": "#f2b344"}
background.add(rule)

texts = svg.add(inkex.Layer.new("Text"))
for content, y, size, colour, weight in [("Alice Martin", 56, 12, "#ffffff", "bold"), ("Sound engineer", 76, 6, "#cfd4da", "normal")]:
    line = inkex.TextElement()
    line.text = content
    line.set("x", "20")
    line.set("y", str(y))
    line.style = {"fill": colour, "font-size": f"{size}px", "font-family": "sans-serif", "font-weight": weight}
    texts.add(line)

document.write(os.environ["LMM_DOCUMENT"])
print("LMM_RESULT: " + json.dumps({"layers": [layer.label for layer in svg.descendants().filter(inkex.Layer)], "elements": len(list(svg.descendants()))}))
```


## Antwort des Hubs

**Antwort des Hubs**

```json
{
  "app": "inkscape",
  "duration_ms": 151,
  "error": null,
  "result": {
    "elements": 8,
    "layers": [
      "Background",
      "Text"
    ]
  },
  "status": "ok",
  "stderr": "",
  "stdout": "",
  "truncated": false
}
```


Das Skript lief in 151 ms: Ein Python-Prozess wurde gestartet und beendet. Das Skript gab sein `result` in der letzten Zeile aus, nach `LMM_RESULT: `, so gibt ein Inkscape-Skript einen Wert zurück. `get_state` beschrieb danach das Arbeitsdokument und gab eine Aufnahme zurück:

**Antwort des Hubs**

```json
{
  "app": "inkscape",
  "app_version": "1.4",
  "bridge_version": null,
  "captured_at": "2026-10-21T12:47:14.185Z",
  "connected": true,
  "content_origin": "document",
  "screenshot": "$XDG_RUNTIME_DIR/libremodular-mcp/captures/inkscape-20261021T124713832Z.png",
  "state": {
    "element_count": 8,
    "height": "105mm",
    "layers": [
      {
        "id": null,
        "label": "Background"
      },
      {
        "id": null,
        "label": "Text"
      }
    ],
    "width": "148mm"
  },
  "warnings": []
}
```


## Erzeugtes Bild

Die Aufnahme ist das Arbeitsdokument, von `inkscape` selbst exportiert, 559 × 397 Pixel für eine Karte von 148 × 105 mm. Der Text ist in der Schrift `sans-serif` dieses Rechners gezeichnet, ein anderer Rechner zeichnet ihn in seiner eigenen. Das Pixel oben links in der Aufnahme ist `#1C385C` und das im Kreis `#C25438`.

![Eine dunkelblaue Karte mit einem kupferfarbenen Kreis oben links, dem Namen Alice Martin in Weiß, einer bernsteinfarbenen Linie und der Rolle Sound engineer in Grau.](https://libremodular.davalan.fr/images/applications/inkscape-name-card.png)

*Die Aufnahme des Arbeitsdokuments nach dem Skript, wie der Hub sie exportiert hat.*


> **Grenze**
>
> Nicht ausprobiert: ein gleichzeitig mit dem Hub geöffnetes Inkscape-Fenster und ein größeres Dokument als dieses.

[Referenz-Leitfaden im Repository](https://github.com/RonanDavalan/LibreModular-MCP/blob/main/docs/modules/inkscape.md)

