Prompts & Code Used For Adobe AE Extension Development Tutorial with AI
Initial Prompt Used With Claude AI:
..............................
I'm building an Adobe After Effects extension. It’s a CEP panel, where I’ll be using HTML, CSS, JavaScript and JSX.
The extension allows users to import a GLB 3D model, modify its color, and add it to the current composition.
My extension is called ‘awesome’, my company name is ‘aianimation’
Please provide the following core files.
I have a folder structure with CSXS, client (for html, css and js files), host for jsx files. Plus am happy to add other folders where needed i.e. to store my pre-made 3D files for importing when a button is pressed.
manifest.xml
index.html: The main HTML file for the extension, including necessary script and stylesheet links, and a basic UI layout color picker, and 1 button.
style.css: A basic CSS file for styling the extension's UI.
main.js: The main JavaScript file that handles user interactions, GLB file loading, texture and color modification, and communication with the JSX script for importing the modified GLB into After Effects.
import.jsx: The JSX script that handles the actual importing of the modified GLB file into the current After Effects composition.
Please also write a .debug file that I will add to the root of my extension. So I can see console messages vid developer tools in Google Chrome. It should look something like this:
<?xml version="1.0" encoding="UTF-8"?>
<ExtensionList>
<Extension Id="com.companyname.extension.panel">
<HostList>
<Host Name="AEFT" Port="7002"/>
</HostList>
</Extension>
</ExtensionList>
Please advise and include on any extra code libraries I should include for the 3D import function to work.
Note
- recent versions of after effects support gab and gltf 3D files.
- jsx files are needed to provide a way to access local files and interact with After Effects.
Please use Three.js and GLTFLoader for handling GLB files, and include error handling and necessary comments in the code.
2nd Updated Prompt Used With Claude AI To Get The Requested Functionality:
..............................
I have this adobe after effects extension I'm developing.
I'd like to change it so there is no input file select option.
Remove import button. Instead have the colour picker and 3 buttons, with an icon for cube, sphere and cone. Using icons loaded via an online cdn resource.
When a button is pressed it should trigger a js function called 'import GLB' . It should pass the name of the item, i.e. a cube, sphere, cone along with the selected colour. To a jsx function (*which are needed to use local storage and import things into after effects'.
It should first read the GLB data (found in a folder called 'GLB', in my extension root, i.e. a file called cube.glb. Then update the datas material colour based on the colour picker value. Then recompile the file to create a new GLB file saved to a 'temp' folder, which I've added to my extension root. Then it should import this new 3D glb file into after effects adding it to the active composition.
Here's my existing code:
HTML:
<!DOCTYPE html> <html> <head> <title>Awesome Extension</title> <link rel="stylesheet" type="text/css" href="style.css"> </head> <body> <h1>Awesome Extension</h1> <input type="file" id="glbFileInput" accept=".glb"> <input type="color" id="colorPicker"> <button id="importButton">Import GLB</button> <script src="CSInterface.js"></script> <script src="main.js"></script> </body> </html>
JS:
const csInterface = new CSInterface(); document.getElementById('importButton').addEventListener('click', function() { const glbFileInput = document.getElementById('glbFileInput'); const colorPicker = document.getElementById('colorPicker'); if (glbFileInput.files.length > 0) { const glbFile = glbFileInput.files[0]; const color = colorPicker.value; csInterface.evalScript(`importGLB("${glbFile.path}", "${color}")`, function(result) { console.log(result); }); } });
JSX:
function importGLB(glbFilePath, color) { try { var comp = app.project.activeItem; if (!(comp instanceof CompItem)) { alert("Please select a composition."); return; } var glbImportOptions = new ImportOptions(); glbImportOptions.file = new File(glbFilePath); var glbItem = app.project.importFile(glbImportOptions); var glbLayer = comp.layers.add(glbItem); glbLayer.threeDLayer = true; // Modify the color of the GLB layer (you may need to adjust this based on the GLB file structure) glbLayer.property("Materials").property(1).property("Diffuse").setValue([hexToRgb(color).r / 255, hexToRgb(color).g / 255, hexToRgb(color).b / 255]); return "GLB imported successfully."; } catch (error) { return "Error importing GLB: " + error.toString(); } } function hexToRgb(hex) { var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) } : null; }
--------------------------------
Final Code:
..............................
Manifest.xml: (update with your own name/company name and extension name.
..............................
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<ExtensionManifest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ExtensionBundleId="com.companyname.extensionname" ExtensionBundleVersion="1.0.0" Version="7.0"> <ExtensionList>
<Extension Id="com.companyname.extensionname.panel" Version="1.0.0" />
</ExtensionList>
<ExecutionEnvironment>
<HostList>
<Host Name="AEFT" Version="15.0" />
</HostList>
<LocaleList>
<Locale Code="All" />
</LocaleList>
<RequiredRuntimeList>
<RequiredRuntime Name="CSXS" Version="9.0" />
</RequiredRuntimeList>
</ExecutionEnvironment>
<DispatchInfoList>
<Extension Id="com.aianimation.awesome.panel">
<DispatchInfo>
<Resources>
<MainPath>./client/index.html</MainPath>
<ScriptPath>./host/import.jsx</ScriptPath>
<ScriptPath>./debug.js</ScriptPath>
<CEFCommandLine />
</Resources>
<Lifecycle>
<AutoVisible>true</AutoVisible>
</Lifecycle>
<UI>
<Type>Panel</Type>
<Menu>Extension Name</Menu>
<Geometry>
<Size>
<Height>300</Height>
<Width>400</Width>
</Size>
</Geometry> </UI>
</DispatchInfo>
</Extension>
</DispatchInfoList>
</ExtensionManifest>
Index.html:
..............................
<!DOCTYPE html>
<html>
<head>
<title>Awesome Extension</title>
<link rel="stylesheet" type="text/css" href="style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
</head>
<body>
<h4>Primitives of Awesome</h4>
<input type="color" id="colorPicker">
<button id="cubeButton"><i class="fas fa-cube"></i></button>
<button id="sphereButton"><i class="fas fa-globe"></i></button>
<button id="coneButton"><i class="fas fa-ice-cream"></i></button>
<script src="CSInterface.js"></script>
<script src="main.js"></script>
</body>
</html>
style.css:
..............................
body {
font-family: Arial, sans-serif; padding: 20px; background-color: rgb(25, 25, 25); } h4 {
margin-bottom: 20px;
color: rgb(90, 90, 90);
}
input[type="file"],
input[type="color"],
button {
margin-bottom: 10px;
}
main.js:
..............................
const csInterface = new CSInterface();
const extensionPath = csInterface.getSystemPath(SystemPath.EXTENSION);
const jsxFilePath = `${extensionPath}/host/import.jsx`;
const gltfFilePath = `${extensionPath}/GLTF/`;
function importGLTF(shape, color) {
csInterface.evalScript(`$.evalFile("${jsxFilePath}")`);
csInterface.evalScript(`importGLTF("${shape}", "${color}", "${gltfFilePath}")`);
}
['cube', 'sphere', 'cone'].forEach(shape => {
document.getElementById(`${shape}Button`).addEventListener('click', () => {
const color = document.getElementById('colorPicker').value;
importGLTF(shape, color);
});
});
import.jsx
.....
function importGLTF(shape, color, extensionPath) {
// alert("Importing GLTF: " + shape + ", " + color + ", " + extensionPath);
try {
varcomp=app.project.activeItem;
if (!(compinstanceofCompItem)) {
// alert("Please select a composition.");
return;
}
vargltfFolder=newFolder(extensionPath);
vargltfFile=newFile(gltfFolder.absoluteURI+"/"+shape+".gltf");
// alert(gltfFile);
// Read the GLTF file
vargltfData=readGLTFData(gltfFile);
// Update the GLTF color
try {
varupdatedGltfData=updateGLTFColor(gltfData, color);
} catch (error) {
// alert("Error updating GLTF color: " + error.toString());
return;
}
// Save the updated GLTF data to a temporary file
vartempFolder=newFolder(extensionPath+"/temp/");
if (!tempFolder.exists) {
tempFolder.create();
}
vartempGltfFile=newFile(tempFolder.absoluteURI+"/"+shape+"_"+color+".gltf");
saveGLTFData(updatedGltfData, tempGltfFile);
// Import the updated GLTF file into After Effects
varimportOptions=newImportOptions();
importOptions.file=tempGltfFile;
varimportedItem=app.project.importFile(importOptions);
varlayer=comp.layers.add(importedItem);
layer.threeDLayer=true;
return"GLTF imported and color updated successfully.";
} catch (error) {
return"Error importing GLTF or updating color: "+error.toString();
}
}
functionreadGLTFData(gltfFile) {
varfile=newFile(gltfFile);
if (!file.open("r")) {
thrownewError("Unable to open the GLTF file.");
}
vargltfData=file.read();
file.close();
returngltfData;
}
functionupdateGLTFColor(gltfData, color) {
// alert("Updating GLTF color: " + color);
try {
//// alert("GLTF data: " + gltfData);
varjsonData=JSON.parse(gltfData);
varmaterials=jsonData.materials;
if (materials&&materials.length>0) {
varmaterial=materials[0];
if (material.pbrMetallicRoughness) {
varbaseColorFactor=material.pbrMetallicRoughness.baseColorFactor;
if (baseColorFactor) {
varrgb=hexToRgb(color);
baseColorFactor[0] =rgb.r/255;
baseColorFactor[1] =rgb.g/255;
baseColorFactor[2] =rgb.b/255;
}
}
}
varupdatedGltfData=JSON.stringify(jsonData);
returnupdatedGltfData;
} catch (error) {
// alert("Error updating GLTF color: " + error.toString());
throwerror;
}
}
functionsaveGLTFData(gltfData, gltfFile) {
varfile=newFile(gltfFile);
if (!file.open("w")) {
thrownewError("Unable to open the GLTF file for writing.");
}
file.write(gltfData);
file.close();
}
functionhexToRgb(hex) {
varresult= /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
returnresult? {
r:parseInt(result[1], 16),
g:parseInt(result[2], 16),
b:parseInt(result[3], 16)
} : null;
}
.debug
..............................
<?xml version="1.0" encoding="UTF-8"?>
<ExtensionList>
<Extension Id="com.companyname.extensionname.panel">
<HostList>
<Host Name="AEFT" Port="7002"/>
</HostList>
</Extension>
</ExtensionList>
Have an awesome day!!... Jon.