Authoring

Emotions and poses

The emotion wheel, rendered face by face, and the three gestures that claim the torso.

A body’s emotion is a point on a wheel: angle in radians, intensity from 0 to 1. The renderer finds the nearest face the character’s pack declares and draws that. Because it is nearest-neighbour, any angle is valid; the names below are the eight points the default pack draws distinctly.

The wheel

Nine close-ups of the same character: NEUTRAL, then the eight named angles at intensity 0.8.

anna around the wheel
Open in playground →
Show all 9 panelsShow first panel only
strip.json
{
  "version": 1,
  "panels": [
    {
      "backdrop": "field",
      "camera": "close-up",
      "bodies": [
        {
          "character": "anna",
          "emotion": {
            "angle": 0,
            "intensity": 0
          }
        }
      ],
      "speakers": [
        {
          "speaker": "caption",
          "balloon": "caption",
          "text": "NEUTRAL: intensity 0"
        }
      ]
    },
    {
      "backdrop": "field",
      "camera": "close-up",
      "bodies": [
        {
          "character": "anna",
          "emotion": {
            "angle": 0,
            "intensity": 0.8
          }
        }
      ],
      "speakers": [
        {
          "speaker": "caption",
          "balloon": "caption",
          "text": "HAPPY: angle 0π/4, intensity 0.8"
        }
      ]
    },
    {
      "backdrop": "field",
      "camera": "close-up",
      "bodies": [
        {
          "character": "anna",
          "emotion": {
            "angle": 0.785398,
            "intensity": 0.8
          }
        }
      ],
      "speakers": [
        {
          "speaker": "caption",
          "balloon": "caption",
          "text": "COY: angle 1π/4, intensity 0.8"
        }
      ]
    },
    {
      "backdrop": "field",
      "camera": "close-up",
      "bodies": [
        {
          "character": "anna",
          "emotion": {
            "angle": 1.570796,
            "intensity": 0.8
          }
        }
      ],
      "speakers": [
        {
          "speaker": "caption",
          "balloon": "caption",
          "text": "BORED: angle 2π/4, intensity 0.8"
        }
      ]
    },
    {
      "backdrop": "field",
      "camera": "close-up",
      "bodies": [
        {
          "character": "anna",
          "emotion": {
            "angle": 2.356194,
            "intensity": 0.8
          }
        }
      ],
      "speakers": [
        {
          "speaker": "caption",
          "balloon": "caption",
          "text": "SCARED: angle 3π/4, intensity 0.8"
        }
      ]
    },
    {
      "backdrop": "field",
      "camera": "close-up",
      "bodies": [
        {
          "character": "anna",
          "emotion": {
            "angle": 3.141593,
            "intensity": 0.8
          }
        }
      ],
      "speakers": [
        {
          "speaker": "caption",
          "balloon": "caption",
          "text": "SAD: angle 4π/4, intensity 0.8"
        }
      ]
    },
    {
      "backdrop": "field",
      "camera": "close-up",
      "bodies": [
        {
          "character": "anna",
          "emotion": {
            "angle": 3.926991,
            "intensity": 0.8
          }
        }
      ],
      "speakers": [
        {
          "speaker": "caption",
          "balloon": "caption",
          "text": "ANGRY: angle 5π/4, intensity 0.8"
        }
      ]
    },
    {
      "backdrop": "field",
      "camera": "close-up",
      "bodies": [
        {
          "character": "anna",
          "emotion": {
            "angle": 4.712389,
            "intensity": 0.8
          }
        }
      ],
      "speakers": [
        {
          "speaker": "caption",
          "balloon": "caption",
          "text": "SHOUT: angle 6π/4, intensity 0.8"
        }
      ]
    },
    {
      "backdrop": "field",
      "camera": "close-up",
      "bodies": [
        {
          "character": "anna",
          "emotion": {
            "angle": 5.497787,
            "intensity": 0.8
          }
        }
      ],
      "speakers": [
        {
          "speaker": "caption",
          "balloon": "caption",
          "text": "LAUGH: angle 7π/4, intensity 0.8"
        }
      ]
    }
  ]
}
strip.json
{
  "version": 1,
  "panels": [
    {
      "backdrop": "field",
      "camera": "close-up",
      "bodies": [
        {
          "character": "anna",
          "emotion": {
            "angle": 0,
            "intensity": 0
          }
        }
      ],
      "speakers": [
        {
          "speaker": "caption",
          "balloon": "caption",
          "text": "NEUTRAL: intensity 0"
        }
      ]
    }
    // … 8 more panels
  ]
}
Name angle radians
HAPPY 0 0
COY π/4 0.785
BORED π/2 1.571
SCARED 3π/4 2.356
SAD π 3.142
ANGRY 5π/4 3.927
SHOUT 3π/2 4.712
LAUGH 7π/4 5.498

Intensity

Intensity picks between faces at the same angle when a pack has several, and at 0 it means NEUTRAL regardless of angle. The default pack has two or three faces per emotion for most characters, so a low and a high intensity often look different.

SAD at three intensities
Open in playground →
Show all 3 panelsShow first panel only
strip.json
{
  "version": 1,
  "panels": [
    {
      "backdrop": "field",
      "camera": "close-up",
      "bodies": [
        {
          "character": "dan",
          "emotion": {
            "angle": 3.141593,
            "intensity": 0.2
          }
        }
      ],
      "speakers": [
        {
          "speaker": "caption",
          "balloon": "caption",
          "text": "SAD at intensity 0.2"
        }
      ]
    },
    {
      "backdrop": "field",
      "camera": "close-up",
      "bodies": [
        {
          "character": "dan",
          "emotion": {
            "angle": 3.141593,
            "intensity": 0.5
          }
        }
      ],
      "speakers": [
        {
          "speaker": "caption",
          "balloon": "caption",
          "text": "SAD at intensity 0.5"
        }
      ]
    },
    {
      "backdrop": "field",
      "camera": "close-up",
      "bodies": [
        {
          "character": "dan",
          "emotion": {
            "angle": 3.141593,
            "intensity": 0.9
          }
        }
      ],
      "speakers": [
        {
          "speaker": "caption",
          "balloon": "caption",
          "text": "SAD at intensity 0.9"
        }
      ]
    }
  ]
}
strip.json
{
  "version": 1,
  "panels": [
    {
      "backdrop": "field",
      "camera": "close-up",
      "bodies": [
        {
          "character": "dan",
          "emotion": {
            "angle": 3.141593,
            "intensity": 0.2
          }
        }
      ],
      "speakers": [
        {
          "speaker": "caption",
          "balloon": "caption",
          "text": "SAD at intensity 0.2"
        }
      ]
    }
    // … 2 more panels
  ]
}

Note

NEUTRAL shares HAPPY’s angle. { angle: 0, intensity: 0 } and { angle: 3.142, intensity: 0 } are the same face. Think of intensity 0 as the centre of the wheel.

Poses

pose is a separate channel from emotion. It claims the torso with a gesture while emotion still picks the face, so a character can wave while looking sad. Three gestures exist: wave, point, shrug. A pack supports a gesture by declaring a torso for it; the default pack supports all three for every character.

The three gestures
Open in playground →
Show all 3 panelsShow first panel only
strip.json
{
  "version": 1,
  "panels": [
    {
      "backdrop": "field",
      "camera": "medium",
      "bodies": [
        {
          "character": "kevin",
          "emotion": {
            "angle": 0,
            "intensity": 0.5
          },
          "pose": "wave"
        }
      ],
      "speakers": [
        {
          "speaker": "kevin",
          "balloon": "speech",
          "text": "\"pose\": \"wave\""
        }
      ]
    },
    {
      "backdrop": "field",
      "camera": "medium",
      "bodies": [
        {
          "character": "kevin",
          "emotion": {
            "angle": 0,
            "intensity": 0.5
          },
          "pose": "point"
        }
      ],
      "speakers": [
        {
          "speaker": "kevin",
          "balloon": "speech",
          "text": "\"pose\": \"point\""
        }
      ]
    },
    {
      "backdrop": "field",
      "camera": "medium",
      "bodies": [
        {
          "character": "kevin",
          "emotion": {
            "angle": 0,
            "intensity": 0.5
          },
          "pose": "shrug"
        }
      ],
      "speakers": [
        {
          "speaker": "kevin",
          "balloon": "speech",
          "text": "\"pose\": \"shrug\""
        }
      ]
    }
  ]
}
strip.json
{
  "version": 1,
  "panels": [
    {
      "backdrop": "field",
      "camera": "medium",
      "bodies": [
        {
          "character": "kevin",
          "emotion": {
            "angle": 0,
            "intensity": 0.5
          },
          "pose": "wave"
        }
      ],
      "speakers": [
        {
          "speaker": "kevin",
          "balloon": "speech",
          "text": "\"pose\": \"wave\""
        }
      ]
    }
    // … 2 more panels
  ]
}

How selection works

Each character has faces and torsos as separate sprites. Per panel, the renderer:

  1. Picks the nearest face to the body’s emotion point.
  2. Picks a torso: the pose’s gesture torso if a pose is set, otherwise the torso nearest the emotion.
  3. Cycles through equally good candidates across panels, so a character repeated in three panels does not show the identical drawing three times.

The cycle is frozen per panel when the strip loads, so a resize redraws the same figures.