export type ElementType = 'code' | 'text' | 'arrow' | 'image' | 'shape' | 'counter' | 'chart' | 'icon' | 'svg' | 'motionPath' | 'video' | 'progress' | 'container' | 'draw' | 'sticky';
/**
 * Per-element keyframe — animates state at a specific time WITHIN a slide's
 * display window. Layered on top of slide-to-slide morphing: morphing handles
 * between-slide transitions, keyframes handle within-slide animation.
 */
export interface Keyframe {
    id: string;
    time: number;
    easing?: 'linear' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'spring';
    position?: Position;
    size?: Size;
    rotation?: number;
    opacity?: number;
    skewX?: number;
    skewY?: number;
    tiltX?: number;
    tiltY?: number;
    borderRadius?: number;
    fontSize?: number;
    fillColor?: string;
    strokeColor?: string;
    strokeWidth?: number;
    backgroundColor?: string;
    color?: string;
    blur?: number;
    brightness?: number;
    contrast?: number;
    saturate?: number;
    grayscale?: number;
    path?: string;
}
export type ShapeType = 'rectangle' | 'circle' | 'triangle' | 'ellipse' | 'star' | 'hexagon';
export interface Position {
    x: number;
    y: number;
}
export interface Size {
    width: number;
    height: number;
}
export type TiltOrigin = string;
export type AnimatableProperty = 'position' | 'rotation' | 'tilt' | 'skew' | 'size' | 'opacity' | 'borderRadius' | 'color' | 'perspective' | 'blur';
export interface PropertySequence {
    property: AnimatableProperty;
    order: number;
    delay: number;
    duration: number;
}
export type EntranceAnimation = 'none' | 'fade' | 'slide-up' | 'slide-down' | 'slide-left' | 'slide-right' | 'pop' | 'scale-in' | 'rotate-in' | 'blur-in' | 'rise' | 'flip-x' | 'flip-y' | 'bounce-in';
export type ExitAnimation = 'none' | 'fade' | 'slide-up' | 'slide-down' | 'slide-left' | 'slide-right' | 'pop' | 'scale-out' | 'rotate-out' | 'blur-out' | 'sink' | 'flip-x' | 'flip-y';
export type EmphasisAnimation = 'none' | 'pulse' | 'shake' | 'flash' | 'wobble' | 'glow-flash' | 'bob-once' | 'tada';
export interface ElementAnimationConfig {
    order: number;
    delay: number;
    duration: number;
    easing: 'linear' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'spring';
    propertySequences?: PropertySequence[];
    entrance?: EntranceAnimation;
    exit?: ExitAnimation;
    emphasis?: EmphasisAnimation;
    entranceDuration?: number;
    exitDuration?: number;
    emphasisDuration?: number;
    emphasisDelay?: number;
}
export type FloatingDirection = 'vertical' | 'horizontal' | 'both';
export type IdlePreset = 'float' | 'breathe' | 'pulse' | 'wiggle' | 'sway' | 'drift' | 'bob' | 'tilt';
export interface FloatingAnimationConfig {
    enabled: boolean;
    direction: FloatingDirection;
    amplitude: number;
    speed: number;
    amplitudeRandomness: number;
    speedRandomness: number;
    preset?: IdlePreset;
}
export interface PathPoint {
    x: number;
    y: number;
    handleIn?: Position;
    handleOut?: Position;
}
export interface MotionPathConfig {
    motionPathId: string;
    startPercent: number;
    endPercent: number;
    autoRotate: boolean;
    orientationOffset: number;
    loop: boolean;
    laps?: number;
}
export interface BaseElement {
    id: string;
    type: ElementType;
    name?: string;
    locked?: boolean;
    groupId?: string;
    /** Auto-layout container parent. When set, position/size is computed
     *  by the container's flex layout pass. */
    containerId?: string;
    /** Per-element keyframes that play DURING this slide. Sorted by time. */
    keyframes?: Keyframe[];
    position: Position;
    size: Size;
    rotation: number;
    skewX: number;
    skewY: number;
    tiltX: number;
    tiltY: number;
    tiltOrigin: TiltOrigin;
    zIndex: number;
    visible: boolean;
    perspective?: number;
    backfaceVisibility?: 'visible' | 'hidden';
    animationConfig?: ElementAnimationConfig;
    floatingAnimation?: FloatingAnimationConfig;
    decorations?: DecorationsConfig;
    depth?: number;
    motionPathId?: string;
    motionPathConfig?: MotionPathConfig;
    /** Solid color for the shape-morph transition only (render-time override). */
    morphColor?: string;
    blur?: number;
    brightness?: number;
    contrast?: number;
    saturate?: number;
    grayscale?: number;
}
export type CodeAnimationMode = 'instant' | 'typewriter' | 'highlight-changes';
export interface CodeAnimationConfig {
    mode: CodeAnimationMode;
    highlightColor: string;
    typewriterSpeed: number;
    highlightDuration: number;
}
export interface CodeElement extends BaseElement {
    type: 'code';
    code: string;
    language: string;
    theme: string;
    filename: string;
    showLineNumbers: boolean;
    highlightedLines: number[];
    blurredLines: number[];
    fontSize: number;
    fontWeight: number;
    padding: number;
    borderRadius: number;
    showHeader: boolean;
    headerStyle: 'macos' | 'windows' | 'none';
    animation: CodeAnimationConfig;
    transparentBackground?: boolean;
    bgColor?: string;
    headerRadius?: number;
    tabRadius?: number;
}
export type TextAnimationMode = 'instant' | 'typewriter' | 'fade-words' | 'fade-letters' | 'handwriting' | 'bounce-in' | 'scramble-in' | 'slot-machine' | 'drop' | 'glitch' | 'marquee' | 'blur-in' | 'stretch' | 'slide-words' | 'wave' | 'typewriter-erase';
export interface TextAnimationConfig {
    mode: TextAnimationMode;
    typewriterSpeed: number;
    duration?: number;
    stagger?: number;
    loop?: boolean;
}
export interface TextElement extends BaseElement {
    type: 'text';
    content: string;
    fontSize: number;
    fontWeight: number;
    fontFamily: string;
    fontStyle?: 'normal' | 'italic';
    textDecoration?: 'none' | 'underline' | 'line-through';
    color: string;
    backgroundColor: string;
    padding: number;
    borderRadius: number;
    textAlign: 'left' | 'center' | 'right';
    opacity: number;
    animation?: TextAnimationConfig;
    textStroke?: {
        enabled: boolean;
        width: number;
        color: string;
    };
    textShadow?: {
        enabled: boolean;
        offsetX: number;
        offsetY: number;
        blur: number;
        color: string;
    };
    hollow?: boolean;
    backgroundImage?: string;
    backgroundPositionX?: number;
    backgroundPositionY?: number;
    backgroundScale?: number;
    /** Optional CSS gradient as the text fill, rendered via
     *  `background-clip: text`. Same shape as `CanvasBackground.gradient`. */
    gradient?: {
        type: 'linear' | 'radial' | 'conic';
        angle?: number;
        colors: string[];
        stops?: GradientStop[];
        radialShape?: 'circle' | 'ellipse';
        radialPosition?: string;
    };
}
export type ArrowAnimationMode = 'none' | 'grow' | 'draw' | 'undraw' | 'draw-undraw' | 'flow';
export interface ArrowAnimationConfig {
    mode: ArrowAnimationMode;
    duration: number;
    loop?: boolean;
    direction?: 'forward' | 'reverse';
}
export type SvgPathAnimationMode = 'none' | 'draw' | 'undraw' | 'draw-undraw' | 'flow';
export interface SvgPathAnimationConfig {
    mode: SvgPathAnimationMode;
    duration: number;
    loop?: boolean;
    direction?: 'forward' | 'reverse';
}
export interface FlowMarkerConfig {
    enabled: boolean;
    count: number;
    size: number;
    color: string;
    speedMs: number;
    direction: 'forward' | 'reverse' | 'bidirectional';
    pattern: 'loop' | 'once' | 'bounce';
    shape: 'dot' | 'square' | 'pulse';
    easing: 'linear' | 'ease-in-out';
}
export interface ArrowElement extends BaseElement {
    type: 'arrow';
    startPoint: Position;
    endPoint: Position;
    controlPoints: Position[];
    color: string;
    strokeWidth: number;
    headSize: number;
    style: 'solid' | 'dashed' | 'dotted';
    showHead: boolean;
    opacity: number;
    animation?: ArrowAnimationConfig;
    flowMarkers?: FlowMarkerConfig;
}
export interface ImageElement extends BaseElement {
    type: 'image';
    src: string;
    objectFit: 'cover' | 'contain' | 'fill';
    borderRadius: number;
    opacity: number;
    blur: number;
    backgroundColor?: string;
    clipMask?: {
        enabled: boolean;
        shapeType: ShapeType;
        borderRadius?: number;
    };
}
export interface CameraViewport {
    x: number;
    y: number;
    width: number;
    height: number;
    rotation?: number;
}
export interface DecorationsConfig {
    glow?: {
        enabled: boolean;
        color: string;
        intensity?: number;
        speedMs?: number;
    };
    shimmer?: {
        enabled: boolean;
        color?: string;
        angle?: number;
        speedMs?: number;
        widthPct?: number;
        randomness?: number;
    };
    gradientShift?: {
        enabled: boolean;
        colors?: string[];
        speedMs?: number;
        angle?: number;
        direction?: 'forward' | 'reverse' | 'snake' | 'chase';
        borderWidth?: number;
    };
    rgbSplit?: {
        enabled: boolean;
        offset?: number;
        speedMs?: number;
    };
}
export interface VideoElement extends BaseElement {
    type: 'video';
    src: string;
    posterImage?: string;
    startTime?: number;
    endTime?: number;
    volume: number;
    muted: boolean;
    autoplay: boolean;
    loop: boolean;
    playbackRate: number;
    objectFit: 'cover' | 'contain' | 'fill';
    borderRadius: number;
    opacity: number;
    showControls?: boolean;
}
export type StrokeStyle = 'solid' | 'dashed' | 'dotted';
export interface ShapeElement extends BaseElement {
    type: 'shape';
    shapeType: ShapeType;
    fillColor: string;
    fillOpacity?: number;
    strokeColor: string;
    strokeOpacity?: number;
    strokeWidth: number;
    strokeStyle?: StrokeStyle;
    strokeDashGap?: number;
    opacity: number;
    borderRadius: number;
    boxShadow?: {
        enabled: boolean;
        offsetX: number;
        offsetY: number;
        blur: number;
        spread: number;
        color: string;
    };
}
export type CounterType = 'number' | 'letter' | 'percentage' | 'currency';
export interface CounterElement extends BaseElement {
    type: 'counter';
    counterType: CounterType;
    startValue: number;
    endValue: number;
    prefix: string;
    suffix: string;
    decimals: number;
    duration: number;
    fontSize: number;
    fontWeight: number;
    fontFamily: string;
    color: string;
    backgroundColor: string;
    padding: number;
    borderRadius: number;
    textAlign: 'left' | 'center' | 'right';
    opacity: number;
}
export type ChartType = 'bar' | 'line' | 'pie' | 'donut' | 'area';
export interface ChartDataPoint {
    label: string;
    value: number;
    color?: string;
}
export interface ChartSeries {
    id: string;
    name: string;
    data: ChartDataPoint[];
    color?: string;
}
export type ChartBarLayout = 'grouped' | 'stacked';
export interface ChartValueFormat {
    prefix?: string;
    suffix?: string;
    decimals?: number;
    abbreviate?: boolean;
}
export interface ChartYAxis {
    min?: number;
    max?: number;
    showLabels?: boolean;
}
export interface ChartElement extends BaseElement {
    type: 'chart';
    chartType: ChartType;
    data: ChartDataPoint[];
    series?: ChartSeries[];
    title: string;
    showLabels: boolean;
    showValues: boolean;
    showGrid: boolean;
    showLegend: boolean;
    animationDuration: number;
    colors: string[];
    useKitPalette?: boolean;
    backgroundColor: string;
    textColor: string;
    fontSize: number;
    padding: number;
    borderRadius: number;
    barLayout?: ChartBarLayout;
    revealStagger?: number;
    valueFormat?: ChartValueFormat;
    yAxis?: ChartYAxis;
}
export interface IconElement extends BaseElement {
    type: 'icon';
    iconName: string;
    iconLibrary: 'lucide' | 'tabler';
    svgContent: string;
    color: string;
    strokeWidth: number;
    fillMode: 'stroke' | 'fill' | 'both';
    animation?: SvgPathAnimationConfig;
}
export interface SvgElement extends BaseElement {
    type: 'svg';
    svgContent: string;
    color?: string;
    opacity: number;
    preserveAspectRatio: string;
    viewBox?: string;
    animation?: SvgPathAnimationConfig;
}
export type DrawBrush = 'pen' | 'marker' | 'highlighter';
export interface DrawElement extends BaseElement {
    type: 'draw';
    points: number[][];
    color: string;
    opacity: number;
    brush: DrawBrush;
    strokeWidth: number;
    thinning?: number;
    smoothing?: number;
    streamline?: number;
    taperStart?: boolean;
    taperEnd?: boolean;
}
export interface StickyElement extends BaseElement {
    type: 'sticky';
    text: string;
    bgColor: string;
    textColor: string;
    fontSize: number;
    fontFamily: string;
    fontWeight: number;
    textAlign: 'left' | 'center' | 'right';
    padding: number;
    borderRadius: number;
    opacity: number;
    shadow?: boolean;
}
export interface MotionPathElement extends BaseElement {
    type: 'motionPath';
    points: PathPoint[];
    closed: boolean;
    pathColor: string;
    pathWidth: number;
    showInPresentation: boolean;
}
export interface ProgressElement extends BaseElement {
    type: 'progress';
    shape: 'bar-horizontal' | 'bar-vertical' | 'ring';
    value: number;
    max: number;
    fillColor: string;
    fillGradient?: {
        type: 'linear' | 'radial' | 'conic';
        angle?: number;
        colors: string[];
        stops?: GradientStop[];
        radialShape?: 'circle' | 'ellipse';
        radialPosition?: string;
    };
    showTrack: boolean;
    trackColor: string;
    roundness: number;
    thickness: number;
    direction: 'ltr' | 'rtl' | 'btt' | 'ttb' | 'cw' | 'ccw';
    indeterminate?: boolean;
    stripeAngle?: number;
    stripeWidth?: number;
    stripeSpeed?: number;
    label?: {
        position: 'inside' | 'top' | 'bottom' | 'left' | 'right' | 'above' | 'below' | 'center' | 'none';
        format: 'percent' | 'value' | 'value-of-max' | 'custom';
        customText?: string;
        fontSize?: number;
        fontWeight?: number;
        color?: string;
    };
    animationDuration?: number;
}
/**
 * Auto-layout container. Holds a list of child element ids and arranges them
 * via flex-style rules. Children remain independently selectable; layout
 * pass writes computed position+size onto each child.
 */
export interface ContainerElement extends BaseElement {
    type: 'container';
    childIds: string[];
    direction: 'row' | 'column';
    gap: number;
    padding: number | {
        top: number;
        right: number;
        bottom: number;
        left: number;
    };
    align: 'start' | 'center' | 'end' | 'stretch';
    justify: 'start' | 'center' | 'end' | 'space-between' | 'space-around' | 'space-evenly';
    fillColor?: string;
    borderColor?: string;
    borderWidth?: number;
    borderRadius?: number;
}
export type CanvasElement = CodeElement | TextElement | ArrowElement | ImageElement | VideoElement | ShapeElement | CounterElement | ChartElement | IconElement | SvgElement | MotionPathElement | ProgressElement | ContainerElement | DrawElement | StickyElement;
export type ParticleShape = 'circle' | 'square' | 'star' | 'triangle';
export interface ParticlesConfig {
    enabled: boolean;
    count: number;
    color: string;
    opacity: number;
    minSize: number;
    maxSize: number;
    speed: number;
    shape: ParticleShape;
    connectDistance: number;
    direction: 'up' | 'down' | 'left' | 'right' | 'random';
}
export type ConfettiMode = 'burst' | 'continuous' | 'fireworks' | 'snow';
export interface ConfettiConfig {
    enabled: boolean;
    mode: ConfettiMode;
    particleCount: number;
    spread: number;
    colors: string[];
    gravity: number;
    drift: number;
    startVelocity: number;
    scalar: number;
}
export interface GradientStop {
    color: string;
    position: number;
}
export interface CanvasBackground {
    type: 'solid' | 'gradient' | 'image' | 'transparent';
    color?: string;
    gradient?: {
        type: 'linear' | 'radial' | 'conic';
        angle?: number;
        colors: string[];
        stops?: GradientStop[];
        radialShape?: 'circle' | 'ellipse';
        radialPosition?: string;
    };
    image?: string;
    particles?: ParticlesConfig;
    confetti?: ConfettiConfig;
}
export type TransitionType = 'none' | 'fade' | 'slide-left' | 'slide-right' | 'slide-up' | 'slide-down' | 'zoom-in' | 'zoom-out' | 'flip' | 'flip-x' | 'flip-y';
export interface TransitionConfig {
    type: TransitionType;
    duration: number;
    easing: 'linear' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out';
}
export interface SlideCanvas {
    width: number;
    height: number;
    background: CanvasBackground;
    elements: CanvasElement[];
}
export interface Slide {
    id: string;
    name: string;
    canvas: SlideCanvas;
    transition: TransitionConfig;
    duration: number;
    camera?: CameraViewport;
    /** Speaker notes — never rendered onto the audience canvas. Kept on the
     *  type so JSON imports preserve them across edit cycles. */
    notes?: string;
    /** Per-slide voice-over track. Played when the slide is shown if the
     *  project has `settings.narrationEnabled` true. `src` is a base64 data
     *  URL; `duration` is the clip length in ms. */
    narration?: {
        src: string;
        duration: number;
    };
}
export interface ProjectSettings {
    defaultCanvasWidth: number;
    defaultCanvasHeight: number;
    defaultTransition: TransitionConfig;
    defaultSlideDuration: number;
    /** How the presentation behaves when looping from last slide back to first.
     *  'reset' = snap all elements back to slide 1 initial state.
     *  'transition' = smoothly morph from last slide to first.
     *  Default: 'reset' */
    loopMode?: 'reset' | 'transition';
    /** When true, per-slide narration is played. Consumers should also
     *  suppress autoplay when this is on so the viewer's first interaction
     *  unlocks the browser audio context. Default: false. */
    narrationEnabled?: boolean;
}
/** Animot project JSON format */
export interface AnimotProject {
    /** Schema version for forward compatibility. Default: 1 */
    schemaVersion?: number;
    id: string;
    name: string;
    slides: Slide[];
    createdAt: number;
    updatedAt: number;
    settings: ProjectSettings;
}
/** Props for the AnimotPresenter component */
export interface AnimotPresenterProps {
    /** URL to JSON file (fetched automatically) */
    src?: string;
    /** Inline JSON object */
    data?: AnimotProject;
    /** Start playing automatically (default: false) */
    autoplay?: boolean;
    /** Loop back to start when reaching end (default: false) */
    loop?: boolean;
    /** Show bottom playback bar (default: true) */
    controls?: boolean;
    /** Show left/right carousel arrows (default: false) */
    arrows?: boolean;
    /** Show progress bar (default: true) */
    progress?: boolean;
    /** Enable keyboard navigation (default: true) */
    keyboard?: boolean;
    /** Override all slide durations (ms) */
    duration?: number;
    /** Initial slide index (default: 0) */
    startSlide?: number;
    /** Force-disable narration playback regardless of the project's
     *  `settings.narrationEnabled`. Useful for preview surfaces (gallery
     *  cards, thumbnails) where audio would be intrusive. Default: false. */
    muteNarration?: boolean;
    /** CSS class for outer container */
    class?: string;
    /** Fired when slide changes */
    onslidechange?: (index: number, total: number) => void;
    /** Fired when last slide is reached (non-loop mode) */
    oncomplete?: () => void;
}
