animejs
Version:
JavaScript animation engine
106 lines (93 loc) • 4.29 kB
JavaScript
/**
* Anime.js - adapters - CJS
* @version v4.5.0
* @license MIT
* @copyright 2026 - Julian Garnier
*/
;
var adapter = require('./adapter.cjs');
var number = require('../../utils/number.cjs');
var helpers = require('./helpers.cjs');
/**
* Global property resolvers for three.js targets. Auto-detect `Color`-typed properties, `Vector2/3/4` axis components, shader uniforms, and TSL `UniformNode` slots on any three.js object. For mesh-like targets, a second resolver walks to `target.material` and runs the same detection there.
*/
const identity = (t) => t;
const getMaterial = (t) => t.material;
const directColorCache = [{}, {}, {}];
const directScalarCache = [{}, {}, {}];
const directVectorCache = [{}, {}, {}];
const materialColorCache = [{}, {}, {}];
const materialScalarCache = [{}, {}, {}];
const materialVectorCache = [{}, {}, {}];
const buildEntry = (name, d, getHost, colorCaches, scalarCaches, vectorCaches) => {
const path = d.path;
if (d.kind === helpers.KIND_COLOR) {
const cache = colorCaches[path];
return cache[name] || (cache[name] = {
get: (t) => helpers.readColorAt(getHost(t), name, path),
set: (t, _, tw) => helpers.writeColorAt(getHost(t), name, tw._numbers, path),
});
}
if (d.kind === helpers.KIND_SCALAR) {
const cache = scalarCaches[path];
return cache[name] || (cache[name] = {
get: (t) => helpers.readScalar(getHost(t), name, path),
set: (t, v) => helpers.writeScalar(getHost(t), name, v, path),
});
}
// KIND_VECTOR
const base = d.base;
const axis = d.axis;
const cache = vectorCaches[path];
return cache[name] || (cache[name] = {
get: (t) => helpers.readVectorAt(getHost(t), base, axis, path),
set: (t, v) => helpers.writeVectorAt(getHost(t), base, axis, v, path),
});
};
// Detect direct Color, Vector axis, uniforms, and UniformNode slots on the target.
// Numeric or boolean direct fields fall through to the engine OBJECT path.
adapter.threeAdapter.registerPropertyResolver((target, name) => {
const d = helpers.classifyTargetProp(target, name);
if (!d) return null;
if (d.kind === helpers.KIND_SCALAR && d.path === helpers.PATH_DIRECT) return null;
return buildEntry(name, d, identity, directColorCache, directScalarCache, directVectorCache);
});
// Walk to target.material for meshes and other Object3D subclasses with a material field.
// Skip when the target already exposes the name directly so a mesh-level mapping wins.
adapter.threeAdapter.registerPropertyResolver((target, name) => {
if (target[name] !== undefined) return null;
const m = target.material;
if (!m) return null;
const first = Array.isArray(m) ? m[0] : m;
if (!first) return null;
const d = helpers.classifyTargetProp(first, name);
if (!d) return null;
return buildEntry(name, d, getMaterial, materialColorCache, materialScalarCache, materialVectorCache);
});
// Convert angle-named scalar fields between degrees and radians so users animate in degrees on any three.js target.
// Object3D Euler rotation is excluded because Euler is not a number, the rotateX/Y/Z mappings handle it.
const ANGLE_NAMES = { rotation: 1, angle: 1 };
const angleEntries = {};
adapter.threeAdapter.registerPropertyResolver((target, name) => {
if (!ANGLE_NAMES[name]) return null;
if (typeof target[name] !== 'number') return null;
return angleEntries[name] || (angleEntries[name] = {
get: (t) => number.radToDeg(t[name]),
set: (t, v) => { t[name] = number.degToRad(v); },
});
});
// Decompose Euler-typed angle fields to axis components in degrees, like rotationX, rotationY, rotationZ when rotation is an Euler.
// Object3D mappings win because static adapter props beat resolvers, so this only catches non-Object3D targets with an Euler rotation field.
const eulerAxisEntries = {};
adapter.threeAdapter.registerPropertyResolver((target, name) => {
const axis = helpers.AXIS_MAP[name[name.length - 1]];
if (!axis) return null;
const base = name.slice(0, -1);
if (!ANGLE_NAMES[base]) return null;
const v = target[base];
if (!v || !v.isEuler) return null;
return eulerAxisEntries[name] || (eulerAxisEntries[name] = {
get: (t) => number.radToDeg(t[base][axis]),
set: (t, v) => { t[base][axis] = number.degToRad(v); },
});
});