#target illustrator (function () { if (app.name !== "Adobe Illustrator") { alert("This script must be run from Adobe Illustrator."); return; } if (app.documents.length === 0) { alert("Open a document first."); return; } var doc = app.activeDocument; var DEFAULT_STROKE_WEIGHT = 0.5; var BRAND_BASELINE = 12; var BRAND_GUTTER = 12; var BRAND_MIN_MARGIN = 12; var GRID_MODES = [ { name: "Standard — 12 column", key: "standard12", cols: 12, desc: "General screen, print, and layout use. Subdivisions: 6, 4, 3, 2." }, { name: "Extended — 24 column", key: "extended24", cols: 24, desc: "For dense layouts, half-column offsets, and more complex compositions." } ]; var COLOR_OPTIONS = [ { name: "Cyan", rgb: [0, 255, 255] }, { name: "Magenta", rgb: [255, 0, 255] }, { name: "Yellow", rgb: [255, 255, 0] }, { name: "Red", rgb: [255, 0, 0] }, { name: "Green", rgb: [0, 200, 0] }, { name: "Blue", rgb: [0, 120, 255] }, { name: "Orange", rgb: [255, 140, 0] }, { name: "Purple", rgb: [140, 0, 255] }, { name: "Gray", rgb: [140, 140, 140] }, { name: "Black", rgb: [0, 0, 0] } ]; function pad(num, width) { var s = String(num); while (s.length < width) s = "0" + s; return s; } function fmtNum(n) { var s = String(Math.round(n * 1000) / 1000); return s.replace(/\.0+$/, "").replace(/(\.\d*[1-9])0+$/, "$1"); } function makeRGB(rgbArr) { var c = new RGBColor(); c.red = rgbArr[0]; c.green = rgbArr[1]; c.blue = rgbArr[2]; return c; } function getColorByName(name) { for (var i = 0; i < COLOR_OPTIONS.length; i++) { if (COLOR_OPTIONS[i].name === name) { return makeRGB(COLOR_OPTIONS[i].rgb); } } return makeRGB([0, 255, 255]); } function getOrCreateLayer(layerName) { for (var i = 0; i < doc.layers.length; i++) { if (doc.layers[i].name === layerName) { return doc.layers[i]; } } var layer = doc.layers.add(); layer.name = layerName; return layer; } function addLine(parent, x1, y1, x2, y2, strokeColor, strokeWeight) { var line = parent.pathItems.add(); line.setEntirePath([[x1, y1], [x2, y2]]); line.stroked = true; line.filled = false; line.strokeColor = strokeColor; line.strokeWidth = strokeWeight; return line; } function getArtboardRect(index) { var r = doc.artboards[index].artboardRect; return { left: r[0], top: r[1], right: r[2], bottom: r[3], width: r[2] - r[0], height: r[1] - r[3] }; } function getTargetArtboardIndexes(scope) { var out = []; if (scope === "Active Artboard") { out.push(doc.artboards.getActiveArtboardIndex()); } else { for (var i = 0; i < doc.artboards.length; i++) { out.push(i); } } return out; } function getLiveRect(abRect, marginValue) { return { left: abRect.left + marginValue, top: abRect.top - marginValue, right: abRect.right - marginValue, bottom: abRect.bottom + marginValue, width: (abRect.right - marginValue) - (abRect.left + marginValue), height: (abRect.top - marginValue) - (abRect.bottom + marginValue) }; } function addGroup(parent, name) { var g = parent.groupItems.add(); g.name = name; return g; } function drawMargins(group, liveRect, color, strokeWeight) { addLine(group, liveRect.left, liveRect.top, liveRect.right, liveRect.top, color, strokeWeight); addLine(group, liveRect.right, liveRect.top, liveRect.right, liveRect.bottom, color, strokeWeight); addLine(group, liveRect.right, liveRect.bottom, liveRect.left, liveRect.bottom, color, strokeWeight); addLine(group, liveRect.left, liveRect.bottom, liveRect.left, liveRect.top, color, strokeWeight); } function drawColumns(group, liveRect, colCount, gutter, color, strokeWeight) { if (colCount < 1) return; var totalGutter = gutter * (colCount - 1); var usable = liveRect.width - totalGutter; if (usable <= 0) return; var colWidth = usable / colCount; var x = liveRect.left; addLine(group, liveRect.left, liveRect.top, liveRect.left, liveRect.bottom, color, strokeWeight); for (var i = 0; i < colCount; i++) { var colLeft = x; var colRight = x + colWidth; addLine(group, colLeft, liveRect.top, colLeft, liveRect.bottom, color, strokeWeight); addLine(group, colRight, liveRect.top, colRight, liveRect.bottom, color, strokeWeight); if (i < colCount - 1) { var gutterLeft = colRight; var gutterRight = colRight + gutter; addLine(group, gutterLeft, liveRect.top, gutterLeft, liveRect.bottom, color, strokeWeight); addLine(group, gutterRight, liveRect.top, gutterRight, liveRect.bottom, color, strokeWeight); } x = colRight + gutter; } addLine(group, liveRect.right, liveRect.top, liveRect.right, liveRect.bottom, color, strokeWeight); } function buildBaselineYPositions(liveRect, baselineStep) { var ys = []; var y = liveRect.bottom; while (y <= liveRect.top + 0.0001) { ys.push(y); y += baselineStep; } return ys; } function drawBaselines(group, liveRect, baselineStep, color, strokeWeight) { if (baselineStep <= 0) return []; var ys = buildBaselineYPositions(liveRect, baselineStep); for (var i = 0; i < ys.length; i++) { addLine(group, liveRect.left, ys[i], liveRect.right, ys[i], color, strokeWeight); } return ys; } function buildArtboardGroupName(abIndex) { return "AB" + pad(abIndex + 1, 2) + "_grid"; } function buildMarginGroupName(marginValue, marginMultiple) { return "margins__bu" + BRAND_BASELINE + "_x" + fmtNum(marginMultiple) + "_val" + fmtNum(marginValue); } function buildColumnGroupName(mode) { if (mode.key === "standard12") { return "columns__standard12_g" + fmtNum(BRAND_GUTTER) + "_subs6-4-3-2"; } return "columns__extended24_g" + fmtNum(BRAND_GUTTER) + "_maps12x2"; } function buildBaselineGroupName() { return "baseline__b" + fmtNum(BRAND_BASELINE); } function validatePositiveNumber(v, label) { if (isNaN(v) || v <= 0) { throw new Error(label + " must be greater than 0."); } } function validatePositiveInteger(v, label) { if (isNaN(v) || v < 1 || Math.floor(v) !== v) { throw new Error(label + " must be an integer greater than or equal to 1."); } } // ---------- UI ---------- var win = new Window("dialog", "VIVA PHX 2026 Grid Generator"); win.orientation = "column"; win.alignChildren = ["fill", "top"]; win.spacing = 10; win.margins = 16; var infoPanel = win.add("panel", undefined, "Rules"); infoPanel.orientation = "column"; infoPanel.alignChildren = ["left", "top"]; infoPanel.margins = 12; infoPanel.spacing = 4; infoPanel.add("statictext", undefined, "Baseline: 12pt / 12px"); infoPanel.add("statictext", undefined, "Gutter: 12pt / 12px"); infoPanel.add("statictext", undefined, "Margin: minimum 12pt, scaled only in multiples of 12"); infoPanel.add("statictext", undefined, "Modes: Standard 12-column or Extended 24-column"); var modePanel = win.add("panel", undefined, "Grid Mode"); modePanel.orientation = "column"; modePanel.alignChildren = ["fill", "top"]; modePanel.margins = 12; modePanel.spacing = 8; var modeRow = modePanel.add("group"); modeRow.orientation = "row"; modeRow.alignChildren = ["left", "center"]; modeRow.add("statictext", undefined, "Mode:"); var modeNames = []; for (var gm = 0; gm < GRID_MODES.length; gm++) modeNames.push(GRID_MODES[gm].name); var modeDropdown = modeRow.add("dropdownlist", undefined, modeNames); modeDropdown.minimumSize.width = 280; modeDropdown.selection = 0; var modeDesc = modePanel.add("statictext", undefined, GRID_MODES[0].desc, { multiline: true }); var targetPanel = win.add("panel", undefined, "Target"); targetPanel.orientation = "row"; targetPanel.alignChildren = ["left", "center"]; targetPanel.margins = 12; targetPanel.add("statictext", undefined, "Apply to:"); var scopeDropdown = targetPanel.add("dropdownlist", undefined, ["Active Artboard", "All Artboards"]); scopeDropdown.selection = 0; var marginPanel = win.add("panel", undefined, "Margins"); marginPanel.orientation = "row"; marginPanel.alignChildren = ["left", "center"]; marginPanel.margins = 12; marginPanel.spacing = 8; marginPanel.add("statictext", undefined, "Margin multiple:"); var marginMultipleInput = marginPanel.add("edittext", undefined, "4"); marginMultipleInput.characters = 6; marginPanel.add("statictext", undefined, "× 12pt"); var stylePanel = win.add("panel", undefined, "Style"); stylePanel.orientation = "row"; stylePanel.alignChildren = ["left", "center"]; stylePanel.margins = 12; stylePanel.add("statictext", undefined, "Line color:"); var colorNames = []; for (var c = 0; c < COLOR_OPTIONS.length; c++) colorNames.push(COLOR_OPTIONS[c].name); var colorDropdown = stylePanel.add("dropdownlist", undefined, colorNames); colorDropdown.selection = 0; stylePanel.add("statictext", undefined, "Stroke (pt):"); var strokeInput = stylePanel.add("edittext", undefined, String(DEFAULT_STROKE_WEIGHT)); strokeInput.characters = 6; var buttons = win.add("group"); buttons.orientation = "row"; buttons.alignment = "right"; buttons.add("button", undefined, "Cancel", { name: "cancel" }); buttons.add("button", undefined, "Build", { name: "ok" }); modeDropdown.onChange = function () { var idx = modeDropdown.selection ? modeDropdown.selection.index : 0; modeDesc.text = GRID_MODES[idx].desc; }; if (win.show() !== 1) return; try { var mode = GRID_MODES[modeDropdown.selection.index]; var scope = scopeDropdown.selection.text; var colorName = colorDropdown.selection.text; var strokeWeight = parseFloat(strokeInput.text); var marginMultiple = parseInt(marginMultipleInput.text, 10); var marginValue = BRAND_MIN_MARGIN * marginMultiple; validatePositiveNumber(strokeWeight, "Stroke weight"); validatePositiveInteger(marginMultiple, "Margin multiple"); var guidesLayer = getOrCreateLayer("guides"); var strokeColor = getColorByName(colorName); var targets = getTargetArtboardIndexes(scope); for (var i = 0; i < targets.length; i++) { var abIndex = targets[i]; var abRect = getArtboardRect(abIndex); var liveRect = getLiveRect(abRect, marginValue); if (liveRect.width <= 0 || liveRect.height <= 0) { throw new Error("Margins consume the full artboard on AB" + pad(abIndex + 1, 2) + "."); } var totalGutter = BRAND_GUTTER * (mode.cols - 1); var usable = liveRect.width - totalGutter; if (usable <= 0) { throw new Error( "The selected mode does not fit on AB" + pad(abIndex + 1, 2) + " with margin " + fmtNum(marginValue) + "pt." ); } var abGroup = addGroup(guidesLayer, buildArtboardGroupName(abIndex)); var gridGroup = addGroup(abGroup, "grid"); var marginsGroup = addGroup(gridGroup, buildMarginGroupName(marginValue, marginMultiple)); var columnsGroup = addGroup(gridGroup, buildColumnGroupName(mode)); var baselineGroup = addGroup(gridGroup, buildBaselineGroupName()); drawMargins(marginsGroup, liveRect, strokeColor, strokeWeight); drawColumns(columnsGroup, liveRect, mode.cols, BRAND_GUTTER, strokeColor, strokeWeight); drawBaselines(baselineGroup, liveRect, BRAND_BASELINE, strokeColor, strokeWeight); } alert("Brand grid generation complete."); } catch (err) { alert("Error: " + err.message); } })();