Kokonkun upgrade — Codex spec part 2

Followup consult to add HEAD ORNAMENT + 8 Moonlighter-style movements (stumble, overexcited-burn, trip-fall, juggle-sparkle, slide, peek-corner, clap, shrug).

User feedback driving this:

  1. “I dont like kokonkun a bit bald, can you add something like cat ear?”
  2. “Similar to moonlighter styles 8 bit, for now just increase the movement, accessories, example like stumbled, or to excited until its burn and return to normal”

OPTION A — Cat Ears

<>
  {/* row y=-1: ear tips */}
  <rect x={6} y={-1} width={1} height={1} fill={outline} />
  <rect x={17} y={-1} width={1} height={1} fill={outline} />
 
  {/* row y=0: upper triangle */}
  <rect x={5} y={0} width={3} height={1} fill={outline} />
  <rect x={6} y={0} width={1} height={1} fill={earIn} />
  <rect x={16} y={0} width={3} height={1} fill={outline} />
  <rect x={17} y={0} width={1} height={1} fill={earIn} />
 
  {/* row y=1: base merges into helmet dome */}
  <rect x={4} y={1} width={5} height={1} fill={outline} />
  <rect x={5} y={1} width={3} height={1} fill={helmetH} />
  <rect x={6} y={1} width={1} height={1} fill={earIn} />
  <rect x={15} y={1} width={5} height={1} fill={outline} />
  <rect x={16} y={1} width={3} height={1} fill={helmetH} />
  <rect x={17} y={1} width={1} height={1} fill={earIn} />
 
  {/* row y=2: chunky helmet overlap / shadow foot */}
  <rect x={5} y={2} width={3} height={1} fill={helmetS} />
  <rect x={16} y={2} width={3} height={1} fill={helmetS} />
</>

OPTION B — Robot Antennas

<>
  {/* row y=-1: bulb tips */}
  <rect x={6} y={-1} width={3} height={1} fill={outline} />
  <rect x={7} y={-1} width={1} height={1} fill={heartL} />
  <rect x={15} y={-1} width={3} height={1} fill={outline} />
  <rect x={16} y={-1} width={1} height={1} fill={heartL} />
 
  {/* row y=0: bulb lower + highlight */}
  <rect x={6} y={0} width={3} height={1} fill={outline} />
  <rect x={7} y={0} width={1} height={1} fill={heartM} />
  <rect x={15} y={0} width={3} height={1} fill={outline} />
  <rect x={16} y={0} width={1} height={1} fill={heartM} />
 
  {/* row y=1: thin posts */}
  <rect x={7} y={1} width={1} height={1} fill={outline} />
  <rect x={16} y={1} width={1} height={1} fill={outline} />
 
  {/* row y=2: socket bases on helmet */}
  <rect x={6} y={2} width={3} height={1} fill={outline} />
  <rect x={7} y={2} width={1} height={1} fill={woodM} />
  <rect x={15} y={2} width={3} height={1} fill={outline} />
  <rect x={16} y={2} width={1} height={1} fill={woodM} />
</>

OPTION C — Bunny Ears

<>
  {/* row y=-1: rounded tips */}
  <rect x={6} y={-1} width={2} height={1} fill={outline} />
  <rect x={16} y={-1} width={2} height={1} fill={outline} />
 
  {/* row y=0: upper ears */}
  <rect x={5} y={0} width={4} height={1} fill={outline} />
  <rect x={6} y={0} width={2} height={1} fill={helmetW} />
  <rect x={15} y={0} width={4} height={1} fill={outline} />
  <rect x={16} y={0} width={2} height={1} fill={helmetW} />
 
  {/* row y=1: inner ear color */}
  <rect x={5} y={1} width={4} height={1} fill={outline} />
  <rect x={6} y={1} width={2} height={1} fill={earIn} />
  <rect x={15} y={1} width={4} height={1} fill={outline} />
  <rect x={16} y={1} width={2} height={1} fill={earIn} />
 
  {/* row y=2: chunky bases */}
  <rect x={4} y={2} width={5} height={1} fill={outline} />
  <rect x={5} y={2} width={3} height={1} fill={helmetH} />
  <rect x={15} y={2} width={5} height={1} fill={outline} />
  <rect x={16} y={2} width={3} height={1} fill={helmetH} />
</>

Recommended default: Option A, cat ears. It fixes the bald dome immediately with the clearest 8-bit silhouette, while staying small enough not to overpower Kokonkun’s helmet. It also gives the best animation readability because each ear can rotate or squash independently.

Ear Animations

animation: earTwitch
duration: 240ms
easing: steps(1, end)
frames:
  f0: { t: 0.00, leftEar: { rot: 0, x: 0, y: 0 }, rightEar: { rot: 0, x: 0, y: 0 } }
  f1: { t: 0.25, leftEar: { rot: -8, x: -1, y: 0 }, rightEar: { rot: 4, x: 0, y: 0 } }
  f2: { t: 0.50, leftEar: { rot: 5, x: 0, y: -1 }, rightEar: { rot: -5, x: 1, y: 0 } }
  f3: { t: 0.75, leftEar: { rot: -3, x: 0, y: 0 }, rightEar: { rot: 2, x: 0, y: 0 } }
  f4: { t: 1.00, leftEar: { rot: 0, x: 0, y: 0 }, rightEar: { rot: 0, x: 0, y: 0 } }
trigger: idle, every 8-12s random
exit: returnToIdle
animation: earDroopTired
duration: 520ms
easing: steps(1, end)
frames:
  f0: { t: 0.00, leftEar: { rot: 0, y: 0 }, rightEar: { rot: 0, y: 0 }, head: { y: 0 } }
  f1: { t: 0.25, leftEar: { rot: -10, y: 0 }, rightEar: { rot: 10, y: 0 }, head: { y: 1 } }
  f2: { t: 0.55, leftEar: { rot: -18, y: 1 }, rightEar: { rot: 18, y: 1 }, head: { y: 1 } }
  f3: { t: 0.80, leftEar: { rot: -14, y: 1 }, rightEar: { rot: 14, y: 1 }, head: { y: 0 } }
  f4: { t: 1.00, leftEar: { rot: 0, y: 0 }, rightEar: { rot: 0, y: 0 }, head: { y: 0 } }
trigger: tired, failedAction, lowEnergyIdle
exit: idle

REQUEST 2 — More Moonlighter-Style Movements

1. stumble

animation: stumble
duration: 760ms
easing: steps(1, end)
frames:
  f0: { t: 0.00, body: { x: 0, y: 0, rot: 0 }, head: { x: 0, y: 0 }, leftLeg: { x: 0, y: 0 }, rightLeg: { x: 0, y: 0 }, leftArm: { rot: 0 }, rightArm: { rot: 0 } }
  f1: { t: 0.12, body: { x: 1, y: 0, rot: 5 }, head: { x: 1, y: 0 }, leftLeg: { x: 1, y: -1 }, rightLeg: { x: -1, y: 1 }, leftArm: { rot: -12 }, rightArm: { rot: 18 } }
  f2: { t: 0.25, body: { x: 3, y: 1, rot: 11 }, head: { x: 2, y: 1 }, eyes: { variant: "wide" }, mouth: { variant: "small-o" }, leftArm: { rot: -28, x: -1 }, rightArm: { rot: 32, x: 1 } }
  f3: { t: 0.40, body: { x: 4, y: 2, rot: -7 }, head: { x: 3, y: 0 }, leftLeg: { x: -1, y: 1 }, rightLeg: { x: 2, y: -1 }, heart: { y: -1 } }
  f4: { t: 0.58, body: { x: 2, y: 0, rot: -12 }, head: { x: 1, y: -1 }, leftArm: { rot: 24 }, rightArm: { rot: -22 }, prop: { particles: "dust-2" } }
  f5: { t: 0.76, body: { x: 1, y: 0, rot: 4 }, head: { x: 0, y: 0 }, eyes: { variant: "blink" }, mouth: { variant: "flat" } }
  f6: { t: 1.00, body: { x: 0, y: 0, rot: 0 }, head: { x: 0, y: 0 }, eyes: { variant: "normal" }, mouth: { variant: "normal" }, leftArm: { rot: 0 }, rightArm: { rot: 0 } }
trigger: walking, carryingHeavy, random 4-7% while moving
exit: resumeWalk

2. overexcited-burn

animation: overexcited-burn
duration: 2040ms
easing: steps(1, end)
frames:
  # build
  f0:  { t: 0.00, body: { y: 0, rot: 0 }, head: { y: 0 }, helmet: { palette: "normal" }, eyes: { variant: "sparkle" }, mouth: { variant: "smile" }, heart: { scale: 1 }, leftEar: { rot: 0 }, rightEar: { rot: 0 } }
  f1:  { t: 0.08, body: { y: -1, rot: -3 }, head: { y: -1 }, heart: { scale: 1.15, y: -1 }, leftArm: { rot: -18 }, rightArm: { rot: 18 }, leftEar: { rot: -6 }, rightEar: { rot: 6 } }
  f2:  { t: 0.16, body: { y: 0, rot: 3 }, head: { y: 0 }, heart: { scale: 1.25, y: -2 }, leftArm: { rot: -28 }, rightArm: { rot: 28 }, prop: { particles: "sparkle-3" } }
  f3:  { t: 0.24, body: { y: -2, rot: 0 }, head: { y: -2 }, eyes: { variant: "star" }, mouth: { variant: "big-smile" }, heart: { scale: 1.4 }, prop: { particles: "sparkle-5" } }
 
  # peak
  f4:  { t: 0.34, body: { y: -1, rot: -5, shakeX: 1 }, head: { y: -1, shakeX: 1 }, helmet: { palette: "hot-1" }, leftEar: { rot: -12 }, rightEar: { rot: 12 }, prop: { particles: "heat-lines-2" } }
  f5:  { t: 0.44, body: { y: 0, rot: 5, shakeX: -1 }, head: { y: 0, shakeX: -1 }, helmet: { palette: "hot-2" }, eyes: { variant: "tiny" }, mouth: { variant: "wobble" }, prop: { particles: "heat-lines-4" } }
 
  # smoke
  f6:  { t: 0.54, body: { y: 1, rot: 0, shakeX: 1 }, head: { y: 0 }, helmet: { palette: "overheat" }, eyes: { variant: "pin" }, mouth: { variant: "small-o" }, prop: { smoke: [{ x: 9, y: -3 }, { x: 14, y: -4 }] } }
  f7:  { t: 0.64, body: { y: 1, rot: -2, shakeX: -1 }, helmet: { palette: "overheat" }, leftArm: { rot: 16 }, rightArm: { rot: -16 }, prop: { smoke: [{ x: 8, y: -5 }, { x: 15, y: -6 }, { x: 12, y: -4 }] } }
 
  # char
  f8:  { t: 0.74, body: { y: 1, rot: 0 }, helmet: { palette: "char-black" }, face: { palette: "soot" }, eyes: { variant: "blank" }, mouth: { variant: "flat" }, heart: { scale: 0.85, palette: "dim" }, prop: { smoke: "puff-4" } }
  f9:  { t: 0.82, body: { y: 0, rot: -6, shakeX: 2 }, head: { shakeX: 2 }, helmet: { palette: "char-black" }, leftArm: { rot: -34 }, rightArm: { rot: 34 }, prop: { soot: "flakes-3" } }
 
  # recover
  f10: { t: 0.90, body: { y: 0, rot: 6, shakeX: -2 }, head: { shakeX: -2 }, helmet: { palette: "soot-fading" }, face: { palette: "normal" }, eyes: { variant: "dizzy" }, prop: { soot: "flakes-5" } }
  f11: { t: 0.96, body: { y: -1, rot: 0 }, head: { y: -1 }, helmet: { palette: "normal" }, eyes: { variant: "blink" }, mouth: { variant: "sheepish" }, heart: { scale: 1.0, palette: "normal" } }
  f12: { t: 1.00, body: { y: 0, rot: 0 }, head: { y: 0 }, helmet: { palette: "normal" }, eyes: { variant: "normal" }, mouth: { variant: "normal" }, leftArm: { rot: 0 }, rightArm: { rot: 0 }, leftEar: { rot: 0 }, rightEar: { rot: 0 } }
trigger: rareCelebration, perfectAction, giftLiked, comboMax
exit: idleHappy

3. trip-fall

animation: trip-fall
duration: 1320ms
easing: steps(1, end)
frames:
  f0: { t: 0.00, body: { x: 0, y: 0, rot: 0 }, head: { x: 0, y: 0 }, eyes: { variant: "normal" } }
  f1: { t: 0.12, body: { x: 2, y: 1, rot: 14 }, head: { x: 2, y: 1 }, leftLeg: { x: 2, y: -1 }, rightLeg: { x: -1, y: 1 }, eyes: { variant: "wide" } }
  f2: { t: 0.24, body: { x: 5, y: 3, rot: 38 }, head: { x: 5, y: 2 }, leftArm: { rot: -45 }, rightArm: { rot: 45 }, mouth: { variant: "small-o" } }
  f3: { t: 0.34, body: { x: 7, y: 5, rot: 90 }, head: { x: 8, y: 5, rot: 90 }, helmet: { impact: true }, prop: { particles: "impact-stars-3" } }
  f4: { t: 0.72, body: { x: 7, y: 5, rot: 90 }, head: { x: 8, y: 5, rot: 90 }, eyes: { variant: "spiral" }, mouth: { variant: "flat" } }
  f5: { t: 0.84, body: { x: 5, y: 3, rot: 45 }, head: { x: 5, y: 2, rot: 20 }, leftArm: { rot: 20 }, rightArm: { rot: -20 } }
  f6: { t: 0.94, body: { x: 1, y: 1, rot: -8 }, head: { x: 1, y: 0, rot: -4 }, eyes: { variant: "blink" } }
  f7: { t: 1.00, body: { x: 0, y: 0, rot: 0 }, head: { x: 0, y: 0, rot: 0 }, eyes: { variant: "normal" }, mouth: { variant: "normal" } }
trigger: failedWalk, obstacleHit, slapstickIdle
exit: idleEmbarrassed

4. juggle-sparkle

animation: juggle-sparkle
duration: 1120ms
easing: steps(1, end)
frames:
  f0: { t: 0.00, body: { y: 0 }, head: { y: 0 }, leftArm: { rot: -18, y: 0 }, rightArm: { rot: 18, y: 0 }, prop: { sparkles: [{ id: 1, x: 6, y: 13 }, { id: 2, x: 12, y: 8 }, { id: 3, x: 18, y: 13 }] } }
  f1: { t: 0.16, leftArm: { rot: -32, y: -1 }, rightArm: { rot: 12 }, eyes: { variant: "look-left" }, prop: { sparkles: [{ id: 1, x: 8, y: 9 }, { id: 2, x: 15, y: 8 }, { id: 3, x: 17, y: 15 }] } }
  f2: { t: 0.32, body: { y: -1 }, head: { y: -1 }, leftArm: { rot: -8 }, rightArm: { rot: 28, y: -1 }, prop: { sparkles: [{ id: 1, x: 12, y: 7 }, { id: 2, x: 18, y: 12 }, { id: 3, x: 7, y: 15 }] } }
  f3: { t: 0.48, leftArm: { rot: 18 }, rightArm: { rot: 36, y: -1 }, eyes: { variant: "look-right" }, prop: { sparkles: [{ id: 1, x: 16, y: 9 }, { id: 2, x: 16, y: 15 }, { id: 3, x: 9, y: 9 }] } }
  f4: { t: 0.64, body: { y: 0 }, head: { y: 0 }, leftArm: { rot: -28, y: -1 }, rightArm: { rot: 6 }, prop: { sparkles: [{ id: 1, x: 18, y: 13 }, { id: 2, x: 11, y: 8 }, { id: 3, x: 6, y: 13 }] } }
  f5: { t: 0.82, leftArm: { rot: -18 }, rightArm: { rot: 18 }, eyes: { variant: "happy" }, prop: { sparkles: "burst-small" } }
  f6: { t: 1.00, body: { y: 0 }, head: { y: 0 }, leftArm: { rot: 0 }, rightArm: { rot: 0 }, prop: { sparkles: [] } }
trigger: idleAlt, shopIdle, every 20-35s random
exit: idle

5. slide

animation: slide
duration: 900ms
easing: steps(1, end)
frames:
  f0: { t: 0.00, body: { x: -32, y: 6, rot: 90 }, head: { x: -32, y: 6, rot: 90 }, eyes: { variant: "determined" }, prop: { dust: "trail-5" } }
  f1: { t: 0.18, body: { x: -18, y: 6, rot: 90 }, head: { x: -18, y: 6, rot: 90 }, leftArm: { rot: -35 }, rightArm: { rot: 35 }, prop: { dust: "trail-4" } }
  f2: { t: 0.36, body: { x: -6, y: 5, rot: 84 }, head: { x: -6, y: 5, rot: 84 }, prop: { dust: "trail-3" } }
  f3: { t: 0.54, body: { x: 2, y: 4, rot: 62 }, head: { x: 2, y: 4, rot: 40 }, eyes: { variant: "wide" }, prop: { dust: "poof-2" } }
  f4: { t: 0.72, body: { x: 1, y: 1, rot: 15 }, head: { x: 1, y: 0, rot: 8 }, leftLeg: { y: 1 }, rightLeg: { y: 1 } }
  f5: { t: 0.88, body: { x: 0, y: -1, rot: -5 }, head: { y: -1 }, mouth: { variant: "smile" } }
  f6: { t: 1.00, body: { x: 0, y: 0, rot: 0 }, head: { x: 0, y: 0, rot: 0 }, leftArm: { rot: 0 }, rightArm: { rot: 0 } }
trigger: entranceVariant, sceneEnterFast
exit: idle

6. peek-corner

animation: peek-corner
duration: 1040ms
easing: steps(1, end)
frames:
  f0: { t: 0.00, body: { x: -24, y: 0 }, head: { x: -20, y: 0 }, helmet: { visible: false }, face: { visible: false } }
  f1: { t: 0.18, head: { x: -14, y: 0 }, helmet: { visible: true }, face: { visible: false }, leftEar: { rot: -6 }, rightEar: { rot: 4 } }
  f2: { t: 0.34, head: { x: -8, y: 0 }, face: { visible: true }, eyes: { variant: "look-right" }, mouth: { variant: "hidden" } }
  f3: { t: 0.52, head: { x: -6, y: -1 }, eyes: { variant: "blink" }, leftEar: { rot: -10 }, rightEar: { rot: 8 } }
  f4: { t: 0.70, head: { x: -8, y: 0 }, eyes: { variant: "look-right" }, mouth: { variant: "small-smile" } }
  f5: { t: 0.86, head: { x: -14, y: 0 }, face: { visible: false } }
  f6: { t: 1.00, head: { x: -20, y: 0 }, helmet: { visible: false }, face: { visible: false } }
trigger: cornerIdle, notificationPeek, pageLoadRare
exit: hiddenIdle

7. clap

animation: clap
duration: 680ms
easing: steps(1, end)
frames:
  f0: { t: 0.00, body: { y: 0 }, head: { y: 0 }, leftArm: { x: -2, rot: -18 }, rightArm: { x: 2, rot: 18 }, eyes: { variant: "happy" }, mouth: { variant: "smile" } }
  f1: { t: 0.14, leftArm: { x: 0, rot: -6 }, rightArm: { x: 0, rot: 6 }, prop: { particles: "clap-1" }, heart: { y: -1 } }
  f2: { t: 0.28, leftArm: { x: -2, rot: -22 }, rightArm: { x: 2, rot: 22 }, body: { y: -1 }, head: { y: -1 } }
  f3: { t: 0.42, leftArm: { x: 0, rot: -4 }, rightArm: { x: 0, rot: 4 }, prop: { particles: "clap-2" } }
  f4: { t: 0.58, leftArm: { x: -2, rot: -20 }, rightArm: { x: 2, rot: 20 }, body: { y: 0 }, head: { y: 0 } }
  f5: { t: 0.72, leftArm: { x: 0, rot: -5 }, rightArm: { x: 0, rot: 5 }, prop: { particles: "clap-3" }, heart: { scale: 1.15 } }
  f6: { t: 1.00, leftArm: { x: 0, rot: 0 }, rightArm: { x: 0, rot: 0 }, heart: { scale: 1 }, eyes: { variant: "normal" } }
trigger: likedGift, successSmall, userClickPositive
exit: idleHappy

8. shrug

animation: shrug
duration: 820ms
easing: steps(1, end)
frames:
  f0: { t: 0.00, body: { y: 0, rot: 0 }, head: { x: 0, y: 0, rot: 0 }, eyes: { variant: "normal" }, mouth: { variant: "flat" }, leftArm: { rot: 0 }, rightArm: { rot: 0 } }
  f1: { t: 0.16, body: { y: 0 }, head: { x: -1, rot: -5 }, eyes: { variant: "look-left" }, leftArm: { rot: -42, y: -2 }, rightArm: { rot: 38, y: -2 }, mouth: { variant: "small-o" } }
  f2: { t: 0.32, head: { x: 1, rot: 5 }, eyes: { variant: "look-right" }, leftArm: { rot: -48, y: -2 }, rightArm: { rot: 44, y: -2 }, prop: { particles: "question-1" } }
  f3: { t: 0.48, head: { x: -1, rot: -4 }, eyes: { variant: "half" }, mouth: { variant: "wobble" }, heart: { y: 1 } }
  f4: { t: 0.66, head: { x: 0, rot: 0 }, leftArm: { rot: -36, y: -1 }, rightArm: { rot: 36, y: -1 }, prop: { particles: "question-2" } }
  f5: { t: 0.84, leftArm: { rot: -10, y: 0 }, rightArm: { rot: 10, y: 0 }, eyes: { variant: "blink" }, mouth: { variant: "flat" } }
  f6: { t: 1.00, body: { y: 0, rot: 0 }, head: { x: 0, y: 0, rot: 0 }, eyes: { variant: "normal" }, mouth: { variant: "normal" }, leftArm: { rot: 0 }, rightArm: { rot: 0 } }
trigger: confusedIdle, invalidAction, emptyResult
exit: idle