Krita
Un modèle pilote Krita 5.2.9 par le Hub pour peindre une carte postale sur deux calques et l’enregistrer dans un fichier .kra. Le premier script a fonctionné. Cette page donne le texte, le script, les réponses du Hub et la capture, et dit comment le pont a été démarré : pas depuis Scripter, qui n’a pas été essayé.
Sur cette page
Démarrer Krita avec son pont
Le guide fait lancer le fichier du pont par l’opérateur depuis Scripter. Cette exécution n’a pas utilisé ce geste. Elle a démarré Krita sur un serveur X virtuel, dans un profil neuf, avec une extension de démarrage dont tout le __init__.py exécute le fichier du pont :
xvfb-run -a krita --nosplash
exec(open('/usr/share/libremodular-mcp/bridges/krita_bridge.py', encoding='utf-8').read())
L’encodage n’est pas facultatif. Le Python embarqué de Krita lit les fichiers dans l’encodage de la locale sous laquelle il a été lancé, et le fichier du pont contient des caractères accentués : sous la locale C, une commande sans encoding='utf-8' s’est arrêtée avec UnicodeDecodeError, comme le consigne la page de compatibilité. L’exécution a utilisé le port 9312 dans config.toml et un jeton neuf. Le port s’est mis à l’écoute 10,4 s après le démarrage, et get_state sur hub a listé Krita comme connecté :
{
"app": "hub",
"app_version": "0.1.0",
"bridge_version": null,
"captured_at": "2026-10-21T12:47:48.951Z",
"connected": true,
"content_origin": "hub",
"screenshot": null,
"state": {
"modules": [
{
"app_version": "5.2.9",
"bridge_version": "1",
"connected": true,
"mode": "tcp",
"name": "krita"
}
]
},
"warnings": []
}Texte donné au modèle
Avant d’écrire, le modèle a appelé get_state sur krita : "document": null. Le document n’existe pas encore, de sorte que le script doit le créer et l’ouvrir dans une fenêtre avant de pouvoir peindre.
Script écrit
Un modèle, Claude Sonnet 5.5, a écrit ce script à partir du guide et de cet état. Ce n’est pas un script tiré des tests du projet. Le script écrit les octets des pixels dans l’ordre bleu, vert, rouge, alpha ; les couleurs de la capture ci-dessous montrent que c’est l’ordre que Krita attend pour ce document. Le script active le mode batch avant saveAs ; ce qui se passe sans lui n’a pas été essayé.
import os
krita = Krita.instance()
document = krita.createDocument(600, 400, "Postcard", "RGBA", "U8", "", 72.0)
krita.activeWindow().addView(document)
root = document.rootNode()
def lerp(a, b, t):
return round(a + (b - a) * t)
top, bottom = (0x1c, 0x38, 0x5c), (0x29, 0xa1, 0x96)
sky_pixels = bytearray()
for y in range(400):
t = y / 399
r, g, b = (lerp(top[i], bottom[i], t) for i in range(3))
sky_pixels += bytes((b, g, r, 255)) * 600
sky = document.createNode("Sky", "paintlayer")
root.addChildNode(sky, None)
sky.setPixelData(bytes(sky_pixels), 0, 0, 600, 400)
hill_pixels = bytearray()
for y in range(400):
for x in range(600):
inside = ((x - 300) / 260) ** 2 + ((y - 400) / 120) ** 2 <= 1
hill_pixels += bytes((0x38, 0x54, 0xC2, 255)) if inside else bytes((0, 0, 0, 0))
hill = document.createNode("Hill", "paintlayer")
root.addChildNode(hill, None)
hill.setPixelData(bytes(hill_pixels), 0, 0, 600, 400)
document.refreshProjection()
document.setBatchmode(True)
path = os.path.join(LMM_WORK_DIR, "postcard.kra")
saved = document.saveAs(path)
result = {"saved": saved, "kra_bytes": os.path.getsize(path), "layers": [node.name() for node in document.topLevelNodes()]}La réponse du Hub
{
"app": "krita",
"duration_ms": 1060,
"error": null,
"result": {
"kra_bytes": 110725,
"layers": [
"Background",
"Sky",
"Hill"
],
"saved": true
},
"status": "ok",
"stderr": "",
"stdout": "",
"truncated": false
}Le script a duré 1,06 s. Le document a trois calques, parce qu’un nouveau document de Krita commence avec un calque Background que le script a laissé intact, sous Sky et Hill. get_state a ensuite décrit le document et renvoyé une capture de sa projection :
{
"app": "krita",
"app_version": "5.2.9",
"bridge_version": "1",
"captured_at": "2026-10-21T12:47:50.526Z",
"connected": true,
"content_origin": "document",
"screenshot": "$XDG_RUNTIME_DIR/libremodular-mcp/captures/krita-20261021T124750502Z.png",
"state": {
"document": {
"active_layer": "{727e9cd9-e6e1-423c-ade7-1bf29d6d5289}",
"color_depth": "U8",
"color_model": "RGBA",
"color_profile": "sRGB-elle-V2-srgbtrc.icc",
"height": 400,
"layers": [
{
"id": "{69f5540d-2916-4771-8df7-1fcad46b677f}",
"name": "Background",
"opacity": 255,
"type": "paintlayer",
"visible": true
},
{
"id": "{ed307be8-5a93-4b16-8739-7508916ea687}",
"name": "Sky",
"opacity": 255,
"type": "paintlayer",
"visible": true
},
{
"id": "{727e9cd9-e6e1-423c-ade7-1bf29d6d5289}",
"name": "Hill",
"opacity": 255,
"type": "paintlayer",
"visible": true
}
],
"name": "Postcard",
"width": 600
}
},
"warnings": []
}L’image produite
La capture est l’image fusionnée que Krita affiche, de 600 par 400 pixels. Les pixels qu’on y lit valent #1C385C en haut, #29A196 en bas et #C25438 dans la colline, les trois couleurs que le texte demandait. Le fichier .kra que le script a enregistré fait 110 725 octets.
