Under construction. Dont look or else!
Preface
The new poser
JSON controls all the animations of a Pokémon just as the old Poser did. It contains the same information for when the Pokémon will perform certain animations, but has received many requested upgrades. Some of these upgrades include multi-bone look animations, support for move animations, and even selecting from a pool of animations for quirks. Functionality of the new Poser will always be maintained and should let addon creators have the same options as the hard-coded Kotlin Posers.
Poser Properties
Before breaking down each section of the new Poser file, let's take a look at all its different properties and how to use them. This section includes all of the different functions of the poser, any configurable options for said function, and how to write each function.
Poses & Animations
There's a handful of Pose types and Animation types that you can make animations for. Poses
are the states a Pokémon is in, like idle or moving. Poses are for assigning animations like your ground idles, ground walks, water idles, etc. The animation types
are the different events in battles that you can assign animations to for each Pokémon. Animation types would include your faints, cries, and attack animations. Below is a list of currently available Animation types and Poses to choose from.
Animations
- faint:
animation.<pokemon>.faint
- The animation that plays when a Pokémon faints. - cry:
animation.<pokemon>.cry
- The animation that plays when a Pokémon is called out or when it starts battle. - recoil:
animation.<pokemon>.recoil
- The animation that plays when a Pokémon takes damage in battle. - physical:
animation.<pokemon>.physical
- The animation that plays when a Pokémon uses a physical move in battle. - special:
animation.<pokemon>.special
- The animation that plays when a Pokémon uses a special move in battle. - status:
animation.<pokemon>.status
- The animation that plays when a pokemon uses a status move in battle.
Poses
- "STAND":
animation.<pokemon>.ground_idle
- The animation that plays when a Pokémon is idle on land.- This pose type is also used for battle-idles:
animation.<pokemon>.battle_idle
- This pose type is also used for battle-idles:
- "PORTRAIT":
animation.<pokemon>.portrait
- The animation that plays in the Party Overlay, or left hand party GUI- This pose often uses the
ground_idle
instead of a dedicated animation.
- This pose often uses the
- "PROFILE":
animation.<pokemon>.profile
- The animation that plays in the Party Menu, or when you press M.- This pose often uses the
ground_idle
instead of a dedicated animation.
- This pose often uses the
- "WALK":
animation.<pokemon>.ground_walk
- The animation that plays when a Pokémon is moving on land - "HOVER":
animation.<pokemon>.air_idle
- The animation that plays when a Pokémon is idle in the air. - "FLY":
animation.<pokemon>.air_fly
- The animation that plays when a Pokémon is moving in the air. - "FLOAT":
animation.<pokemon>.water_idle
- The animation that plays when a Pokémon is idle in or on water. - "SWIM":
animation.<pokemon>.water_swim
- The animation that plays when a Pokémon is moving in or on water. - "SLEEP":
animation.<pokemon>.sleep
- The animation that plays when a Pokémon is asleep. Usually on land. - "SHOULDER_LEFT":
animation.<pokemon>.shoulder_left
- The animation that plays when the Pokémon is on the player's left shoulder. - "SHOULDER_RIGHT":
animation.<pokemon>.shoulder_right
- The animation that plays when the Pokémon is on the player's right shoulder.
q.bedrock_stateful
The function q.bedrock_stateful()
allows you to assign a stateful animation to an animation type. Stateful animations
are meant to animate just a few bones of the Pokémon and get overlaid on the current pose. An example would be cries only animating the mouth or head of the Pokémon. A stateful animation won't take control of the whole model to play its animation.
Here is an example of the 2 stateful animations, cry and recoil, in the poser:
"cry": "q.bedrock_stateful('blastoise', 'cry')", "recoil": "q.bedrock_stateful('blastoise', 'recoil')",
q.bedrock_primary
The function q.bedrock_primary()
allows you to assign a primary animation to an animation type. Primary animations
are meant to take control of the entire model to play its animation and will clear any previous animations it was doing. An example would be a Pokémon's physical attack animation. When a Pokémon uses a physical move, it should clear the battle idle animation and play its physical animation instead. These animations often move the whole body and many of its limbs. When the physical animation is done, it returns control of the model to the battle idle after the physical animation has finished and should play a short transition animation in between.
Since Primary animations behave in a similar way to swapping poses, they can use special transition animation types via the q.curve
property written within its sub properties. These provide different types of smoothness to the interpolation and will be explained in the next section.
Below is an example of the 4 primary animation in the poser:
"faint": "q.bedrock_primary('blastoise', 'faint', q.curve('one'))", "physical": "q.bedrock_primary('blastoise', 'physical', q.curve('symmetrical_wide'))", "special": "q.bedrock_primary('blastoise', 'special', q.curve('symmetrical_wide'))", "status": "q.bedrock_primary('blastoise', 'status', q.curve('symmetrical_wide'))"
q.curve
The function q.curve()
is a sub function for q.bedrock_primary()
which allows the animation to interpolate back into the main pose. This allows the transition between animations to behave similarly to linear keyframes and smooth keyframes when animating.
The q.curve function comes with 3 options for now which are:
one
: Does not interpolate at all. Just jumps from one animation to the next. Preferred for faint animations.symmetric
: Interpolates in a similar fashion to 2 smooth keyframes in blockbench. Not preferable, but is an option.symmetrical_wide
: Interpolates in a similar fashion to 2 smooth keyframes in blockbench, but with a wider margin. The preferred choice when transitioning from moves.
Below is an example of the 2 main q.curve types:
"faint": "q.bedrock_primary('blastoise', 'faint', q.curve('one'))", "physical": "q.bedrock_primary('blastoise', 'physical', q.curve('symmetrical_wide'))",
Portraits and Profiles & Scale and Translation
Portrait and Profile are the poses that are used when rendering any Pokémon in a GUI or Menu. Portrait is used for the left hand party screen, or Party Overlay, and Profile is used for the Party Menu. The poser file assigns some Scale
and Translation
values to these poses which control the camera location for rendering the Pokémon. There is a dev tool that you can enable in the Config which allows you to use some customizable keys to move the camera around the Pokémon in these menus. This tool will print the Scale and Translation values when the associated hotkey is pressed.
Translation
values control the location of the camera for the Portrait or Profile. Translation is a set of 3 values which represent xyz coordinates. You will mainly be changing the first 2 values, or the x and y axis values. X for left and right, and Y for up and down. The Z value is rarely used, but is important for really big models that are not being fully rendered in the menus. It often needs a larger Z value.
Scale
values control the amount of zoom for the Portrait or Profile. A value less than one should make it zoom out and a value greater than one will zoom in. Sometimes with larger models, the camera cannot render the whole Pokémon no matter how far you zoom out. The back side of the Pokémon may not be rendered. This means you need to increase the Translation z value.
Below is a short breakdown of the previously mentioned properties:
"portraitScale": 1.65, "portraitTranslation": [0, -0.6, 0], "profileScale": 1, "profileTranslation": [0, 0.15, 0],
Conditions
You can expand the amount of animations a Pokémon can have and when they should be played by using conditions
. Conditions are what allow for battle animations despite the standing
and battle-idle
poses both using the "STAND"
pose type. Typically, if you want different animations using the same pose types, then you must set one pose's condition to true, and the other pose's matching condition to false. You can mix and match these conditions to make something like an animation that only plays in battle, if it is raining while the sun is setting.
List of Currently Implemented Conditions:
"isBattle"
: The Pokémon must be in a battle."isTouchingWater"
: The Pokémon must be touching water. Not necessarily underwater."isTouchingWaterOrRain"
: The Pokémon must be touching water or rain. Again, not necessarily underwater."isSubmergedInWater"
: The Pokémon must be underwater. The red line on the hitbox must be below the surface."isStandingOnRedSand"
: The Pokémon must be standing on red sand."isStandingOnSand"
: The Pokémon must be standing on sand"isStandingOnSandOrRedSand"
: The Pokémon must be standing on either sand or red sand."isDusk"
: It must be "Dusk" time in the world, or roughly at sunset.
Below is an example of 2 poses using the "STAND"
pose type and Conditions
to separate the battle-idle animation from the ground idle animation:
- In these scenarios, you want one pose to have the condition set to true, and any other pose that shares the same pose type to have the condition set to false.
"battle-standing": { "poseTypes": ["STAND"], "isBattle": true, "animations": [ "q.bedrock('blastoise', 'battle_idle')" ] }, "standing": { "poseTypes": ["STAND", "NONE", "PORTRAIT", "PROFILE"], "isBattle": false, "animations": [ "q.bedrock('blastoise', 'ground_idle')" ] },
Transformed Parts
This function allows you to transform parts of the model when the Pokémon is in a certain pose. You can change the location, rotation, and visibility of bones for each pose. This allows you to make some slight adjustments to an in-game animation without having to edit the animation itself. While there aren't many examples of this function, it's most common use is to hide model parts when a Pokémon is not in its battle idle. This is the case with Rillaboom and its drum.
A great use for location and rotation transformation is to adjust shoulder animations. You don't have to account for the model location on the player shoulder when making the animation. If it doesn't line up in the game, you can move the whole model using this function.
The visibility transformation allows you to hide a specific bone in the model when the Pokémon is currently in a pose. This can be used to hide certain bones if needed. This allows you to do things like making Rillaboom use its drum for its battle-idle. It also allows Typhlosion to have its flames ignited only during battle. Something to keep in mind is that if you want a bone to be visible only during battle, then you must set this bone as invisible for all other poses. This is why transformedParts
is written under every pose in the poser file breakdown.
Below is an example of all the transformed part properties being used. This is mostly a demonstration of your options when using this function. If this example was applied in game, Charizard's wings would be detached from its body, but only the left wing would be invisible. Realistically, you would never want to do something like that.
"transformedParts": [ { "part": "wing_right", "position": [10, 0, 0], "rotation": [0, 0, 0], "isVisible": true }, { "part": "wing_left", "position": [-10, 0, 0], "rotationrotation": [0, 0, 0], "isVisible": false } ]
Quirks
Quirk animations are extra animations that you can have play over the main animation list. What makes them different from the previous animation overwrite function is that these quirks can have extra properties applied to them. You can make them loop a certain number of times and include timers for these quirks. The most common example of a quirk animation would be the blink animations. By default, a quirk animation should play once every 8-20 seconds!
Making a quirk in your poser file would largely depend on an animator making these quirky little animations to play in game. You can do more than just blinking animations. You can make a Pokémon roar, sneeze, or dance and have it play as a quirk for its standing pose or any other pose. A timer can then be applied to these quirk animations so you could end up with something like charizard doing a roar every 30-60 seconds when its idle. It's a very flexible sub system for animations that is only limited by your creativity.
Here is a list of properties that can affect quirks:
"loopTimes": Int = 1 // The number of times the animation should play for the quirk "minSecondsBetweenOccurrences": Float = 8 // The decimal-friendly number of seconds that is the minimum between the quirk playing once and it playing a second time "maxSecondsBetweenOccurrences": Float = 30 // What do you think "animations": List<Animation> = [] // The list of animations to play (together) when this quirk runs "name": String // The name of the quirk
Placeholder Animations
the placeholder animations cobblemon uses if a pokemon is not animated based on the body type of the pokemon. AAAAAAAAAAAAAAAAAAAAAA
Poser File Breakdown
The poser
file requires an animation
JSON to assign animations to a model
. You're always going to want to be familiar with all the animations that were made for a model. If you assign an animation type that doesn't exist in the animation JSON then the game will crash! Also, if a bone you listed in the poser doesn't exist on the model then the game will crash! Once you figure out what animations were made for your target Pokémon model, you can simply apply the existing animations to appropriate poses
.
Here is a breakdown of an example poser file which includes all the different properties that can be assigned. Hover over the underlined text to see more information. Every kind of possible poser function is included in this example at least once! So make sure that you review the whole file to see why some things are written the way they are.
- This example is not meant to be used as a template.
{ "portraitScale": 1.3, "portraitTranslation": [-0.7, 2.1, 0], "profileScale": 0.45, "profileTranslation": [-0.1, 1.0, 0], "animations": { "faint": "q.bedrock_primary('blastoise', 'faint', q.curve('one'))", "cry": "q.bedrock_stateful('blastoise', 'cry')", "recoil": "q.bedrock_stateful('blastoise', 'recoil')", "physical": "q.bedrock_primary('blastoise', 'physical', q.curve('symmetrical_wide'))", "special": "q.bedrock_primary('blastoise', 'special', q.curve('symmetrical_wide'))", "status": "q.bedrock_primary('blastoise', 'status', q.curve('symmetrical_wide'))" }, "poses": { "battle-standing": { "poseTypes": ["STAND"], "isBattle": true, "animations": [ "q.look('head_ai')", "q.bedrock('blastoise', 'battle_idle')" ], "quirks": [ "q.bedrock_quirk('blastoise', 'blink')", "q.bedrock_quirk('blastoise', q.array('quirk_battle_idle', 'quirk_battle_idle2'), 30, 60, 1)" ] }, "standing": { "poseTypes": ["STAND", "NONE", "PORTRAIT", "PROFILE"], "isBattle": false, "animations": [ "q.look('head_ai')", "q.bedrock('blastoise', 'ground_idle')" ], "quirks": [ "q.bedrock_quirk('blastoise', 'blink')", "q.bedrock_quirk('blastoise', 'quirk_ground_idle', 20, 60, 1)" ] }, "walking": { "poseTypes": ["WALK"], "animations": [ "q.look('head_ai')", "q.bedrock('blastoise', 'ground_walk')" ], "quirks": ["q.bedrock_quirk('blastoise', 'blink')"] }, "float": { "poseTypes": ["FLOAT"], "animations": [ "q.look('head_ai')", "q.bedrock('blastoise', 'water_idle')" ], "quirks": ["q.bedrock_quirk('blastoise', 'blink')"] }, "swim": { "poseTypes": ["SWIM"], "animations": [ "q.look('head_ai')", "q.bedrock('blastoise', 'water_swim')" ], "quirks": ["q.bedrock_quirk('blastoise', 'blink')"] }, "sleep": { "poseTypes": ["SLEEP"], "animations": ["q.bedrock('blastoise', 'sleep')"] } } }
Poser File Example
Instead of making poser
files from scratch each time, you can use other custom Pokémon posers as a template. Just be aware of the animations each Pokémon has. Also be aware that some Pokémon don't use a head bone
.
Here is an example of a poser file for a custom starly
that includes all currently implemented poses and their appropriate animations.
- Blink animations are not applied to the sleep pose. This is because you don't blink when you sleep!
{ "portraitScale": 1.3, "portraitTranslation": [-0.7, 2.1, 0], "profileScale": 0.45, "profileTranslation": [-0.1, 1.0, 0], "animations": { "faint": "q.bedrock_primary('blastoise', 'faint', q.curve('one'))", "cry": "q.bedrock_stateful('blastoise', 'cry')", "recoil": "q.bedrock_stateful('blastoise', 'recoil')", "physical": "q.bedrock_primary('blastoise', 'physical', q.curve('symmetrical_wide'))", "special": "q.bedrock_primary('blastoise', 'special', q.curve('symmetrical_wide'))", "status": "q.bedrock_primary('blastoise', 'status', q.curve('symmetrical_wide'))" }, "poses": { "battle-standing": { "poseTypes": ["STAND"], "isBattle": true, "animations": [ "q.look('head_ai')", "q.bedrock('blastoise', 'battle_idle')" ], "quirks": [ "q.bedrock_quirk('blastoise', 'blink')", "q.bedrock_quirk('blastoise', q.array('quirk_battle_idle', 'quirk_battle_idle2'), 30, 60, 1)" ] }, "standing": { "poseTypes": ["STAND", "NONE", "PORTRAIT", "PROFILE"], "isBattle": false, "animations": [ "q.look('head_ai')", "q.bedrock('blastoise', 'ground_idle')" ], "quirks": [ "q.bedrock_quirk('blastoise', 'blink')", "q.bedrock_quirk('blastoise', 'quirk_ground_idle', 20, 60, 1)" ] }, "walking": { "poseTypes": ["WALK"], "animations": [ "q.look('head_ai')", "q.bedrock('blastoise', 'ground_walk')" ], "quirks": ["q.bedrock_quirk('blastoise', 'blink')"] }, "float": { "poseTypes": ["FLOAT"], "animations": [ "q.look('head_ai')", "q.bedrock('blastoise', 'water_idle')" ], "quirks": ["q.bedrock_quirk('blastoise', 'blink')"] }, "swim": { "poseTypes": ["SWIM"], "animations": [ "q.look('head_ai')", "q.bedrock('blastoise', 'water_swim')" ], "quirks": ["q.bedrock_quirk('blastoise', 'blink')"] }, "sleep": { "poseTypes": ["SLEEP"], "animations": ["q.bedrock('blastoise', 'sleep')"] } } }