CommunityBildgithub.com

4hm4di/ahkab-illustrator-text

Verwenden Sie diese Fähigkeit, wenn Sie in Illustrator bearbeitbare Layouts (Magazine, Profile, Broschüren) als SVG/PDF erstellen, sodass jeder Absatz in einem eigenen bearbeitbaren Textfeld (Area-Type) und nicht in gruppierten Zeilen vorliegt.

Was ist ahkab-illustrator-text?

Diese Fähigkeit (Ahkab Illustrator Text) wandelt SVG/PDF-Seitenlayouts in native Adobe Illustrator-Dokumente um, in denen jeder Textabsatz als ein separates, bearbeitbares Textfeld (Area-Type oder Point-Type) vorliegt, anstatt als gruppierte Zeilen. Sie ist speziell für die Erstellung von Magazinen, Profilen, Broschüren und anderen layoutsensitiven Druckprodukten konzipiert, die eine nachträgliche manuelle Bearbeitung in Illustrator erfordern. Die Fähigkeit generiert ein ExtendScript (.jsx), das alle Textinformationen (Position, Größe, Schriftart, Farbe, Laufweite) sowie die Seitengeometrie als JavaScript-Objektliteral enthält. Der Benutzer führt dieses Skript in Illustrator aus, das automatisch ein neues Dokument mit den korrekten Ebenen, Artboards und Textfeldern erstellt, die exakt mit den ursprünglichen SVG-Positionen übereinstimmen. Unterstützt werden SVG-Dateien mit strukturierten Ebenen (L01_Backgrounds, L02_…) und ein schriftartenbasiertes Fallback-System. Die Fähigkeit arbeitet mit einer Mock-Testumgebung für Node.js, um das Skript vor der Auslieferung zu validieren. Sie ist plattformunabhängig und funktioniert mit jeder SVG- oder PDF-Quelle, die strukturierte Layouts erzeugt.

Funktioniert mit✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/4hm4di/ahkab-illustrator-text/tree/HEAD/ahkab-illustrator-text

Installed? Explore more Bild skills: steipete/songsee, affaan-m/frontend-design, mattpocock/improve-codebase-architecture · View all 6 →

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Ahkab Illustrator Text — native Illustrator text (one paragraph = one text box)

By Ahmad Abdullahi Kabeer · Graphcent

Why

Illustrator always splits imported SVG and PDF text into one text object per line, grouped together. No SVG markup prevents this. So: keep the SVG pages for the artwork, and rebuild ALL text natively inside Illustrator with an ExtendScript (.jsx) build script that the user runs once (File > Scripts > Other Script…). The script saves a genuine .ai.

Workflow

  1. Record text while generating pages. Wherever the page generator emits <text>, also store a record per page: {id, kind: 'area'|'point', layer: '05', x, y (first baseline, SVG y-down, pt), w (box width), lead, n (wrapped line count), size, anchor: 'start'|'middle'|'end', ls (letter-spacing pt), runs: [[text, weight, '#RRGGBB'], …], name}
    • Wrapped paragraphs (and multi-line titles) -> area. Single-line labels, numbers, kickers -> point.
    • Use exactly the x/y/width/leading used to draw the SVG, so positions match the PDF.
    • Give meaningful names (e.g. Name — slot 01, Biography — slot 04).
  2. SVG page requirements: files pages/NN_Name.svg (NN = page number); top-level groups id="L01_Backgrounds", L02_… etc. with data-name = readable layer name. Keep text in the SVGs too (fallback + PDF rendering).
  3. Generate the .jsx by embedding the records as a JS object literal (json.dumps(..., ensure_ascii=True) — ExtendScript is ES3, no JSON.parse needed).
  4. Dry-run the generated .jsx in Node against a mock of the Illustrator DOM (app, documents.add, open, textFrames.areaText/pointText, pathItems.rectangle, artboards, textFonts.getByName, enums). Check: counts of area/point frames, every frame has contents + font + name, rect coords are numbers, artboards = pages.
  5. Document in the README that the editable .ai comes from running the script; opening SVG/PDF directly still gives split lines. Say plainly the script was tested on a mock, not in Illustrator itself.

Core script logic (ExtendScript)

#target illustrator
var PAGE_TEXT = /* {"1":[records…], "2":[…]} */;
app.userInteractionLevel = UserInteractionLevel.DONTDISPLAYALERTS;
app.coordinateSystem = CoordinateSystem.DOCUMENTCOORDINATESYSTEM;   // y increases upward
// 1) doc = app.documents.add(DocumentColorSpace.RGB, W, H); create named layers (doc.layers.add() adds on top).
// 2) per page p: artboard rect [left, top, left+W, top-H] with left = col*(W+GAP), top = -row*(H+GAP).
//    src = app.open(svgFile); delete imported text:
//      for (var i = src.textFrames.length-1; i >= 0; i--) src.textFrames[i].remove();
//    find groups/sub-layers whose name matches /^L?(0[1-9])/ and duplicate into the matching layer:
//      item.duplicate(targetLayer, ElementPlacement.PLACEATBEGINNING).translate(left - sr[0], top - sr[1]);
//    (iterate container.pageItems, filter typename === 'GroupItem'; do not compare DOM objects with ===)
//    src.close(SaveOptions.DONOTSAVECHANGES); then buildText(PAGE_TEXT[pageNo], left, top).
var FONT_CANDIDATES = { 300:["Kreadon-L","Outfit-Light"], 400:["Kreadon-R","Kreadon-M","Outfit-Regular"],
  500:["Kreadon-M","Outfit-Medium"], 600:["Kreadon-Demi","Kreadon-D","Outfit-SemiBold"],
  700:["Kreadon-B","Outfit-Bold"], 800:["Kreadon-EB","Outfit-ExtraBold"] };  // put the project's PostScript names first
function fontFor(w){ var n=FONT_CANDIDATES[w]||FONT_CANDIDATES[400]; for(var i=0;i<n.length;i++){ try{ return app.textFonts.getByName(n[i]); }catch(e){} } return null; }
function rgb(h){ var c=new RGBColor(); h=h.replace('#',''); c.red=parseInt(h.substr(0,2),16); c.green=parseInt(h.substr(2,2),16); c.blue=parseInt(h.substr(4,2),16); return c; }
function styleRange(r,w,size,col,lsPt,lead){ var a=r.characterAttributes, f=fontFor(w); if(f) a.textFont=f; a.size=size;
  if(lead){ a.autoLeading=false; a.leading=lead; } a.fillColor=rgb(col); a.tracking=Math.round((lsPt||0)/size*1000); }
function buildText(recs, left, top){
  for (var i=0;i<recs.length;i++){ var t=recs[i], layer=layerByKey[t.layer]||layerByKey['06'], s='', tf;
    for (var r=0;r<t.runs.length;r++) s+=t.runs[r][0];
    if (t.kind==='area'){ var lead=t.lead||t.size*1.4;
      var rect=layer.pathItems.rectangle(top-(t.y-lead), left+t.x-1, t.w+2, (t.n+1)*lead);  // +1 line slack for font swaps
      tf=layer.textFrames.areaText(rect); tf.contents=s; styleRange(tf.textRange,t.runs[0][1],t.size,t.runs[0][2],t.ls,lead);
      try{ tf.firstBaseline=FirstBaselineType.LEADING; }catch(e){ tf.translate(0,-(lead-t.size*0.95)); }
    } else { tf=layer.textFrames.pointText([left+t.x, top-t.y]); tf.contents=s; styleRange(tf.textRange,t.runs[0][1],t.size,t.runs[0][2],t.ls,null); }
    tf.textRange.paragraphAttributes.justification = t.anchor==='middle'?Justification.CENTER:(t.anchor==='end'?Justification.RIGHT:Justification.LEFT);
    // rich spans: for runs after the first whose weight/colour differ, style chars [pos, pos+len):
    //   try { var rr=tf.textRange.characters[pos]; rr.length=len; styleRange(rr,…); } catch(e){ per-character loop }
    tf.name = t.name || t.id; } }
// 3) IllustratorSaveOptions {pdfCompatible:true, compressed:true, embedLinkedFiles:true}; doc.saveAs(File(root+'/<Name>.ai'));
//    Show a final alert with any notes (e.g. missing fonts). Wrap everything in try/catch and restore userInteractionLevel.

Checks before delivering

  • Mock dry-run passes; the paragraph count matches the number of wrapped text blocks in the generator.
  • Area boxes use the original width (+2pt) so line breaks match the PDF; with a wider replacement font they reflow inside the box.
  • README explains: run the script for the editable .ai; Find/Replace Font if swapping typefaces; the script was not run inside Illustrator by Claude.

Verwandte Skills