feat(2d): improve property declarations

This PR splits property declarations into separate decorators.
`@initial()`, `interpolation()`, and `wrapper()` were added.

The following declaration:
```ts
@compound(['x', 'y'], Vector2)
@property(undefined, Vector2.lerp, Vector2)
public declare readonly position: Signal<Vector2, this>;
```
becomes:
```ts
@compound(['x', 'y'])
@wrapper(Vector2)
@property()
public declare readonly position: Signal<Vector2, this>;
```

Eliminating the need to repeat `Vector2` in both decorators.
This commit is contained in:
aarthificial
2022-11-17 19:25:41 +01:00
committed by Jacob
parent 6a84120d94
commit 27e7d267ee
15 changed files with 398 additions and 188 deletions

View File

@@ -1,4 +1,4 @@
import {computed, property} from '../decorators';
import {computed, initial, property} from '../decorators';
import {Signal, SignalValue} from '@motion-canvas/core/lib/utils';
import {Shape, ShapeProps} from './Shape';
import {CodeTree, parse, diff, ready, MorphToken} from 'code-fns';
@@ -16,7 +16,8 @@ export interface CodeProps extends ShapeProps {
}
export class CodeBlock extends Shape {
@property('')
@initial('')
@property()
public declare readonly code: Signal<CodeTree, this>;
private progress: number | null = null;

View File

@@ -1,5 +1,5 @@
import {Signal, SignalValue} from '@motion-canvas/core/lib/utils';
import {computed, property} from '../decorators';
import {computed, initial, property} from '../decorators';
import {Rect as RectType, Vector2} from '@motion-canvas/core/lib/types';
import Color from 'colorjs.io';
import {drawImage} from '../utils';
@@ -15,10 +15,12 @@ export class Image extends Rect {
@property()
public declare readonly src: Signal<string, this>;
@property(1)
@initial(1)
@property()
public declare readonly alpha: Signal<number, this>;
@property(true)
@initial(true)
@property()
public declare readonly smoothing: Signal<boolean, this>;
protected readonly image: HTMLImageElement;

View File

@@ -1,4 +1,12 @@
import {compound, computed, Property, property} from '../decorators';
import {
compound,
computed,
initial,
interpolation,
Property,
property,
wrapper,
} from '../decorators';
import {
Origin,
PossibleSpacing,
@@ -87,100 +95,129 @@ export interface LayoutProps extends NodeProps {
}
export class Layout extends Node {
@property(null)
@initial(null)
@property()
public declare readonly layout: Signal<LayoutMode, this>;
@property(null)
@initial(null)
@property()
public declare readonly maxWidth: Signal<Length, this>;
@property(null)
@initial(null)
@property()
public declare readonly maxHeight: Signal<Length, this>;
@property(null)
@initial(null)
@property()
public declare readonly minWidth: Signal<Length, this>;
@property(null)
@initial(null)
@property()
public declare readonly minHeight: Signal<Length, this>;
@property(null)
@initial(null)
@property()
public declare readonly ratio: Signal<number | null, this>;
@property(0)
@initial(0)
@property()
public declare readonly marginTop: Signal<number, this>;
@property(0)
@initial(0)
@property()
public declare readonly marginBottom: Signal<number, this>;
@property(0)
@initial(0)
@property()
public declare readonly marginLeft: Signal<number, this>;
@property(0)
@initial(0)
@property()
public declare readonly marginRight: Signal<number, this>;
@compound(
{
top: 'marginTop',
bottom: 'marginBottom',
left: 'marginLeft',
right: 'marginRight',
},
Spacing,
)
@property(undefined, Spacing.lerp, Spacing)
@compound({
top: 'marginTop',
bottom: 'marginBottom',
left: 'marginLeft',
right: 'marginRight',
})
@wrapper(Spacing)
@property()
public declare readonly margin: Property<PossibleSpacing, Spacing, this>;
@property(0)
@initial(0)
@property()
public declare readonly paddingTop: Signal<number, this>;
@property(0)
@initial(0)
@property()
public declare readonly paddingBottom: Signal<number, this>;
@property(0)
@initial(0)
@property()
public declare readonly paddingLeft: Signal<number, this>;
@property(0)
@initial(0)
@property()
public declare readonly paddingRight: Signal<number, this>;
@compound(
{
top: 'paddingTop',
bottom: 'paddingBottom',
left: 'paddingLeft',
right: 'paddingRight',
},
Spacing,
)
@property(undefined, Spacing.lerp, Spacing)
@compound({
top: 'paddingTop',
bottom: 'paddingBottom',
left: 'paddingLeft',
right: 'paddingRight',
})
@wrapper(Spacing)
@property()
public declare readonly padding: Property<PossibleSpacing, Spacing, this>;
@property('row')
@initial('row')
@property()
public declare readonly direction: Signal<FlexDirection, this>;
@property(null)
@initial(null)
@property()
public declare readonly basis: Signal<FlexBasis, this>;
@property(0)
@initial(0)
@property()
public declare readonly grow: Signal<number, this>;
@property(1)
@initial(1)
@property()
public declare readonly shrink: Signal<number, this>;
@property('nowrap')
@initial('nowrap')
@property()
public declare readonly wrap: Signal<FlexWrap, this>;
@property('normal')
@initial('normal')
@property()
public declare readonly justifyContent: Signal<FlexJustify, this>;
@property('normal')
@initial('normal')
@property()
public declare readonly alignItems: Signal<FlexAlign, this>;
@property(null)
@initial(null)
@property()
public declare readonly gap: Signal<Length, this>;
@property(null)
@initial(null)
@property()
public declare readonly rowGap: Signal<Length, this>;
@property(null)
@initial(null)
@property()
public declare readonly columnGap: Signal<Length, this>;
@property(null)
@initial(null)
@property()
public declare readonly fontFamily: Signal<string | null, this>;
@property(null)
@initial(null)
@property()
public declare readonly fontSize: Signal<number | null, this>;
@property(null)
@initial(null)
@property()
public declare readonly fontStyle: Signal<string | null, this>;
@property(null)
@initial(null)
@property()
public declare readonly fontWeight: Signal<number | null, this>;
@property(null)
@initial(null)
@property()
public declare readonly lineHeight: Signal<number | null, this>;
@property(null)
@initial(null)
@property()
public declare readonly letterSpacing: Signal<number | null, this>;
@property(null)
@initial(null)
@property()
public declare readonly textWrap: Signal<boolean | null, this>;
@property(0)
@initial(0)
@property()
protected declare readonly customX: Signal<number, this>;
@property(0)
@initial(0)
@property()
public declare readonly x: Signal<number, this>;
protected getX(): number {
if (this.isLayoutRoot()) {
@@ -193,9 +230,11 @@ export class Layout extends Node {
this.customX(value);
}
@property(0)
@initial(0)
@property()
protected declare readonly customY: Signal<number, this>;
@property(0)
@initial(0)
@property()
public declare readonly y: Signal<number, this>;
protected getY(): number {
if (this.isLayoutRoot()) {
@@ -208,9 +247,11 @@ export class Layout extends Node {
this.customY(value);
}
@property(null)
@initial(null)
@property()
protected declare readonly customWidth: Signal<Length, this>;
@property(null)
@initial(null)
@property()
public declare readonly width: Property<Length, number, this>;
protected getWidth(): number {
return this.computedSize().width;
@@ -252,9 +293,11 @@ export class Layout extends Node {
lock && this.releaseSize();
}
@property(null)
@initial(null)
@property()
protected declare readonly customHeight: Signal<Length, this>;
@property(null)
@initial(null)
@property()
public declare readonly height: Property<Length, number, this>;
protected getHeight(): number {
return this.computedSize().height;
@@ -297,8 +340,9 @@ export class Layout extends Node {
lock && this.releaseSize();
}
@compound(['width', 'height'], Vector2)
@property(undefined, Vector2.lerp, Vector2)
@compound({x: 'width', y: 'height'})
@wrapper(Vector2)
@property()
public declare readonly size: Property<
{width: Length; height: Length},
Vector2,
@@ -349,30 +393,38 @@ export class Layout extends Node {
this.size(value);
}
@property(0)
@initial(0)
@property()
public declare readonly rotation: Signal<number, this>;
@property(0)
@initial(0)
@property()
public declare readonly offsetX: Signal<number, this>;
@property(0)
@initial(0)
@property()
public declare readonly offsetY: Signal<number, this>;
@compound({x: 'offsetX', y: 'offsetY'}, Vector2)
@property(undefined, Vector2.lerp, Vector2)
@compound({x: 'offsetX', y: 'offsetY'})
@wrapper(Vector2)
@property()
public declare readonly offset: Signal<Vector2, this>;
@property(1)
@initial(1)
@property()
public declare readonly scaleX: Signal<number, this>;
@property(1)
@initial(1)
@property()
public declare readonly scaleY: Signal<number, this>;
@compound({x: 'scaleX', y: 'scaleY'}, Vector2)
@property(undefined, Vector2.lerp, Vector2)
@compound({x: 'scaleX', y: 'scaleY'})
@wrapper(Vector2)
@property()
public declare readonly scale: Signal<Vector2, this>;
@property(undefined, Vector2.lerp, Vector2)
@wrapper(Vector2)
@property()
public declare readonly absoluteScale: Signal<Vector2, this>;
protected getAbsoluteScale(): Vector2 {
@@ -396,11 +448,13 @@ export class Layout extends Node {
return scale.div(parentScale);
}
@compound(['x', 'y'], Vector2)
@property(undefined, Vector2.lerp, Vector2)
@compound(['x', 'y'])
@wrapper(Vector2)
@property()
public declare readonly position: Signal<Vector2, this>;
@property(undefined, Vector2.lerp, Vector2)
@wrapper(Vector2)
@property()
public declare readonly absolutePosition: Signal<Vector2, this>;
protected getAbsolutePosition(): Vector2 {
@@ -432,13 +486,15 @@ export class Layout extends Node {
}
}
@property(false)
@initial(false)
@property()
public declare readonly clip: Signal<boolean, this>;
public readonly element: HTMLElement;
public readonly styles: CSSStyleDeclaration;
@property(0)
@initial(0)
@property()
protected declare readonly sizeLockCounter: Signal<number, this>;
public constructor({tagName = 'div', ...props}: LayoutProps) {

View File

@@ -1,4 +1,12 @@
import {compound, computed, initialize, property} from '../decorators';
import {
compound,
computed,
initial,
initialize,
interpolation,
property,
wrapper,
} from '../decorators';
import {Vector2, Rect, transformScalar} from '@motion-canvas/core/lib/types';
import {
createSignal,
@@ -38,13 +46,16 @@ export interface NodeProps {
export class Node implements Promisable<Node> {
public declare isClass: boolean;
@property(false)
@initial(false)
@property()
public declare readonly cache: Signal<boolean, this>;
@property(false)
@initial(false)
@property()
public declare readonly composite: Signal<boolean, this>;
@property('source-over')
@initial('source-over')
@property()
public declare readonly compositeOperation: Signal<
GlobalCompositeOperation,
this
@@ -70,7 +81,8 @@ export class Node implements Promisable<Node> {
}
}
@property(1)
@initial(1)
@property()
public declare readonly opacity: Signal<number, this>;
@computed()
@@ -78,44 +90,57 @@ export class Node implements Promisable<Node> {
return (this.parent()?.absoluteOpacity() ?? 1) * this.opacity();
}
@property(0)
@initial(0)
@property()
public declare readonly blur: Signal<number, this>;
@property(1)
@initial(1)
@property()
public declare readonly brightness: Signal<number, this>;
@property(1)
@initial(1)
@property()
public declare readonly contrast: Signal<number, this>;
@property(0)
@initial(0)
@property()
public declare readonly grayscale: Signal<number, this>;
@property(0)
@initial(0)
@property()
public declare readonly hue: Signal<number, this>;
@property(0)
@initial(0)
@property()
public declare readonly invert: Signal<number, this>;
@property(1)
@initial(1)
@property()
public declare readonly saturate: Signal<number, this>;
@property(0)
@initial(0)
@property()
public declare readonly sepia: Signal<number, this>;
@property('')
@initial('')
@property()
public declare readonly shadowColor: Signal<string, this>;
@property(0)
@initial(0)
@property()
public declare readonly shadowBlur: Signal<number, this>;
@property(0)
@initial(0)
@property()
public declare readonly shadowOffsetX: Signal<number, this>;
@property(0)
@initial(0)
@property()
public declare readonly shadowOffsetY: Signal<number, this>;
@compound({x: 'shadowOffsetX', y: 'shadowOffsetY'}, Vector2)
@property(undefined, Vector2.lerp, Vector2)
@compound({x: 'shadowOffsetX', y: 'shadowOffsetY'})
@wrapper(Vector2)
@property()
public declare readonly shadowOffset: Signal<Vector2, this>;
@computed()

View File

@@ -1,7 +1,7 @@
import {Signal, SignalValue} from '@motion-canvas/core/lib/utils';
import {Rect as RectType} from '@motion-canvas/core/lib/types';
import {Shape, ShapeProps} from './Shape';
import {property} from '../decorators';
import {initial, property} from '../decorators';
import {drawRoundRect} from '../utils';
export interface RectProps extends ShapeProps {
@@ -9,7 +9,8 @@ export interface RectProps extends ShapeProps {
}
export class Rect extends Shape {
@property(0)
@initial(0)
@property()
public declare readonly radius: Signal<number, this>;
public constructor(props: RectProps) {

View File

@@ -1,5 +1,5 @@
import {CanvasStyle} from '../partials';
import {computed, property} from '../decorators';
import {computed, initial, property} from '../decorators';
import {createSignal, Signal, SignalValue} from '@motion-canvas/core/lib/utils';
import {Rect} from '@motion-canvas/core/lib/types';
import {Layout, LayoutProps} from './Layout';
@@ -19,21 +19,29 @@ export interface ShapeProps extends LayoutProps {
}
export abstract class Shape extends Layout {
@property(null)
@initial(null)
@property()
public declare readonly fill: Signal<CanvasStyle, this>;
@property(null)
@initial(null)
@property()
public declare readonly stroke: Signal<CanvasStyle, this>;
@property(false)
@initial(false)
@property()
public declare readonly strokeFirst: Signal<boolean, this>;
@property(0)
@initial(0)
@property()
public declare readonly lineWidth: Signal<number, this>;
@property('miter')
@initial('miter')
@property()
public declare readonly lineJoin: Signal<CanvasLineJoin, this>;
@property('butt')
@initial('butt')
@property()
public declare readonly lineCap: Signal<CanvasLineCap, this>;
@property([])
@initial([])
@property()
public declare readonly lineDash: Signal<number[], this>;
@property(0)
@initial(0)
@property()
public declare readonly lineDashOffset: Signal<number, this>;
protected readonly rippleStrength = createSignal<number, this>(0);

View File

@@ -1,4 +1,4 @@
import {property} from '../decorators';
import {initial, interpolation, property} from '../decorators';
import {Signal, SignalValue} from '@motion-canvas/core/lib/utils';
import {textLerp} from '@motion-canvas/core/lib/tweening';
import {Shape, ShapeProps} from './Shape';
@@ -22,7 +22,9 @@ export class Text extends Shape {
}
}
@property('', textLerp)
@initial('')
@interpolation(textLerp)
@property()
public declare readonly text: Signal<string, this>;
public constructor({children, ...rest}: TextProps) {

View File

@@ -1,5 +1,5 @@
import {SignalValue, isReactive} from '@motion-canvas/core/lib/utils';
import {capitalize} from './property';
import {capitalize, PropertyMetadata} from './property';
import {addInitializer} from './initializers';
/**
@@ -40,33 +40,25 @@ import {addInitializer} from './initializers';
* @param mapping - An array of signals to turn into a compound property or a
* record mapping the property in the compound object to the
* corresponding signal.
* @param klass - A class used to instantiate the returned value.
*/
export function compound(
mapping: string[] | Record<string, string>,
klass?: new (value: any) => any,
): PropertyDecorator {
return (target: any, key) => {
const metaKey = `meta${capitalize(key.toString())}`;
const meta: PropertyMetadata<any> = target[metaKey];
const entries = Array.isArray(mapping)
? mapping.map(key => [key, key])
: Object.entries(mapping);
if (klass) {
target.constructor.prototype[`get${capitalize(key.toString())}`] =
function () {
const object = Object.fromEntries(
entries.map(([key, property]) => [key, this[property]()]),
);
return new klass(object);
};
} else {
target.constructor.prototype[`get${capitalize(key.toString())}`] =
function () {
return Object.fromEntries(
entries.map(([key, property]) => [key, this[property]()]),
);
};
}
target.constructor.prototype[`get${capitalize(key.toString())}`] =
function () {
const object = Object.fromEntries(
entries.map(([key, property]) => [key, this[property]()]),
);
return meta?.wrapper ? new meta.wrapper(object) : object;
};
target.constructor.prototype[`set${capitalize(key.toString())}`] =
function set(value: SignalValue<any>) {

View File

@@ -11,15 +11,8 @@ export function addInitializer<T>(target: any, initializer: Initializer<T>) {
// and it's not the target object itself
!Object.prototype.hasOwnProperty.call(target, INITIALIZERS)
) {
const props = [];
let base = Object.getPrototypeOf(target);
while (base) {
if (Object.prototype.hasOwnProperty.call(base, INITIALIZERS)) {
props.push(...base[INITIALIZERS]);
}
base = Object.getPrototypeOf(base);
}
target[INITIALIZERS] = props;
const base = Object.getPrototypeOf(target);
target[INITIALIZERS] = [...base[INITIALIZERS]];
}
target[INITIALIZERS].push(initializer);

View File

@@ -20,6 +20,12 @@ export function capitalize<T extends string>(value: T): Capitalize<T> {
return <Capitalize<T>>(value[0].toUpperCase() + value.slice(1));
}
export interface PropertyMetadata<T> {
default?: T;
interpolationFunction?: InterpolationFunction<T>;
wrapper?: new (value: any) => T;
}
export interface Property<
TSetterValue,
TGetterValue extends TSetterValue,
@@ -157,6 +163,18 @@ export function createProperty<
return handler;
}
const PROPERTIES = Symbol.for('properties');
export function getPropertiesOf(
value: any,
): Record<string, PropertyMetadata<any>> {
if (value && typeof value === 'object') {
return value[PROPERTIES] ?? {};
}
return {};
}
/**
* Create a signal property decorator.
*
@@ -174,44 +192,136 @@ export function createProperty<
* ```ts
* class Example {
* \@property()
* public declare color: Signal<Color, this>;
*
* \@customProperty()
* public declare colorString: Signal<string, this>;
*
* protected getColorString() {
* return this.color().toString();
* }
*
* protected setColorString(value: SignalValue<string>) {
* this.color(
* isReactive(value)
* ? () => new Color(value())
* : new Color(value)
* );
* }
* public declare length: Signal<number, this>;
* }
* ```
*
* @param initial - An option initial value of the property.
* @param interpolationFunction - The default function used to interpolate
* between values.
* @param klass - A class used to instantiate the returned value.
*/
export function property<T>(
initial?: T,
interpolationFunction?: InterpolationFunction<T>,
klass?: new (value: any) => T,
): PropertyDecorator {
export function property<T>(): PropertyDecorator {
return (target: any, key) => {
let lookup: Record<string | symbol, PropertyMetadata<T>>;
if (!target[PROPERTIES]) {
target[PROPERTIES] = lookup = {};
} else if (
target[PROPERTIES] &&
!Object.prototype.hasOwnProperty.call(target, PROPERTIES)
) {
target[PROPERTIES] = lookup = Object.fromEntries<PropertyMetadata<T>>(
Object.entries(
<Record<string | symbol, PropertyMetadata<T>>>target[PROPERTIES],
).map(([key, meta]) => [key, {...meta}]),
);
} else {
lookup = target[PROPERTIES];
}
const meta = (lookup[key] = lookup[key] ?? {});
addInitializer(target, (instance: any, context: any) => {
instance[key] = createProperty(
instance,
<string>key,
context.defaults[key] ?? initial,
interpolationFunction ?? deepLerp,
klass,
context.defaults[key] ?? meta.default,
meta.interpolationFunction ?? deepLerp,
meta.wrapper,
);
});
};
}
/**
* Create an initial property value decorator.
*
* @remarks
* This decorator specifies the initial value of a property.
* Must be specified before the {@link property} decorator.
*
* @example
* ```ts
* class Example {
* \@initial(1)
* \@property()
* public declare length: Signal<number, this>;
* }
* ```
*
* @param value - The initial value of the property.
*/
export function initial<T>(value: T): PropertyDecorator {
return (target: any, key) => {
const meta: PropertyMetadata<T> = target[PROPERTIES]?.[key];
if (!meta) {
console.error(`Missing property decorator for "${key.toString()}"`);
return;
}
meta.default = value;
};
}
/**
* Create a property interpolation function decorator.
*
* @remarks
* This decorator specifies the interpolation function of a property.
* The interpolation function is used when tweening between different values of
* the property.
* Must be specified before the {@link property} decorator.
*
* @example
* ```ts
* class Example {
* \@interpolation(textLerp)
* \@property()
* public declare text: Signal<string, this>;
* }
* ```
*
* @param value - The interpolation function for the property.
*/
export function interpolation<T>(
value: InterpolationFunction<T>,
): PropertyDecorator {
return (target: any, key) => {
const meta: PropertyMetadata<T> = target[PROPERTIES]?.[key];
if (!meta) {
console.error(`Missing property decorator for "${key.toString()}"`);
return;
}
meta.interpolationFunction = value;
};
}
/**
* Create a property wrapper decorator.
*
* @remarks
* This decorator specifies the wrapper of a property.
* Instead of returning the raw value of the property, an instance of the
* wrapper is returned. The actual value is passed as the first parameter to the
* constructor.
* Must be specified before the {@link property} decorator.
*
* @example
* ```ts
* class Example {
* \@wrapper(Vector2)
* \@property()
* public declare offset: Signal<Vector2, this>;
* }
* ```
*
* @param value - The wrapper class for the property.
*/
export function wrapper<T>(
value: (new (value: any) => T) & {lerp?: InterpolationFunction<T>},
): PropertyDecorator {
return (target: any, key) => {
const meta: PropertyMetadata<T> = target[PROPERTIES]?.[key];
if (!meta) {
console.error(`Missing property decorator for "${key.toString()}"`);
return;
}
meta.wrapper = value;
if ('lerp' in value) {
meta.interpolationFunction ??= value.lerp;
}
};
}

View File

@@ -1,4 +1,12 @@
import {compound, computed, initialize, property} from '../decorators';
import {
compound,
computed,
initial,
initialize,
interpolation,
property,
wrapper,
} from '../decorators';
import {Vector2} from '@motion-canvas/core/lib/types';
import {Signal} from '@motion-canvas/core/lib/utils';
@@ -24,32 +32,43 @@ export interface GradientProps {
}
export class Gradient {
@property('linear')
@initial('linear')
@property()
public declare readonly type: Signal<GradientType, this>;
@property(0)
@initial(0)
@property()
public declare readonly fromX: Signal<number, this>;
@property(0)
@initial(0)
@property()
public declare readonly fromY: Signal<number, this>;
@compound({x: 'fromX', y: 'fromY'})
@property(undefined, Vector2.lerp, Vector2)
@wrapper(Vector2)
@property()
public declare readonly from: Signal<Vector2, this>;
@property(0)
@initial(0)
@property()
public declare readonly toX: Signal<number, this>;
@property(0)
@initial(0)
@property()
public declare readonly toY: Signal<number, this>;
@compound({x: 'toX', y: 'toY'})
@property(undefined, Vector2.lerp, Vector2)
@wrapper(Vector2)
@property()
public declare readonly to: Signal<Vector2, this>;
@property(0)
@initial(0)
@property()
public declare readonly angle: Signal<number, this>;
@property(0)
@initial(0)
@property()
public declare readonly fromRadius: Signal<number, this>;
@property(0)
@initial(0)
@property()
public declare readonly toRadius: Signal<number, this>;
@property([])
@initial([])
@property()
public declare readonly stops: Signal<GradientStop[], this>;
public constructor(props: GradientProps) {

View File

@@ -1,4 +1,4 @@
import {computed, initialize, property} from '../decorators';
import {computed, initial, initialize, property} from '../decorators';
import {Signal} from '@motion-canvas/core/lib/utils';
export type CanvasRepetition =
@@ -17,7 +17,8 @@ export interface PatternProps {
export class Pattern {
@property()
public declare readonly image: Signal<CanvasImageSource, this>;
@property(null)
@initial(null)
@property()
public declare readonly repetition: Signal<CanvasRepetition, this>;
public constructor(props: PatternProps) {

View File

@@ -144,7 +144,7 @@ export class Vector2 {
if (Array.isArray(one)) {
this.x = one[0];
this.y = one[0];
this.y = one[1];
return;
}

View File

@@ -18,7 +18,7 @@
"paths": {
"@motion-canvas/core/lib/jsx-runtime": ["jsx-runtime.ts"]
},
"types": ["node", "prismjs", "three", "dom-webcodecs", "jest"]
"types": ["node", "dom-webcodecs", "jest"]
},
"include": ["src"]
}

View File

@@ -12,7 +12,7 @@
},
"dependencies": {
"@motion-canvas/core": "*",
"@motion-canvas/legacy": "*"
"@motion-canvas/2d": "*"
},
"devDependencies": {
"@motion-canvas/ui": "*",