import { type ItemDefVaultRef } from './gunConfigRules'; /** The `emote.playback` vocabulary — the manifest's enum. */ export declare const EMOTE_PLAYBACKS: readonly ["oneshot", "loop"]; export type EmotePlayback = (typeof EMOTE_PLAYBACKS)[number]; /** Clip duration ceilings, seconds. A performance that outruns the one-shot cap has to declare itself a loop. */ export declare const EMOTE_ONESHOT_MAX_S = 10; export declare const EMOTE_LOOP_MAX_S = 60; /** TRANSITIONS: ceilings on the optional enter/exit clips, seconds. On a `oneshot` the whole chain also owes * EMOTE_ONESHOT_MAX_S — the player is locked for all of it, and movement cannot break a one-shot. */ export declare const EMOTE_INTRO_MAX_S = 5; export declare const EMOTE_OUTRO_MAX_S = 5; /** Playback an emote is read as when it declares none — the manifest leaves the field optional. */ export declare const DEFAULT_EMOTE_PLAYBACK: EmotePlayback; export declare const EMOTE_JOINER_OFFSET_MAX_M = 3; export declare const EMOTE_JOINER_YAW_MAX_DEG = 180; /** The OFFER: seconds into the initiator's clip they wind up to and hold while waiting. The real ceiling is * that clip's measured duration (a freeze past the end is nothing) — this is the manifest's coarse guard. */ export declare const EMOTE_OFFER_AT_MAX_S = 600; /** The joiner's placement, as the descriptor carries it. */ export type EmoteJoinerOffset = { x: number; z: number; yawDeg: number; }; export declare const EMOTE_CATEGORIES: readonly ["regular", "sit", "lie"]; export type EmoteCategory = (typeof EMOTE_CATEGORIES)[number]; /** What the backend stores when the product body names none — so omitting the flag is the same as sending it. */ export declare const DEFAULT_EMOTE_CATEGORY: EmoteCategory; export declare function isEmoteCategory(value: unknown): value is EmoteCategory; export type EmoteCheckResult = { errors: string[]; warnings: string[]; /** emote.clip as authored: a relative path pre-publish, a pinned vault ref post-publish, or null. */ clipRef: string | ItemDefVaultRef | null; /** The declared playback, defaulted — what the duration cap is measured against. */ playback: EmotePlayback; /** Descriptor-relative `assets.audio` refs (pre-publish form) — existence-checked by validate, uploaded by publish. */ relativeAudioRefs: string[]; /** PAIRED emotes: `emote.roles.joiner.clip` in the same two forms, or null when the emote is a solo one. */ joinerClipRef: string | ItemDefVaultRef | null; /** TRANSITIONS: `emote.intro` / `emote.outro` in the same two forms, or null when the emote authors none. */ introClipRef: string | ItemDefVaultRef | null; outroClipRef: string | ItemDefVaultRef | null; /** PAIRED emotes: the authored `emote.roles.offerAtS`, or null when absent (the clip's first frame) or unusable. */ offerAtS: number | null; }; /** The block set IS the item's type (the manifest's own rule), so an `emote` block is what makes this the emote lane. */ export declare function isEmoteDescriptor(input: unknown): boolean; /** The joiner's placement: three finite numbers, bounded exactly as the manifest schema bounds them. */ export declare function checkJoinerOffset(offset: unknown, where: string): string[]; /** The offer pose is held INSIDE the initiator's clip, so an instant past its end freezes on nothing. */ export declare function checkEmoteOfferAt(offerAtS: number, durationS: number, label: string): string[]; /** `--offer-at ` → the held offer instant. Throws the flag's own shape error. */ export declare function parseOfferAtS(raw: string): number; /** `--joiner-offset "x,z,yawDeg"` → the offset the descriptor carries. Throws the flag's own shape error. */ export declare function parseJoinerOffset(raw: string): EmoteJoinerOffset; /** * Run the emote lane's structural rules over a parsed descriptor. Collects every violation instead of * throwing on the first, like the gun-config pass; the manifest's schema validation is a separate pass. * The clip's DURATION is not checked here — it needs the file bytes, so validate measures and calls * checkEmoteClipDuration. */ export declare function checkEmoteRules(input: unknown): EmoteCheckResult; export type EmoteClipMeasurement = { /** Seconds of the longest animation in the clip, or null when the GLB does not say. */ durationS: number | null; animationCount: number; errors: string[]; warnings: string[]; }; /** * Measure an emote clip GLB: it must be a glTF 2.0 carrying at least one animation, and the longest * animation's end time is the duration the caps are enforced against. An unmeasurable duration WARNS * rather than blocks — the cap belongs to whoever can actually read the clip. */ export declare function measureEmoteClip(bytes: Buffer, label: string): EmoteClipMeasurement; /** The duration caps, against a measured clip and the playback it declares. */ export declare function checkEmoteClipDuration(durationS: number, playback: EmotePlayback, label: string): string[]; /** * The transition caps, against the measured chain. Each transition owes its own ceiling on either playback; * a `oneshot` ALSO owes the one-shot cap on intro + clip + outro, because the emote lock spans the whole * chain and movement cannot break a one-shot — an uncapped chain is an unbreakable lock. A null is an * absent or unmeasurable clip, and only what could be measured is judged. */ export declare function checkEmoteChainDuration(introS: number | null, bodyS: number | null, outroS: number | null, playback: EmotePlayback): string[];