• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
6

Per-Character Scripting Public Beta Announcement

Adobe Employee ,
Nov 20, 2023 Nov 20, 2023

Copy link to clipboard

Copied

Hi everyone, 

With After Effects (Beta) 24.2.0 build 17, we have added some very significant and long-awaited additions to the TextDocument DOM:

  • The properties of individual characters can now be changed independently of the others with the new CharacterRange and ParagraphRange objects. 
  • New paragraphCount attribute will return the number of paragraphs in the TextDocument. 
  • New paragraphCharacterIndexesAt method will return the paragraph bounds from a character index—useful if you have a character index and wonder what the character index bounds of the paragraph it is part of. 
  • It is now possible to faithfully round trip a mixed-property Text Layer via the TextDocument without losing individual properties. 
  • boxTextPos will now accept negative values (this was a long-standing bug.) 

You can read the updated docs here: https://ae-scripting.docsforadobe.dev/introduction/changelog.html. 

 

The CharacterRange and ParagraphRange will benefit from a short explanation. 

The former is returned by the characterRange() function where the parameters are character indexes, and the latter by the paragraphRange() function where the parameters are paragraph indexes. With them, you have all the same familiar character and paragraph properties that are available on the TextDocument, but now they apply to the effective character index range which was used to construct the specific range object. 

For example: 

 

 

var td = ....layer(1).property(“Source Text”).value; 
td.text; => “Hello, World!” 
var cr = td.characterRange(0,5); 
cr.text; => “Hello” 
cr.text = “After Effects”; // replace “Hello” with “After Effects” 
cr.text; => “After” 
td.text; => “After Effects, World!” 

 

 

 

Though these new objects share the same character and paragraph property definitions, there are still a few differences of note. 

  • A TextDocument character attribute on read returns the attribute's value for the first character in the Text layer, but on write applies it to the whole Text layer. Because of this, a TextDocument character property is never mixed. 
  • A TextDocument paragraph attribute on read and write is for all the characters in the Text layer. Because of this, a TextDocument paragraph property can be mixed. 
  • A CharacterRange and ParagraphRange object can return mixed if the range exceeds one character or paragraph, mixed is always indicated by returning undefined (except for .justification). 
  • The TextDocument fillColor and strokeColor will throw an exception on read if the corresponding applyFill and applyStroke properties are not set - the CharacterRange and ParagraphRange objects will not. 

 

PerCharacter_StyleEdit_ScriptUISample.png


We have built a demo script exercising the new CharacterRange and ParagraphRange hooks to get you started. You can get it from our Github repository: https://github.com/AdobeDocs/after-effects/blob/main/samples/PerCharacter_StyleEdit_ScriptUISample.j...

 
Remember, these scripting hooks are currently in Beta and are subject to change. 
 
We can't wait to see what you'll be building with these new hooks. 

 
PerCharacterScripting.png

 Douglas, John and Sebastien 

TOPICS
Feature request , Performance

Views

10.0K

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Adobe Employee , May 14, 2024 May 14, 2024

Hi all,

Thank you so much for your feedback on these new per-character scripting APIs. We are happy to announce that these are available for use in the release version of After Effects 24.3. The documentation on https://ae-scripting.docsforadobe.dev/ has also been updated to reflect the wider release of the APIs.

 

Thanks again,

- Douglas, John,and Sebastien

Votes

Translate

Translate
Enthusiast ,
Feb 16, 2024 Feb 16, 2024

Copy link to clipboard

Copied

@Douglas_Waterfall Do you have any thoughts on how best to identify mixed styles in an existing text layer? An obvious example would be doing find/replace on a certain font or color inside a mix style text layer.

 

It looks like I can characterRange the whole text then say, see if font comes back undefined, then continue to drill down ever more fine grained (or characterRange each pair of characters, or just compare every single character). But of course there are any number of font attributes that can be different between each character.

 

Ideally it would be something like returning and array of character ranges that encompassed every difference, or we could choose between all attributes or just certain ones. I realise that is something we can potentially code, even if it's fiddly and laborious.

 

It appears that any time you set a character range, it will push the style settings for the first character onto all characters in that range. Not entirely surprising although I hoped it would just touch the altered attributes. That suggests the safest alternative would be to set each character one at a time, but that seems non-ideal.

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe Employee ,
Feb 16, 2024 Feb 16, 2024

Copy link to clipboard

Copied

Hi Paul.

 

After Effects does not have styles (or exposes them) so there is no exposed concept of "difference".

Thus attributes just are without a claim to one value being more important than another.

 

If you are looking for mixed attributes then the only way to do it is indeed to walk each character and find out what the attribute is and see if it does not match what you expected.

 

The only style we have is conceptually default which is what you get when you call resetChar/ParaStyle in the UI or in scripting.  Having  an API which would return overrides relative to this style has seemed useful to me, and it is on my list to explore. However, I do not think this would help you with figuring out different overrides on a span of text.

 

Not sure what you mean by this:

It appears that any time you set a character range, it will push the style settings for the first character onto all characters 

 

Unless you've discovered a bug, setting an attribute via a CharacterRange immediately applies only that attribute to the range of character spanned by the CharacterRange. Likewise if you read the attribute, we access that same range and return the value or mixed, as appropriate.

 

Sounds like you are seeing something different, or have a different mental model of what is going on. If you the former - I want to know about it immediately.

 

Perhaps you mean what happens when you apply text via a CharacterRange? That is implemented internally as a delete/insert operation so after the delete only one set of attributes remains and those then are extended as the text is inserted. Think about what happens when you interact with a TextLayer by hand - it is the same conceptual model.

 

Are you perhaps trying to replace text character for character and preserve the original styling?

 

Douglas Waterfall

After Effects Engineering

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Feb 16, 2024 Feb 16, 2024

Copy link to clipboard

Copied

When I talk about styles I basically just mean all the various different text attributes. I realise there aren't any style groups as such. Yes I'm talking about making only certain changes while preserving all other styling.

 

And yes I meant apply text via the CharacterRange. I had two characters with different colors, used CharacterRange to change the text for those two characters and the second character got the first character's color. It makes sense when you describe it as an insert/delete.

 

Manual editing text does let you select a character range and then only affect the attribute being changed in the Character Panel, so I hoped perhaps it would be more like that. So I was just checking if there might be some fast track to know if or where those differences existed. But that's fine. I was already beginning to suspect character by character was the only way and it is at least possible now.

 

I guess I could grab a CharacterRange for the whole text and check every single exposed text attribute (I'm not sure if everything has been exposed yet, but it's probably close enough), then if any come back as undefined I will know to create a CharacterRange for each character one at a time to apply whatever specific attribute changes are required. Maybe because I'm just editing the CharacterRange / TextDocument rather than repeatedly applying it to the SourceText prop it won't be too slow.

 

Just doing a search/replace on say font or color that preserves all other styles is a lot easier for me to wrap my head around than what to do when changing the text characters in an existing mixed style text layer. I guess at that point the user really needs to be selecting ranges and editing manually in the comp so the intent is clear.

 

I could preserve the styles but any change in character length would not result in those styles shuffling accordingly. Unless I did come up with a solution for splitting then into groups of matching attributes then present them for editing in that way.

 

Thanks as always.

Paul

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe Employee ,
Feb 16, 2024 Feb 16, 2024

Copy link to clipboard

Copied

@Paul Tuersley wondering if you are wishing for this API

 

CharacterRange.replaceText(String text)

 

Here we would replace the character without disturbing the styling, and if the new string is longer than the current range then the last attribute is just applied to the extra.

 

Perhaps you might share more information on the transformation/edit you are trying to achieve.

 

Douglas Waterfall

After Effects Engineering

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Feb 16, 2024 Feb 16, 2024

Copy link to clipboard

Copied

@Douglas_Waterfall Saw your response after posting my reply to your first response. CharacterRange.replaceText(String text) does sound like something that could be very useful.

 

My general focus on this is for my pt_TextEdit script. It gives people a list of all text layers in a project, and the ability to edit both the text and style attributes all from that one panel, along with search/replace for fonts and text across all keyframes. So it's basically about giving users as much control as possible for whatever they might want to do.

 

The main problem has always been that it destroys any mixed styles. So project-wide search/replace fonts and text without destroying styles is one part of that and it sounds like that replaceText thing could certainly help on the text replace side (font replace will already work even if it means going one character at a time).

 

But then rather than the single EditText box that lets the user edit a single text layer's contents (updating live in the project) I'm thinking of how to present the text for editing when it contains mixed styles. So rather than a single EditText it could be a separate EditText box for each 'style block'.

 

And it seems I can brute force that. Compare every attribute on every character then define a new range each time there's a difference. My initial hunch is the replaceText thing won't be necessary in this case, as I'd just be doing an insert/delete for each CharacterRange block (from last to first I imagine) but for the search/replace text side of things it could save me having to do these extra steps. I've not got far enough yet to find out how long it'll take a script to compare every attribute of every character on every keyframe of every text layer in a project!

 

Briefly on the allfonts stuff, pt_TextEdit always just presented a list of previously found fonts. Now I can tap into the font list that will also dramatically improve and I've made good progress with fontID, a new font list manager (filters for styles, character sets, saved groups). Now it just needs access to read/write favorites so it can benefit people wanting to manage the Character Panel font list too!

 

Thanks!

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Feb 19, 2024 Feb 19, 2024

Copy link to clipboard

Copied

@Douglas_Waterfall  Just following up now I've experimented more. It was good to know I wasn't missing anything before I got fully into it.

 

I have found a decent way to detect mixed style attributes in existing text. Start with checking all attributes on a full character range, then check each character pair on any flagged attributes, to create an array of 'style block' ranges. Presenting this as a series of edittext boxes with onChanging live comp updates while preserving those style blocks all seems to work well.

 

For search/replace I'm doing it one character at a time if the whole range comes back as mixed. On last loop either extend the CR range, or add more characters into the last CR range depending on if search or replace string was longer. Trying to preserve style intent when replacing mixed single/multi-byte characters would add more complexity but I imagine I could get there eventually.

 

So I don't really need that CR.replaceString() API. I guess it might be nice to have, but it seems quite solvable with what we already have. Thanks!

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Mar 17, 2024 Mar 17, 2024

Copy link to clipboard

Copied

Hi, im not sure how much experience you have with after effects scripting but whenever I try to use the new characterRange function it is always undefined. i have even copy and pasted the code from both youtube and adobe developers but I always get an error at the Characterrange section of the code. My after effects is the newest version and i use Extend Script debugger. Do you have any ideas what could be going worng

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Mar 17, 2024 Mar 17, 2024

Copy link to clipboard

Copied

Is it the beta version? Otherwise you won't be able to use the CharacterRange

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Mar 17, 2024 Mar 17, 2024

Copy link to clipboard

Copied

ohhhhh thats so helpful, ive been trying to figure this out for 5 hours lol. thank you so much!

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Mar 18, 2024 Mar 18, 2024

Copy link to clipboard

Copied

No worries! 😄
And if you want a function to test if it's available:

 

function isCharacterRangeWorking(){

  var test = new TextDocument("docText");
  // Check if the TextDocument object has the characterRange method
  if (test.hasOwnProperty("characterRange")) {
    // The method is available
    return true;
  } else {
    // The method is not available
    return false;
  }
}

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Mar 18, 2024 Mar 18, 2024

Copy link to clipboard

Copied

I acually wrote this function where I turn the first character in a text layer blue, is it possible to use the setValueAtTime function to turn the firts character blue 10 frames after it starts being displayed. this is my current code: 

function bounceText(startTime, endTime, text, font, fontSize) {
    var comp = app.project.activeItem;
    if (!comp || !(comp instanceof CompItem)) {
      alert("Please select or open a composition first.");
      return;
    }
 
    // Begin the undo group
    app.beginUndoGroup("Create Bounce Text");
 
    // Create text layer
    var textLayer = comp.layers.addText("Bounce Text");
 
    // Customizing text properties
    var textProp = textLayer.property("Source Text");
    var textDocument = textProp.value;
    myString = text;
    textDocument.resetCharStyle();
    textDocument.fontSize = fontSize;
    textDocument.fillColor = [1, 1, 1];
    textDocument.strokeColor = [0, 0, 0];
    textDocument.strokeWidth = 2;
    textDocument.font = font;
    textDocument.strokeOverFill = true;
    textDocument.applyStroke = true;
    textDocument.applyFill = true;
    textDocument.text = myString;
    textDocument.justification = ParagraphJustification.CENTER_JUSTIFY;
    textDocument.tracking = 50;
 
    // Change the color of the first character to blue
    var textReferenceArray = textDocument.toString().split("");
    var firstCharRange = textDocument.characterRange(0, 1);
    firstCharRange.fillColor = [0, 0, 1]; // Blue color
 
    textProp.setValue(textDocument);
 
    // Set in and out points for layer visibility
    textLayer.inPoint = startTime;
    textLayer.outPoint = endTime;
 
 
    // End the undo group
    app.endUndoGroup();
  }

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Mar 18, 2024 Mar 18, 2024

Copy link to clipboard

Copied

all my current attemps give me an error

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Mar 18, 2024 Mar 18, 2024

Copy link to clipboard

Copied

Can you grab what you need from here (sorry in a hurry)?

 

 

var ts = layer.sourceText; // you need the layer
var td = ts.value;

var myCh = td.characterRange(1);
myCh.fillColor = RGBcolor; // you need the RGBcolor

if (ts.isTimeVarying) {

  var atTime = app.project.activeItem.time;
  ts.setValueAtTime(atTime, td);
    
}else{
  
  ts.setValue(td);
}

 

 

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Mar 18, 2024 Mar 18, 2024

Copy link to clipboard

Copied

Thank you for your response. I implimented it and for some reason

textDocument.isTimeVarying is always false (but the first character is blue so charachter range is still working), here is my code, is the issue apparent? 
function bounceText(startTime, endTime, text, font, fontSize) {
    var comp = app.project.activeItem;
    if (!comp || !(comp instanceof CompItem)) {
      alert("Please select or open a composition first.");
      return;
    }
 
    // Begin the undo group
    app.beginUndoGroup("Create Bounce Text");
 
    // Create text layer
    var textLayer = comp.layers.addText("Bounce Text");
 
    // Customizing text properties
    var textProp = textLayer.property("Source Text");
    var textDocument = textProp.value;
    myString = text;
    textDocument.resetCharStyle();
    textDocument.fontSize = fontSize;
    textDocument.fillColor = [1, 1, 1];
    textDocument.strokeColor = [0, 0, 0];
    textDocument.strokeWidth = 2;
    textDocument.font = font;
    textDocument.strokeOverFill = true;
    textDocument.applyStroke = true;
    textDocument.applyFill = true;
    textDocument.text = myString;
    textDocument.justification = ParagraphJustification.CENTER_JUSTIFY;
    textDocument.tracking = 50;
 
    // Change the color of the first character to blue
   
 
    textProp.setValue(textDocument);

    var textReferenceArray = textDocument.toString().split("");
    var firstCharRange = textDocument.characterRange(0, 1);
    firstCharRange.fillColor = [0, 0, 1]; // Blue color

    if (textDocument.isTimeVarying) {

        var atTime = app.project.activeItem.time;
        textProp.setValueAtTime(atTime+.1, textDocument);
        alert("Time is varying")
 
         
      }else{
       
        textProp.setValue(textDocument);
      }


    // textProp.setValueAtTime(startTime+.1, textDocument)
 
    // Set in and out points for layer visibility
    textLayer.inPoint = startTime;
    textLayer.outPoint = endTime;
 
 
    // End the undo group
    app.endUndoGroup();
  }

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Mar 18, 2024 Mar 18, 2024

Copy link to clipboard

Copied

isTimeVarying was to check if the property has keyframes.... but in your case you can remove that part. Not needed.
If I put this in a jsx file it seems to work fine:

 

    var comp = app.project.activeItem;

    // Create text layer
    var textLayer = comp.layers.addText("Bounce Text");
 
    // Customizing text properties
    var textProp = textLayer.property("Source Text");
    var textDocument = textProp.value;
    var firstCharRange = textDocument.characterRange(0);

    textDocument.resetCharStyle();
    textDocument.fontSize = 50;
    textDocument.fillColor = [1, 1, 1];
    textDocument.strokeColor = [0, 0, 0];
    textDocument.strokeWidth = 2;
    textDocument.strokeOverFill = true;
    textDocument.applyStroke = true;
    textDocument.applyFill = true;
    textDocument.text = "Let's try this";
    textDocument.justification = ParagraphJustification.CENTER_JUSTIFY;
    textDocument.tracking = 50;
 
    // Change the color of the first character to blue
    firstCharRange.fillColor = [0, 0, 1]; // Blue color

    textProp.setValue(textDocument);
      

 

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Mar 18, 2024 Mar 18, 2024

Copy link to clipboard

Copied

Thank you for this response, but my goal is the set the first character to blue 1 second after the text layer begins displaying. I need this logic to create a color animation on the text. 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Mar 18, 2024 Mar 18, 2024

Copy link to clipboard

Copied

Ha ok, so after setting the tracking with

textDocument.tracking = 50;

you need this:

 

textProp.setValue(textDocument);
textProp.addKey(0); // CREATE A KEYFRAME FIRST

firstCharRange.fillColor = [0, 0, 1]; // Blue color
// THEN USE SETVALUEATTIME TO CREATE ANOTHER KEY WITH THE BLUE CHARACTER
textProp.setValueAtTime(1,textDocument);

 

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Mar 18, 2024 Mar 18, 2024

Copy link to clipboard

Copied

It Worked! Thank you so much!! I can finally finish my project!! You saved me hours of tedius documentation reading lol, I really apreciate this!

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Mar 18, 2024 Mar 18, 2024

Copy link to clipboard

Copied

No worries, sorry if I didn't get you wanted from the beginning. 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Mar 18, 2024 Mar 18, 2024

Copy link to clipboard

Copied

Its all good, you soved the two things I was completly stuck on lol. I don't think I would have figured this out on my own. Thank you again!

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Mar 21, 2024 Mar 21, 2024

Copy link to clipboard

Copied

Thank you again for your help! I now have an animation to where I can change the font color of each word.  I was also wondering if you know how to add a background highlight box behind each word also, I sent a youtube video that has the captioning style I'm talking about in this reply

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Mar 21, 2024 Mar 21, 2024

Copy link to clipboard

Copied

this is my code so far, I'm wondering if it is possible to add the highlighted box behind each word as well: 

function bounceText(startTime, endTime, text, font, fontSize, wordTimeStamps) {
    var comp = app.project.activeItem;
    if (!comp || !(comp instanceof CompItem)) {
        alert("Please select or open a composition first.");
        return;
    }

    // alert(toString(wordTimeStamps))

    // Begin the undo group
    app.beginUndoGroup("Create Bounce Text");

    // Create text layer
    var textLayer = comp.layers.addText(text);

    // Customizing text properties
    var textProp = textLayer.property("Source Text");
    var textDocument = textProp.value;


    // var firstCharRange = textDocument.characterRange(0);

    var words = text.split(" ");
    var wordRanges = [];
    var startIndex = 0;
    for (var i = 0; i < words.length; i++) {
        var word = words[i];
        var endIndex = startIndex + word.length;
        // alert(startIndex)
        // alert(endIndex)
        wordRanges.push(textDocument.characterRange(startIndex,endIndex));
        if(i < words.length-1){
            startIndex = endIndex +1  ; // Account for the space character
        }
       
    }
    // alert(wordRanges.length)


    myString = text;
    textDocument.resetCharStyle();
    textDocument.fontSize = fontSize;
    textDocument.fillColor = [1, 1, 1];
    textDocument.strokeColor = [0, 0, 0];
    textDocument.strokeWidth = 2;
    textDocument.font =font;
    textDocument.strokeOverFill = true;
    textDocument.applyStroke = true;
    textDocument.applyFill = true;
    textDocument.text = myString;

    textDocument.text = text;

    textDocument.justification = ParagraphJustification.CENTER_JUSTIFY;
    textDocument.tracking = 50;
    textProp.setValue(textDocument)

   
    textProp.addKey(0); // CREATE A KEYFRAME FIRST

    // firstCharRange.fillColor = [0, 0, 1]; // Blue color
    // THEN USE SETVALUEATTIME TO CREATE ANOTHER KEY WITH THE BLUE CHARACTER
    // textProp.setValueAtTime(1.5,textDocument);

     // Highlight each word based on the provided timestamps
     for (var i = 0; i < words.length; i++) {
        var wordRange = wordRanges[i];

        if (i < wordTimeStamps.length) {
            var wordStartTime = wordTimeStamps[i];
            var nextWordStartTime = i === wordTimeStamps.length - 1 ? endTime : wordTimeStamps[i + 1];

            // Highlight the word by changing its fill color
            wordRange.fillColor = [0, 0, 1]; // Blue color
            textProp.setValueAtTime(wordStartTime, textDocument);
 
            // Reset the word color after the next word starts
            wordRange.fillColor = [1, 1, 1]; // White color
            textProp.setValueAtTime(nextWordStartTime, textDocument);

           


        }
    }

    // Set in and out points for layer visibility
    textLayer.inPoint = startTime;
    textLayer.outPoint = endTime;

    // Set keyframes for bounce effect
    var scaleProperty = textLayer.property("Transform").property("Scale");
    var smallScale = [50, 50]; // Start small
    var bigScale = [120, 120]; // Then big
    var normalScale = [100, 100]; // Finally, back to normal size

    // Adding keyframes
    scaleProperty.setValueAtTime(startTime, smallScale);
    scaleProperty.setValueAtTime(startTime + comp.frameDuration * 2, bigScale);
    scaleProperty.setValueAtTime(startTime + comp.frameDuration * 4, normalScale);

    // End the undo group
    app.endUndoGroup();
}

var numberlist = [5, 6, 7, 8, 9,10,11]

bounceText(numberlist[0], numberlist[(numberlist.length-1)], "This is a " +"\r"+"test for real", "Impact", 150, numberlist);







Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Mar 21, 2024 Mar 21, 2024

Copy link to clipboard

Copied

No sorry bro, you're going a bit too far now. And I don't even know how to get the width of a single word inside a text layer...

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Mar 21, 2024 Mar 21, 2024

Copy link to clipboard

Copied

its all good, do you think the functions textDocument.boxTextPos, and textDocument.boxTextSize would make this possible? Also to you know how to make a box cause i have no idea lol. If your not sure I'll test it out when I get a chance, and I can send you the solution if your interested.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Mar 21, 2024 Mar 21, 2024

Copy link to clipboard

Copied

I would make a rectangle underneath the text and change it's position and dimension according to the text.
Not sure about those scripting hooks sorry... They are new to me.

This scripts does it so you just need to find out how
https://madebyloop.co.uk/after-effects-scripts/highlight-underline-after-effects-script/#:~:text=Her...

Some clues here: https://creativecow.net/forums/thread/text-highlight-expression-selector/

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Resources