Ce document explique les différences de syntaxe de langage entre le moteur d’expressions JavaScript et l’ancien moteur d’expressions ExtendScript dans After Effects 16.0.

Reportez-vous à ce document afin d’apprendre comment améliorer vos expressions pour le moteur d’expressions JavaScript, ou savoir quand corriger les erreurs qui surviennent lorsque des expressions écrites pour les versions antérieures d’After Effects ne sont pas évaluées par le moteur d’expressions JavaScript.

Le langage d’expression dans After Effects est basé sur le JavaScript, qui est une mise en œuvre d’ECMAScript. Le moteur d’expressions JavaScript dans After Effects 16.0 est basé sur ECMAScript 2018. L’ancien moteur d’expressions ExtendScript est lui basé sur ECMAScript 3 (1999). (Adobe ExtendScript est également le langage utilisé pour les scripts dans After Effects et d’autres applications d’Adobe.)

Vous pouvez suivre les exemples fournis ci-dessous, et les utiliser en tant que conseils sur la façon d’écrire des expressions fonctionnant aussi bien dans le moteur d’expressions JavaScript que dans l’ancien moteur d’expressions ExtendScript.

Les principales différences de syntaxe entre le moteur d’expressions JavaScript et l’ancien moteur d’expressions ExtendScript sont :

Syntaxe JavaScript moderne : améliorations apportées au langage d’expression

Les expressions peuvent utiliser la syntaxe JavaScript d’ECMAScript 2018

De nombreux ajouts ont été appliqués au langage JavaScript depuis ECMAScript 3. De nouvelles méthodes plus compactes et plus lisibles à employer avec les chaînes, les tableaux et les objets ont été ajoutées. Il existe également de nouvelles manières de déclarer des variables et des fonctions, ainsi que de nouveaux paramètres par défaut, opérateurs de propagation, etc. Ce document ne couvre pas ces changements, étant donné qu’ils concernent le langage JavaScript en lui-même. Des ressources permettant d’en savoir plus sur les nombreux ajouts relatifs à la syntaxe sont accessibles via les liens suivants :

Ressources détaillées supplémentaires recommandées pour apprendre le JavaScript :

.value n’est plus requise lors de la liaison à d’autres propriétés du texte source

Lorsqu’il est fait référence à une valeur distincte pour une propriété de texte source, l’ancien moteur ExtendScript nécessite l’ajout de .value à la fin de la propriété. Le moteur JavaScript montre la valeur de la propriété par défaut à moins qu’un autre attribut comme .propertyIndex ou .name soit explicitement employé.

Par exemple :

thisComp.layer("Solid 1").transform.position
 
// In the Legacy engine, this evaluates to "[object Property]" when applied to a Source Text property.
// In the JavaScript engine, this evaluates to the value of the Position property of layer "Solid 1" when applied to a Source Text property.

Gel des valeurs de propriété avec posterizeTime(0)

Dans After Effects 16.0, posterizeTime(0) gèle la valeur d’une propriété de la composition à l’instant 0. Cela est valable à la fois pour l’ancien moteur ExtendScript et le moteur JavaScript.

Remarque :

Cela n’est pas rétrocompatible et peut engendrer des résultats inattendus dans les versions d’After Effects antérieures à la version 16.0.

Ancienne syntaxe non compatible

Presque toutes les syntaxes d’expressions de l’ancien moteur d’expressions ExtendScript sont compatibles avec le moteur d’expressions JavaScript. Toutefois, certaines syntaxes anciennes ne sont pas compatibles avec le moteur d’expressions JavaScript. Cela est parfois lié à des changements de syntaxe dans le JavaScript moderne. Dans les autres cas, la syntaxe obsolète ou dépassée a été supprimée. Des exemples de syntaxes valides et non valides sont fournis ci-dessous.

La plupart de ces différences de syntaxe peuvent être corrigées par l’intermédiaire du scripting d’application qui permet de réécrire les expressions.

Différences de syntaxe if...else

Il est généralement recommandé d’écrire les instructions if...else avec des sauts de ligne et des accolades, conformément aux consignes de MDN. Bien que l’ancien moteur ExtendScript tolérait la syntaxe libre des instructions if...else, le moteur JavaScript est lui plus strict à ce sujet. Une syntaxe if...else non correcte ne sera pas évaluée par le moteur JavaScript.

Terminer une expression d’une instruction if sans else n’est pas autorisé

Lorsqu’une expression se termine par une instruction if, sans instruction else, le moteur JavaScript ne parvient pas à évaluer l’expression, et l’erreur « Undefined value used in expression (could be an out of range array subscript?) » apparaît. Dans l’ancien moteur ExtendScript, l’expression suivante est évaluée sur 100 si le délai est supérieur à 1 seconde, autrement elle l’est sur 50 :

var x = 50;
if ( time > 1 ) {
    x = 100
}
// The "else" here is implied but not stated.

Le moteur JavaScript a besoin de la portion else de l’instruction pour qu’elle soit explicitement énoncée lorsqu’il s’agit de la dernière instruction de l’expression :

var x = 50;
if ( time > 1 ) {
    x = 100;
} else {
    x;
}

L’évaluation sera correctement effectuée à la fois dans l’ancien moteur ExtendScript et dans le moteur JavaScript.

if et else ne peuvent se trouver sur la même ligne sans accolades

Une instruction if...else sur une seule ligne sans accolades sera correctement évaluée dans l’ancien moteur ExtendScript, mais échouera dans le moteur JavaScript et engendrera une erreur de type « Syntax Error: Unexpected token else » ou « Undefined value used in expression (could be an out of range array subscript?) ». L’erreur varie, selon le contexte et le type de propriété.

Dans l’ancien moteur ExtendScript, l’expression suivante est évaluée sur 100 si le délai est supérieur à 1 seconde, autrement elle l’est sur 50 :

if ( time > 1 ) 100 else 50;

Le moteur JavaScript nécessite des sauts de ligne et des accolades pour évaluer les instructions if...else. Pour les cas simples, l’opérateur ternaire peut être utilisé à la place. Toutes les syntaxes suivantes peuvent être utilisées avec le moteur JavaScript :

// Solution A: adding a line break before "else" will allow both engines to evaluate correctly.
 
if ( time > 1 ) 100
else 50;
 
// Solution B: adding correct bracketing will also allow both engines to evaluate correctly.
 
if ( time > 1 ) { 100 } else { 50 };
 
// Solution C: Use a ternary operator in place of the if...else statement, which also evaluates correctly in both engines.
 
time > 1 ? 100 : 50;

Toutes les solutions ci-dessus sont correctement évaluées dans le moteur JavaScript et dans l’ancien moteur ExtendScript.

Les expressions ne peuvent pas se terminer par une déclaration de fonction

Si une expression se termine par une déclaration de fonction, le moteur JavaScript ne parvient pas à l’évaluer et cela engendre l’erreur « Object of type found where a Number, Array, or Property is needed ». Dans le moteur JavaScript, le dernier élément évalué doit renvoyer une valeur, plutôt que d’en déclarer une.

L’exemple suivant fonctionne avec l’ancien moteur, mais pas avec le moteur JavaScript :

timesTen( value );  // The Legacy engine evaluates this line, even though the function is declared below.
 
function timesTen ( val ) {
    return val * 10
}

Lorsqu’une fonction est appelée en tant que dernière ligne (à la place de la déclaration), l’expression est correctement évaluée dans les deux moteurs :

function timesTen ( val ) {
    return val * 10
}
 
timesTen( value );  // The JavaScript engine needs the function call to happen below the declaration in order to return the correct value.

la syntaxe abrégée this() n’est pas autorisée ; utilisation de thisLayer() à la place

Dans l’ancien moteur ExtendScript, this pouvait être utilisé comme abréviation de thisLayer. Dans le moteur JavaScript, this fait référence à l’objet global et thisLayer doit être utilisé à la place. L’utilisation de this dans le moteur JavaScript engendrera généralement l’erreur « this is not a function ».

Dans l’exemple ExtendScript suivant, this est utilisé pour créer un lien compact avec une propriété de position de couche de texte d’une propriété de texte source :

this(5)(2).value;

Dans le moteur JavaScript, this doit être remplacé par thisLayer :

thisLayer(5)(2).value;

L’utilisation de thisLayer est compatible avec les deux moteurs d’expressions.

L’accès aux caractères de l’index de tableau de la propriété de texte source requiert .value

Dans l’ancien moteur d’expressions ExtendScript, il était possible d’accéder aux caractères d’une propriété avec l’ajout d’accolades comme pour un tableau :

text.sourceText[0]      // Returns the first character of the Source Text property's text value.

Dans le moteur JavaScript, .value doit être ajouté afin d’accéder aux caractères :

text.sourceText.value[0]    // Returns the first character of the Source Text property's text value.

Cette syntaxe est compatible avec les deux moteurs.

Les propriétés et les méthodes snake case ne sont pas autorisées

Les propriétés et méthodes snake case obsolètes (écrites avec un tiret bas plutôt qu’en camelCase) ne sont pas prises en charge par le moteur JavaScript. Les versions en camelCase devraient être utilisées à la place, puisqu’elles sont compatibles avec les deux moteurs. Vous trouverez ci-dessous la liste des propriétés et méthodes snake case obsolètes et de leur version en camelCase correspondant.

Propriétés snake case Propriétés en camelCase Méthodes snake case Méthodes en camelCase

this_comp

this_layer

this_property

color_depth

has_parent

in_point

out_point

start_time

has_video

has_audio

audio_active

anchor_point

audio_levels

time_remap

casts_shadows

light_transmission

accepts_shadows

accepts_lights

frame_duration

shutter_angle

shutter_phase

num_layers

pixel_aspect

point_of_interest

depth_of_field

focus_distance

blur_level

cone_angle

cone_feather

shadow_darkness

shadow_diffusion

active_camera

thisComp

thisLayer

thisProperty

colorDepth

hasParent

inPoint

outPoint

startTime

hasVideo

hasAudio

audioActive

anchorPoint

audioLevels

timeRemap

castsShadows

lightTransmission

acceptsShadows

acceptsLights

frameDuration

shutterAngle

shutterPhase

numLayers

pixelAspect

pointOfInterest

depthOfField

focusDistance

blurLevel

coneAngle

coneFeather

shadowDarkness

shadowDiffusion

activeCamera

value_at_time()

velocity_at_time()

speed_at_time()

nearest_key()

posterize_time()

look_at()

seed_random()

gauss_random()

ease_in()

ease_out()

rgb_to_hsl()

hsl_to_rgb()

degrees_to_radians()

radians_to_degrees()

from_comp_to_surface()

to_comp_vec()

from_comp_vec()

to_world_vec()

from_world_vec()

to_comp()

from_comp()

to_world()

from_world()

temporal_wiggle()

loop_in_duration()

loop_out_duration()

loop_in()

loop_out()

valueAtTime()

velocityAtTime()

speedAtTime()

nearestKey()

posterizeTime()

lookAt()

seedRandom()

gaussRandom()

easeIn()

easeOut()

rgbToHsl()

hslToRgb()

degreesToRadians()

radiansToDegrees()

fromCompToSurface()

toCompVec()

fromCompVec()

toWorldVec()

fromWorldVec()

toComp()

fromComp()

toWorld()

fromWorld()

temporalWiggle()

loopInDuration()

loopOutDuration()

loopIn()

loopOut()

Utilisation d’eval() avec les expressions codées sous forme binaire (.jsxbin)

Les expressions codées au format binaire ExtendScript (enregistrées sous forme de fichiers .jsxbin à partir d’ExtendScript ToolKit CC) ne sont pas prises en charge par le moteur JavaScript.

Si vous souhaitez obfusquer une expression, utilisez l’ancien moteur ExtendScript ou une autre méthode d’obfuscation compatible avec ECMAScript 2018. Certaines méthodes d’obfuscation peuvent ne pas être compatibles avec aucun des deux moteurs d’expressions.

Prise en charge limitée de l’objet $. (dollar)

Les méthodes et propriétésd’objet $. (dollar) sont spécifiques au langage ExtendScript et rarement prises en charge par le moteur JavaScript. Ce tableau présente les utilisations de l’objet $. (dollar)prises en charge et non prises en charge :

Utilisations de $. non prises en charge Utilisation de $. prises en charge

$.fileName

$.hiResTimes

$.stack

$.evalFile()

$.liste()

$.setenv()

$.getenv()

$.appEncoding

$.buildDate

$.decimalPoint

$.dictionary

$.error

$.flags

$.includePath

$.level

$.ligne

$.locale

$.localize

$.memCache

$.os

$.screens

$.strict

$.version

$.build

$.engineName (non prise en charge dans l’ancien moteur ExtendScript)

$.global

Non prise en charge de …reflect.properties, …reflect.methods et toSource()

reflect.properties et reflect.methods ne sont pas prises en charge dans le moteur JavaScript ; ces méthodes spécifiques à ExtendScript n’ont aucun équivalent direct en JavaScript.

toSource() est considérée comme obsolète en JavaScript et ne fait partie d’aucune piste standard.

Pour voir la liste des propriétés et méthodes disponibles pour une propriété d’After Effects semblable à ce qui était fourni par les méthodes ci-dessus, utilisez l’expression suivante sur une propriété de texte source et liez-la à la propriété de votre choix, par exemple, en utilisant l’option d’effets au lieu de thisProperty sur la ligne 1 :

let obj = thisProperty;     // Replace "thisProperty" with a property-link to your desired property.
let props = [];
 
do {
    Object.getOwnPropertyNames(obj).forEach(prop => {
        if (props.indexOf(prop) === -1) {
            props.push(prop);
        }
    });
} while (obj = Object.getPrototypeOf(obj));
 
props.join("\n");           // Returns an array of strings listing the properties and methods available.

L’expression ci-dessus n’est pas compatible avec l’ancien moteur ExtendScript. Elle utilise une syntaxe et des méthodes non disponibles dans ECMAScript 3.

Exigences syntaxiques pour les bibliothèques d’expressions .jsx et eval() avec le moteur JavaScript

Lors de l’utilisation d’expressions d’une bibliothèque de fonctions d’expressions .jsx ou lorsqu’une expression est appelée dans eval(), certaines syntaxes doivent être modifiées :

Un préfixe explicite de type thisLayer. ou thisProperty. doit être ajouté à toute méthode native ou à tout attribut qui n’est pas explicitement appelé sur une couche ou dans une propriété. Le préfixe indique au moteur JavaScript l’objet appelé par la méthode ou l’attribut.

Les opérations mathématiques sur les valeurs de tableaux comme la position doivent être calculées à l’aide d’un vecteur mathématique ou via les fonctions de bouclage afin d’agir sur chaque élément du tableau. Les opérateurs mathématiques saturés, comme la position + [100,100] ne seront pas évalués.

Lors de l’utilisation du moteur JavaScript, les expressions sont prétraitées avant leur évaluation afin de rendre certains éléments de la syntaxe des expressions ExtendScript lisibles par le nouveau moteur. Cependant, ces tâches de prétraitement ne sont pas effectuées lors de l’évaluation des expressions d’une bibliothèque de fonctions d’expressions .jsx ou lorsqu’une expression est appelée dans eval(). Dans ces cas de figure, les modifications de syntaxe ci-dessus doivent être effectuées manuellement. Toutes ces modifications de syntaxe sont rétrocompatibles avec l’ancien moteur ExtendScript. De cette façon, une bibliothèque d’expressions .jsx écrite pour fonctionner avec le moteur JavaScript fonctionnera également avec l’ancien moteur ExtendScript.

Astuce relative aux performances : en raison de l’absence de prétraitement, l’appel d’expressions complexes d’une bibliothèque .jsx avec cette syntaxe et le moteur JavaScript peut mener à de meilleures performances, en comparaison avec l’appel de la même expression directement via la propriété.

Attribuez explicitement aux méthodes et attributs natifs le préfixe thisLayer. ou thisProperty.

Le tableau suivant répertorie les méthodes et les attributs qui nécessitent un préfixe. Par exemple, time doit être écrit tel que thisLayer.time, tandis que wiggle() doit être écrit tel que thisProperty.wiggle()

Ces préfixes sont obligatoires uniquement lorsque l’attribut ou la méthode n’est pas déjà explicitement appelé sur une autre couche ou propriété. Par exemple, lorsque vous écrivez thisComp.layer(1).hasParent, l’ajout de thisLayer. n’est pas nécessaire, car .hasParent est déjà explicitement appelé sur la couche layer(1).

Méthodes nécessitant le préfixe thisLayer. Attributs nécessitant le préfixe thisLayer. Méthodes nécessitant le préfixe thisProperty. Attributs nécessitant le préfixethisProperty.
comp()
footage()
posterizeTime()
add()
sub()
mul()
div()
clamp()
length()
dot()
normalize()
cross()
lookAt()
timeToFrames()
framesToTime()
timeToTimecode()
timeToFeetAndFrames()
timeToNTSCTimecode()
timeToCurrentFormat()
seedRandom()
random()
gaussRandom()
noise()
degreesToRadians()
radiansToDegrees()
linear()
ease()
easeIn()
easeOut()
rgbToHsl()
hslToRgb()
hexToRgb()
mask()
sourceRectAtTime()
sourceTime()
sampleImage()
toComp()
fromComp()
toWorld()
fromWorld()
toCompVec()
fromCompVec()
toWorldVec()
fromWorldVec()
fromCompToSurface()
time
source
thisProject
colorDepth
transform
anchorPoint
position
scale
rotation
opacity
orientation
rotationX
rotationY
rotationZ
lightTransmission
castsShadows
acceptsShadows
acceptsLights
ambient
diffuse
specular
specularIntensity
shininess
specularShininess
metal
audioLevels
timeRemap
marker
name
width
height
index
parent
hasParent
inPoint
outPoint
startTime
hasVideo
hasAudio
active
enabled
audioActive
cameraOption
pointOfInterest
zoom
depthOfField
focusDistance
aperature
blurLevel
irisShape
irisRotation
irisRoundness
irisAspectRatio
irisDiffractionFringe
highlightGain
highlightThreshold
highlightSaturation
lightOption
intensity
color
coneAngle
coneFeather
shadowDarkness
shadowDiffusion
valueAtTime()
velocityAtTime()
speedAtTime()
wiggle()
temporalWiggle()
smooth()
loopIn()
loopOut()
loopInDuration()
loopOutDuration()
key()
nearestKey()
propertyGroup()
points()
inTangents()
outTangents()
isClosed()
pointsOnPath()
tangentOnPath()
normalOnPath()
createPath()

velocity
speed
numKeys
propertyIndex

Remplacement des opérateurs mathématiques par des fonctions de vecteurs mathématiques

Le moteur JavaScript et l’ancien moteur ExtendScript permettent de saturer les opérateurs mathématiques des tableaux en utilisant une syntaxe semblable à position + [100,100], mais cela ne fonctionne pas pour les expressions d’une bibliothèque de fonctions d’expressions .jsx ou à l’intérieur de eval().

Afin d’exécuter des opérations mathématiques sur des propriétés de tableau comme la position, l’échelle, etc., les équivalents des vecteurs mathématiques doivent être utilisés pour les additions, soustractions, multiplications et divisions. Les fonctions de vecteurs mathématiques fonctionnent également avec les nombres ordinaires. Ainsi, une fonction pouvant être appelée sur des propriétés de n’importe quel type de données devrait utiliser les fonctions de vecteurs mathématiques.

Remarque :

Le préfixe thisLayer. doit être utilisé avec les fonctions de vecteurs mathématiques.

  • Addition : thisLayer.add(vec1, vec2)
  • Soustraction : thisLayer.sub(vec1, vec2)
  • Multiplication : thisLayer.mul(vec, quantité)
  • Division : thisLayer.div(vec, quantité)

Vous trouverez ci-dessous des exemples d’expressions utilisant des opérations mathématiques standard et des vecteurs mathématiques mis à jour. Les expressions de vecteurs mathématiques utilisent également le préfixe thisLayer. ou thisProperty. lorsque nécessaire.

Pour trouver la différence entre une méthode wiggle() et la valeur d’une propriété de position :

// Standard Math:
wiggle() - value;
 
 
// Vector Math:
thisLayer.sub( thisProperty.wiggle(), value );

Pour effectuer une interpolation entre deux valeurs semblables à linear(), mais avec une plage étendue au-delà du minimum et du maximum définis :

// Standard Math:
value1 + ( ( t - tMin ) / ( tMax - tMin ) ) * ( value2 - value1 );
 
 
// Vector Math:
thisLayer.add( value1, thisLayer.mul( thisLayer.div( thisLayer.sub( t, tMin ), thisLayer.sub( tMax, tMin ) ), thisLayer.sub( value2, value1 ) ) );

Pour lire une propriété de position en boucle à l’intérieur et à l’extérieur :

// Standard Math:
loopIn( "cycle" ) + loopOut( "cycle" ) - value;
 
 
// Vector Math:
thisLayer.sub( thisLayer.add( thisProperty.loopIn( "cycle" ), thisProperty.loopOut( "cycle" ) ), value );

Ce produit est distribué sous licence Creative Commons Attribution - Pas d’utilisation commerciale - Partage à l’identique 3.0 non transposé  Les publications Twitter™ et Facebook ne sont pas couvertes par les dispositions Creative Commons.

Mentions légales   |   Politique de confidentialité en ligne