CommunityImagengithub.com

4hm4di/ahkab-illustrator-text

Úsalo al entregar diseños editables en Illustrator (revistas, perfiles, folletos) creados como SVG/PDF, donde cada párrafo se convierta en un cuadro de texto de tipo área editable, no en líneas agrupadas.

¿Qué es ahkab-illustrator-text?

Esta habilidad resuelve el problema común de que Illustrator divida el texto importado desde SVG y PDF en objetos de texto separados por línea, agrupados, lo que dificulta la edición. En lugar de intentar evitarlo mediante marcado SVG, el skill implementa un flujo de trabajo que registra toda la información del texto (posición, tamaño, fuente, color, etc.) durante la generación de páginas y la incrusta en un script de ExtendScript (.jsx). Este script, ejecutado por el usuario en Illustrator (Archivo > Scripts > Otro script...), reconstruye el texto nativamente como cuadros de texto de área o punto, asegurando que cada párrafo sea un cuadro editable independiente, y guarda un archivo .ai genuino. Es compatible con flujos de trabajo de diseño editorial que usan Claude, Cursor u otros agentes para generar prototipos en SVG/PDF, pero necesitan archivos Illustrator editables para el trabajo final. El script incluye lógica para manejar capas con nombres significativos, cuadros de área con ancho coincidente, fuentes candidatas con fallback, y estilos enriquecidos, y se recomienda una prueba en seco previa con un mock del DOM de Illustrator para verificar la integridad antes de la entrega.

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

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

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Ahkab Illustrator Text — texto nativo de Illustrator (un párrafo = un cuadro de texto)

Por Ahmad Abdullahi Kabeer · Graphcent

Por qué

Illustrator siempre divide el texto SVG y PDF importado en un objeto de texto por línea, agrupados. Ningún marcado SVG lo evita. Por lo tanto: conserva las páginas SVG para la ilustración y reconstruye TODO el texto de forma nativa dentro de Illustrator con un script de ExtendScript (.jsx) que el usuario ejecuta una vez (Archivo > Scripts > Otro script...). El script guarda un .ai genuino.

Flujo de trabajo

  1. Registra el texto mientras generas páginas. Donde el generador de páginas emita <text>, también almacena un registro por página: {id, kind: 'area'|'point', layer: '05', x, y (primera línea base, SVG y abajo, pt), w (ancho del cuadro), lead, n (recuento de líneas envueltas), size, anchor: 'start'|'middle'|'end', ls (espaciado entre letras pt), runs: [[texto, peso, '#RRGGBB'], …], name}
    • Párrafos envueltos (y títulos de varias líneas) -> area. Etiquetas de una línea, números, subtítulos -> point.
    • Usa exactamente los x/y/ancho/interlineado utilizados para dibujar el SVG, para que las posiciones coincidan con el PDF.
    • Asigna nombres significativos (por ejemplo, Nombre — ranura 01, Biografía — ranura 04).
  2. Requisitos de la página SVG: archivos pages/NN_Nombre.svg (NN = número de página); grupos de nivel superior id="L01_Fondos", L02_… etc. con data-name = nombre de capa legible. Mantén el texto también en los SVG (respaldo + renderizado PDF).
  3. Genera el .jsx incrustando los registros como un literal de objeto JS (json.dumps(..., ensure_ascii=True) — ExtendScript es ES3, no necesita JSON.parse).
  4. Haz una prueba en seco del .jsx generado en Node contra un mock del DOM de Illustrator (app, documents.add, open, textFrames.areaText/pointText, pathItems.rectangle, artboards, textFonts.getByName, enums). Verifica: recuento de marcos de área/punto, cada marco tiene contenido + fuente + nombre, las coordenadas del rect son números, los artboards = páginas.
  5. Documenta en el README que el .ai editable proviene de ejecutar el script; abrir SVG/PDF directamente sigue dando líneas divididas. Indica claramente que el script se probó en un mock, no en Illustrator mismo.

Lógica central del script (ExtendScript)

#target illustrator
var PAGE_TEXT = /* {"1":[registros…], "2":[…]} */;
app.userInteractionLevel = UserInteractionLevel.DONTDISPLAYALERTS;
app.coordinateSystem = CoordinateSystem.DOCUMENTCOORDINATESYSTEM;   // y aumenta hacia arriba
// 1) doc = app.documents.add(DocumentColorSpace.RGB, W, H); crea capas con nombre (doc.layers.add() añade encima).
// 2) por página p: rect del artboard [left, top, left+W, top-H] con left = col*(W+GAP), top = -row*(H+GAP).
//    src = app.open(svgFile); elimina el texto importado:
//      for (var i = src.textFrames.length-1; i >= 0; i--) src.textFrames[i].remove();
//    encuentra grupos/subcapas cuyo nombre coincida con /^L?(0[1-9])/ y duplícalos en la capa correspondiente:
//      item.duplicate(targetLayer, ElementPlacement.PLACEATBEGINNING).translate(left - sr[0], top - sr[1]);
//    (itera container.pageItems, filtra typename === 'GroupItem'; no compares objetos DOM con ===)
//    src.close(SaveOptions.DONOTSAVECHANGES); luego 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"] };  // pon los nombres PostScript del proyecto primero
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 línea de margen para cambios de fuente
      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);
    // tramos enriquecidos: para tiradas después de la primera cuyo peso/color difieran, estilo caracteres [pos, pos+len):
    //   try { var rr=tf.textRange.characters[pos]; rr.length=len; styleRange(rr,…); } catch(e){ bucle por carácter }
    tf.name = t.name || t.id; } }
// 3) IllustratorSaveOptions {pdfCompatible:true, compressed:true, embedLinkedFiles:true}; doc.saveAs(File(root+'/<Nombre>.ai'));
//    Muestra una alerta final con cualquier nota (p. ej., fuentes faltantes). Envuelve todo en try/catch y restaura userInteractionLevel.

Verificaciones antes de entregar

  • La prueba en seco del mock pasa; el recuento de párrafos coincide con el número de bloques de texto envueltos en el generador.
  • Los cuadros de área usan el ancho original (+2pt) para que los saltos de línea coincidan con el PDF; con una fuente de reemplazo más ancha, se reajustan dentro del cuadro.
  • El README explica: ejecuta el script para el .ai editable; Buscar/Reemplazar fuente si se cambian tipografías; el script no fue ejecutado dentro de Illustrator por Claude.

Skills relacionados