En este documento se explican las diferencias de sintaxis del lenguaje de expresiones entre los motores de expresiones de JavaScript y ExtendScript heredado en After Effects 16.0.

Consulte este documento para obtener más información sobre cómo mejorar las expresiones del motor de expresiones de JavaScript, o bien para corregir los errores que se producen cuando las expresiones escritas para las versiones anteriores de After Effects no se evalúan en el motor de expresiones de JavaScript.

El lenguaje de expresión en After Effects se basa en JavaScript, que es una implementación de ECMAScript. El motor de expresiones de JavaScript en After Effects 16.0 se basa en ECMAScript 2018. El motor de expresiones de ExtendScript heredado se basa en ECMAScript 3 (1999). (Adobe ExtendScript es también el lenguaje utilizado para crear scripts en After Effects y en otras aplicaciones de Adobe).

Puede seguir los ejemplos que se ofrecen a continuación, así como las directrices para la creación de expresiones que funcionen en los motores de expresiones tanto de JavaScript como de ExtendScript heredado.

Las principales diferencias entre los motores de expresiones de JavaScript y ExtendScript heredado son las siguientes:

Sintaxis JavaScript moderna: se han realizado mejoras en el lenguaje de expresiones.

Las expresiones pueden utilizar la sintaxis JavaScript de ECMAScript 2018.

Se han agregado muchos elementos al lenguaje JavaScript desde ECMAScript 3. Hay nuevos métodos, más compactos y legibles, para utilizar con cadenas, matrices y objetos. También hay nuevas formas de declarar variables y funciones, así como parámetros predeterminados, operadores de propagación y mucho más. En este documento no se tratan dichos cambios, ya que son generales del lenguaje JavaScript. En los siguientes vínculos encontrará recursos para obtener más información sobre dichas adiciones a la sintaxis:

Recursos adicionales recomendados en los que se trata JavaScript en profundidad:

.value ya no es necesario al realizar una vinculación a otras propiedades desde Source Text.

Al hacer referencia a otro valor de propiedad desde una propiedad de Source Text, el motor de ExtendScript heredado requiere que se agregue .value al final de la propiedad. El motor de JavaScript muestra el valor de la propiedad de forma predeterminada, a no ser que se utilice explícitamente otro atributo como .propertyIndex o .name.

Por ejemplo:

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.

Es posible congelar valores de propiedades con posterizeTime(0).

En After Effects 16.0, posterizeTime(0) permite congelar el valor de propiedad en el momento 0 en la composición. Se aplica tanto al motor de JavaScript como al motor de ExtendScript heredado.

Nota:

Esta característica no es compatible con versiones anteriores y puede provocar resultados inesperados en las versiones de After Effects anteriores a la 16.0.

La sintaxis heredada no es compatible.

Casi toda la sintaxis de las expresiones del motor de expresiones de ExtendScript heredado es compatible con el motor de expresiones de JavaScript. Sin embargo, cierta sintaxis heredada no es compatible con el motor de expresiones de JavaScript. En ocasiones, esto se debe a los cambios de sintaxis en el JavaScript moderno. En otros casos, se han retirado algunos elementos obsoletos o anticuados de la sintaxis. A continuación se ofrecen algunos ejemplos de la sintaxis, tanto de los elementos que funcionan como de los que no.

La mayor parte de estas diferencias en la sintaxis se puede corregir mediante la creación de scripts de aplicación que reescriban las expresiones.

Diferencias en la sintaxis if...else

En general, se recomienda escribir siempre las declaraciones if...else con saltos de línea y corchetes de acuerdo con las directrices de MDN. El motor de ExtendScript heredado toleraba la sintaxis de las declaraciones if...else, pero el motor de JavaScript es muy estricto. La sintaxis if...else incorrecta no se evalúa al utilizar el motor de JavaScript.

No se permite terminar una expresión en una declaración if sin un elemento else.

Si una expresión termina con una declaración if sin una declaración else, el motor de JavaScript no evaluará la expresión y arrojará el código de error “Undefined value used in expression (could be an out of range array subscript?)” (Se ha utilizado un valor sin definir en la expresión. ¿Puede ser un subscript de matriz fuera del intervalo?). En el motor ExtendScript heredado, la siguiente expresión se evalúa como 100, si el tiempo es superior a 1 segundo; en caso contrario, se evalúa como 50:

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

El motor de JavaScript necesita que la parte else de la declaración se establezca de forma explícita si es la última declaración de la expresión:

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

Este uso se evalúa correctamente tanto en el motor de JavaScript como en el motor de ExtendScript heredado.

Los elementos if y else no pueden estar en la misma línea sin corchetes.

Una declaración·if...else¬en·una·sola·línea·sin·corchetes·se·evalúa·en·el·motor·de·ExtendScript·heredado,·pero·no·lo·hace·en·el·motor·de·JavaScript,·donde·arroja·un·error·similar·a·“Syntax·Error:·Unexpected·token·else”·(Error·de·sintaxis:·token·else·inesperado)·o·“Undefined·value·used·in·expression·(could·be·an·out·of·range·array·subscript?)”·(Se ha utilizado un valor sin definir en la expresión. ¿Puede ser un subscript de matriz fuera del intervalo?). El error varía en función del contexto y el tipo de propiedad.

En el motor ExtendScript heredado, la siguiente expresión se evalúa como 100, si el tiempo es superior a 1 segundo; en caso contrario, se evalúa como 50:

if ( time > 1 ) 100 else 50;

El motor de JavaScript requiere saltos de línea o corchetes para evaluar las declaraciones if...else. Para casos sencillos, se puede utilizar el operador ternario. Con el motor de JavaScript se puede utilizar cualquiera de las siguientes sintaxis:

// 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;

Todas las soluciones anteriores se evalúan correctamente tanto en el motor de JavaScript como en el motor de ExtendScript heredado.

Las expresiones no pueden terminar en una declaración de función.

Si una expresión termina con una declaración de función, el motor de JavaScript no evalúa la expresión y arroja el error “Object of type found where a Number, Array, or Property is needed” (Se ha encontrado un objeto de tipo, pero se necesitaba un número, una matriz o una propiedad). En el motor de JavaScript, el último elemento evaluado debe devolver un valor, en lugar de declararlo.

El ejemplo siguiente funciona en el motor heredado, pero no en el de JavaScript:

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

Si en la última línea se llama a una función (y no a una declaración), la expresión se evalúa correctamente en ambos motores:

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.

No se admite la sintaxis abreviada this(); debe utilizarse thisLayer().

En el motor de ExtendScript heredado, this se permitía siempre como abreviatura de thisLayer.En el motor de JavaScript, this se refiere al objeto global y debe utilizarse thisLayer. Utilizar this en el motor de JavaScript suele tener como resultado el error “this is not a function” (Este elemento no es una función).

En el ejemplo de ExtendScript heredado siguiente, this se utiliza para crear un vínculo compacto con una propiedad Text Layer Position desde la propiedad Source Text:

this(5)(2).value;

En el motor de JavaScript, this debe sustituirse por thisLayer:

thisLayer(5)(2).value;

El uso de thisLayer es compatible con ambos motores de expresiones.

El acceso del índice de matriz de la propiedad Source Text a los caracteres requiere .value.

En el motor de expresiones de ExtendScript heredado, es posible acceder a los caracteres de una propiedad de texto mediante una notación de corchetes como una matriz:

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

En el motor de JavaScript, debe agregarse .value para acceder a los caracteres:

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

Esta sintaxis es compatible con ambos motores.

No se permiten las propiedades ni los métodos en formato Snake_case.

El motor de JavaScript no admite las propiedades y los métodos Snake_case obsoletos (escritos con un guion bajo y no en formato camelCase). Deben utilizarse las versiones en formato camelCase, pues estas son compatibles con ambos motores. A continuación se ofrece una lista de propiedades Snake_case obsoletas y su equivalente en camelCase.

Propiedades Snake_case Propiedades camelCase Métodos Snake_case Métodos 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()

Se permite el uso de eval() con expresiones con codificación binaria (.jsxbin).

El motor de JavaScript no admite las expresiones codificadas en el formato binario de ExtendScript (guardadas como un archivo binario .jsxbin desde ExtendScript ToolKit CC).

Si desea ofuscar una expresión, utilice el motor de ExtendScript heredado o use un método de ofuscación diferente que sea compatible con ECMAScript 2018. Algunos métodos de ofuscación pueden no ser compatibles con ambos motores de expresión.

La compatibilidad es limitada para el objeto $. (dólar).

Los métodos y las propiedades del objeto $. (dólar) son específicos de ExtendScript, y el motor de JavaScript no los admite en su mayoría. En esta tabla se muestran los usos compatibles y no compatibles del objeto $. (dólar):

$. no compatible $. compatible

$.fileName

$.hiResTimes

$.stack

$.evalFile()

$.list()

$.setenv()

$.getenv()

$.appEncoding

$.buildDate

$.decimalPoint

$.dictionary

$.error

$.flags

$.includePath

$.level

$.line

$.locale

$.localize

$.memCache

$.os

$.screens

$.strict

$.version

$.build

$.engineName (no compatible en el motor ExtendScript heredado)

$.global

No se admiten los elementos ...reflect.properties, ...reflect.methods ni toSource().

reflect.properties y reflect.methods no son compatibles con el motor de JavaScript. Se trata de métodos específicos de ExtendScript que no tienen equivalente directo en JavaScript.

toSource() se considera obsoleto en JavaScript y no es parte de ninguna pista estándar.

Para ver una lista de las propiedades y los métodos disponibles para cualquier propiedad de After Effects, como se ha hecho con los métodos anteriores, utilice la siguiente expresión en una propiedad Source Text y vincúlela a la propiedad de destino deseada. Por ejemplo, se puede utilizar el icono espiral en lugar de thisProperty en la línea 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.

La expresión anterior no es compatible con el motor de ExtendScript heredado. Utiliza sintaxis y métodos no disponibles en ECMAScript 3.

Requisitos de sintaxis para las bibliotecas de expresiones .jsx y eval() con el motor de JavaScript

Cuando se utilizan expresiones dentro de una biblioteca de funciones de expresiones .jsx, o cuando se llama a una expresión dentro de eval(), es preciso modificar ciertos elementos de la sintaxis:

Es preciso agregar un prefijo explícito thisLayer. o thisProperty. a cualquier método o atributo nativo al que no se llame explícitamente en una capa o propiedad. El prefijo indica al motor de JavaScript el objeto para el que se llama al método o atributo.

Las operaciones matemáticas realizadas sobre valores de matriz como Position deben calcularse utilizando la matemática vectorial, o bien funciones de bucle o iteración que actúen sobre todos los elementos de la matriz. Los operadores matemáticos sobrecargados, como position + [100,100], no se evaluarán.

Si se utiliza el motor de JavaScript, las expresiones de ExtendScript heredado se preprocesan antes de su evaluación para que la sintaxis de algunas de ellas sea legible para el nuevo motor. Sin embargo, estas tareas de preprocesamiento no se realizan al evaluar expresiones de una biblioteca de funciones de expresiones .jsx, o al llamar a una expresión dentro de eval(). En estos casos, las modificaciones de sintaxis indicadas deben realizarse de forma manual. Todas estas modificaciones de sintaxis son retrocompatibles con el motor ExtendScript heredado, de modo que una biblioteca de expresiones .jsx escrita para que funcione con el motor de JavaScript también funcionará con el motor ExtendScript heredado.

Sugerencia de rendimiento: Debido a la falta de preprocesamiento, las llamadas a expresiones complejas desde una biblioteca .jsx con la sintaxis y el motor de JavaScript pueden tener mejor rendimiento que las llamadas a las mismas expresiones directamente desde una propiedad.

Los métodos y atributos nativos deben incluir de forma explícita los prefijos thisLayer. o thisProperty.

En la tabla siguiente se enumeran los métodos y atributos que requieren un prefijo. Por ejemplo, time debe escribirse thisLayer.time, mientras que wiggle() debe escribirse thisProperty.wiggle()

Estos prefijos solo son necesarios en los casos en los que el atributo o método no recibe explícitamente una llamada en otra capa o propiedad. Por ejemplo, cuando se realiza la llamada thisComp.layer(1).hasParent, no es necesario agregar thisLayer. porque .hasParent ya está recibiendo explícitamente una llamada en layer(1).

Métodos que requieren thisLayer. Atributos que requieren thisLayer. Métodos que requieren thisProperty. Atributos que requieren thisProperty.
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

Se reemplazan los operadores matemáticos por funciones vectoriales.

Tanto el motor de JavaScript como el de ExtendScript heredado permiten utilizar operadores matemáticos de sobrecarga en matrices empleando sintaxis como position + [100,100], aunque esto no funciona para las expresiones de una biblioteca de funciones de expresiones .jsx o dentro de eval().

Para realizar operaciones matemáticas en propiedades de matrices como Position, Scale, etc., se deben utilizar los equivalentes vectoriales para la suma, resta, multiplicación y división. Las funciones matemáticas vectoriales también sirven para números regulares, por lo que, en el caso de una propiedad que pueda utilizar ambos tipos de datos en una llamada, se debe emplear la función vectorial.

Nota:

Para las funciones matemáticas vectoriales debe utilizarse el prefijo thisLayer..

  • Suma: thisLayer.add(vec1, vec2)
  • Resta: thisLayer.sub(vec1, vec2)
  • Multiplicación: thisLayer.mul(vec, amount)
  • División: thisLayer.div(vec, amount)

A continuación se ofrecen ejemplos de expresiones que utilizan operaciones estándar y operaciones vectoriales actualizadas. Las expresiones vectoriales también utilizan los prefijos thisLayer. o thisProperty. apropiados cuando es necesario.

Para encontrar la diferencia entre un wiggle() y el valor de una propiedad Position:

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

Para realizar una interpolación entre dos valores, de un modo similar a como se hace con linear(), pero con un rango que se extiende más allá de los valores mínimo y máximo definidos:

// 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 ) ) );

Para entrar y salir de un bucle de una propiedad Position:

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

Esta obra está autorizada con arreglo a la licencia de Reconocimiento-NoComercial-CompartirIgual 3.0 Unported de Creative Commons.  Los términos de Creative Commons no cubren las publicaciones en Twitter™ y Facebook.

Avisos legales   |   Política de privacidad en línea