Skip to main content
Participant
July 19, 2025
Answered

After Effects Scripting: "Object is Invalid" Error with Stroke and Fill Properties

  • July 19, 2025
  • 1 reply
  • 280 views
function convertTextToShapes() {
    var myComp = app.project.activeItem;
    if (!myComp || !(myComp instanceof CompItem)) {
        alert("please select a composition.");
        return null;
    }
    var selectedLayers = myComp.selectedLayers;
    var textLayer = selectedLayers[0];
    if (!(textLayer instanceof TextLayer)) {
        alert("please select a text layer.");
        return null;
    }
    app.beginUndoGroup("convert text to shapes");

    try {
        var originalTextLayerName = textLayer.name;
        app.executeCommand(3781);

        var shapeLayer = myComp.selectedLayers[0];
        shapeLayer.name = originalTextLayerName + "-shapes";

        // textLayer.enabled = false;
        // textLayer.remove();
        return shapeLayer;
    } catch (e) {
        alert("something went wrong." + e.toString());
        return null;
    } finally {
        app.endUndoGroup();
    }
};

var convertedShapeLayer = convertTextToShapes();
app.beginUndoGroup("add expressions to shapes");

(function addExpressions(shapeLayer) {
    var contents = shapeLayer.property("Contents");
    for (var i = 1; i <= contents.numProperties; i++) {
        var group = contents.property(i);
        if(group.matchName == "ADBE Vector Group") {
            var groupContents = group.property("Contents");
            var charIndex = i - 1;

            groupContents.property(2).remove();
            groupContents.property(2).remove();

            var strokes = groupContents.addProperty("ADBE Vector Graphic - Stroke");
            strokes.name = "setStrokes";
            var fills = groupContents.addProperty("ADBE Vector Graphic - Fill");
            fills.name = "setFills";
            alert(strokes.name + " " + fills.name);

            var trimPaths = groupContents.addProperty("ADBE Vector Filter - Trim");
            trimPaths.name = "setTrimPaths";

            strokes.property("ADBE Vector Stroke Width").setValue(1);
            strokes.property("ADBE Vector Stroke Color").setValue([1, 1, 1, 1]);

            fills.property("Opacity").expression = 
                            'function getBezierX(t, p1x, p2x) {\r' +
                '    return 3 * Math.pow(1 - t, 2) * t * p1x + 3 * (1 - t) * Math.pow(t, 2) * p2x + Math.pow(t, 3);\r' +
                '}\r' +
                '\r' +
                'function getBezierY(t, p1y, p2y) {\r' +
                '    return 3 * Math.pow(1 - t, 2) * t * p1y + 3 * (1 - t) * Math.pow(t, 2) * p2y + Math.pow(t, 3);\r' +
                '}\r' +
                'function cubicBezierInternal(inputTime, x1, y1, x2, y2) {\r' +
                '    var t = Math.max(0, Math.min(1, inputTime));\r' +
                '\r' +
                '    if (t === 0) return 0;\r' +
                '    if (t === 1) return 1;\r' +
                '\r' +
                '    var start = 0.0;\r' +
                '    var end = 1.0;\r' +
                '    var u = t;\r' +
                '    var iterations = 8;\r' +
                '    for (var i = 0; i < iterations; i++) {\r' +
                '        var guessX = getBezierX(u, x1, x2);\r' +
                '        if (guessX < t) {\r' +
                '            start = u;\r' +
                '        } else {\r' +
                '            end = u;\r' +
                '        }\r' +
                '        u = (start + end) / 2;\r' +
                '    }\r' +
                '    return getBezierY(u, y1, y2);\r' +
                '}\r' +
                'function animateWithBezier(animStartTime, animDuration, startValue, endValue, bezierParams) {\r' +
                '    var x1 = bezierParams[0];\r' +
                '    var y1 = bezierParams[1];\r' +
                '    var x2 = bezierParams[2];\r' +
                '    var y2 = bezierParams[3];\r' +
                '\r' +
                '    var normalizedTime = (time - animStartTime) / animDuration;\r' +
                '\r' +
                '    var easedProgress = 0;\r' +
                '    if (time >= animStartTime && time <= animStartTime + animDuration) {\r' +
                '        easedProgress = cubicBezierInternal(normalizedTime, x1, y1, x2, y2);\r' +
                '    } else if (time > animStartTime + animDuration) {\r' +
                '        easedProgress = 1;\r' +
                '    }\r' +
                '    return startValue + (endValue - startValue) * easedProgress;\r' +
                '}\r' +
                '\r' +
                'var BEZIER_EASE = [0.25, 0.1, 0.25, 1.0];\r' +
                'var BEZIER_EASE_IN = [0.42, 0, 1.0, 1.0];\r' +
                'var BEZIER_EASE_OUT = [0, 0, 0.58, 1.0];\r' +
                'var BEZIER_EASE_IN_OUT = [0.42, 0, 0.58, 1.0];\r' +
                'var BEZIER_LINEAR = [0, 0, 1.0, 1.0];\r' +
                '\r' +
                '\r' +
                'var animate1 = animateWithBezier(' + i / 15 + 0.5 +  ', 0.5, 0, 100, [0, 0, 0, 0]);\r' +
                '\r' +
                'animate1\r'
            ;

            trimPaths.property("End").expression = 
                'function getBezierX(t, p1x, p2x) {\r' +
                '    return 3 * Math.pow(1 - t, 2) * t * p1x + 3 * (1 - t) * Math.pow(t, 2) * p2x + Math.pow(t, 3);\r' +
                '}\r' +
                '\r' +
                'function getBezierY(t, p1y, p2y) {\r' +
                '    return 3 * Math.pow(1 - t, 2) * t * p1y + 3 * (1 - t) * Math.pow(t, 2) * p2y + Math.pow(t, 3);\r' +
                '}\r' +
                'function cubicBezierInternal(inputTime, x1, y1, x2, y2) {\r' +
                '    var t = Math.max(0, Math.min(1, inputTime));\r' +
                '\r' +
                '    if (t === 0) return 0;\r' +
                '    if (t === 1) return 1;\r' +
                '\r' +
                '    var start = 0.0;\r' +
                '    var end = 1.0;\r' +
                '    var u = t;\r' +
                '    var iterations = 8;\r' +
                '    for (var i = 0; i < iterations; i++) {\r' +
                '        var guessX = getBezierX(u, x1, x2);\r' +
                '        if (guessX < t) {\r' +
                '            start = u;\r' +
                '        } else {\r' +
                '            end = u;\r' +
                '        }\r' +
                '        u = (start + end) / 2;\r' +
                '    }\r' +
                '    return getBezierY(u, y1, y2);\r' +
                '}\r' +
                'function animateWithBezier(animStartTime, animDuration, startValue, endValue, bezierParams) {\r' +
                '    var x1 = bezierParams[0];\r' +
                '    var y1 = bezierParams[1];\r' +
                '    var x2 = bezierParams[2];\r' +
                '    var y2 = bezierParams[3];\r' +
                '\r' +
                '    var normalizedTime = (time - animStartTime) / animDuration;\r' +
                '\r' +
                '    var easedProgress = 0;\r' +
                '    if (time >= animStartTime && time <= animStartTime + animDuration) {\r' +
                '        easedProgress = cubicBezierInternal(normalizedTime, x1, y1, x2, y2);\r' +
                '    } else if (time > animStartTime + animDuration) {\r' +
                '        easedProgress = 1;\r' +
                '    }\r' +
                '    return startValue + (endValue - startValue) * easedProgress;\r' +
                '}\r' +
                '\r' +
                'var BEZIER_EASE = [0.25, 0.1, 0.25, 1.0];\r' +
                'var BEZIER_EASE_IN = [0.42, 0, 1.0, 1.0];\r' +
                'var BEZIER_EASE_OUT = [0, 0, 0.58, 1.0];\r' +
                'var BEZIER_EASE_IN_OUT = [0.42, 0, 0.58, 1.0];\r' +
                'var BEZIER_LINEAR = [0, 0, 1.0, 1.0];\r' +
                '\r' +
                '\r' +
                'var animate1 = animateWithBezier(' + i / 15 +  ', 0.5, 0, 100, [0, 0, 0, 0]);\r' +
                '\r' +
                'animate1\r'
            ;
        }
    }
})(convertedShapeLayer);

app.endUndoGroup();

This is my first attempt at writing an After Effects script to animate text.

However, when I run it, I consistently get the error:

strokes.property("ADBE Vector Stroke Width").setValue(1);
strokes.property("ADBE Vector Stroke Color").setValue([1, 1, 1, 1]);

These two lines show "Unable to execute script at line 51 Object is invalid".

Perhaps the same issue applies to fills as well, but trimPaths works fine.

I've tried changing the content within property(""). I referenced the After Effects scripting documentation to find the correct values, but no matter what I change, I still get the same error. What I don't understand most is why trimPaths works correctly while the others don't.

Correct answer Slayemus

Thanks for your reply, I found the solution to this problem at https://ae-scripting.docsforadobe.dev/property/propertygroup/#propertygroupaddproperty 

1 reply

Dan Ebberts
Community Expert
Community Expert
July 20, 2025

Just a guess, but I think that adding a new property to groupContents may invalidate any existing references to the other properties in that group. If that's what's happening, you should be able to fix it by adding this (to refresh the object references for the stroke and fill) after your statement that adds the trim path:

strokes = groupContents.property("ADBE Vector Graphic - Stroke");
fills = groupContents.property("ADBE Vector Graphic - Fill");
SlayemusAuthorCorrect answer
Participant
July 20, 2025

Thanks for your reply, I found the solution to this problem at https://ae-scripting.docsforadobe.dev/property/propertygroup/#propertygroupaddproperty