ADR-287: Update Emote schema with outcomes (Social Emotes)

More details about this document
Latest published version:
https://adr.decentraland.org/adr/ADR-287
Authors:
cyaiox
Feedback:
GitHub decentraland/adr (pull requests, new issue, open issues)
Edit this documentation:
GitHub View commits View commits on githistory.xyz

Abstract

We are implementing a new feature named Social Emotes, which will allow multiple players to interact with this new kind of emote.

These new emotes will have a new property named outcomes, which lets authors define the animation to execute and specify whether it loops or not.

Context, Reach & Prioritization

Solution Space Exploration

GLB Authoring: Naming Convention

To ensure consistency across exported GLB clips, we suggest the use of the following pattern: <Action>_(Start | Start_Prop | Avatar | Prop | AvatarOther)

Rules

Examples:

Rationale

Specification

Versioned schema (off-chain)

export type ArmatureId = "Armature" | "Armature_Prop" | "Armature_Other"

export type EmoteClip = {
  animation: string // GLB clip name "HighFive_Avatar" (suggested, not enforced)
  loop: boolean
}

export type StartAnimation = {
  Armature: EmoteClip
  Armature_Prop?: EmoteClip
}

export type OutcomeGroup = {
  title: string
  // Any subset of armatures; validated at runtime to ensure at least one
  clips: Partial<Record<ArmatureId, EmoteClip>>
}

export type EmoteDataADR287 = {
  category: EmoteCategory
  representations: EmoteRepresentationADR74[]
  tags: string[]
  loop: boolean
  startAnimation: StartAnimation
  randomizeOutcomes: boolean
  outcomes: OutcomeGroup[]
}

Example (two-armature outcomes):

const emoteWithADR287Data = {
  // ...,
  emoteDataADR287: {
    // ...,
    startAnimation: {
      Armature: {
        animation: "HighFive_Start",
        loop: true
      }
    },
    randomizeOutcomes: false,
    outcomes: [
      {
        title: "High Five",
        clips: {
          Armature: {
            animation: "HighFive_Avatar",
            loop: false
          },
          Armature_Other: {
            animation: "HighFive_AvatarOther",
            loop: false
          }
        }
      }
    ]
  }
}

Outcome semantics

Contract metadata (on-chain)

ADR-74 extended the metadata to include loop and then additionalProperties (sound/geometry) by appending fields on the right to avoid breaking older parsers. We follow the same pattern:

Where:

Deriving outcomeType from the schema

Type unions

export type Emote = EmoteADR74 | EmoteADR287

export type EmoteADR287 = BaseItem &
  (StandardProps | ThirdPartyProps) & { emoteDataADR287: EmoteDataADR287 }

(Union pattern follows ADR-74’s versioned types approach.)

Validation

Examples

Random outcomes (off-chain)

const emoteWithADR287Data = {
  // ...,
  emoteDataADR287: {
    // ...,
    startAnimation: {
      Armature: {
        animation: "Hug_Start",
        loop: true
      }
    },
    randomizeOutcomes: true,
    outcomes: [
      {
        title: "Hug Short",
        clips: {
          Armature: {
            animation: "HugShort_Avatar",
            loop: false
          },
          Armature_Other: {
            animation: "HugShort_AvatarOther",
            loop: false
          }
        }
      },
      {
        title: "Hug Long",
        clips: {
          Armature: {
            animation: "HugLong_Avatar",
            loop: false
          },
          Armature_Other: {
            animation: "HugLong_AvatarOther",
            loop: false
          }
        }
      }
    ]
  }
}
// outcomeType => "ro"

Resulting on-chain metadata (example)

${version}:${type}:${name}:${description}:${category}:${bodyShapeTypes}:${loop}:${additionalProperties}:ro

Note: The actual list of outcomes[] is not encoded on-chain.

References

License

Copyright and related rights waived via CC0-1.0. Draft