mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-14 19:27:05 -04:00
G2: improve editing reliability and Windows rendering fidelity
This commit is contained in:
1 parent
b46be83ab4
commit
39e6907b5f
101 files changed
+1727
-351
No files matched your search
@@ -0,0 +1,44 @@
|
||||
// Original behavior probe. Run this function body through AEsync's `run -f` command.
|
||||
// Creates only a temporary text layer and removes its composition before returning.
|
||||
// No Adobe assets, application internals, presets or implementation code are read.
|
||||
var comp = null, layer, p, cases, results = [], times = [], i, j, c, values, output;
|
||||
cases = [
|
||||
["easy", 0, 100, 0, 100 / 3, 0, 100 / 3],
|
||||
["high_influence", 0, 100, 0, 80, 0, 80],
|
||||
["asymmetric", 0, 100, 20, 80, 80, 60],
|
||||
["overshoot", 0, 100, 400, 40, -100, 40],
|
||||
["descending", 100, 0, -20, 60, -80, 80],
|
||||
["equal_endpoints", 50, 50, 100, 40, -100, 40],
|
||||
["maximum_influence", 0, 100, 0, 100, 0, 100],
|
||||
["minimum_maximum", 0, 100, 0, 0.1, 0, 100]
|
||||
];
|
||||
for (i = 0; i <= 20; i++) times.push(i / 20);
|
||||
try {
|
||||
comp = app.project.items.addComp("EffectCraft original ease oracle", 64, 64, 1, 2, 20);
|
||||
layer = comp.layers.addText("Original behavioral probe");
|
||||
p = layer.property("ADBE Transform Group").property("ADBE Rotate Z");
|
||||
for (i = 0; i < cases.length; i++) {
|
||||
c = cases[i];
|
||||
while (p.numKeys > 0) p.removeKey(p.numKeys);
|
||||
p.setValueAtTime(0, c[1]);
|
||||
p.setValueAtTime(1, c[2]);
|
||||
p.setInterpolationTypeAtKey(1, KeyframeInterpolationType.BEZIER, KeyframeInterpolationType.BEZIER);
|
||||
p.setInterpolationTypeAtKey(2, KeyframeInterpolationType.BEZIER, KeyframeInterpolationType.BEZIER);
|
||||
p.setTemporalAutoBezierAtKey(1, false);
|
||||
p.setTemporalAutoBezierAtKey(2, false);
|
||||
p.setTemporalContinuousAtKey(1, false);
|
||||
p.setTemporalContinuousAtKey(2, false);
|
||||
p.setTemporalEaseAtKey(1, [new KeyframeEase(0, 100 / 3)], [new KeyframeEase(c[3], c[4])]);
|
||||
p.setTemporalEaseAtKey(2, [new KeyframeEase(c[5], c[6])], [new KeyframeEase(0, 100 / 3)]);
|
||||
values = [];
|
||||
for (j = 0; j < times.length; j++) values.push(p.valueAtTime(times[j], true));
|
||||
results.push({name:c[0], from:c[1], to:c[2], outSpeed:c[3], outInfluence:c[4], inSpeed:c[5], inInfluence:c[6], times:times, values:values, applied:{outSpeed:p.keyOutTemporalEase(1)[0].speed, outInfluence:p.keyOutTemporalEase(1)[0].influence, inSpeed:p.keyInTemporalEase(2)[0].speed, inInfluence:p.keyInTemporalEase(2)[0].influence, outAuto:p.keyTemporalAutoBezier(1), inAuto:p.keyTemporalAutoBezier(2), outContinuous:p.keyTemporalContinuous(1), inContinuous:p.keyTemporalContinuous(2)}});
|
||||
}
|
||||
output = {aeVersion:app.version, cases:results};
|
||||
comp.remove();
|
||||
comp = null;
|
||||
return JSON.stringify(output);
|
||||
} catch (e) {
|
||||
if (comp !== null) comp.remove();
|
||||
throw e;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// Clean-room scalar property comparison. Raw host observations remain gitignored.
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
|
||||
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const cli = process.argv[2];
|
||||
if (!cli || !fs.existsSync(cli)) throw new Error('Usage: node examples/check-ae-ease.mjs <aesync/server/dist/cli.js>');
|
||||
const tolerance = 1e-7;
|
||||
function run(command, args) {
|
||||
const result = spawnSync(command, args, { cwd: root, windowsHide: true, encoding: 'utf8', maxBuffer: 8 * 1024 * 1024 });
|
||||
if (result.status !== 0) throw new Error(result.stderr || result.stdout || 'Process failed');
|
||||
return JSON.parse(result.stdout.replace(/^\uFEFF/, '').trim());
|
||||
}
|
||||
const ec = run('cargo', ['run', '--quiet', '-p', 'effectcraft-keyframe', '--example', 'ae_ease_samples']);
|
||||
const ae = run(process.execPath, [cli, 'run', '-f', path.join(root, 'examples', 'ae-ease-oracle.jsx'), '--raw']);
|
||||
const local = path.join(root, 'plan', 'aftereffects', 'ref', 'ease');
|
||||
fs.mkdirSync(local, { recursive: true });
|
||||
fs.writeFileSync(path.join(local, 'ae-observations.json'), JSON.stringify(ae, null, 2) + '\n');
|
||||
fs.writeFileSync(path.join(local, 'effectcraft-samples.json'), JSON.stringify(ec, null, 2) + '\n');
|
||||
if (ae.cases.length !== ec.cases.length) throw new Error('Case count mismatch');
|
||||
const scores = ae.cases.map(reference => {
|
||||
const candidate = ec.cases.find(c => c.name === reference.name);
|
||||
if (!candidate || reference.values.length !== candidate.values.length) throw new Error('Missing or truncated case: ' + reference.name);
|
||||
for (const key of ['from', 'to', 'outSpeed', 'outInfluence', 'inSpeed', 'inInfluence']) {
|
||||
if (!Number.isFinite(reference[key]) || Math.abs(reference[key] - candidate[key]) > 1e-9) throw new Error('Case metadata mismatch: ' + reference.name + '/' + key);
|
||||
}
|
||||
for (const key of ['outSpeed', 'outInfluence', 'inSpeed', 'inInfluence']) {
|
||||
if (!Number.isFinite(reference.applied[key]) || Math.abs(reference.applied[key] - reference[key]) > 1e-9) throw new Error('AE changed requested ease: ' + reference.name + '/' + key);
|
||||
}
|
||||
if (reference.applied.outAuto || reference.applied.inAuto || reference.applied.outContinuous || reference.applied.inContinuous) throw new Error('Unexpected automatic ease');
|
||||
const errors = reference.values.map((value, i) => {
|
||||
if (!Number.isFinite(value) || !Number.isFinite(candidate.values[i]) || reference.times[i] !== candidate.times[i]) throw new Error('Invalid or mismatched sample: ' + reference.name);
|
||||
return Math.abs(value - candidate.values[i]);
|
||||
});
|
||||
const maxAbsoluteError = Math.max(...errors);
|
||||
return { name: reference.name, samples: errors.length, maxAbsoluteError, pass: maxAbsoluteError <= tolerance };
|
||||
});
|
||||
const report = { generatedAt: new Date().toISOString(), aeVersion: ae.aeVersion, property: 'Rotation (scalar)', tolerance, cases: scores, pass: scores.every(c => c.pass) };
|
||||
fs.mkdirSync(path.join(root, 'docs', 'fidelity'), { recursive: true });
|
||||
fs.writeFileSync(path.join(root, 'docs', 'fidelity', 'keyframe-ease.json'), JSON.stringify(report, null, 2) + '\n');
|
||||
console.log(JSON.stringify(report, null, 2));
|
||||
if (!report.pass) process.exitCode = 1;
|
||||
Reference in new issue
Block a user