MEMORY: Penpot API directe port 9003, gotchas pixel-perfect
This commit is contained in:
@@ -165,6 +165,83 @@ create_text { fileId, pageId, text, x, y, textAlign, ... } ← PAS de parentId
|
||||
- Uploader sur CopyParty : `curl -X PUT http://192.168.1.150:3923/anytype/image.png --data-binary @image.png`
|
||||
- Puis : `upload_file_media_from_url { fileId, url: "http://192.168.1.150:3923/anytype/image.png" }`
|
||||
|
||||
## Penpot API Directe — Pixel-perfect (⭐ À UTILISER EN PRIORITÉ)
|
||||
|
||||
### Pourquoi directe > MCP
|
||||
- MCP : auto-calcule les dims texte, pas de `parentId` pour les textes → pas de contrôle pixel-perfect
|
||||
- API directe : contrôle total (x, y, width, height, parentId, contenu riche)
|
||||
|
||||
### Accès
|
||||
- **URL backend** : `http://192.168.1.150:9003/api/rpc/command/<cmd>` (port 9003 exposé = penpot-backend:6060)
|
||||
- **Auth** : `Authorization: Token <access_token>` (dans l'en-tête HTTP)
|
||||
- **Token** : récupérable dans Penpot UI → Profile → Access Tokens
|
||||
- **Format corps** : JSON **kebab-case** (ex: `page-id`, `frame-id`, `fill-color`)
|
||||
- **Réponse** : kebab-case aussi (`default-team-id`, `default-project-id`)
|
||||
- ⚠️ L'accès via nginx port 9001 retourne un user vide même avec le bon token — **toujours utiliser le port 9003**
|
||||
|
||||
### Workflow création poster (Node.js)
|
||||
```js
|
||||
// 1. Auth + IDs
|
||||
const prof = await rpc('get-profile');
|
||||
const teamId = prof['default-team-id'];
|
||||
const projectId = prof['default-project-id'];
|
||||
|
||||
// 2. Créer fichier
|
||||
const file = await rpc('create-file', { 'project-id': projectId, name: 'Mon affiche', 'is-shared': false });
|
||||
const FILE_ID = file.id;
|
||||
const PAGE_ID = Object.keys(file.data?.['pages-index'] || {})[0] || file.data?.pages?.[0];
|
||||
|
||||
// 3. Ajouter shapes une par une (revn incrémental !)
|
||||
for (const change of changes) {
|
||||
const result = await rpc('update-file', {
|
||||
id: FILE_ID, 'session-id': randomUUID(), revn: currentRevn, vern: 0,
|
||||
changes: [change]
|
||||
});
|
||||
currentRevn = result.revn;
|
||||
}
|
||||
```
|
||||
|
||||
### Format d'une change `add-obj`
|
||||
```js
|
||||
{
|
||||
type: 'add-obj',
|
||||
id: '<uuid>',
|
||||
'page-id': PAGE_ID,
|
||||
'frame-id': ROOT, // '00000000-0000-0000-0000-000000000000' = root
|
||||
'parent-id': ROOT,
|
||||
obj: {
|
||||
id, type: 'rect'|'text'|'frame', name,
|
||||
x, y, width, height,
|
||||
'parent-id': ROOT, 'frame-id': ROOT,
|
||||
fills: [{ 'fill-color': '#C0392B', 'fill-opacity': 1 }],
|
||||
selrect: { x, y, width, height, x1, y1, x2, y2 },
|
||||
points: [{x,y},{x:x+w,y},{x:x+w,y:y+h},{x,y:y+h}],
|
||||
transform: {a:1,b:0,c:0,d:1,e:0,f:0},
|
||||
'transform-inverse': {a:1,b:0,c:0,d:1,e:0,f:0},
|
||||
// Pour un text :
|
||||
content: { type:'root', children:[{ type:'paragraph-set', children:[{
|
||||
type:'paragraph', 'text-align':'center', children:[{
|
||||
text: 'Mon texte',
|
||||
'font-id':'gfont-work-sans', 'font-family':'Work Sans',
|
||||
'font-size':'48', 'font-weight':'700', 'font-style':'normal',
|
||||
'letter-spacing':'2', 'line-height': 1.2, 'text-decoration':'none',
|
||||
fills:[{'fill-color':'#FFFFFF', 'fill-opacity':1}],
|
||||
}]
|
||||
}]}]}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ⚠️ Gotchas critiques
|
||||
- **Envoyer 1 change à la fois** (pas toutes en même temps) + incrémenter `revn`
|
||||
- **`type: 'frame'`** échoue avec erreur `:shapes nil` → utiliser `type: 'rect'` comme fond
|
||||
- **toKebab()** : tous les paramètres JS en camelCase → convertir en kebab-case avant envoi
|
||||
- **`text` content** : bien mettre le champ `text:` dans le nœud enfant (sinon validation error)
|
||||
- **Texte centré** : mettre `x:0, width:W` (toute la largeur) + `text-align: 'center'` dans le paragraphe
|
||||
|
||||
### Script de référence
|
||||
`/home/node/.openclaw/workspace/penpot-api-direct.mjs` — poster 600×900 complet, 16 shapes
|
||||
|
||||
## Podcasts & Vidéos — Transcription
|
||||
- Je peux **récupérer et transcrire** des podcasts/vidéos en ligne
|
||||
- **Méthode :**
|
||||
|
||||
Reference in New Issue
Block a user