molstar
Version:
A comprehensive macromolecular library.
156 lines (155 loc) • 10.9 kB
JavaScript
/**
* Copyright (c) 2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { bool, float, int, list, OptionalField, RequiredField, str, union, nullable, literal, dict } from '../generic/field-schema.js';
import { SimpleParamsSchema, UnionParamsSchema } from '../generic/params-schema.js';
import { TreeSchema } from '../generic/tree-schema.js';
import { ColorT, ContinuousPalette, DiscretePalette, Matrix, Vector3 } from '../mvs/param-types.js';
const Easing = literal('linear', 'bounce-in', 'bounce-out', 'bounce-in-out', 'circle-in', 'circle-out', 'circle-in-out', 'cubic-in', 'cubic-out', 'cubic-in-out', 'exp-in', 'exp-out', 'exp-in-out', 'quad-in', 'quad-out', 'quad-in-out', 'sin-in', 'sin-out', 'sin-in-out');
const _Noise = {
/** Magnitude of the noise to apply to the interpolated value. */
noise_magnitude: OptionalField(float, 0, 'Magnitude of the noise to apply to the interpolated value.')
// support cummulative noise?
};
const _Common = {
/** Reference to the node. */
target_ref: RequiredField(str, 'Reference to the node.'),
/** Value accessor. */
property: RequiredField(union(str, list(union(str, int))), 'Value accessor.'),
/** Start time of the transition in milliseconds. */
start_ms: OptionalField(float, 0, 'Start time of the transition in milliseconds.'),
/** Duration of the transition in milliseconds. */
duration_ms: RequiredField(float, 'Duration of the transition in milliseconds.'),
};
const _Frequency = {
/** Determines how many times the interpolation loops. Current T = frequency * t mod 1. */
frequency: OptionalField(int, 1, 'Determines how many times the interpolation loops. Current T = frequency * t mod 1.'),
/** Whether to alternate the direction of the interpolation for frequency > 1. */
alternate_direction: OptionalField(bool, false, 'Whether to alternate the direction of the interpolation for frequency > 1.'),
};
const _Easing = {
/** Easing function to use for the transition. */
easing: OptionalField(Easing, 'linear', 'Easing function to use for the transition.'),
};
const ScalarInterpolation = {
..._Common,
..._Frequency,
..._Easing,
/** Start value. If a list of values is provided, each element will be interpolated separately. If unset, parent state value is used. */
start: OptionalField(nullable(union(float, list(float))), null, 'Start value. If a list of values is provided, each element will be interpolated separately. If unset, parent state value is used.'),
/** End value. If a list of values is provided, each element will be interpolated separately. If unset, only noise is applied. */
end: OptionalField(nullable(union(float, list(float))), null, 'End value. If a list of values is provided, each element will be interpolated separately. If unset, only noise is applied.'),
/** Whether to round the values to the closest integer. Useful for example for trajectory animation. */
discrete: OptionalField(bool, false, 'Whether to round the values to the closest integer. Useful for example for trajectory animation.'),
..._Noise,
};
const Vec3Interpolation = {
..._Common,
..._Frequency,
..._Easing,
/** Start value. If unset, parent state value is used. Must be array of length 3N (x1, y1, z1, x2, y2, z2, ...). */
start: OptionalField(nullable(list(float)), null, 'Start value. If unset, parent state value is used. Must be array of length 3N (x1, y1, z1, x2, y2, z2, ...).'),
/** End value. Must be array of length 3N (x1, y1, z1, x2, y2, z2, ...). If unset, only noise is applied. */
end: OptionalField(nullable(list(float)), null, 'End value. Must be array of length 3N (x1, y1, z1, x2, y2, z2, ...). If unset, only noise is applied.'),
/** Whether to use spherical interpolation. */
spherical: OptionalField(bool, false, 'Whether to use spherical interpolation.'),
..._Noise,
};
const RotationMatrixInterpolation = {
..._Common,
..._Frequency,
..._Easing,
/** Start value. If unset, parent state value is used. */
start: OptionalField(nullable(Matrix), null, 'Start value. If unset, parent state value is used.'),
/** End value. If unset, only noise is applied. */
end: OptionalField(nullable(Matrix), null, 'End value. If unset, only noise is applied.'),
..._Noise,
};
const ColorInterpolation = {
..._Common,
..._Frequency,
..._Easing,
/** Start value. If unset, parent state value is used. */
start: OptionalField(union(nullable(ColorT), dict(union(int, str), ColorT)), null, 'Start value. If unset, parent state value is used.'),
/** End value. */
end: OptionalField(union(nullable(ColorT), dict(union(int, str), ColorT)), null, 'End value.'),
/** Palette to sample colors from. Overrides start and end values. */
palette: OptionalField(nullable(union(DiscretePalette, ContinuousPalette)), null, 'Palette to sample colors from. Overrides start and end values.'),
};
const TransformationMatrixInterpolation = {
..._Common,
/** Pivot point for rotation and scale. */
pivot: OptionalField(nullable(Vector3), null, 'Pivot point for rotation and scale.'),
/** Start rotation value. If unset, parent state value is used. */
rotation_start: OptionalField(nullable(Matrix), null, 'Start rotation value. If unset, parent state value is used.'),
/** End rotation value. If unset, only noise is applied */
rotation_end: OptionalField(nullable(Matrix), null, 'End rotation value. If unset, only noise is applied.'),
/** Magnitude of the noise to apply to the rotation. */
rotation_noise_magnitude: OptionalField(float, 0, 'Magnitude of the noise to apply to the rotation.'),
/** Easing function to use for the rotation. */
rotation_easing: OptionalField(Easing, 'linear', 'Easing function to use for the rotation.'),
/** Determines how many times the rotation interpolation loops. Current T = frequency * t mod 1. */
rotation_frequency: OptionalField(int, 1, 'Determines how many times the rotation interpolation loops. Current T = frequency * t mod 1.'),
/** Whether to alternate the direction of the interpolation for frequency > 1. */
rotation_alternate_direction: OptionalField(bool, false, 'Whether to alternate the direction of the interpolation for frequency > 1.'),
/** Start translation value. If unset, parent state value is used. */
translation_start: OptionalField(nullable(Vector3), null, 'Start translation value. If unset, parent state value is used.'),
/** End translation value. If unset, only noise is applied. */
translation_end: OptionalField(nullable(Vector3), null, 'End translation value. If unset, only noise is applied.'),
/** Magnitude of the noise to apply to the translation. */
translation_noise_magnitude: OptionalField(float, 0, 'Magnitude of the noise to apply to the translation.'),
/** Easing function to use for the translation. */
translation_easing: OptionalField(Easing, 'linear', 'Easing function to use for the translation.'),
/** Determines how many times the translation interpolation loops. Current T = frequency * t mod 1. */
translation_frequency: OptionalField(int, 1, 'Determines how many times the translation interpolation loops. Current T = frequency * t mod 1.'),
/** Whether to alternate the direction of the interpolation for frequency > 1. */
translation_alternate_direction: OptionalField(bool, false, 'Whether to alternate the direction of the interpolation for frequency > 1.'),
/** Start scale value. If unset, parent state value is used. */
scale_start: OptionalField(nullable(Vector3), null, 'Start scale value. If unset, parent state value is used.'),
/** End scale value. If unset, only noise is applied. */
scale_end: OptionalField(nullable(Vector3), null, 'End scale value. If unset, only noise is applied.'),
/** Magnitude of the noise to apply to the scale. */
scale_noise_magnitude: OptionalField(float, 0, 'Magnitude of the noise to apply to the scale.'),
/** Easing function to use for the scale. */
scale_easing: OptionalField(Easing, 'linear', 'Easing function to use for the scale.'),
/** Determines how many times the scale interpolation loops. Current T = frequency * t mod 1. */
scale_frequency: OptionalField(int, 1, 'Determines how many times the scale interpolation loops. Current T = frequency * t mod 1.'),
/** Whether to alternate the direction of the interpolation for frequency > 1. */
scale_alternate_direction: OptionalField(bool, false, 'Whether to alternate the direction of the interpolation for frequency > 1.'),
};
export const MVSAnimationSchema = TreeSchema({
rootKind: 'animation',
nodes: {
animation: {
description: 'Animation root node',
parent: [],
params: SimpleParamsSchema({
/** Frame time in milliseconds. */
frame_time_ms: OptionalField(float, 1000 / 60, 'Frame time in milliseconds.'),
/** Total duration of the animation. If not specified, computed as maximum of all transitions. */
duration_ms: OptionalField(nullable(float), null, 'Total duration of the animation. If not specified, computed as maximum of all transitions.'),
/** Determines whether the animation should autoplay when a snapshot is loaded */
autoplay: OptionalField(bool, true, 'Determines whether the animation should autoplay when a snapshot is loaded.'),
/** Determines whether the animation should loop when it reaches the end. */
loop: OptionalField(bool, false, 'Determines whether the animation should loop when it reaches the end.'),
/** Determines whether the camera state should be included in the animation. */
include_camera: OptionalField(bool, false, 'Determines whether the camera state should be included in the animation.'),
/** Determines whether the canvas state should be included in the animation. */
include_canvas: OptionalField(bool, false, 'Determines whether the canvas state should be included in the animation.'),
}),
},
interpolate: {
description: 'This node enables interpolating between values',
parent: ['animation'],
params: UnionParamsSchema('kind', 'Interpolation kind', {
scalar: SimpleParamsSchema(ScalarInterpolation),
vec3: SimpleParamsSchema(Vec3Interpolation),
rotation_matrix: SimpleParamsSchema(RotationMatrixInterpolation),
transform_matrix: SimpleParamsSchema(TransformationMatrixInterpolation),
color: SimpleParamsSchema(ColorInterpolation),
})
}
}
});