[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6EE95NNSYZTGCSDTXYB3VXF":3,"skill-same:01M6EE95NNSYZTGCSDTXYB3VXF":72},{"skillNo":4,"name":5,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":19,"linkOnly":20,"markdownContent":21,"markdownBody":21,"frontMatter":22,"refName":23,"commitSha":24,"skillDirectory":25,"forksCount":26,"repositoryHtmlUrl":27,"repositoryHomepageUrl":28,"ownerHtmlUrl":29,"ownerBlogUrl":6,"ownerDescription":30,"updatedAt":31,"install":32,"resources":45},"01M6EE95NNSYZTGCSDTXYB3VXF","after-effects",null,"ComeOnOliver\u002Fskillshub","ComeOnOliver","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F43215937?v=4","01M6E5JNFECJAAVFE0W7SMWWD2","Haoran Shu","01M6E5JNNDQS7AJZDYFQ8TPZCK",67,"MIT","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002FTerminalSkills\u002Fskills\u002Fafter-effects\u002FSKILL.md",[],[18],"after effects","2026-11-10 10:12:30",false,"# After Effects\n\n## Overview\n\nAutomate Adobe After Effects — the industry-standard motion graphics and compositing tool. This skill covers ExtendScript for programmatic project manipulation, CEP\u002FUXP panel development, expressions for procedural animation, aerender CLI for headless batch rendering, MOGRT template automation, data-driven graphics, and production pipeline integration. Build repeatable workflows for social media content, broadcast graphics, and VFX pipelines.\n\n## Instructions\n\n### Step 1: Scripting Approaches\n\n1. **ExtendScript** (.jsx) — Full project DOM access, runs inside AE\n2. **Expressions** — Per-property JavaScript-like code, runs per-frame\n3. **CEP\u002FUXP Panels** — HTML\u002FJS panels with ExtendScript bridge\n4. **aerender** — Command-line renderer (headless)\n\n**Run an ExtendScript:**\n```bash\n# From AE: File > Scripts > Run Script File\n# Or place in Scripts\u002FStartup\u002F for auto-run\n# macOS CLI:\nosascript -e 'tell application \"Adobe After Effects 2024\" to DoScript \"$.evalFile(\\\"\u002Fpath\u002Fto\u002Fscript.jsx\\\")\"'\n```\n\n### Step 2: ExtendScript — Project & Layer Operations\n\n```javascript\nvar project = app.project;\n\n\u002F\u002F Create composition\nvar comp = project.items.addComp(\"Social Post\", 1080, 1920, 1, 10, 30);\n\n\u002F\u002F Import footage\nvar footage = project.importFile(new ImportOptions(new File(\"\u002Fpath\u002Fto\u002Ffootage.mp4\")));\n\n\u002F\u002F Add layers to comp\nvar layer = comp.layers.add(footage);\nvar textLayer = comp.layers.addText(\"Hello World\");\n\n\u002F\u002F Configure text\nvar textProp = textLayer.property(\"Source Text\");\nvar textDoc = textProp.value;\ntextDoc.fontSize = 72;\ntextDoc.fillColor = [1, 1, 1];\ntextDoc.font = \"Arial-BoldMT\";\ntextProp.setValue(textDoc);\n\n\u002F\u002F Animate position with easing\nvar position = textLayer.property(\"Position\");\nposition.setValueAtTime(0, [960, 540]);\nposition.setValueAtTime(1, [960, 300]);\nvar ease = new KeyframeEase(0, 75);\nposition.setTemporalEaseAtKey(1, [ease, ease]);\nposition.setTemporalEaseAtKey(2, [ease, ease]);\n\n\u002F\u002F Add effect\nvar blur = textLayer.property(\"Effects\").addProperty(\"Gaussian Blur\");\nblur.property(\"Blurriness\").setValue(5);\n```\n\n### Step 3: Template Automation (Data-Driven)\n\n```javascript\n\u002F\u002F template-batch.jsx — Replace text layers in a template from CSV data\nfunction processTemplate(comp, data) {\n    for (var i = 1; i \u003C= comp.numLayers; i++) {\n        var layer = comp.layer(i);\n        if (layer instanceof TextLayer && data.hasOwnProperty(layer.name)) {\n            var textProp = layer.property(\"Source Text\");\n            var textDoc = textProp.value;\n            textDoc.text = data[layer.name];\n            textProp.setValue(textDoc);\n        }\n    }\n}\n\n\u002F\u002F CSV format: Title,Subtitle,Date\n\u002F\u002F Template has text layers named: Title, Subtitle, Date\nvar templateComp = app.project.activeItem;\nvar csvData = readCSV(\"\u002Fpath\u002Fto\u002Fdata.csv\");  \u002F\u002F Parse CSV into array of objects\n\nfor (var r = 0; r \u003C csvData.length; r++) {\n    var newComp = templateComp.duplicate();\n    newComp.name = \"Output_\" + (r + 1);\n    processTemplate(newComp, csvData[r]);\n}\n```\n\n### Step 4: Expressions\n\n```javascript\n\u002F\u002F Wiggle: wiggle(5, 50)   — 5 times\u002Fsec, 50px amplitude\n\u002F\u002F Loop: loopOut(\"cycle\")\n\u002F\u002F Fade in: linear(time, 0, 1, 0, 100)\n\n\u002F\u002F Bounce expression (apply to Position)\namplitude = 15; frequency = 3; decay = 5; n = 0;\nif (numKeys > 0) { n = nearestKey(time).index; if (key(n).time > time) n--; }\nif (n > 0) {\n    t = time - key(n).time;\n    value + amplitude * Math.sin(frequency * t * 2 * Math.PI) \u002F Math.exp(decay * t);\n} else { value; }\n\n\u002F\u002F Typewriter (on Source Text)\nstr = value; n = Math.round(time * 20); str.substr(0, n);\n\n\u002F\u002F Counter: Math.round(linear(time, 0, 3, 0, 1000));\n\n\u002F\u002F Follow null with delay\ndelay = 0.5;\nthisComp.layer(\"Null 1\").position.valueAtTime(time - delay);\n```\n\n### Step 5: aerender — Command-Line Rendering\n\n```bash\n# Basic render\naerender -project \"\u002Fpath\u002Fto\u002Fproject.aep\" -comp \"Main Comp\" -output \"\u002Frenders\u002Foutput.mov\"\n\n# With settings\naerender \\\n  -project \"\u002Fpath\u002Fto\u002Fproject.aep\" \\\n  -comp \"Main Comp\" \\\n  -output \"\u002Frenders\u002Foutput_[####].png\" \\\n  -RStemplate \"Best Settings\" \\\n  -OMtemplate \"PNG Sequence\" \\\n  -s 0 -e 300 -mp\n\n# macOS path: \u002FApplications\u002FAdobe\\ After\\ Effects\\ 2024\u002Faerender\n# Windows: \"C:\\Program Files\\Adobe\\Adobe After Effects 2024\\Support Files\\aerender.exe\"\n```\n\n**Batch render script:**\n```bash\n#!\u002Fbin\u002Fbash\nAERENDER=\"\u002FApplications\u002FAdobe After Effects 2024\u002Faerender\"\nfor aep in \u002Fprojects\u002F*.aep; do\n    name=$(basename \"$aep\" .aep)\n    \"$AERENDER\" -project \"$aep\" -RStemplate \"Best Settings\" -OMtemplate \"H.264\" \\\n        -output \"\u002Frenders\u002F${name}.mp4\" -mp\ndone\n```\n\n### Step 6: MOGRT & CEP Panels\n\n**Automate MOGRT property setup:**\n```javascript\nvar comp = app.project.activeItem;\nvar textLayer = comp.layer(\"Title\");\nvar sourceText = textLayer.property(\"Source Text\");\ncomp.addMotionGraphicsTemplateController(sourceText);\n\u002F\u002F Then export via Essential Graphics panel\n```\n\n**CEP panel bridge** (call ExtendScript from panel JS):\n```javascript\nconst csInterface = new CSInterface();\nfunction runInAE(script) {\n    return new Promise((resolve, reject) => {\n        csInterface.evalScript(script, (result) => {\n            if (result === \"EvalScript error.\") reject(result);\n            else resolve(result);\n        });\n    });\n}\n\u002F\u002F Example: get comp names from AE\nconst result = await runInAE(`\n    var names = [];\n    for (var i = 1; i \u003C= app.project.numItems; i++) {\n        if (app.project.item(i) instanceof CompItem) names.push(app.project.item(i).name);\n    }\n    JSON.stringify(names);\n`);\n```\n\n## Examples\n\n### Example 1: Batch-generate 50 social media cards from a spreadsheet\n**User prompt:** \"I have a CSV with 50 rows of product names, prices, and image paths. Write an ExtendScript that duplicates my 'Product Card' template comp for each row, replaces the Title, Price, and Photo layers, and queues them all for rendering.\"\n\nThe agent will create a `.jsx` script that reads the CSV file, iterates over each row, duplicates the template composition, replaces text layer values using `property(\"Source Text\")`, swaps the Photo layer source via `replaceSource()` with imported images, adds each comp to the render queue with H.264 output settings, and logs progress to the ExtendScript console.\n\n### Example 2: Set up a nightly render pipeline with aerender\n**User prompt:** \"Create a bash script that finds all .aep files in \u002Fprojects\u002Fdaily-renders\u002F, renders the 'Export' comp from each one as ProRes 422 to \u002Foutput\u002FYYYY-MM-DD\u002F, and sends a Slack notification when done.\"\n\nThe agent will write a shell script that iterates over `.aep` files using a for loop, calls `aerender` with `-comp \"Export\"` and `-OMtemplate \"Apple ProRes 422\"` targeting a date-stamped output directory, captures exit codes to track successes and failures, and posts a summary to a Slack webhook with `curl` when all renders complete.\n\n## Guidelines\n\n- ExtendScript uses ES3 syntax (no `let`\u002F`const`, no arrow functions, no template literals) so always use `var` and string concatenation\n- Always close clips and release file handles in batch scripts to avoid AE running out of memory on large jobs\n- Use `app.beginUndoGroup()` and `app.endUndoGroup()` around ExtendScript modifications so the entire operation can be reverted with a single undo\n- Test aerender commands with a short frame range (`-s 0 -e 10`) before running full batch renders to catch template or path errors early\n- MOGRT templates must have properties added to the Essential Graphics panel before export; scripting can add controllers but cannot create the MOGRT file itself\n",{},"main","def8531e65114c0fca8fb8551c1871ee0eed705c","skills\u002FTerminalSkills\u002Fskills\u002Fafter-effects",24,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub","https:\u002F\u002Fskillshub.wtf","https:\u002F\u002Fgithub.com\u002FComeOnOliver","AI & Blockchain Engineer\r\n","2026-06-24 22:07:19",{"source":7,"skillName":5,"commands":33,"prompt":43,"zipAvailable":44},[34,37,40],{"tool":35,"command":36},"npx","npx skills add ComeOnOliver\u002Fskillshub --skill after-effects",{"tool":38,"command":39},"bunx","bunx skills add ComeOnOliver\u002Fskillshub --skill after-effects",{"tool":41,"command":42},"pnpm","pnpm dlx skills add ComeOnOliver\u002Fskillshub --skill after-effects","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002FTerminalSkills\u002Fskills\u002Fafter-effects\u002FSKILL.md",true,[46,52,56,60,64,68],{"path":47,"resourceType":48,"resourceTypeDesc":49,"sizeBytes":50,"sourceHtmlUrl":51},"references\u002Fci.md","REFERENCE","参考文档",2223,"https:\u002F\u002Fgithub.com\u002Fpattanation\u002FNorvik\u002Fblob\u002Fclaude\u002Finstall-gsd-build-foQdV\u002F.agents\u002Fskills\u002Fservice-virtualization\u002Freferences\u002Fci.md",{"path":53,"resourceType":48,"resourceTypeDesc":49,"sizeBytes":54,"sourceHtmlUrl":55},"references\u002Fmsw.md",7415,"https:\u002F\u002Fgithub.com\u002Fpattanation\u002FNorvik\u002Fblob\u002Fclaude\u002Finstall-gsd-build-foQdV\u002F.agents\u002Fskills\u002Fservice-virtualization\u002Freferences\u002Fmsw.md",{"path":57,"resourceType":48,"resourceTypeDesc":49,"sizeBytes":58,"sourceHtmlUrl":59},"references\u002Frecord-replay.md",2945,"https:\u002F\u002Fgithub.com\u002Fpattanation\u002FNorvik\u002Fblob\u002Fclaude\u002Finstall-gsd-build-foQdV\u002F.agents\u002Fskills\u002Fservice-virtualization\u002Freferences\u002Frecord-replay.md",{"path":61,"resourceType":48,"resourceTypeDesc":49,"sizeBytes":62,"sourceHtmlUrl":63},"references\u002Ftestcontainers.md",3214,"https:\u002F\u002Fgithub.com\u002Fpattanation\u002FNorvik\u002Fblob\u002Fclaude\u002Finstall-gsd-build-foQdV\u002F.agents\u002Fskills\u002Fservice-virtualization\u002Freferences\u002Ftestcontainers.md",{"path":65,"resourceType":48,"resourceTypeDesc":49,"sizeBytes":66,"sourceHtmlUrl":67},"references\u002Ftoxiproxy.md",3935,"https:\u002F\u002Fgithub.com\u002Fpattanation\u002FNorvik\u002Fblob\u002Fclaude\u002Finstall-gsd-build-foQdV\u002F.agents\u002Fskills\u002Fservice-virtualization\u002Freferences\u002Ftoxiproxy.md",{"path":69,"resourceType":48,"resourceTypeDesc":49,"sizeBytes":70,"sourceHtmlUrl":71},"references\u002Fwiremock.md",3663,"https:\u002F\u002Fgithub.com\u002Fpattanation\u002FNorvik\u002Fblob\u002Fclaude\u002Finstall-gsd-build-foQdV\u002F.agents\u002Fskills\u002Fservice-virtualization\u002Freferences\u002Fwiremock.md",[73,87,97,106,112,119],{"skillNo":74,"name":75,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":76,"categories":77,"keywords":83,"publishedAt":19},"01M6FKJN13GMG4KY57J3QD8GY5","model-hierarchy-skill","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzscole\u002Fmodel-hierarchy-skill\u002Fmodel-hierarchy-skill\u002FSKILL.md",[78],{"categoryNo":79,"categoryName":80,"taxonomyType":81,"taxonomyTypeDesc":82},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[84,85,86],"model","model hierarchy","model hierarchy skill",{"skillNo":88,"name":89,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":90,"categories":91,"keywords":93,"publishedAt":19},"01M6FKJJJ6GCAMR4PPPRD12M5X","zoom-mcp","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-mcp\u002FSKILL.md",[92],{"categoryNo":79,"categoryName":80,"taxonomyType":81,"taxonomyTypeDesc":82},[94,95,96],"MCP","zoom","zoom mcp",{"skillNo":98,"name":99,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":100,"categories":101,"keywords":102,"publishedAt":19},"01M6FKJE3KYT3KPEZMEEHYKA6K","zoom-apps-sdk","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-apps-sdk\u002FSKILL.md",[],[103,104,105,95],"sdk","zoom apps sdk","apps",{"skillNo":107,"name":108,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":109,"categories":110,"keywords":111,"publishedAt":19},"01M6FKJ9EDH9Q5VWDF8HAJRSP0","windows","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwindows\u002FSKILL.md",[],[108],{"skillNo":113,"name":114,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":115,"categories":116,"keywords":118,"publishedAt":19},"01M6FKJ666BEEFC3AE9GJ72Q93","whiteboard","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwhiteboard\u002FSKILL.md",[117],{"categoryNo":79,"categoryName":80,"taxonomyType":81,"taxonomyTypeDesc":82},[114],{"skillNo":120,"name":121,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":122,"categories":123,"keywords":124,"publishedAt":19},"01M6FKJ21WFCDGTJQ2Q91T9DVW","websockets","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwebsockets\u002FSKILL.md",[],[121]]