Faces in packs and clips
Add looks, eye shapes and reaction changes to a resource pack, and key the face in any clip. Every key, value and range, with full files to copy.
-
Punchy! Studio
-
Blockbench
This page has not been translated into Brazilian Portuguese yet, so it is shown in English. Read in English
On this page
A pack can give Punchy! Moves new looks, new drawn eye shapes and a different look for a reaction, and any animation clip can change the face while it plays. This page is for pack makers. You will make a look called cheeky, an eye shape called gem and a reaction that plays the look when you start running in Punchy! Studio, and key the face in a clip in Punchy! Studio or in Blockbench. Then every key and value is listed, with complete files you can copy.
If you only want to change your own settings or your own eyes, read the Faces overview and the Face editor first.
Before you start
- Install Punchy! Moves from Modrinth or CurseForge (Getting started has the steps) and make a resource pack with a
pack.mcmeta. Create an animation shows how. - Look at your player in third person. First person draws no face.
- Use a skin with clear eyes. If the face finds no eyes on your skin, it draws no face on it, and Studio’s Face tab says so. You can mark the eyes by hand in the Face editor, and Studio uses those marks too.
- Names of looks and eye shapes use lower case letters, digits and underscores. The game lower-cases a name and turns spaces into underscores, and Studio accepts up to 48 characters.
Where the files go
A face has three kinds of parts, and a clip can add a fourth thing on top.
| What | Where it lives in a pack | What it holds |
|---|---|---|
| Looks | assets/ | A whole expression: lids, brows, pupils, marks and a shape for each eye. |
| Eye shapes | assets/ | Pixel art for an eye, in one or more colors. |
| Reaction changes | assets/ | Which look a reaction plays, and how strong the reaction is. |
| Faces in clips | In the clips of assets/ | A look held for the clip, or face channels keyed like any bone. |
The name of a look or shape is its file name without .json. Files must sit directly in looks or shapes. A file in a subfolder is not read.
Your own folder works like a pack for looks and shapes: config/punchy_moves/faces/looks and config/punchy_moves/faces/shapes. A reaction change from a player is picked in the face editor’s Test tab instead of a file.
A later layer wins by name. Your own folder wins over the packs, a pack higher in the list wins over a lower one, and all of them win over the built-in looks and shapes. Moves reads every face file when the game starts and again on each resource reload, so press F3+T after a change.
Make a face
Pick the tool you work in. The files these steps write are listed in full in The same pack as files.
In Punchy! Studio
Punchy! Studio makes every part of a face, shows it on your own skin as Punchy! Moves draws it, and writes the files for you. These steps use a pack with a wave clip, such as the one Your first pack makes in Studio. If you do not have Punchy! Studio yet, get it from Modrinth or CurseForge. The recordings below were made with the example pack provided by Crafto, Fluid & Foolish, installed in the game.
Make the look
- In Punchy! Studio, choose Third Person with the switch between the menus and the workspace tabs and open your pack. See Punchy! Studio for making or opening one.
- Open the Face tab. On the left is the Faces list with Looks, Eye shapes and Reactions. In the middle is your skin’s face, with the eyes the game found.
- Choose File > New Look (Ctrl+N), type the Name
cheekyand press Create. - Set Extends to
happy. Every part you do not set now comes from Happy. - Set Left lid to 1 for a wink, Blush to 1 and Brow tilt to -0.5. The preview shows each change as Punchy! Moves draws it.

A built-in look offers Change in Pack, which writes the pack’s own version under the same name, and New Look from This.
Draw the eye shape
- Choose File > New Eye Shape (Ctrl+Shift+N), type the Name
gemand press Create. The shape starts with empty grids for eyes one and two texels tall. - The grid opens at the eye size your skin’s eyes use. The Eye size list marks it as on your skin. Each square of the grid is half a texel.
- Set Color to Own color and type
#4FC3F7. Paint the outline of a gem on the grid with the pointer. This is color 1. - Under Colors, press + to add color 2. The new color is picked, and the picker below changes it: choose a dark blue. Click a few squares in the middle of the gem.
- Press + again for color 3, choose white and paint a glint in one corner.
- Click a swatch to paint with that color again. Right-click one for Remove color.
- Leave Mirror for the left eye ticked, so both eyes face the same way from the nose.
- Select the look
cheekyagain and set its Right eye togem. Leave the left eye as it is, winking.

For every other eye size you want the shape on, pick the size in the menu under Grid size (it reads None, left of Remove size): it adds an empty grid of that size to paint. An eye with no grid of its size takes the nearest one, kept in its middle.
Give a reaction the look
- Click Reactions in the Faces list to open it (or type in Search faces), and find Starting a run under Running and crouching.
- Set Plays to
cheeky. From now on, starting a run makes this face. - To make it outrank or give way to other reactions, tick Own priority and change Priority. Reset Reaction leaves it as the game has it.

Key the face in a clip
- Open the Animation tab and the
waveclip, and put the playhead at 0.3 s. - Go back to the Face tab, select the look
cheekyand press Key in Clip (K). The look is keyed in the clip at the playhead, held in full. - In the Animation tab, the outliner’s Face now lists Look: cheeky and Face mix, which Studio keyed with it.
- For a blink, select Lids and set its Value to 0 at 0.9 s, 1 at 1.0 s and 0 again at 1.1 s. Without the key at 0.9 s, the lids would stay shut from the start of the clip, because a channel holds its first key’s value before it.
- Turn on View > Game View and scrub the clip. Your own player shows the face, with your pack’s look and eye shape, before you export.


Export and try it
- Press Ctrl+E (File > Export to Resource Pack). In Export Punchy Moves Pack, keep Turn the pack on and reload ticked and press Export.
- The pack now has
faces/looks/cheeky.json,faces/shapes/gem.jsonandfaces/triggers.json, written as Punchy! Moves reads them, and the face keys are in the clip. - Close the editor with F6 and press F5 twice to see your player from the front. Stand still, press C and pick Wave, the emote Your first pack makes of the clip. Your player waves with the cheeky look and the blink you keyed.
- Start a run. For a moment your face is the cheeky look, this time from the reaction.

Video coming soon
The Game view plays the face keys of a clip, but it does not preview reaction changes. Export, and start a run in third person to see yours.
In Blockbench
Blockbench keys the face in a clip: a look, an eye shape or any face channel, at the playhead, with the face drawn on the rig’s head as you scrub. The look and eye shape files themselves are made in Punchy! Studio or by hand (The same pack as files), and then keyed here. A rig exported from Studio lists your pack’s own looks and eye shapes in the panel. The plain rig lists the built-in ones.
Key a look, an eye shape and a channel
- Load
punchy_moves_rig.jsand open the rig as The Blockbench rig describes. In the Moves Face panel, click Use a skin and pick your skin, a 64 by 64 PNG. The panel says which eyes it found. - Open the Animate tab and select your animation, or add one with the + button.
- With the playhead at 0, find Look in the Moves Face panel. Pick
happy, leave the number beside it at 1 and press Key. This keys the look and also Face mix at 1 when the clip has none yet. - Move the playhead to 1.0 s, set the number to 0 and press Key. The look lets go.
- Select the bone
face_shape_arc_leftin theeye_shapesfolder of the outliner, put the playhead at 1.1 s and add a position key with Y at 0. Without it the wink would show from the start of the clip, because a channel holds its first key’s value before that key. - Move to 1.2 s. Under Eye shapes, pick
arcfor Left eye and press Key. The head shows a wink. To let the shape go, put the playhead at 1.8 s and add a position key with Y at 0 on the same bone. - Under Channels at the playhead, put the playhead at 0 and press the Key of Pupils with both sliders at 0. Move to 1.8 s, drag the X slider of Pupils to 1 and press its Key. Move to 2.0 s, drag it back to 0 and press Key again.
- Press play to check the face. When you are done, choose Animation > Export Animations and save into your pack’s
assets/punchy_moves/animationsfolder.

Video coming soon
The file Blockbench writes holds the face as bones whose names start with face_, in the clip next to the body bones. Faces in clips lists every one.

The same pack as files
This is the same pack as the steps above, written by hand. It holds the look with the face key of the clip, which plays the same as the face_look_cheeky and face_mix keys the steps make. Put it in your resourcepacks folder as my_first_pack, or add the faces folder and the changes to the pack from Getting started.
my_first_pack/
pack.mcmeta
assets/
punchy_moves/
animations/
wave.json
compat/
emotes.json
faces/
looks/
cheeky.json
shapes/
gem.json
triggers.json
pack.mcmeta, with the resource format of Minecraft 1.21.11. On another version, put that version’s number from the table on Resource packs in place of the 75s:
{
"pack": {
"description": "My first Punchy Moves pack",
"pack_format": 75,
"min_format": 75,
"max_format": 75
}
}
faces/shapes/gem.json, an eye shape in three colors:
{
"closed": false,
"color": "#4FC3F7",
"colors": { "2": "#0D47A1", "3": "#FFFFFF" },
"on_white": false,
"mirror": true,
"grids": {
"4x2": [".##.", "#23#"],
"4x4": [".##.", "#22#", "#23#", ".##."]
}
}
faces/looks/cheeky.json, a look that uses it:
{
"extends": "happy",
"lid_left": 1,
"blush": 1,
"tilt": -0.5,
"eyes": ["gem", "open"]
}
faces/triggers.json, which makes starting a run play the look:
{
"kickoff": "cheeky"
}
animations/wave.json, the wave clip with the look held for its whole length and one blink at 1 second:
{
"format_version": "1.8.0",
"animations": {
"wave": {
"animation_length": 1.2,
"loop": true,
"face": "cheeky",
"bones": {
"right_arm": {
"rotation": {
"0": [0, 0, 0],
"0.3": [0, 0, 140],
"0.6": [0, 0, 110],
"0.9": [0, 0, 140],
"1.2": [0, 0, 0]
}
},
"head": {
"rotation": { "0.3": [0, 0, 8] }
},
"face_lids": {
"position": { "0.0": [0, 0, 0], "0.9": [0, 0, 0], "1.0": [0, 1, 0], "1.1": [0, 0, 0] }
}
}
}
}
}
compat/emotes.json, which puts the clip on the emote wheel:
{
"format_version": "2",
"defaults": { "animations": {} },
"emotes": {
"entries": [
{ "id": "wave", "display_name": "Wave", "animation": "wave" }
]
}
}
- In the game, open Options, then Resource Packs, move my_first_pack to the right-hand list and press Done. Press F3+T if the game was already running.
- Switch to third person with F5. Start a run: the face turns cheeky for a moment, with the left eye winking and the right eye the blue gem.
- Stand still and press C to open the emote wheel. Pick Wave. Your player waves with the cheeky face and blinks at 1 second.
Video coming soon
Looks
A look is one JSON file in faces/looks. Every key is optional, and a key you leave out keeps its value from the look you extend, or 0.
| Key | Type | Default | What it does | Example |
|---|---|---|---|---|
extends | look name | none | Starts from another look: one in a pack or a built-in one. A look in your own folder can also start from a pack's look, but a pack's look cannot start from one in your own folder. Every part the look does not set comes from it. An unknown name leaves this look out. | "excited" |
lids | number, 0 to 1 | 0 | Both top lids, from open (0) to shut (1). | |
lid_right | number, 0 to 1 | 0 | The avatar's right eye shut at least this far. A wink is one lid at 1. | 1 |
lid_left | number, 0 to 1 | 0 | The avatar's left eye shut at least this far. | 1 |
slant | number, -1 to 1 | 0 | The lids step down toward the nose (positive, a cross look) or away from it (negative, a sad look). | 0.8 |
lower | number, 0 to 1 | 0 | The lower lids rise. | |
cheeks | number, 0 to 1 | 0 | The cheeks push the lower lids up, as in a smile. A value above 1 adds nothing. | |
wide | number, 0 to 1 | 0 | The whites of the eyes grow upward, by up to 1 texel. A value above 1 adds nothing. | |
pupils | [x, y] | center | Where the pupils sit, in texels. x is toward the avatar's left and y is up. Both numbers are needed. | [0.5, 0.25] |
swing | number | 0 | The pupils swing from side to side on their own. Not clamped. | 0.3 |
tremble | number | 0 | The pupils shake. Not clamped, and scaled by 0.25 when drawn. | 0.4 |
brows | number or [right, left] | 0 | One number moves both brows, up when positive, in texels. An array is the avatar's right brow and then the left, and it must hold two numbers. | [1, 0] |
brow_right | number | 0 | The right brow alone, in texels, up positive. | |
brow_left | number | 0 | The left brow alone, in texels, up positive. | |
tilt | number, -1 to 1 | 0 | The inner ends of the brows go up (positive, worried) or down (negative, cross). | -1 |
blush | number, 0 to 1 | 0 | Pink cheeks. | |
tears | number, 0 to 1 | 0 | Tears running from the eyes. Past 0.35 a drop also falls. | |
sweat | number, 0 to 1 | 0 | A drop of sweat on the forehead. It shows past 0.35. | |
bags | number, 0 to 1 | 0 | Dark rings under the eyes. | |
anger | number, 0 to 1 | 0 | The anger vein on the forehead. It shows past 0.35. | |
sparkle | number, 0 to 1 | 0 | A second glint low in each pupil. It shows past 0.35, and only while the player has Eye sparkle on Line or Dot. | |
bob | number | 0 | The brows bob to a beat. Not clamped, and scaled by 0.3 when drawn. | |
eyes | shape name or [right, left] | open | The shape each eye takes. One name sets both eyes. An array sets the avatar's right eye and then the left, and must hold two names. open is the painted eye and blank is its white alone. A name that is not a known shape leaves the look out. | ["gem", "open"] |
blink | number, 0 or more | none (the pace of the look it extends, else the usual pace) | How often the eyes blink while the look plays. 1 is the usual pace, 0 never blinks and a bigger number blinks more often. A negative number counts as 0. |
The right eye is the avatar’s own right, which is the left half of the face on the skin file. Other keys in a look file are ignored, so a misspelled key changes nothing. A look that cannot be read is left out, and the rest of the pack’s looks still load.
Three looks to copy
faces/looks/gleam.json, wide eyes with a glint and slow blinks:
{
"extends": "happy",
"wide": 1,
"pupils": [0.5, 0.25],
"sparkle": 1,
"blink": 0.5
}
faces/looks/mismatch.json, a heart in one eye, one brow raised:
{
"eyes": ["heart", "open"],
"brows": [1, 0],
"tilt": 0.5,
"swing": 0.3
}
faces/looks/grumble.json, a grumpy, tired face:
{
"extends": "neutral",
"lids": 0.3,
"slant": 0.8,
"lower": 0.4,
"bags": 1,
"tilt": -1,
"anger": 1,
"tremble": 0.4,
"blink": 0.6
}
The looks that come with Moves
There are 40, in the editor’s order: neutral, happy, joyful, excited, sparkly, love, proud, smug, relaxed, zen, wink, sly, sneaky, curious, focused, squint, determined, furious, menacing, strain, surprised, shocked, scared, nervous, worried, sad, crying, pain, wince, dizzy, knocked, sick, tired, sleepy, bored, cold, hot, blinded, wary and shut.
These short names also work anywhere you type a look: cross, calm, flutter, narrow, wink_left, wink_right, startled, glum, uneasy, cheery, intent, aghast, hurting, drowsy, laugh, angry, glance_left and glance_right.
A look in your pack with a built-in name replaces the built-in look wherever a reaction plays it unchanged. Save a happy.json and the reactions that play Happy as it is play yours. A reaction that adjusts Happy, such as looking toward something or blinking at a changed pace, keeps the built-in one.
Eye shapes
An eye shape is pixel art that replaces an eye while a look or a clip asks for it. It is one JSON file in faces/shapes, with one drawing for each eye size.
Moves has nine shapes of its own: open (the eye as the skin paints it), line (shut, a single line), arc (a smile’s arch), cup (a cup), press (squeezed shut, shown as > <), cross (an x), spiral, heart and blank (the eye’s white alone). line, arc, cup, press and cross are closed shapes. A pack or a player can redraw any of them under its own name, except open and blank, and every look that uses the shape then draws the new one.
| Key | Type | Default | What it does | Example |
|---|---|---|---|---|
gridsRequired | object | One drawing per eye size, in half texels. Each key is <columns>x<rows>, both from 1 to 16, and each value is a list of row texts. The number of rows and the width of every row must match the key, or the shape is left out. | { "4x2": [". | |
color | "line" or #RRGGBB | line | What # paints, called color 1. line is the eye's line color, so the shape follows every skin and the player's Line color of closed eyes. A hex color, with or without #, is fixed. Text that is not a hex color leaves the shape out. | "#4FC3F7" |
colors | object | none | Up to eight more colors, named by the digit the grids paint them with, from "2" to "9". Each is a hex color. A digit with no color here paints nothing. | { "2": "#0D47A1", "3": "#FFFFFF" } |
closed | boolean | false | The eye is closed in this shape, so blinks pass it by: no blink lid is drawn over it, and a change between two closed shapes skips the quick blink. | |
on_white | boolean | false | The box under the drawing is the eye's white instead of the lid's skin. | |
mirror | boolean | true | The avatar's left eye shows the drawing mirrored, so both eyes face the same way from the nose. An eye in the middle is never flipped. |
Grids
A grid is a picture of the eye’s box. Each square is half a texel of the skin. The key says how many squares wide and tall: 4x2 is an eye two texels wide and one tall, 4x4 is two by two, and 4x3 is two wide and one and a half tall. Studio marks the size your skin’s eyes use in its Eye size list.
Give a grid for every size you want the shape on. An eye with no grid of its size takes the nearest grid, kept in its middle.
The box is filled with the lid’s skin (or the eye’s white, with on_white), and the squares you paint go over it. Each character of a row is one square:
| Character | What it paints |
|---|---|
. | Nothing. The box shows through. |
# | The shape’s own color, color 1 from color. |
X, x, 1, o, O, * | The same as #. |
2 to 9 | The color of that digit from colors. A digit with no color paints nothing. |
| Any other character | Nothing. |
Colors 2 to 9
Color 1 is the color key. Colors 2 to 9 are the colors object, so a shape can use nine colors in all. Write each as exactly six hex digits, with or without #, such as #FFD447. A three digit color is read with zeros in front (#FD4 becomes 000FD4, a dark blue). A color of more than six digits is not read as red, green, blue and alpha: depending on its digits it either leaves the shape out or is read as its last six digits.
This shape, faces/shapes/rainbow.json, uses all eight extra colors, one for each digit:
{
"closed": false,
"color": "line",
"colors": {
"2": "#FF4D4D",
"3": "#FF9F43",
"4": "#FFD447",
"5": "#A6F2B8",
"6": "#5FF2E0",
"7": "#4FC3F7",
"8": "#CFB2FF",
"9": "#FFA8D2"
},
"mirror": true,
"grids": {
"4x2": ["2345", "6789"],
"4x4": ["2345", "2345", "6789", "6789"]
}
}
Redraw a built-in shape
Save a shape under a built-in name and Moves draws yours instead, everywhere the shape plays. This faces/shapes/arc.json redraws the smile’s arch with your own pixels. It is a closed shape, and its line follows each skin’s line color:
{
"closed": true,
"color": "line",
"grids": {
"4x2": [".##.", "#..#"],
"4x4": ["....", ".##.", "#..#", "#..#"]
}
}
A shape drawn on the white, faces/shapes/ring.json, a dark ring on the eye’s white:
{
"closed": false,
"color": "#2A2A2A",
"on_white": true,
"grids": {
"4x4": [".##.", "#..#", "#..#", ".##."]
}
}
Reaction changes
faces/triggers.json changes what a reaction plays. Each key is a reaction’s id, and the full list with each id and priority is on Face reactions. The value is a look name, or an object with look and priority.
| Key | Type | Default | What it does | Example |
|---|---|---|---|---|
<reaction id>Required | string or object | A look name, or an object with the keys below. The id is the one in Face reactions. | "kickoff": "cheeky" | |
look | look name | the reaction's own look | The look the reaction plays when it applies. A name that is not found keeps the reaction's own look. | "cheeky" |
priority | whole number | the reaction's own priority | How strong the reaction is. The strongest reaction that applies sets the whole look, so a bigger number wins. | 900 |
This file is valid as it stands:
{
"kickoff": "cheeky",
"munch": { "look": "gleam" },
"shear": { "look": "cheeky", "priority": 900 },
"sneak": { "priority": 500 }
}
Starting a run (kickoff) plays cheeky. Eating (munch) plays gleam at its own priority. Shearing (shear) plays cheeky at 900, which is above Eating at 850, where it was 785. Sneaking (sneak) keeps its look and rises from 385 to 500.
Every pack’s triggers.json counts. When two packs change the same reaction, the higher pack wins, and its entry replaces the lower one whole, priority included. The player’s own pick in the face editor’s Test tab wins over a pack’s change, and the player’s reaction switches still turn reactions on and off.
Faces in clips
Any clip can carry a face, in two ways that mix: hold a look for the whole clip, or key face channels like any other bone. Face keys are read from the clips in a pack’s animations folders.
Hold a look
The face key of a clip takes a look’s name, or an object with look and mix.
| Key | Type | Default | What it does | Example |
|---|---|---|---|---|
face | look name or object | none | A look held for the whole clip. A name is trimmed, lower-cased and its spaces become underscores. A blank name does nothing. | "sleepy" |
face.look | string | The look's name. It must be text. | "proud" | |
face.mix | number, 0 to 1 | 1 | How much of the face the clip takes over from the reactions. 1 is all of it, so the face is only the look. | 0.8 |
{
"format_version": "1.8.0",
"animations": {
"wake_up": {
"animation_length": 2.5,
"face": "sleepy",
"bones": {
"head": { "rotation": { "0.0": [12, 0, 0], "2.5": [0, 0, 0] } }
}
},
"proud_pose": {
"animation_length": 2.0,
"face": { "look": "proud", "mix": 0.8 },
"bones": {
"head": { "rotation": { "0.0": [0, 0, 0], "1.0": [-6, 0, 0], "2.0": [0, 0, 0] } }
}
}
}
}
This is a shorthand for two face bones held for the whole clip: face_mix at mix and face_look_<name> at 1. A face bone that the clip keys itself replaces the shorthand’s.
Key face channels
The face is a set of bones named face_... in the same clip, keyed like any other bone. You need no cubes. Moves reads each bone’s position and uses its Y value, and the pupils use X as well. Rotation and scale of a face bone are not read. A bone you do not key stays at 0 and leaves the face alone.
A face key takes lerp_mode and easing like any other key. To use them, write the key as an object, as in the last example below. A key written as an array is always linear. The values are the face’s own units, shares of an eye and texels on the skin, not model pixels, so the same keys work on every skin.
A bone held for the whole clip can be written as one array, inside the clip’s bones object:
{
"bones": {
"face_mix": { "position": [0, 1, 0] }
}
}
Or keyed over time, with the time in seconds as the key:
{
"bones": {
"face_cheeks": {
"position": { "0.0": [0, 0, 0], "0.3": [0, 1, 0], "1.0": [0, 1, 0], "1.3": [0, 0, 0] }
}
}
}
To ease into a key, write that key as an object with post for the value and easing for the curve (the curves are listed in Animation files). The easing shapes the move that ends on that key:
{
"bones": {
"face_cheeks": {
"position": {
"0.0": [0, 0, 0],
"0.3": { "post": [0, 1, 0], "easing": "easeInOutSine" },
"1.0": [0, 1, 0],
"1.3": [0, 0, 0]
}
}
}
}
| Key | Type | Default | What it does | Example |
|---|---|---|---|---|
face_mix | position Y, 0 to 1 | 0 | How much of the face the clip takes over from the reactions. At 0 your keys add to the reactions' face. At 1 the face is only what the clip keys. | |
face_ | position Y, 0 to 1 | 0 | How much of a look the clip holds. The name is a look of your own folder, of a pack, or a built-in look or short name. Key two looks to cross fade between them. Weights add up when two bones name the same look, and a look that does not exist is skipped. | face_ |
face_ | position Y | 0 | That eye takes the shape while the value is above 0.5. The strongest shape wins. A shape bone with no side sets both eyes. A shape that does not exist is skipped. | face_ |
face_lids | position Y, 0 to 1 | 0 | Both top lids, added on top of the looks. | |
face_ | position Y, 0 to 1 | 0 | One eye shut at least this far. | |
face_slant | position Y, -1 to 1 | 0 | Lid slant, as the look key. | |
face_ | position Y, 0 to 1 | 0 | Lower lids, cheeks and wide eyes, as the look keys. Cheeks and wide stop at 1. | |
face_tilt | position Y, -1 to 1 | 0 | Brow tilt, as the look key. | |
face_ | position X and Y, in texels | 0, 0 | The pupils. Positive X is toward the avatar's left and positive Y is up. | [1, 0, 0] |
face_brows | position Y, in texels | 0 | Both brows, up when positive, down when negative. | |
face_ | position Y, in texels | 0 | One brow. | |
face_ | position Y | 0 | Pupil sway, tremble and brow bob, as the look keys. | |
face_ | position Y, 0 to 1 | 0 | The marks, as the look keys. | |
face_ | position Y | 0 | Above 0.5, the face's own blinks stop. Use it for a clip that keys every blink itself. |
How a clip’s face adds up
Each frame, every part of the face is the reactions’ look, less the share that face_mix takes over, plus each held look by its weight, plus the keyed parts. In numbers: part = (1 minus mix) times the reactions’ value, plus the keyed value. Say the reactions show blush 0.5, and a clip keys face_mix at 0.5 and face_blush at 0.5. The blush is 0.5 times 0.5, plus 0.5, which is 0.75. With face_mix at 1 it would be just 0.5. For the parts that have a range, the sum is clamped when the face is drawn, so a blush of 1.4 shows as 1.
With no face_mix, keyed parts simply add to whatever face the reactions show, such as an extra blink or a raised brow.
Each eye shows the strongest shape the clip keys past 0.5. If it keys none, then while face_mix is past 0.5 the eye takes the shape of the strongest held look, and otherwise the shape the reactions show. While face_mix is past 0.5 the face blinks at the pace of the strongest held look, the usual pace if that look sets none.
A clip’s face shows over every reaction up to a long fall and a hard landing. Only a swelling creeper, a warden, the hurt startle, sleeping and dying show over it. The face eases in and out with the clip.
Clips to copy
cheer holds Happy for a second, winks with a smile, then looks cross. Each channel’s first key holds a value of 0 on purpose (in cheer, face_look_happy starts at 1 to hold Happy from the first frame): a channel holds its first key’s value before that key, so nothing shows until the move starts.
{
"format_version": "1.8.0",
"animations": {
"cheer": {
"animation_length": 3.0,
"bones": {
"face_mix": { "position": { "0.0": [0, 0, 0], "0.2": [0, 1, 0], "2.7": [0, 1, 0], "3.0": [0, 0, 0] } },
"face_look_happy": { "position": { "0.0": [0, 1, 0], "1.0": [0, 1, 0], "1.2": [0, 0, 0] } },
"face_shape_arc_left": { "position": { "1.2": [0, 0, 0], "1.25": [0, 1, 0], "1.8": [0, 1, 0], "1.85": [0, 0, 0] } },
"face_cheeks": { "position": { "1.2": [0, 0, 0], "1.3": [0, 1, 0], "1.8": [0, 1, 0], "1.9": [0, 0, 0] } },
"face_brows": { "position": { "1.9": [0, 0, 0], "2.2": [0, -0.75, 0], "2.7": [0, 0, 0] } },
"face_tilt": { "position": { "1.9": [0, 0, 0], "2.2": [0, -1, 0], "2.7": [0, 0, 0] } },
"face_anger": { "position": { "2.0": [0, 0, 0], "2.1": [0, 1, 0], "2.5": [0, 1, 0], "2.6": [0, 0, 0] } }
}
}
}
}
look_around has no face_mix, so its keys add to the face the reactions show. The pupils glance left, then right, and the brows rise at the first glance:
{
"format_version": "1.8.0",
"animations": {
"look_around": {
"animation_length": 3.0,
"bones": {
"head": { "rotation": { "0.0": [0, 0, 0], "1.0": [0, 20, 0], "2.0": [0, -20, 0], "3.0": [0, 0, 0] } },
"face_pupils": { "position": { "0.0": [0, 0, 0], "1.0": [1, 0, 0], "2.0": [-1, 0, 0], "3.0": [0, 0, 0] } },
"face_brows": { "position": { "0.0": [0, 0, 0], "1.0": [0, 0.5, 0], "1.5": [0, 0, 0] } }
}
}
}
}
slow_blinks stops the face’s own blinks and keys two blinks itself:
{
"format_version": "1.8.0",
"animations": {
"slow_blinks": {
"animation_length": 3.0,
"bones": {
"face_blink_off": { "position": [0, 1, 0] },
"face_lids": {
"position": {
"0.0": [0, 0, 0],
"0.8": [0, 0, 0],
"1.2": [0, 1, 0],
"1.6": [0, 0, 0],
"2.2": [0, 0, 0],
"2.6": [0, 1, 0],
"3.0": [0, 0, 0]
}
}
}
}
}
}
mood_swing cross fades from Sad to Happy, then turns both eyes into hearts. It uses face_mix at 1, so the face is only what the clip keys:
{
"format_version": "1.8.0",
"animations": {
"mood_swing": {
"animation_length": 3.0,
"bones": {
"face_mix": { "position": [0, 1, 0] },
"face_look_sad": { "position": { "0.0": [0, 1, 0], "1.0": [0, 1, 0], "1.5": [0, 0, 0] } },
"face_look_happy": { "position": { "0.0": [0, 0, 0], "1.0": [0, 0, 0], "1.5": [0, 1, 0], "3.0": [0, 1, 0] } },
"face_shape_heart": { "position": { "2.0": [0, 0, 0], "2.05": [0, 1, 0], "2.6": [0, 1, 0], "2.65": [0, 0, 0] } }
}
}
}
}
A clip only plays when a compat file points to it, for example as an emote. See Compat files and Animation files.
Emotes and looks
An emote can name a look that plays with it: "face": "happy", or "expression". An emote with no face plays Happy.
The name is matched exactly as typed, in lower case, against the built-in looks and their short names, such as wink_left and wink_right. A capital letter, a space or a look that only your pack defines plays Happy. If your pack redraws a built-in look under its name, your version plays, except for the short names wink_right, flutter, glance_left and glance_right, which always play the built-in drawing.
To play a look that is new in your pack with an emote, name it in the emote’s clip with face, as wave does above. Only your own player’s emotes carry a face. See Keys and emotes and Compat files.
{
"format_version": "2",
"emotes": {
"entries": [
{ "id": "wink", "display_name": "Wink", "animation": "wink_clip", "face": "wink_left" },
{ "id": "doze", "display_name": "Doze", "animation": "wake_up", "face": "sleepy" }
]
}
}
The first entry needs a clip named wink_clip in your animations, and the second uses the wake_up clip from above. An emote whose clip is not loaded does not reach the wheel.
Values and ranges
Units are the face’s own. A share is 0 to 1 of the way, and a texel is one pixel of the skin’s face.
| Part | Keys | Range and unit |
|---|---|---|
| Lids | lids, lid_right, lid_left | 0 to 1, open to shut. |
| Lid slant | slant | -1 to 1. Positive steps down toward the nose, negative away from it. |
| Lower lids | lower | 0 to 1. |
| Cheeks | cheeks | 0 to 1. Above 1 adds nothing. |
| Wide eyes | wide | 0 to 1, in texels. Above 1 adds nothing. |
| Pupils | pupils, face_ | Texels. X is toward the avatar’s left, Y is up. The Blockbench panel’s sliders run from -2 to 2. |
| Brows | brows, brow_right, brow_left, face_brows | Texels, up positive. A negative value lowers the brow. |
| Brow tilt | tilt | -1 to 1. Positive raises the inner ends (worried), negative lowers them (cross). |
| Pupil sway, tremble, bob | swing, tremble, bob | Not clamped. Tremble is scaled by 0.25 and bob by 0.3 when drawn. 1 is a full effect. |
| Marks | blush, tears, sweat, bags, anger, sparkle | 0 to 1. sweat, anger and the glint from sparkle show past 0.35, and tears add a falling drop past 0.35. |
| Blink pace | blink | 0 or more. 1 is usual, 0 never. |
| Clip mix | face.mix, face_mix | 0 to 1. |
| Look weight | face_ | 0 to 1. |
| Shapes and no blinks | face_, face_, face_ | Active above 0.5. |
| Reaction priority | priority | A whole number. The biggest one that applies wins. |
Lids, lower lids, cheeks, wide eyes, lid slant, brow tilt and the marks act as the nearest end of their range when the face is drawn, so a stray 1.4 on a lid is a closed lid. Pupil sway, tremble and bob are not clamped. Pupils and brows take any number, but the drawing stops them: a pupil is drawn only inside its eye, and toward the outer corner it can slide 0.3 texel further than its room, narrowing against the edge. A brow stops at the top of the face and never drops over more than half of its eye.
Things that go wrong
A file is left out
- A look is missing. It was left out because
extendsnames an unknown look,eyesnames an unknown shape or has fewer than two names in an array,pupilsorbrowshas too few numbers, or a value is not a number. The other looks still load. - An eye shape is missing. It has no
grids, a grid whose rows do not match its key, a size outside 1 to 16, or acolororcolorsvalue that is not a hex color. A shape namedopenorblankis refused, because those two cannot be redrawn. - None of a file’s reaction changes work. A
triggers.jsonthat does not parse, or that has an entry whosepriorityis not a number or whoselookis an object, is skipped whole. An entry whose value is a list ornullis skipped on its own. - The rest of an animation file is lost. A clip’s
faceobject whoselookis an object, an empty list or a list of several items stops that clip and the rest of its file. The clips before it stay. Writelookas text in quotes. - A file is in a subfolder. Looks and shapes are read only directly in
faces/looksandfaces/shapes.
Unreadable looks, eye shapes and triggers.json files in a pack are named in the game’s log, in messages that start with Face:. Search logs/latest.log for Face:. Files in your own folder are named only when the game starts. Press F3+T after a fix.
A clip file that stops this way is not named in the log, so check that the face of each clip is text, or an object whose look is text.
To see one for yourself, copy faces/looks/grumble.json from Three looks to copy into my_first_pack/assets/punchy_moves/faces/looks/, next to cheeky.json. In the copy, delete the last line, the closing }. Press F3+T, then search logs/latest.log for Face:. The line names punchy_moves:faces/looks/grumble.json and says why it could not be read. Each line in the log starts with a time and the thread, so read the whole line. Put the brace back and press F3+T again to load the look.
Video coming soon
Nothing shows
- The face does not change. A reaction id that is not in the reaction list, or spelled differently, changes nothing. A look name in
triggers.jsonthat no look has keeps the reaction’s own look. - A clip’s face is hidden. A creeper about to blow, a warden, a hit, sleeping and dying show over a clip’s face.
- A clip’s look mixes with the reactions’ face. Without
face_mixa held look adds to what the reactions show. Keyface_mixat 1 with the look, or useface, which does it for you. - The lids stay shut. A channel holds its first key’s value before that key. Key the channel at 0 at the start of the clip, then key the move.
- A misspelled channel does nothing. A bone named
face_cheekinstead offace_cheeksis kept and changes nothing on the face. In a clip with noanimation_length, its keys still count toward the clip’s length. - An emote shows Happy. The emote’s
faceonly knows built-in look names, in lower case. Name your own look in the clip withface. - No face at all. First person draws none, and a skin the face finds no eyes on has none. See the Face editor.
Colors go wrong
- A color comes out dark. It has three digits, which are read with leading zeros. Write six, such as
#FFD447. - A color has the wrong hue. It has eight digits starting with 0 to 7, and only the last six are read. Write six.
- A shape disappears. A color that is not hex, an eight digit color starting with 8 to F (such as
#FF4FC3F7, with the alpha first), a longer color too large to read, or a missinggridsleaves the shape out. - A digit in a grid paints nothing. The shape’s
colorshas no color for that digit.
Related pages
- Faces overview for how the face is drawn and which settings a player has.
- Face reactions for every reaction, its id and its priority.
- Face editor for marking eyes and testing looks and reactions.
- The face marker for skin makers.
- Punchy! Studio and Game view to make and watch faces on your own player.
- The Blockbench rig for keying the face in Blockbench.
- Animation files and Compat files for the clips and the files that play them.
- Keys and emotes for the emote wheel.
Last checked against the mod on 30 October 2026.