@vvfx/ge-ir 0.0.1-beat.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +66 -0
- package/dist/ge2ir/converter.d.ts +3 -0
- package/dist/ge2ir/index.d.ts +2 -0
- package/dist/ge2ir/merge/merge.d.ts +9 -0
- package/dist/ge2ir/parsers/animation-parser.d.ts +4 -0
- package/dist/ge2ir/parsers/component-parser.d.ts +16 -0
- package/dist/ge2ir/parsers/keyframe-parser.d.ts +7 -0
- package/dist/ge2ir/parsers/timeline-parser.d.ts +9 -0
- package/dist/ge2ir/parsers/transform-parser.d.ts +3 -0
- package/dist/ge2ir/pool/pool.d.ts +4 -0
- package/dist/ge2ir/reverse/blend-mode.d.ts +2 -0
- package/dist/ge2ir/reverse/coordinate.d.ts +1 -0
- package/dist/ge2ir/reverse/end-behavior.d.ts +3 -0
- package/dist/ge2ir/reverse/timing.d.ts +2 -0
- package/dist/ge2ir/scene-reader.d.ts +3 -0
- package/dist/ge2ir/types.d.ts +24 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +4812 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +4790 -0
- package/dist/index.mjs.map +1 -0
- package/dist/ir2ge/assembly/generator.d.ts +23 -0
- package/dist/ir2ge/assembly/scene-assembly.d.ts +11 -0
- package/dist/ir2ge/builders/animation.d.ts +4 -0
- package/dist/ir2ge/builders/bezier.d.ts +44 -0
- package/dist/ir2ge/builders/component.d.ts +13 -0
- package/dist/ir2ge/builders/effects.d.ts +9 -0
- package/dist/ir2ge/builders/layer.d.ts +5 -0
- package/dist/ir2ge/builders/timeline.d.ts +9 -0
- package/dist/ir2ge/builders/timing.d.ts +17 -0
- package/dist/ir2ge/index.d.ts +14 -0
- package/dist/ir2ge/ir/anchor-strategy.d.ts +24 -0
- package/dist/ir2ge/ir/layer-dimensions.d.ts +13 -0
- package/dist/ir2ge/ir/layer-utils.d.ts +14 -0
- package/dist/ir2ge/ir/parent-link.d.ts +15 -0
- package/dist/ir2ge/ir/specific.d.ts +14 -0
- package/dist/ir2ge/post-process/ge-mask-remap.d.ts +18 -0
- package/dist/ir2ge/post-process/index.d.ts +31 -0
- package/dist/ir2ge/post-process/mask.d.ts +26 -0
- package/dist/ir2ge/post-process/parenting.d.ts +3 -0
- package/dist/ir2ge/post-process/visibility.d.ts +26 -0
- package/dist/ir2ge/types.d.ts +37 -0
- package/dist/ir2ge/utils.d.ts +14 -0
- package/dist/shared/coordinate.d.ts +11 -0
- package/dist/shared/ge2ir-metadata.d.ts +17 -0
- package/dist/shared/types.d.ts +60 -0
- package/package.json +42 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified IR → GE scene generation pipeline. All IR sources (lottie, dsl2ge,
|
|
3
|
+
* future) are processed here. Source-specific features are gated by data
|
|
4
|
+
* existence (e.g. mask, precomp, shape layers are absent in dsl IR and
|
|
5
|
+
* naturally skipped); `ir.source` branches are used only for B-class real
|
|
6
|
+
* semantic differences that cannot be expressed via data existence.
|
|
7
|
+
*/
|
|
8
|
+
import type { IRComposition } from '@vvfx/animation-ir';
|
|
9
|
+
import type { JSONScene } from '@galacean/effects-specification';
|
|
10
|
+
/**
|
|
11
|
+
* Convert an IR composition to a GE JSONScene.
|
|
12
|
+
*
|
|
13
|
+
* All IR sources (lottie, dsl2ge, future) go through this single unified
|
|
14
|
+
* pipeline. Source-specific features are gated by data existence (e.g. mask,
|
|
15
|
+
* precomp, shape layers are absent in dsl IR and naturally skipped);
|
|
16
|
+
* `ir.source` branches are used only for B-class real semantic differences
|
|
17
|
+
* that cannot be expressed via data existence.
|
|
18
|
+
*
|
|
19
|
+
* The optional `duration` arg is a caller override; lottie2ge currently passes
|
|
20
|
+
* the duration computed from the raw json upstream. When omitted, the
|
|
21
|
+
* canonical assembler derives it from `(outPoint - inPoint) / frameRate`.
|
|
22
|
+
*/
|
|
23
|
+
export declare function convertIRToGE(ir: IRComposition, duration?: number): JSONScene;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type IRComposition } from '@vvfx/animation-ir';
|
|
2
|
+
import { type JSONScene } from '@galacean/effects-specification';
|
|
3
|
+
import type { ECSCollector, ProcessedItem } from '../types';
|
|
4
|
+
/**
|
|
5
|
+
* Assemble the top-level GE JSONScene wrapper from a populated collector.
|
|
6
|
+
*
|
|
7
|
+
* Reads composition-level properties (`name`, `width`/`height`, `endBehavior`,
|
|
8
|
+
* `backgroundColor`) directly from the IR. The optional `duration` arg is a
|
|
9
|
+
* caller override — when omitted, derived from `(outPoint - inPoint) / frameRate`.
|
|
10
|
+
*/
|
|
11
|
+
export declare function assembleScene(ir: IRComposition, collector: ECSCollector, processedItems: ProcessedItem[], duration?: number): JSONScene;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { IRComposition, IRLayerNode } from '@vvfx/animation-ir';
|
|
2
|
+
import type { LayerProcessingContext, TransformAnimation } from '../types';
|
|
3
|
+
export declare function buildTransformAnimation(layer: IRLayerNode, ctx: LayerProcessingContext): TransformAnimation;
|
|
4
|
+
export declare function buildColorAnimation(layer: IRLayerNode, ir: IRComposition): Record<string, unknown> | undefined;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts IR keyframe-based animation data to GE BezierKeyframeValue format.
|
|
3
|
+
*
|
|
4
|
+
* GE BezierKeyframeValue format per keyframe:
|
|
5
|
+
* - First: [EASE_OUT(3), [t, v, out_cp_x, out_cp_y]]
|
|
6
|
+
* - Middle: [EASE(1), [in_cp_x, in_cp_y, t, v, out_cp_x, out_cp_y]]
|
|
7
|
+
* - Last: [EASE_IN(2), [in_cp_x, in_cp_y, t, v]]
|
|
8
|
+
*
|
|
9
|
+
* Time is normalized to [0, 1] based on the layer's visible frame range (ip → op).
|
|
10
|
+
*/
|
|
11
|
+
import type { IRAnimatedProperty, IRVec3 } from '@vvfx/animation-ir';
|
|
12
|
+
import { type BezierKeyframeValue } from '@galacean/effects-specification';
|
|
13
|
+
export interface IRToGETimeContext {
|
|
14
|
+
/** Layer visible start frame. */
|
|
15
|
+
startFrame: number;
|
|
16
|
+
/** Layer visible end frame. */
|
|
17
|
+
endFrame: number;
|
|
18
|
+
}
|
|
19
|
+
export interface IRPositionGEResult {
|
|
20
|
+
/** Timing curves in BezierKeyframeValue format (1D, time-domain only). */
|
|
21
|
+
curves: BezierKeyframeValue[][];
|
|
22
|
+
/** Path points per segment: [[start_x, start_y], [end_x, end_y]]. */
|
|
23
|
+
pathPoints: [[number, number], [number, number]][];
|
|
24
|
+
/** Spatial control points per segment: [[to_x, to_y], [ti_x, ti_y]]. */
|
|
25
|
+
controlPoints: [[number, number], [number, number]][];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Convert a 1D animated property (opacity / rotation) to GE BezierKeyframeValue[][].
|
|
29
|
+
* Returns a single-element outer array with the full curve.
|
|
30
|
+
*/
|
|
31
|
+
export declare function irScalarKeyframesToGE(property: IRAnimatedProperty<number>, timeContext: IRToGETimeContext): BezierKeyframeValue[][] | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Convert a multi-dimensional animated property (scale / anchor) to GE BezierKeyframeValue[][].
|
|
34
|
+
* Returns one curve per dimension in the outer array.
|
|
35
|
+
*/
|
|
36
|
+
export declare function irVectorKeyframesToGE(property: IRAnimatedProperty<IRVec3>, timeContext: IRToGETimeContext): BezierKeyframeValue[][] | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* Convert position keyframes to GE path animation format (pp/cp + timing curves).
|
|
39
|
+
*/
|
|
40
|
+
export declare function irPositionKeyframesToGE(property: IRAnimatedProperty<IRVec3>, timeContext: IRToGETimeContext): IRPositionGEResult | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Determine if a property has enough keyframes to warrant keyframe mode (pkf/skf/rkf/okf).
|
|
43
|
+
*/
|
|
44
|
+
export declare function shouldUseKeyframeMode(property: IRAnimatedProperty): boolean;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { IRComposition, IRLayerNode, IRShapeData } from '@vvfx/animation-ir';
|
|
2
|
+
import type { LayerProcessingContext } from '../types';
|
|
3
|
+
export declare function buildComponent(layer: IRLayerNode, itemId: string, anchorScaleX: number, anchorScaleY: number, ctx: LayerProcessingContext): string | undefined;
|
|
4
|
+
/**
|
|
5
|
+
* Copy the raw GE mask object (from ge2ir passthrough metadata) onto a freshly
|
|
6
|
+
* built component, as a top-level `mask` field matching GE's structure. For a
|
|
7
|
+
* mask SOURCE this carries `{isMask:true, alphaMaskEnabled}`; for a TARGET it
|
|
8
|
+
* carries `{isMask:false, reference, inverted}` where `reference.id` is still
|
|
9
|
+
* the stale GE1 component id — `applyGeMaskRemap` rewrites it in post-process.
|
|
10
|
+
* No-op for non-ge sources (Lottie masks go through the IRLayerNode.mask path).
|
|
11
|
+
*/
|
|
12
|
+
export declare function applyGeMask(ir: IRComposition, layer: IRLayerNode, component: Record<string, unknown>): void;
|
|
13
|
+
export declare function buildShapeOptions(shapeData: IRShapeData, ratio: number, ctx?: LayerProcessingContext): Record<string, unknown>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type IRBlendMode } from '@vvfx/animation-ir';
|
|
2
|
+
import type { DataPath } from '@galacean/effects-specification';
|
|
3
|
+
import type { ECSCollector, GETransform } from '../types';
|
|
4
|
+
export { estimateTextWidth } from '../utils';
|
|
5
|
+
export declare function buildGETransform(position: [number, number, number], eulerHint: [number, number, number], scale: [number, number, number]): GETransform;
|
|
6
|
+
export declare function getGEItemType(type: string): string;
|
|
7
|
+
export declare function getGEItemTypeCode(type: string): string;
|
|
8
|
+
export declare function registerTexture(collector: ECSCollector, imageUrl: string, cache: Map<string, DataPath>): DataPath;
|
|
9
|
+
export declare function mapBlendingMode(blendMode: IRBlendMode | undefined): number | undefined;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { IRLayerNode } from '@vvfx/animation-ir';
|
|
2
|
+
import type { LayerProcessingContext } from '../types';
|
|
3
|
+
export declare function processNullLayer(layer: IRLayerNode, ctx: LayerProcessingContext): void;
|
|
4
|
+
export declare function processParentLayer(layer: IRLayerNode, ctx: LayerProcessingContext): void;
|
|
5
|
+
export declare function processVisualLayer(layer: IRLayerNode, ctx: LayerProcessingContext): void;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ECSCollector, TransformAnimation } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Build the ObjectBindingTrack + Activation/Transform/SpriteColor child tracks
|
|
4
|
+
* for one VFX item. Shared by lottie2ge and dsl2ge generators.
|
|
5
|
+
*
|
|
6
|
+
* The SpriteColor track is omitted for null layers (itemType `'null'` or
|
|
7
|
+
* the GE numeric code `'3'`).
|
|
8
|
+
*/
|
|
9
|
+
export declare function buildTimelineTracks(collector: ECSCollector, delay: number, duration: number, endBehavior: number, animation: TransformAnimation, itemType: string): string;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { IRLayerNode } from '@vvfx/animation-ir';
|
|
2
|
+
/**
|
|
3
|
+
* Map an IR layer's time range to GE delay/duration in seconds, applying
|
|
4
|
+
* the time-stretch and offset semantics from `IRTimeContext`.
|
|
5
|
+
*
|
|
6
|
+
* dsl-source IRs leave `stretch` and `offsetFrame` undefined, in which case
|
|
7
|
+
* this collapses to `delay = startFrame / fr` and
|
|
8
|
+
* `duration = (endFrame - startFrame) / fr` — exactly what dsl2ge used to
|
|
9
|
+
* compute inline.
|
|
10
|
+
*
|
|
11
|
+
* Zero/negative durations are clamped to a 0.0001 epsilon so GE keeps the
|
|
12
|
+
* activation track alive for the (degenerate) layer.
|
|
13
|
+
*/
|
|
14
|
+
export declare function computeLayerTiming(layer: IRLayerNode, frameRate: number): {
|
|
15
|
+
delay: number;
|
|
16
|
+
layerDuration: number;
|
|
17
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { convertIRToGE } from './assembly/generator';
|
|
2
|
+
export type { DataPath, JSONScene } from '@galacean/effects-specification';
|
|
3
|
+
export { readLottieSpecific } from './ir/specific';
|
|
4
|
+
export type { LottieLayerSpecific } from './ir/specific';
|
|
5
|
+
export { isTransformOnlyParentLink } from './ir/parent-link';
|
|
6
|
+
export type { ECSCollector, GEDataPath, GEItem, GEPoolIndex, GERecord, GETransform } from '../shared/types';
|
|
7
|
+
export type { ProcessedItem, TransformAnimation } from './types';
|
|
8
|
+
export { assembleScene } from './assembly/scene-assembly';
|
|
9
|
+
export { estimateTextWidth, roundNumber, lerp, createId, toDataPath } from './utils';
|
|
10
|
+
export { DEFAULT_CLIP_MODE, DEFAULT_CAMERA_FOV, DEFAULT_CAMERA_Z, get2dTo3dRatio, convert2dTo3dPoint, } from '../shared/coordinate';
|
|
11
|
+
export { irScalarKeyframesToGE, irVectorKeyframesToGE, irPositionKeyframesToGE, shouldUseKeyframeMode, } from './builders/bezier';
|
|
12
|
+
export type { IRToGETimeContext, IRPositionGEResult } from './builders/bezier';
|
|
13
|
+
export { buildTimelineTracks } from './builders/timeline';
|
|
14
|
+
export { normalizeChildVisibilityByParentDelays } from './post-process/visibility';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { IRComposition, IRLayerNode } from '@vvfx/animation-ir';
|
|
2
|
+
/**
|
|
3
|
+
* How the generator should handle a layer's anchor offset.
|
|
4
|
+
*
|
|
5
|
+
* - `inline-anchor` — emit one VFX item with `renderer.anchor` baked into the
|
|
6
|
+
* GE renderer and `anchorOffset` shifted into `transform.position`. Centered
|
|
7
|
+
* layers also use this kind with `anchorScale = [0.5, 0.5]` and
|
|
8
|
+
* `anchorOffset = [0, 0]`.
|
|
9
|
+
* - `split-null-sprite` — emit a null+sprite hierarchy so the transform pivot
|
|
10
|
+
* sits at the anchor; the sprite carries the visual content and is parented
|
|
11
|
+
* to the null with an anchor-relative position.
|
|
12
|
+
*
|
|
13
|
+
* The split decision is read from `IRLayerNode.transformSplit` when set by the
|
|
14
|
+
* producer; for lottie IR without that flag the accessor falls back to
|
|
15
|
+
* runtime geometry checks (rotation/scale animation + off-center anchor).
|
|
16
|
+
*/
|
|
17
|
+
export type AnchorStrategy = {
|
|
18
|
+
kind: 'inline-anchor';
|
|
19
|
+
anchorScale: [number, number];
|
|
20
|
+
anchorOffset: [number, number];
|
|
21
|
+
} | {
|
|
22
|
+
kind: 'split-null-sprite';
|
|
23
|
+
};
|
|
24
|
+
export declare function getStaticAnchorBehavior(ir: IRComposition, layer: IRLayerNode): AnchorStrategy;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { IRLayerNode } from '@vvfx/animation-ir';
|
|
2
|
+
/**
|
|
3
|
+
* Read the producer-baked display size from an IR layer. When the producer
|
|
4
|
+
* did not resolve one, returns `fallback` (defaults to `{ 1, 1 }` — the
|
|
5
|
+
* value every existing call site was using inline).
|
|
6
|
+
*/
|
|
7
|
+
export declare function getLayerDisplaySize(layer: IRLayerNode, fallback?: {
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
}): {
|
|
11
|
+
width: number;
|
|
12
|
+
height: number;
|
|
13
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { IRLayerNode } from '@vvfx/animation-ir';
|
|
2
|
+
import type { IRToGETimeContext } from '../builders/bezier';
|
|
3
|
+
import type { LayerProcessingContext } from '../types';
|
|
4
|
+
export { computeLayerTiming } from '../builders/timing';
|
|
5
|
+
export declare function computeStaticPosition(layer: IRLayerNode, ctx: LayerProcessingContext, anchorOffsetX?: number, anchorOffsetY?: number): [number, number, number];
|
|
6
|
+
export declare function getStaticAnchor(layer: IRLayerNode): [number, number];
|
|
7
|
+
export declare function applyScalePositionAdjust(position: [number, number, number], layer: IRLayerNode, layerWidth: number, layerHeight: number, ratio: number): [number, number, number];
|
|
8
|
+
export declare function computeAnchorInfo(layer: IRLayerNode, layerWidth: number, layerHeight: number): {
|
|
9
|
+
anchorScaleX: number;
|
|
10
|
+
anchorScaleY: number;
|
|
11
|
+
anchorOffsetX: number;
|
|
12
|
+
anchorOffsetY: number;
|
|
13
|
+
};
|
|
14
|
+
export declare function getTimeContext(layer: IRLayerNode): IRToGETimeContext;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { IRLayerNode } from '@vvfx/animation-ir';
|
|
2
|
+
/**
|
|
3
|
+
* True when the layer's parent only inherits transform — visibility and
|
|
4
|
+
* lifetime are independent of the parent's window.
|
|
5
|
+
*
|
|
6
|
+
* Reads `IRLayerReference.linkKind` directly. Producers that don't set the
|
|
7
|
+
* field (e.g. dsl2ge) effectively get `false` here, which is the correct
|
|
8
|
+
* default for "full" parent containment.
|
|
9
|
+
*
|
|
10
|
+
* Lottie's parser sets `linkKind: 'transform-only'` when a child's parent
|
|
11
|
+
* relationship comes from `layer.parent` rather than precomp expansion;
|
|
12
|
+
* `applyPostProcess` consumes this to decide whether to advance the parent's
|
|
13
|
+
* activation track when the child starts earlier.
|
|
14
|
+
*/
|
|
15
|
+
export declare function isTransformOnlyParentLink(layer: IRLayerNode): boolean;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read-side accessors for the `IRLayerNode.specific.lottie` slot.
|
|
3
|
+
*
|
|
4
|
+
* The shared generator must not branch on lottie semantics directly — every
|
|
5
|
+
* lottie-specific read goes through these helpers so the rest of `ir2ge` stays
|
|
6
|
+
* agnostic to the producing tool.
|
|
7
|
+
*
|
|
8
|
+
* `isTransformOnlyParentLink` used to live here, reading
|
|
9
|
+
* `specific.lottie.explicitParent`. It was promoted to a generic IR field
|
|
10
|
+
* (`IRLayerReference.linkKind`); the accessor now lives at `./parent-link.ts`.
|
|
11
|
+
*/
|
|
12
|
+
import type { IRLayerNode, LottieLayerSpecific } from '@vvfx/animation-ir';
|
|
13
|
+
export type { LottieLayerSpecific };
|
|
14
|
+
export declare function readLottieSpecific(layer: IRLayerNode): LottieLayerSpecific | undefined;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ECSCollector } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Remap GE mask references after ge2ir round-trip.
|
|
4
|
+
*
|
|
5
|
+
* ge2ir carries each masked component's raw `mask` object verbatim (via
|
|
6
|
+
* `IRLayerNode.metadata.ge2ir.geMask`), but `mask.reference.id` still points at the
|
|
7
|
+
* ORIGINAL (GE1) mask-source component id, which ir2ge has regenerated. This
|
|
8
|
+
* pass rewrites every target's `reference.id` from the stale GE1 id to the
|
|
9
|
+
* freshly-minted GE2 component id, using the `geComponentId → newId` map built
|
|
10
|
+
* during the layer walk.
|
|
11
|
+
*
|
|
12
|
+
* Mirrors `applyParenting`: an IR-side reference (here the stale id stored in
|
|
13
|
+
* data) → map → regenerated id → written in place. Mask SOURCE components have
|
|
14
|
+
* no `reference` and are skipped. Dangling references (source not regenerated —
|
|
15
|
+
* e.g. dropped by the null+sprite merger) have their `mask` removed so the GE
|
|
16
|
+
* runtime doesn't choke on an id that resolves to nothing.
|
|
17
|
+
*/
|
|
18
|
+
export declare function applyGeMaskRemap(collector: ECSCollector, geComponentIdToNewId: Record<string, string>): void;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { IRComposition } from '@vvfx/animation-ir';
|
|
2
|
+
import type { ECSCollector, ProcessedItem } from '../types';
|
|
3
|
+
import { type MaskLayerLookup } from './mask';
|
|
4
|
+
export type { MaskLayerLookup } from './mask';
|
|
5
|
+
/**
|
|
6
|
+
* Post-emit state populated by the unified pipeline's per-layer walk.
|
|
7
|
+
* All fields beyond `collector` + `processedItems` are optional — each
|
|
8
|
+
* post-process step is gated on the presence of the data it needs, not
|
|
9
|
+
* on `ir.source`. Steps that only apply to certain sources naturally
|
|
10
|
+
* no-op when the relevant data is absent (e.g. dsl IR has no masks).
|
|
11
|
+
*/
|
|
12
|
+
export interface PostProcessState {
|
|
13
|
+
collector: ECSCollector;
|
|
14
|
+
processedItems: ProcessedItem[];
|
|
15
|
+
/** Per-layer lookups consumed by the shared mask post-process. */
|
|
16
|
+
maskLookup?: MaskLayerLookup;
|
|
17
|
+
layerToItemId?: Record<number, string>;
|
|
18
|
+
parentIndexSet?: Set<number>;
|
|
19
|
+
ratio?: number;
|
|
20
|
+
width?: number;
|
|
21
|
+
height?: number;
|
|
22
|
+
frameRate?: number;
|
|
23
|
+
/** GE1→GE2 component-id map for remapping ge2ir mask passthrough references. */
|
|
24
|
+
geComponentIdToNewId?: Record<string, string>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Run post-emit mutations on the collector before `assembleScene`.
|
|
28
|
+
* Order: parenting → mask → visibility. Each step is gated on whether
|
|
29
|
+
* the pipeline supplied the required tracking state.
|
|
30
|
+
*/
|
|
31
|
+
export declare function applyPostProcess(ir: IRComposition, state: PostProcessState): void;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mask post-process: emits a mask shape item + component for each layer that
|
|
3
|
+
* carries `IRMaskData`, propagating the mask reference to the layer's renderer
|
|
4
|
+
* component or — for parent layers — to descendant renderers.
|
|
5
|
+
*
|
|
6
|
+
* The decision to emit (per-layer) is gated solely on `layer.mask != null`,
|
|
7
|
+
* so any IR producer can opt in by writing the field. Currently only lottie
|
|
8
|
+
* IR has masks; dsl IR leaves `mask` undefined and this module no-ops for it.
|
|
9
|
+
*
|
|
10
|
+
* The lookup callbacks let each pipeline plug in its own layer-to-emitted-id
|
|
11
|
+
* mapping — lottie keeps `layerToItemId`/`layerToComponentId`/`parentIndexSet`
|
|
12
|
+
* during emission, dsl tracks differently. Mask handling stays generic.
|
|
13
|
+
*/
|
|
14
|
+
import type { IRComposition } from '@vvfx/animation-ir';
|
|
15
|
+
import type { ECSCollector, ProcessedItem } from '../types';
|
|
16
|
+
/**
|
|
17
|
+
* Pipeline-specific lookups consumed during mask emission. A pipeline that
|
|
18
|
+
* never produces masks can pass stub callbacks (the iterator skips layers
|
|
19
|
+
* without `mask`, so the callbacks are never invoked in that case).
|
|
20
|
+
*/
|
|
21
|
+
export interface MaskLayerLookup {
|
|
22
|
+
getItemId(layerIndex: number): string | undefined;
|
|
23
|
+
getComponentId(layerIndex: number): string | undefined;
|
|
24
|
+
isParentLayer(layerIndex: number): boolean;
|
|
25
|
+
}
|
|
26
|
+
export declare function applyMasks(ir: IRComposition, collector: ECSCollector, processedItems: ProcessedItem[], ratio: number, width: number, height: number, frameRate: number, lookup: MaskLayerLookup): void;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
interface ProcessedItemRef {
|
|
2
|
+
itemId: string;
|
|
3
|
+
objectBindingTrackId: string;
|
|
4
|
+
}
|
|
5
|
+
interface NormalizeVisibilityParams {
|
|
6
|
+
items: Record<string, unknown>[];
|
|
7
|
+
miscs: Record<string, unknown>[];
|
|
8
|
+
processedItems: ProcessedItemRef[];
|
|
9
|
+
/** Item IDs whose parent-child relationship only inherits transform, not visibility. */
|
|
10
|
+
transformOnlyParentLinkItemIds?: Set<string>;
|
|
11
|
+
roundNumber: (value: number, precision: number) => number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Normalize child visibility delays so children never appear before their parent.
|
|
15
|
+
*
|
|
16
|
+
* Topologically sorts items (parent-first) so by the time we process any child
|
|
17
|
+
* its parent's delay/duration are already finalized. For transform-only
|
|
18
|
+
* parent-link children, we instead advance the parent's delay/duration so the
|
|
19
|
+
* child can render from its own start time (GE requires the parent to be active
|
|
20
|
+
* for transform inheritance, but the parent-link relationship does not propagate
|
|
21
|
+
* visibility). Only the ActivationTrack clip is updated; TransformTrack
|
|
22
|
+
* keyframes are normalized to the original time range and would hold their
|
|
23
|
+
* first frame value if the track started earlier.
|
|
24
|
+
*/
|
|
25
|
+
export declare function normalizeChildVisibilityByParentDelays({ items, miscs, processedItems, transformOnlyParentLinkItemIds, roundNumber, }: NormalizeVisibilityParams): void;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { IRComposition } from '@vvfx/animation-ir';
|
|
2
|
+
import type { DataPath } from '@galacean/effects-specification';
|
|
3
|
+
import type { ECSCollector } from '../shared/types';
|
|
4
|
+
export type { ECSCollector, GEDataPath, GEItem, GEPoolIndex, GERecord, GETransform } from '../shared/types';
|
|
5
|
+
/**
|
|
6
|
+
* Bookkeeping for a fully emitted item: its VFXItemData id and the
|
|
7
|
+
* ObjectBindingTrack that owns its child Activation/Transform/SpriteColor
|
|
8
|
+
* tracks. The optional `layerIndex` lets source-specific post-processing
|
|
9
|
+
* (e.g. lottie visibility normalization) trace items back to the IR layer.
|
|
10
|
+
*/
|
|
11
|
+
export interface ProcessedItem {
|
|
12
|
+
itemId: string;
|
|
13
|
+
objectBindingTrackId: string;
|
|
14
|
+
layerIndex?: number;
|
|
15
|
+
}
|
|
16
|
+
/** Per-channel animation payload consumed by the timeline tracks. */
|
|
17
|
+
export interface TransformAnimation {
|
|
18
|
+
positionOverLifetime?: Record<string, unknown> | null;
|
|
19
|
+
rotationOverLifetime?: Record<string, unknown> | null;
|
|
20
|
+
sizeOverLifetime?: Record<string, unknown> | null;
|
|
21
|
+
colorOverLifetime?: Record<string, unknown> | null;
|
|
22
|
+
}
|
|
23
|
+
/** Per-layer context threaded through the unified layer processors. */
|
|
24
|
+
export interface LayerProcessingContext {
|
|
25
|
+
/** Full IR composition; needed by shared accessors that dispatch on `ir.source`. */
|
|
26
|
+
ir: IRComposition;
|
|
27
|
+
collector: ECSCollector;
|
|
28
|
+
processedItems: ProcessedItem[];
|
|
29
|
+
layerToItemId: Record<number, string>;
|
|
30
|
+
layerToComponentId: Record<number, string>;
|
|
31
|
+
textureCache: Map<string, DataPath>;
|
|
32
|
+
parentIndexSet: Set<number>;
|
|
33
|
+
ratio: number;
|
|
34
|
+
width: number;
|
|
35
|
+
height: number;
|
|
36
|
+
frameRate: number;
|
|
37
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { DataPath } from '@galacean/effects-specification';
|
|
2
|
+
/** Generate a 32-char hex GE entity id (UUID v4 with dashes stripped). */
|
|
3
|
+
export declare function createId(): string;
|
|
4
|
+
/** Wrap an id into a `{ id }` GE DataPath reference. */
|
|
5
|
+
export declare function toDataPath(id: string): DataPath;
|
|
6
|
+
/** Round a number to the given decimal precision (default 4). */
|
|
7
|
+
export declare function roundNumber(value: number, precision?: number): number;
|
|
8
|
+
/** Linear interpolation between `a` and `b` by `factor` ∈ [0, 1]. */
|
|
9
|
+
export declare function lerp(a: number, b: number, factor: number): number;
|
|
10
|
+
/**
|
|
11
|
+
* Rough text width estimate used when the IR layer does not record a
|
|
12
|
+
* measured width. Average character width ≈ 0.6 × fontSize.
|
|
13
|
+
*/
|
|
14
|
+
export declare function estimateTextWidth(text: string, fontSize: number, letterSpacing?: number): number;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const DEFAULT_CAMERA_Z = 8;
|
|
2
|
+
export declare const DEFAULT_CAMERA_FOV = 60;
|
|
3
|
+
export declare const DEFAULT_CLIP_MODE = 1;
|
|
4
|
+
/** 2D pixel space -> GE 3D world unit ratio for a given canvas size. */
|
|
5
|
+
export declare function get2dTo3dRatio(width: number, height: number): number;
|
|
6
|
+
/**
|
|
7
|
+
* Convert a 2D point in canvas pixel space (origin top-left) to a GE 3D world
|
|
8
|
+
* point (origin centered, Y flipped). The `z` parameter applies the GE camera
|
|
9
|
+
* adapter to stay perspective-correct for non-zero Z layers.
|
|
10
|
+
*/
|
|
11
|
+
export declare function convert2dTo3dPoint(x: number, y: number, z: number, width: number, height: number): [number, number, number];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { IRComposition, IRLayerNode } from '@vvfx/animation-ir';
|
|
2
|
+
/**
|
|
3
|
+
* Round-trip passthrough contract written by ge2ir and consumed by ir2ge.
|
|
4
|
+
*
|
|
5
|
+
* Supported keys:
|
|
6
|
+
* positionOverLifetime, rotationOverLifetime, sizeOverLifetime,
|
|
7
|
+
* colorOverLifetime, geComponentId, geMask.
|
|
8
|
+
*/
|
|
9
|
+
export interface GE2IRPassthroughMetadata {
|
|
10
|
+
positionOverLifetime?: Record<string, unknown>;
|
|
11
|
+
rotationOverLifetime?: Record<string, unknown>;
|
|
12
|
+
sizeOverLifetime?: Record<string, unknown>;
|
|
13
|
+
colorOverLifetime?: Record<string, unknown>;
|
|
14
|
+
geComponentId?: string;
|
|
15
|
+
geMask?: Record<string, unknown>;
|
|
16
|
+
}
|
|
17
|
+
export declare function readGE2IRMetadata(ir: IRComposition, layer: IRLayerNode): GE2IRPassthroughMetadata | undefined;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { DataPath } from '@galacean/effects-specification';
|
|
2
|
+
export type GERecord = Record<string, unknown>;
|
|
3
|
+
export type GEDataPath = DataPath;
|
|
4
|
+
export type GEPoolIndex = Map<string, GERecord>;
|
|
5
|
+
/** GE transform block emitted on every VFX item. */
|
|
6
|
+
export interface GETransform {
|
|
7
|
+
position: {
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
z: number;
|
|
11
|
+
};
|
|
12
|
+
eulerHint: {
|
|
13
|
+
x: number;
|
|
14
|
+
y: number;
|
|
15
|
+
z: number;
|
|
16
|
+
};
|
|
17
|
+
scale: {
|
|
18
|
+
x: number;
|
|
19
|
+
y: number;
|
|
20
|
+
z: number;
|
|
21
|
+
};
|
|
22
|
+
anchor?: {
|
|
23
|
+
x: number;
|
|
24
|
+
y: number;
|
|
25
|
+
};
|
|
26
|
+
size?: {
|
|
27
|
+
x: number;
|
|
28
|
+
y: number;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/** A single VFXItemData entry in a GE scene. */
|
|
32
|
+
export interface GEItem {
|
|
33
|
+
id: string;
|
|
34
|
+
dataType: string;
|
|
35
|
+
name: string;
|
|
36
|
+
duration: number;
|
|
37
|
+
type: string;
|
|
38
|
+
visible: boolean;
|
|
39
|
+
endBehavior: number;
|
|
40
|
+
delay: number;
|
|
41
|
+
renderLevel: string;
|
|
42
|
+
content?: GERecord;
|
|
43
|
+
components: GEDataPath[];
|
|
44
|
+
transform: GETransform;
|
|
45
|
+
parentId?: string;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Build-time accumulators shared by every generator. Each pool maps to a
|
|
49
|
+
* top-level array on the emitted JSONScene.
|
|
50
|
+
*/
|
|
51
|
+
export interface ECSCollector {
|
|
52
|
+
images: Array<{
|
|
53
|
+
id: string;
|
|
54
|
+
url: string;
|
|
55
|
+
}>;
|
|
56
|
+
components: GERecord[];
|
|
57
|
+
items: GEItem[];
|
|
58
|
+
textures: GERecord[];
|
|
59
|
+
miscs: GERecord[];
|
|
60
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vvfx/ge-ir",
|
|
3
|
+
"version": "0.0.1-beat.2",
|
|
4
|
+
"description": "Galacean Effects and animation IR bidirectional conversion package",
|
|
5
|
+
"module": "./dist/index.mjs",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"import": "./dist/index.mjs",
|
|
14
|
+
"require": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@galacean/effects-specification": "^2.8.0",
|
|
20
|
+
"uuid": "^13.0.0",
|
|
21
|
+
"@vvfx/animation-ir": "0.0.1-beat.2"
|
|
22
|
+
},
|
|
23
|
+
"contributors": [
|
|
24
|
+
{
|
|
25
|
+
"name": "澄弈"
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"author": "Ant Group CO., Ltd.",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public",
|
|
32
|
+
"registry": "https://registry.npmjs.org"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"prebuild": "pnpm clean",
|
|
36
|
+
"build": "pnpm build:declaration && pnpm build:module",
|
|
37
|
+
"build:module": "rollup -c --bundleConfigAsCjs",
|
|
38
|
+
"build:declaration": "tsc -b ../animation-ir tsconfig.json --emitDeclarationOnly",
|
|
39
|
+
"clean": "rimraf dist *.tsbuildinfo",
|
|
40
|
+
"test": "vitest run"
|
|
41
|
+
}
|
|
42
|
+
}
|