/* * ============================================================ * MG 排版动效 · 40 秒版 v3 · AE 2022 (22.x) / ExtendScript * 1920x1080 / 30fps / 1200 帧 / 13 个节奏点 * * v3 修正: * · addSolid / fillColor 只吃 3 分量 RGB(v2 传 4 分量,AE 2022 直接报错) * · 每个图层都有明确入点/出点,不再有图层压穿后面的段落 * · 文字用 sourceRectAtTime 包围盒定锚点,(x,y) 就是视觉位置 * * 运行:AE 2022 → 文件 → 脚本 → 运行脚本文件… * ============================================================ */ (function mgTypeMotion40() { // ================= 配置 ================= var C = { black: "0D0D0D", white: "FFFFFF", orange: "F2500A", blue: "1B3AF0", cream: "F3EDE4" }; var CFG = { compName: "MG_TYPE_40S", width: 1920, height: 1080, fps: 30, duration: 40 }; // 字体候选:取第一个能用上的(AE 里没有的会抛错,被跳过) var FONTS = ["Arial-BoldMT", "Arial-Bold", "HelveticaNeue-Bold", "Inter-Bold", "MicrosoftYaHei-Bold", "SimHei", "PingFangSC-Semibold", "MyriadPro-Bold"]; var TEXT = { label: "MOTION STUDY / 01", hero: "MOTION", big1: "MAKE", big2: "IT MOVE", note1: "02 / BUILD", seq: ["TYPE", "SHAPE", "TIME"], marquee: "KEEP IT MOVING \u00B7 ", grid: "GRID", repeat: "MOTION", strip: ["KEEP IT MOVING", "TYPE / SHAPE / TIME", "STUDY 01"], num: "01", letters: ["T", "I", "M", "E"], circle: "MOVE", study: "STUDY", note2: "01 / 40S", collage: ["MOTION", "TYPE", "TIME", "01", "STUDY", "GRID"], outro1: "MOTION STUDY 01", outro2: "AE 2022 / 30FPS / 40S" }; // 段落边界 [起, 止],单位帧 var BEAT = { A: [0, 96], B: [96, 192], C: [192, 288], D: [288, 384], E: [384, 480], F: [480, 576], G: [576, 672], H: [672, 768], I: [768, 864], J: [864, 960], K: [960, 1056], L: [1056, 1140], M: [1140, 1200] }; var END = 1200; // ================= 工具 ================= function rgb(hex) { hex = String(hex).replace("#", ""); return [parseInt(hex.substr(0, 2), 16) / 255, parseInt(hex.substr(2, 2), 16) / 255, parseInt(hex.substr(4, 2), 16) / 255]; } // 仅矢量填充/描边使用(这两个属性要 4 分量) function rgba(hex) { var c = rgb(hex); c.push(1); return c; } function T(f) { return f / CFG.fps; } function tg(l) { return l.property("ADBE Transform Group"); } function P(l) { return tg(l).property("ADBE Position"); } function S(l) { return tg(l).property("ADBE Scale"); } function A(l) { return tg(l).property("ADBE Anchor Point"); } function O(l) { return tg(l).property("ADBE Opacity"); } function R(l) { return tg(l).property("ADBE Rotate Z"); } function k(prop, frame, value, mode) { prop.setValueAtTime(T(frame), value); var i = prop.nearestKeyIndex(T(frame)); if (mode === "linear") { prop.setInterpolationTypeAtKey(i, KeyframeInterpolationType.LINEAR, KeyframeInterpolationType.LINEAR); } else if (mode === "hold") { prop.setInterpolationTypeAtKey(i, KeyframeInterpolationType.HOLD, KeyframeInterpolationType.HOLD); } else { prop.setInterpolationTypeAtKey(i, KeyframeInterpolationType.BEZIER, KeyframeInterpolationType.BEZIER); } return i; } // 纯色层:addSolid 的颜色必须是 [r,g,b] function solid(comp, hex, name, f0, f1) { var s = comp.layers.addSolid(rgb(hex), name, CFG.width, CFG.height, 1); s.inPoint = T(f0 === undefined ? 0 : f0); s.outPoint = T(f1 === undefined ? END : f1); return s; } // 文字层:入点/出点 + 用包围盒定锚点 function text(comp, str, size, hex, x, y, align, f0, f1) { var l = comp.layers.addText(str); l.inPoint = T(f0 === undefined ? 0 : f0); l.outPoint = T(f1 === undefined ? END : f1); var src = l.property("ADBE Text Properties").property("ADBE Text Document"); var td = src.value; td.text = str; td.fontSize = size; td.fillColor = rgb(hex); // 3 分量 // fauxBold 在 AE 2022 里是只读属性,改字体代替 for (var fi = 0; fi < FONTS.length; fi++) { try { td.font = FONTS[fi]; break; } catch (eF) {} } td.justification = (align === "center") ? ParagraphJustification.CENTER_JUSTIFY : ParagraphJustification.LEFT_JUSTIFY; src.setValue(td); // 锚点落到文字包围盒上,(x,y) 即 视觉中心 / 左中 try { var r = l.sourceRectAtTime(l.inPoint, false); if (r && r.width > 0) { if (align === "center") { A(l).setValue([r.left + r.width / 2, r.top + r.height / 2]); } else { A(l).setValue([r.left, r.top + r.height / 2]); } } } catch (e2) {} P(l).setValue([x, y]); return l; } function shapeLayer(comp, name, f0, f1) { var l = comp.layers.addShape(); l.name = name; l.inPoint = T(f0 === undefined ? 0 : f0); l.outPoint = T(f1 === undefined ? END : f1); return l; } function grp(layer, name) { var g = layer.property("ADBE Root Vectors Group").addProperty("ADBE Vector Group"); g.name = name; return g; } function contents(g) { return g.property("ADBE Vectors Group"); } function rectG(g, w, h) { var r = contents(g).addProperty("ADBE Vector Shape - Rect"); r.property("ADBE Vector Rect Size").setValue([w, h]); } function ellG(g, w, h) { var e = contents(g).addProperty("ADBE Vector Shape - Ellipse"); e.property("ADBE Vector Ellipse Size").setValue([w, h]); } function pathG(g, verts, inT, outT, closed) { var p = contents(g).addProperty("ADBE Vector Shape - Group"); var sh = new Shape(); sh.vertices = verts; sh.closed = !!closed; if (inT) sh.inTangents = inT; if (outT) sh.outTangents = outT; p.property("ADBE Vector Shape").setValue(sh); } function fillG(g, hex) { var f = contents(g).addProperty("ADBE Vector Graphic - Fill"); f.property("ADBE Vector Fill Color").setValue(rgba(hex)); // 4 分量 } function strokeG(g, hex, w) { var s = contents(g).addProperty("ADBE Vector Graphic - Stroke"); s.property("ADBE Vector Stroke Color").setValue(rgba(hex)); // 4 分量 s.property("ADBE Vector Stroke Width").setValue(w); } // 线:一条 2 点路径(绝对坐标,相对图层原点) function addLine(g, x1, y1, x2, y2) { var p = contents(g).addProperty("ADBE Vector Shape - Group"); var sh = new Shape(); sh.vertices = [[x1, y1], [x2, y2]]; sh.closed = false; p.property("ADBE Vector Shape").setValue(sh); } // 点:一个椭圆子形状,用官方 matchName ADBE Vector Ellipse Position 摆位 function addDot(g, x, y, size) { var e = contents(g).addProperty("ADBE Vector Shape - Ellipse"); e.property("ADBE Vector Ellipse Size").setValue([size, size]); e.property("ADBE Vector Ellipse Position").setValue([x, y]); } // 方块:一个矩形子形状 function addSquare(g, x, y, w) { var r = contents(g).addProperty("ADBE Vector Shape - Rect"); r.property("ADBE Vector Rect Size").setValue([w, w]); r.property("ADBE Vector Rect Position").setValue([x, y]); } // 淡入淡出(帧号必须落在图层出入点之间) function fade(layer, fIn, fInEnd, fOutStart, fOut) { var o = O(layer); k(o, fIn, 0, "linear"); k(o, fInEnd, 100); if (fOutStart !== undefined) { k(o, fOutStart, 100); k(o, fOut, 0, "linear"); } // 首帧外部保持隐藏 if (fIn > 0) { /* in 之前图层不存在,无需处理 */ } } // ================= 开始 ================= app.beginUndoGroup("MG 40s v3 自动搭建"); try { var comp = app.project.items.addComp(CFG.compName, CFG.width, CFG.height, 1, CFG.duration, CFG.fps); comp.bgColor = rgb(C.black); // 3 分量 comp.motionBlur = true; var i, g; // ---------- 常驻 ---------- solid(comp, C.black, "BG_BLACK", 0, END); var grid = shapeLayer(comp, "GRID", 0, END); g = grp(grid, "lines"); var gx, gy; for (gx = -960; gx <= 960; gx += 72) { addLine(g, gx, -540, gx, 540); } for (gy = -540; gy <= 540; gy += 72) { addLine(g, -960, gy, 960, gy); } strokeG(g, C.white, 1); P(grid).setValue([CFG.width / 2, CFG.height / 2]); fade(grid, 0, 26, 1150, 1190); var label = text(comp, TEXT.label, 26, C.white, 110, 90, "left", 0, END); fade(label, 10, 24, 1120, 1150); // ---------- Beat A 0-96 ---------- var bA = BEAT.A; var hero = text(comp, TEXT.hero, 330, C.white, 960, 540, "center", bA[0], bA[1]); P(hero).setValue([960, 940]); k(P(hero), 14, [960, 940], "linear"); k(P(hero), 34, [960, 540]); k(P(hero), 62, [960, 520]); fade(hero, 12, 20); hero.motionBlur = true; var strike = shapeLayer(comp, "STRIKE", 18, bA[1]); g = grp(strike, "bar"); rectG(g, 1240, 10); fillG(g, C.orange); P(strike).setValue([960, 520]); S(strike).setValue([0, 100]); k(S(strike), 24, [0, 100], "linear"); k(S(strike), 42, [100, 100]); R(strike).setValue(-3); k(R(strike), 24, -3); k(R(strike), 92, -8); strike.motionBlur = true; // ---------- Beat B 96-192 ---------- var bB = BEAT.B; var card = solid(comp, C.cream, "CARD", bB[0], bB[1]); A(card).setValue([CFG.width / 2, CFG.height]); P(card).setValue([CFG.width / 2, CFG.height * 2]); k(P(card), 96, [CFG.width / 2, CFG.height * 2], "linear"); k(P(card), 110, [CFG.width / 2, CFG.height]); k(P(card), 178, [CFG.width / 2, CFG.height]); k(P(card), 192, [CFG.width / 2, 0], "linear"); card.motionBlur = true; var b1 = text(comp, TEXT.big1, 300, C.black, 130, 400, "left", bB[0], bB[1]); P(b1).setValue([-420, 400]); k(P(b1), 108, [-420, 400], "linear"); k(P(b1), 124, [130, 400]); b1.motionBlur = true; var b2 = text(comp, TEXT.big2, 300, C.black, 130, 730, "left", bB[0], bB[1]); P(b2).setValue([-980, 730]); k(P(b2), 116, [-980, 730], "linear"); k(P(b2), 132, [130, 730]); b2.motionBlur = true; var bNote = text(comp, TEXT.note1, 40, C.orange, 130, 930, "left", bB[0], bB[1]); fade(bNote, 140, 154, 176, 190); // ---------- Beat C 192-288 ---------- var bC = BEAT.C; var barB = solid(comp, C.blue, "BAR_BLUE", bC[0], bC[1]); S(barB).setValue([100, 18]); P(barB).setValue([-800, 300]); k(P(barB), 192, [-800, 300], "linear"); k(P(barB), 208, [960, 300]); k(P(barB), 272, [960, 300]); k(P(barB), 288, [2760, 300], "linear"); barB.motionBlur = true; var barO = solid(comp, C.orange, "BAR_ORANGE", 198, bC[1]); S(barO).setValue([100, 46]); P(barO).setValue([2760, 850]); k(P(barO), 198, [2760, 850], "linear"); k(P(barO), 216, [960, 850]); k(P(barO), 272, [960, 850]); k(P(barO), 288, [-800, 850], "linear"); barO.motionBlur = true; var seqY = [300, 560, 850]; var seqS = [170, 210, 150]; var seqC = [C.white, C.white, C.black]; for (i = 0; i < TEXT.seq.length; i++) { var wq = text(comp, TEXT.seq[i], seqS[i], seqC[i], 960, seqY[i], "center", bC[0], bC[1]); S(wq).setValue([40, 40]); k(S(wq), 206 + i * 13, [40, 40], "linear"); k(S(wq), 216 + i * 13, [106, 106]); k(S(wq), 224 + i * 13, [100, 100]); fade(wq, 206 + i * 13, 214 + i * 13, 264, 276); wq.motionBlur = true; } var dots = shapeLayer(comp, "DOTS_ROW", 210, bC[1]); g = grp(dots, "row"); for (i = 0; i < 46; i++) { addDot(g, i * 16, 0, 8); } fillG(g, C.black); P(dots).setValue([-200, 980]); k(P(dots), 210, [-200, 980], "linear"); k(P(dots), 268, [1500, 980]); dots.motionBlur = true; // ---------- Beat D 288-384 ---------- var bD = BEAT.D; var blueBg = solid(comp, C.blue, "BG_BLUE", bD[0], bD[1]); A(blueBg).setValue([CFG.width / 2, CFG.height]); S(blueBg).setValue([100, 0]); k(S(blueBg), 288, [100, 0], "linear"); k(S(blueBg), 302, [100, 100]); k(S(blueBg), 370, [100, 100]); k(S(blueBg), 384, [100, 0], "linear"); blueBg.motionBlur = true; var mqStr = TEXT.marquee + TEXT.marquee + TEXT.marquee + TEXT.marquee + TEXT.marquee; var mq = text(comp, mqStr, 200, C.white, 0, 540, "left", bD[0], bD[1]); P(mq).setValue([400, 540]); k(P(mq), 288, [400, 540], "linear"); k(P(mq), 384, [-3200, 540], "linear"); mq.motionBlur = true; var mq2 = text(comp, TEXT.marquee + TEXT.marquee, 96, C.cream, 0, 780, "left", bD[0], bD[1]); P(mq2).setValue([-600, 780]); k(P(mq2), 288, [-600, 780], "linear"); k(P(mq2), 384, [1500, 780], "linear"); mq2.motionBlur = true; // ---------- Beat E 384-480 ---------- var bE = BEAT.E; solid(comp, C.cream, "BG_CREAM", bE[0], bE[1]); var checkA = shapeLayer(comp, "CHECK_A", bE[0], bE[1]); g = grp(checkA, "sq"); var cxi, cyi; for (cxi = 0; cxi < 8; cxi++) { for (cyi = 0; cyi < 5; cyi++) { addSquare(g, -840 + cxi * 240, -420 + cyi * 240, 120); } } fillG(g, C.blue); P(checkA).setValue([960, 540]); S(checkA).setValue([100, 100]); k(S(checkA), 384, [0, 0], "linear"); k(S(checkA), 404, [100, 100]); checkA.motionBlur = true; var checkB = shapeLayer(comp, "CHECK_B", bE[0], bE[1]); g = grp(checkB, "sq"); for (cxi = 0; cxi < 8; cxi++) { for (cyi = 0; cyi < 5; cyi++) { addSquare(g, -720 + cxi * 240, -540 + cyi * 240, 120); } } fillG(g, C.orange); P(checkB).setValue([960, 540]); S(checkB).setValue([100, 100]); k(S(checkB), 388, [0, 0], "linear"); k(S(checkB), 410, [100, 100]); checkB.motionBlur = true; var gridWord = text(comp, TEXT.grid, 300, C.black, 960, 540, "center", bE[0], bE[1]); S(gridWord).setValue([130, 130]); k(S(gridWord), 396, [130, 130], "linear"); k(S(gridWord), 414, [100, 100]); fade(gridWord, 396, 408, 466, 478); gridWord.motionBlur = true; // ---------- Beat F 480-576 ---------- var bF = BEAT.F; var faces = [[480, C.blue], [960, C.white], [1440, C.orange]]; for (i = 0; i < faces.length; i++) { var face = shapeLayer(comp, "FACE_" + i, bF[0], bF[1]); g = grp(face, "ring"); ellG(g, 200, 200); strokeG(g, faces[i][1], 8); g = grp(face, "eyeL"); ellG(g, 18, 18); fillG(g, faces[i][1]); g.property("ADBE Vector Transform Group") .property("ADBE Vector Position").setValue([-45, -30]); g = grp(face, "eyeR"); ellG(g, 18, 18); fillG(g, faces[i][1]); g.property("ADBE Vector Transform Group") .property("ADBE Vector Position").setValue([45, -30]); g = grp(face, "mouth"); pathG(g, [[-52, 34], [0, 6], [52, 34]], [[-22, 8], [-26, 8], [22, 8]], [[22, 8], [26, 8], [-22, 8]]); strokeG(g, faces[i][1], 7); P(face).setValue([faces[i][0], 420]); S(face).setValue([0, 0]); k(S(face), 486 + i * 8, [0, 0], "linear"); k(S(face), 496 + i * 8, [112, 112]); k(S(face), 504 + i * 8, [100, 100]); fade(face, 486 + i * 8, 494 + i * 8, 556, 572); face.motionBlur = true; } for (i = 0; i < 5; i++) { var rep = text(comp, TEXT.repeat, 54, C.white, 960, 640 + i * 76, "center", bF[0], bF[1]); fade(rep, 512 + i * 6, 522 + i * 6, 552, 570); } // ---------- Beat G 576-672 ---------- var bG = BEAT.G; var strips = [ [TEXT.strip[0], 120, C.white, 300], [TEXT.strip[1], 86, C.orange, 540], [TEXT.strip[2], 120, C.white, 780] ]; for (i = 0; i < strips.length; i++) { var st = text(comp, strips[i][0], strips[i][1], strips[i][2], 0, strips[i][3], "left", bG[0], bG[1]); R(st).setValue(-8); P(st).setValue([2400, strips[i][3]]); k(P(st), 576 + i * 8, [2400, strips[i][3]], "linear"); k(P(st), 668, [-1600, strips[i][3]], "linear"); st.motionBlur = true; } // ---------- Beat H 672-768 ---------- var bH = BEAT.H; var num = text(comp, TEXT.num, 700, C.white, 960, 540, "center", bH[0], bH[1]); S(num).setValue([140, 140]); k(S(num), 672, [140, 140], "linear"); k(S(num), 692, [100, 100]); k(S(num), 744, [100, 100], "linear"); k(S(num), 768, [320, 320], "linear"); fade(num, 672, 684, 750, 768); num.motionBlur = true; var numRule = shapeLayer(comp, "RULE_MID", bH[0], bH[1]); g = grp(numRule, "bar"); rectG(g, 6, 620); fillG(g, C.orange); P(numRule).setValue([960, 540]); S(numRule).setValue([100, 0]); k(S(numRule), 676, [100, 0], "linear"); k(S(numRule), 700, [100, 100]); k(S(numRule), 744, [100, 100]); k(S(numRule), 768, [100, 0], "linear"); // ---------- Beat I 768-864 ---------- var bI = BEAT.I; var card2 = solid(comp, C.white, "CARD2", bI[0], bI[1]); A(card2).setValue([CFG.width / 2, CFG.height]); P(card2).setValue([CFG.width / 2, CFG.height * 2]); k(P(card2), 768, [CFG.width / 2, CFG.height * 2], "linear"); k(P(card2), 782, [CFG.width / 2, CFG.height]); k(P(card2), 850, [CFG.width / 2, CFG.height]); k(P(card2), 864, [CFG.width / 2, 0], "linear"); card2.motionBlur = true; var lettersX = [-330, -110, 110, 330]; for (i = 0; i < TEXT.letters.length; i++) { var ch = text(comp, TEXT.letters[i], 420, C.black, 960 + lettersX[i], 540, "center", bI[0], bI[1]); S(ch).setValue([60, 60]); k(S(ch), 782 + i * 7, [60, 60], "linear"); k(S(ch), 792 + i * 7, [108, 108]); k(S(ch), 800 + i * 7, [100, 100]); fade(ch, 782 + i * 7, 790 + i * 7); ch.motionBlur = true; } // ---------- Beat J 864-960 ---------- var bJ = BEAT.J; var bgOrange = solid(comp, C.orange, "BG_ORANGE", bJ[0], bJ[1]); fade(bgOrange, 864, 872); var disc = shapeLayer(comp, "DISC", 866, bJ[1]); g = grp(disc, "c"); ellG(g, 760, 760); fillG(g, C.white); P(disc).setValue([960, 540]); S(disc).setValue([0, 0]); k(S(disc), 868, [0, 0], "linear"); k(S(disc), 892, [100, 100]); disc.motionBlur = true; var moveWord = text(comp, TEXT.circle, 200, C.black, 960, 540, "center", 880, bJ[1]); S(moveWord).setValue([90, 90]); k(S(moveWord), 886, [90, 90], "linear"); k(S(moveWord), 902, [100, 100]); fade(moveWord, 886, 896); // ---------- Beat K 960-1056 ---------- var bK = BEAT.K; var halftone = shapeLayer(comp, "HALFTONE", bK[0], bK[1]); g = grp(halftone, "d"); var hxi, hyi; for (hxi = 0; hxi < 12; hxi++) { for (hyi = 0; hyi < 8; hyi++) { addDot(g, hxi * 24, hyi * 24, 12); } } fillG(g, C.white); P(halftone).setValue([1320, 300]); S(halftone).setValue([0, 0]); k(S(halftone), 960, [0, 0], "linear"); k(S(halftone), 980, [100, 100]); halftone.motionBlur = true; var studyWord = text(comp, TEXT.study, 220, C.white, 240, 480, "left", 962, bK[1]); P(studyWord).setValue([-300, 480]); k(P(studyWord), 966, [-300, 480], "linear"); k(P(studyWord), 986, [240, 480]); studyWord.motionBlur = true; var studyNote = text(comp, TEXT.note2, 48, C.orange, 240, 640, "left", bK[0], bK[1]); fade(studyNote, 996, 1008, 1040, 1054); // ---------- Beat L 1056-1140 ---------- var bL = BEAT.L; var spots = [ [180, 240, -6], [1180, 200, 5], [560, 520, -3], [1400, 620, 8], [260, 820, 4], [1020, 900, -7] ]; for (i = 0; i < TEXT.collage.length; i++) { var cw = text(comp, TEXT.collage[i], 160 + (i % 3) * 50, (i % 2 === 0) ? C.white : C.orange, spots[i][0], spots[i][1], "left", bL[0], bL[1]); R(cw).setValue(spots[i][2]); var f0 = 1056 + i * 12; fade(cw, f0, f0 + 6, f0 + 10, f0 + 16); S(cw).setValue([100, 100]); k(S(cw), f0, [70, 70], "linear"); k(S(cw), f0 + 6, [100, 100]); cw.motionBlur = true; } // ---------- Beat M 1140-1200 ---------- var bM = BEAT.M; var rule = shapeLayer(comp, "RULE_END", bM[0], END); g = grp(rule, "bar"); rectG(g, 900, 6); fillG(g, C.orange); P(rule).setValue([960, 700]); S(rule).setValue([0, 100]); k(S(rule), 1144, [0, 100], "linear"); k(S(rule), 1164, [100, 100]); var outro = text(comp, TEXT.outro1, 150, C.white, 960, 500, "center", 1146, END); fade(outro, 1148, 1164); var outro2 = text(comp, TEXT.outro2, 40, C.orange, 960, 600, "center", 1154, END); fade(outro2, 1156, 1172); comp.openInViewer(); alert("搭建完成:" + CFG.compName + "\n40 秒 / 30fps / 1200 帧 / 13 个节奏点\n\n" + "改文案:TEXT 改配色:C 改段落:BEAT"); } catch (err) { alert("脚本出错(第 " + err.line + " 行):\n" + err.toString()); } app.endUndoGroup(); })();