(function () { if (app.documents.length === 0) { alert("Open a document first."); return; } var doc = app.activeDocument; var CSV = "Step,Size,Multiplier,Role,Artist Tier,Weight,Tracking (em),Tracking (pt),Tracking (Adobe),Leading (×),Leading (pt),Leading (px/web)\n" + "0,12,×1,Meta,—,560,+0.083em,+1pt,+83,1.0,12pt,12px\n" + "1,18,×1.5,—,—,—,—,—,—,—,—,—\n" + "2,24,×2,Kicker,—,440,+0.083em,+2pt,+83,1.0,24pt,24px\n" + "3,36,×3,—,—,—,—,—,—,—,—,—\n" + "4,48,×4,Body,—,560,−0.021em,−1pt,−21,1.12,54pt,54px\n" + "5,72,×6,—,Tier 5,560,−0.042em,−3pt,−42,1.0,72pt,72px\n" + "6,96,×8,Heading 2,Tier 4,700,−0.042em,−4pt,−42,0.875,84pt,84px\n" + "7,144,×12,—,—,—,—,—,—,—,—,—\n" + "8,192,×16,Heading 1,\"Tier 2, Tier 3\",700,−0.042em,−8pt,−42,0.875,168pt,168px\n" + "9,288,×24,Display,Tier 1,700,−0.042em,−12pt,−42,0.833,240pt,240px\n" + "10,384,×32,Display Large,—,700,−0.042em,−16pt,−42,0.833,320pt,320px"; function parseCSV(text) { var rows = []; var i = 0; var field = ""; var row = []; var inQuotes = false; function pushField() { row.push(field); field = ""; } function pushRow() { if (row.length > 1 || (row.length === 1 && row[0] !== "")) rows.push(row); row = []; } while (i < text.length) { var c = text.charAt(i); if (inQuotes) { if (c === '"') { if (i + 1 < text.length && text.charAt(i + 1) === '"') { field += '"'; i += 2; continue; } else { inQuotes = false; i++; continue; } } else { field += c; i++; continue; } } else { if (c === '"') { inQuotes = true; i++; continue; } if (c === ",") { pushField(); i++; continue; } if (c === "\n") { pushField(); pushRow(); i++; continue; } if (c === "\r") { i++; continue; } field += c; i++; } } pushField(); pushRow(); return rows; } function hexToRGBColor(hex) { var h = hex.replace("#", ""); var r = parseInt(h.substr(0, 2), 16); var g = parseInt(h.substr(2, 2), 16); var b = parseInt(h.substr(4, 2), 16); var c = new RGBColor(); c.red = r; c.green = g; c.blue = b; return c; } function findFontByNames(candidates) { for (var i = 0; i < candidates.length; i++) { try { return app.textFonts.getByName(candidates[i]); } catch (e) {} } return null; } function normalizeDash(val) { if (val === undefined || val === null) return null; var s = String(val).replace(/\s+/g, " ").replace(/^\s+|\s+$/g, ""); if (s === "" || s === "—" || s === "–" || s === "-") return null; return s; } function parseNumberMaybe(s) { s = normalizeDash(s); if (s === null) return null; s = s.replace("−", "-"); var m = s.match(/-?\d+(\.\d+)?/); if (!m) return null; var n = parseFloat(m[0]); if (isNaN(n)) return null; return n; } function buildLabeledBlock(header, row) { var lines = []; for (var i = 0; i < header.length; i++) { var label = header[i]; var val = (row[i] !== undefined) ? row[i] : ""; if (val === undefined || val === null) val = ""; lines.push(label + ": " + String(val)); } return lines.join("\r"); } var neorisVariable = findFontByNames([ "TTNeorisVariable-Roman", "TT Neoris Variable", "TT Neoris Variable Roman", "TTNeorisVariable" ]); var neorisRegular = findFontByNames([ "TTNeoris-Regular", "TT Neoris Regular", "TT Neoris" ]); var neorisMedium = findFontByNames([ "TTNeoris-Medium", "TT Neoris Medium" ]); var neorisBold = findFontByNames([ "TTNeoris-Bold", "TT Neoris Bold" ]); var fallback = null; try { fallback = app.textFonts.getByName("ArialMT"); } catch (e) { fallback = null; } function pickFontForWeight(weightNumber) { if (neorisVariable) return neorisVariable; if (weightNumber === null || weightNumber === undefined) { return neorisRegular || fallback; } if (weightNumber >= 650) return neorisBold || neorisMedium || neorisRegular || fallback; if (weightNumber >= 500) return neorisMedium || neorisBold || neorisRegular || fallback; return neorisRegular || fallback; } var rows = parseCSV(CSV); if (!rows || rows.length < 2) { alert("CSV parse failed or has no data rows."); return; } var header = rows[0]; var body = rows.slice(1); var abIndex = doc.artboards.getActiveArtboardIndex(); var ab = doc.artboards[abIndex]; var r = ab.artboardRect; var left = r[0], top = r[1]; var margin = 48; var x = left + margin; var y = top - margin; var fillColor = hexToRGBColor("#A6A6A6"); var blockGap = 28; var group = doc.groupItems.add(); group.name = "Type Scale Rows"; function indexOfHeader(name) { for (var i = 0; i < header.length; i++) if (header[i] === name) return i; return -1; } var idxSize = indexOfHeader("Size"); var idxWeight = indexOfHeader("Weight"); var idxTrackingAdobe = indexOfHeader("Tracking (Adobe)"); var idxLeadingPt = indexOfHeader("Leading (pt)"); var idxLeadingMult = indexOfHeader("Leading (×)"); for (var i = 0; i < body.length; i++) { var row = body[i]; var sizePt = parseNumberMaybe(row[idxSize]); if (sizePt === null) sizePt = 12; var weightNum = parseNumberMaybe(row[idxWeight]); var trackingAdobe = parseNumberMaybe(row[idxTrackingAdobe]); if (trackingAdobe === null) trackingAdobe = 0; var leadingPt = parseNumberMaybe(row[idxLeadingPt]); if (leadingPt === null) { var leadMult = parseNumberMaybe(row[idxLeadingMult]); if (leadMult !== null) leadingPt = sizePt * leadMult; else leadingPt = sizePt * 1.0; } var content = buildLabeledBlock(header, row); var tf = doc.textFrames.add(); tf.kind = TextType.POINTTEXT; tf.contents = content; tf.position = [x, y]; var tr = tf.textRange; tr.fillColor = fillColor; tr.characterAttributes.size = sizePt; tr.characterAttributes.tracking = Math.round(trackingAdobe); tr.characterAttributes.leading = leadingPt; var f = pickFontForWeight(weightNum); if (f) tr.characterAttributes.textFont = f; tf.move(group, ElementPlacement.PLACEATEND); var h = tf.height; y -= (h + blockGap); } })();