CHP Format - DragonRatTiger/CHPEditor GitHub Wiki
CHP (CHara Pomyu?) files are used to display animated characters in PMS-supported applications.
Below is a list of all information related to the CHP format, intended for creators to understand how this file format works, and intended for developers as a reference for how to implement support for this file format.
Format
All commands begin with a #
symbol + the name of the command, and then followed by the value(s) needed. All commands and their value(s) must be separated by tabs (\t
) or whitespace (
). Empty values are disposed of before the rest are processed in order.
In addition, comments can be added to a CHP file. All comments must begin with //
, and any text written after until the next newline will not be parsed. /
can also be used, but must be at the very beginning of the line.
Example :
// ------------------------
#CharName Chara Name
#Artist ãŠãĨãĶãģ
// ------------------------
#CharBMP char-bmp-1p.bmp
#CharFace char-face-1p.bmp
#SelectCG char-select-1p.bmp
#CharTex char-tex-1p.bmp
// ------------------------
All commands and their values are always case-insensitive. This also applies for rect entries & file names. For example, all of these are legal, and are treated as the same command :
#CharName Chara Name
#charname Chara Name
#CHARNAME Chara Name
Textures
There are currently 8 possible textures that can be loaded. Every single texture is optional, and can be loaded through a local, case-insensitive file path. Image format support is dependent on the program, but any common image format should be safe.
Command | Usage |
---|---|
#CharBMP |
The primary spritesheet used by a character. Utilized by #Patern and #Layer . |
#CharTex |
The secondary spritesheet used by a character. Utilized by #Texture . |
#CharFace |
The character's render, typically separated into two sprites on a single texture. In FeelingPomu2nd, the smaller sprite is used during character selection, and the larger sprite is used during song loading & the results screen, showing off the rival character's full render. |
#SelectCG |
The character's miniature icon. In FeelingPomu2nd, this icon appears during character selection. |
#CharBMP2P |
The 2P variant of #CharBMP . If unavailable, the texture loaded by #CharBMP is used instead. |
#CharTex2P |
The 2P variant of #CharTex . If unavailable, the texture loaded by #CharTex is used instead. |
#CharFace2P |
The 2P variant of #CharFace . If unavailable, the texture loaded by #CharFace is used instead. |
#SelectCG2P |
The 2P variant of #SelectCG . While this command is not supported in FeelingPomu2nd, this command was later added to beatoraja. If unavailable, the texture loaded by #SelectCG is used instead. |
Example :
// ------------------------
#CharName Chara Name
#Artist ãŠãĨãĶãģ
// ------------------------
#CharBMP char-bmp-1p.bmp
#CharFace char-face-1p.bmp
#SelectCG char-select-1p.bmp
#CharTex char-tex-1p.bmp
#CharBMP2P char-bmp-2p.bmp
#CharFace2P char-face-2p.bmp
#SelectCG2P char-select-2p.bmp // Not supported on FeelingPomu2nd, but is supported on beatoraja
#CharTex2P char-tex-2p.bmp
// ------------------------
Since BMP files are commonplace for Pomyu Chara textures, they often lack an alpha channel. To utilize alphas, the bottom-right pixel of the image is used as the color key. For example, if the bottom-right pixel is RGBA255,0,255,255
, any pixel that matches these values are not drawn on-screen.
Exceptions to this rule are CharFace
/CharFace2P
, where the color key is always pure black (255,255,255,255
), and SelectCG
/SelectCG2P
, where they have no color key.
2P Textures
Each texture comes with a 2P (Player 2) variant. If 2P is selected, and a 2P texture is available, the character will be drawn with a 2P texture. If 2P is selected, but a 2P texture is missing, the character will instead be drawn with its 1P texture.
Behavior in FeelingPomu2nd
BMP files are standard in FeelingPomu2nd, but any common image format is typically supported. However, FeelingPomu2nd lacks support for an alpha channel. If an image contains an alpha channel, the game will attempt to ignore it. As a result, some images with alpha channels could become distorted when loaded.
Animation & Timeline
CHP supports a total of 18 Animations, each triggered based on specific conditions in-game. Each animation will play either once or loop until the animation changes. Required/optional/unsupported animations depends on the program.
Animations are created through the use of the #Patern
, #Texture
, or #Layer
commands, which contains the Animation ID & its frames. The speed of the animation inherits the value of #Anime
by default, but can be modified by #Flame
(misspelling of "frame") per animation. Every animation command must have an equal number of frames, or safely fallback to the least number of frames to avoid unexpected behavior.
Example :
#Patern 1 0203040506070809
#Patern 1 0F0F0F0F0F0F0F0F FEFEFEFEFEFEFEFE
#Layer 1 2425262728292A2B
// There can be any number of #Patern, #Texture, and #Layer commands in a single animation.
#Flame 2 50
#Patern 2 101213141516
#Texture 2 AAABACADAEAF
// Using the #Flame command, we can change Animation 2's framerate to a value other than #Anime's value (which is currently 83ms per frame).
#Loop 3 5
#Patern 3 5051525354606162636465666768696A
// Animations which can loop support the #Loop command, which lets you specify where to begin looping your animation after it plays its entire animation once.
// This value is zero-indexed, however, meaning that "0" is considered the first frame.
// For example, if you write "5", the animation will continue its loop beginning from the 6th frame instead of the 1st frame.
#Patern 4 A0A1A2A3A4A5
#Texture 4 B0B1B2B3B4
#Layer 4 C0C1C2C3C4C5C6C7
// Do not create an unequal amount of frames! This may create unintended behavior for applications not designed to handle this.
// As a note for programmers, you should use the least number of frames as a fallback, to avoid unusual behavior.
Below is a list of animations and how they're typically triggered, according to FeelingPomu2nd :
ID | Name | Trigger | Notes | Looping |
---|---|---|---|---|
1 | Neutral | - | Default idle animation. Continues playing if there are no notes to respond to before the end of the idle animation. If a note is responded to, Animations 6-12 can be triggered based on how the note is hit + the side the character is on, after the animation finishes. | â |
2 | Second | 50% or higher gauge | Between 50% and 75% gauge, this animation replaces Neutral. At >75% gauge, Neutral & Second alternate. | â |
3 | Ojama | Rival sets off Ojama | Rival side | â |
4 | Miss | Miss a note | Player side | â |
5 | Standing | Plays once at the beginning of a song | - | â |
6 | Fever | Hitting great while at 100% gauge | Player side | â |
7 | Great | Hitting great | Player side | â |
8 | Good | Hitting good | Player side | â |
9 | Player hits Bad | Player hits bad | Rival side | â |
10 | Player hits Fever | Player hits perfect | Rival side | â |
11 | Player hits Great | Player hits great | Rival side | â |
12 | Player hits Good | Player hits good | Rival side | â |
13 | Unknown | - | There is no knowledge over what this animation is for or how it's triggered. Documentation has not been found anywhere, live or archived. | â |
14 | Dance | "Dance" Ojama must be active | Rival side; The character's animation will be overlayed on top of the gameplay area, disturbing the player's ability to see the notes. | â |
15 | Win | Clear the song with less than 100% gauge (Player Side) / Player fails the song (Rival side) | - | â |
16 | Lose | Fail the song (Player Side) / Player clears the song (Rival side) | - | â |
17 | Fever Win | Clear the song with 100% gauge | Player side | â |
18 | Attacked by Ojama | Rival sets off Ojama | Player side | â |
Legacy Chara Animations
Pomyu Charas determined to be Legacy characters have slightly different behavior when switching between animations. Rather than wait for the idle animation to finish to determine the next animation, the character will immediately play its next animation as soon as a note is hit/missed, assuming its previous non-idle animation is already finished.
Drawing Frames
After specifying sprite/offset coordinates, each index may be used as a frame through the use of #Patern
, #Texture
, and #Layer
commands. Each of these commands are drawn in different layers, with #Patern
being drawn first, #Texture
being drawn second, and #Layer
being drawn last. However, there can be any number of #Patern
/#Texture
/#Layer
commands in a single animation. The same command written in different lines determines what order they're drawn in, with the first instance of the command being drawn first.
#Patern
and #Layer
are capable of drawing sprites, and can optionally offset them as well. However, they will not draw past the boundary set by the character's #Size
, and will be trimmed if they cross that boundary.
#Texture
is capable of drawing sprites and optionally offsetting, similarly to #Patern
and #Layer
. However, it's also able to cross its boundary, as well as support the ability to change their opacity and rotation. In order to utilize the ability to change opacity, frames for sprite & offset are required to be written, and can not be skipped in favor of jumping to the next adjustable property. Similarly, rotation can not be adjusted without having sprite/offset/alpha frames already written.
Unlike using indexes for sprite/offset, alpha/rotation always uses Base16 values (00~FF), even if #Data
were to use a value other than 16.
Example :
#Patern 1 02030405060708 FFFFFFFFFFFFFF
// Uses indexes #02, #03, #04, #05, #06, #07, and #08 to draw sprites, with each index's given coordinates
// While optional, the second string of text is used to offset the sprite, and/or rescale the sprite by stretching/shrinking it to the offset's size. If excluded, the sprite will always begin drawing at coordinates 0,0 , and the sprite size will stay the same.
// Assuming #Anime's value is set to 83, this animation will last 83ms * 7 (581ms), or 0.581 seconds.
// This is drawn first, before #Texture and #Layer are drawn.
#Texture 1 50515253545556 FAFAFAFAFEFEFE FFFF800080FFFF 00204060402000
// This is the only command of the three that allows for alpha & rotation to be adjusted. This is also the only command of the three that can cross the character's boundary.
// Offset must be specified before alpha can be adjusted, and alpha must be specified before rotation can be adjusted.
// This is drawn second, after #Patern and before #Layer are drawn.
#Layer 1 90919293949596
// Follows the same rules as #Patern.
// This is drawn last, after #Patern and #Texture are drawn.
Drawing Rules
When drawing sprites, there are some rules for developers to consider :
- If a sprite has a size of 0x0, or a size of 1x1, do not draw the sprite, regardless of the offset's size.
- Coordinates with negative width/height are acceptable, and the sprite should be drawn as if it was flipped in those respective directions.
- Avoid drawing any pixels past a spritesheet's boundaries.
- In FeelingPomu2nd, any pixels outside of a spritesheet's boundaries are drawn as pure black pixels. This behavior likely isn't intended.
- If the current animation is set to 13 (Dance), expand the crop boundary for
#Patern
and#Layer
to fit the playfield instead.
Handling Invalid Frames
Sometimes, an animation may have a frame that uses invalid chars, or goes beyond the scope of available hex values. In this case, the developer should fallback to the previous frame as a replacement for that current frame.
Tweening
Tweening is supported through the use of two dashes (--
) for each frame tweened. When one or more are placed between two frames, it will linearly transition from point A to point B. Sprite, offset, alpha, and rotation can be tweened for a smoother animation.
Tweening behavior based on how the timeline is written is still being studied, but the general behavior is like so :
#Anime 83
...
#Patern 1 02030405060708 A2----------A3
// Gradually shift this pattern's offset from A2 to A3, starting from the millisecond the first frame begins,
// and ending from the millisecond the last frame ends.
// This happens in the span of 83 * 7 ms (581ms, or 0.581 seconds).
#Texture 1 151515151515161616161616 FFFFFFFFFFFFFFFFFFFFFFFF FF--------0000--------FF
// In this, the alpha of this texture shifts from 255, to 0, and back to 255.
// The previous tweening behavior specified above applies here as well.
// This tween starts from the millisecond the 1st frame begins, to the millisecond the 6th frame ends.
// After this, the next tween starts from the millisecond the 7th frame begins, to the millisecond the final frame ends.
#Layer 1 B0------B1------B0
// Tweening between sprite coordinates is legal as well, though every character i've seen has never made use of this. (Maybe they didn't know it was possible?)
// However, the tweening behavior from the last two examples differs here.
// Because there is only one frame between these two tweens, continuing to use the same behavior from the last two examples will produce choppy animations instead.
// This behavior hasn't been fully explored, but the best way for programmers to handle this is to divide this frame's length by 2, and use that as your middle ground when jumping to the next tween.
Commands
Chara Info
Text-based information about a character.
#CharName
Specifies the name of the character. This text value rarely appears, and the character's Name Image is displayed instead.
Example :
#CharName åĪŠé
#Artist
Specifies the creator(s) of the character. This usually includes the name of the animator, as well as anyone who assisted in this character's creation/animation (if applicable).
Example :
#Artist ãŠãĨãĶãģ
Bitmaps
Image files referenced for a character's animations.
All file paths given are case-insensitive.
#CharBMP
Color Key: Auto or R0,G0,B0,A255
The primary image file used for a character. This image is referenced by #Patern
and #Layer
when displaying animation.
Example :
#CharBMP char-bmp-1p.bmp
#CharBMP2P
Color Key: Auto or R0,G0,B0,A255
Similar to #CharBMP
, but is used for a character's 2P palette.
Example :
#CharBMP2P char-bmp-2p.bmp
#CharTex
Color Key: Auto or R0,G0,B0,A255
The secondary image file used by a character. Unlike #CharBMP
, this image file is used exclusively by #Texture
.
Example :
#CharTex char-tex-1p.bmp
#CharTex2P
Color Key: Auto or R0,G0,B0,A255
Similar to #CharTex
, but is used for a character's 2P palette.
Example :
#CharTex2P char-tex-2p.bmp
#CharFace
Color Key: R0,G0,B0,A255
A 640x480 texture which displays a character's upper-body portrait and full-body portrait. These portraits typically appear during character selection & song options in FeelingPomu2nd.
FeelingPomu2nd have hard-coded rects for these portraits: x0,y0,w256,h256
for upper-body portrait, and x320,y0,w320,h480
for full-body portraits.
Example :
#CharFace char-face-1p.bmp
#CharFace2P
Color Key: R0,G0,B0,A255
Similar to #CharBMP, but is used for a character's 2P palette.
Example :
#CharFace2P char-face-2p.bmp
#SelectCG
Color Key: None
The miniature player icon that displays during character selection in FeelingPomu2nd.
Unlike the other Bitmap commands, there is no #SelectCG2P
command available in FeelingPomu2nd.
Example :
#SelectCG char-select-1p.bmp
Chara Settings
Various settings for how character animations should be handled and displayed.
#AutoColorSet
Determines if a character's spritesheets should use a color key for transparency, via. selecting the bottom-right pixel of each spritesheet. If this command is excluded from the CHP file, the color key will default to R0,G0,B0 (black). This command does not affect the color key for CharFace & SelectCG.
Example :
#AutoColorSet
#Anime
Sets the default animation framerate in milliseconds.
Example :
#Anime 50 // 50ms is 0.05 seconds per frame, aka. 20fps
#Size
Sets the character's resolution in pixels. The values set the character's width and height, respectively. 167x271 is the standard resolution, but any value is possible.
Example :
#Size 167 271
#Wait
Set's the character's Idle animation loop count, before determining which animation to switch to based on the user's performance.
Example :
#Wait 1
#Data
Determines the hexadecimal base size, which controls how many rects can be created. The value most often used is 16 (16^2 -> 256 max rects).
If this command is missing, this marks the character as Legacy, and only supports up to 100 rects. Refer to Animation Data for details.
Example :
#Data 16
Animation Data
#00~#FF
Each entry contains a Rect (x, y, width, height), which determines which sprite to display when called, or where to position/scale that sprite when called. The maximum number of rects that can be created are determined by the value of #Data
powered by 2. (i.e. If Data is set to 16, 256 (16^2) total Rects can be created)
Note that #00
and #01
are used for Name Image and Background respectively (but you can still use these values in your animations). Outside of this, #02
~#FF
can be used for anything.
These entries are case-insensitive.
Example :
#00 1 1633 131 29
// Assuming this file follows standard FeelingPomu2nd sizes, 131x29 is the standard resolution for name images
#01 1 1 167 271
// Assuming this file follows standard FeelingPomu2nd sizes, 167x271 is the standard resolution for background
#02 169 1 167 271
#03 337 1 167 271
#04 505 1 167 271
#05 673 1 167 271
#06 841 1 167 271
#07 1009 1 167 271
#08 1177 1 167 271
#09 1 273 167 271
#0A 169 273 167 271
#0B 337 273 167 271
#0C 505 273 167 271
#0D 673 273 167 271
#0E 841 273 167 271
#0F 1009 273 167 271
#10 1177 273 167 271
However, legacy Pomyu Charas only use integers to register Rect entries, despite their animations still calling for hexadecimal values. This means that legacy Pomyu Charas can only use up to 100 Rects (#0
~#99
) no matter what.
#Flame
Overrides #Anime
for the specified animation. (This command name is a misspelling of "Frame".)
Example :
#Flame 14 75 // Set State 14 (Dance) animation speed to 75ms per frame
#Loop
Determines at which frame to begin looping the rest of the specified animation. This command only applies to animations that are intended to constantly play, such as clear animations (Lose/Win/Fever Win), Ojama/Disturb animations, and Dance animation.
Example :
#Loop 15 9 // Loop from frame #9 onwards
Timeline Data
These commands will display frames based on the entries listed. More information on how these work can be found here.
None of these commands are explicitly required, and an animation can have no keyframes at all.
#Patern
The first animation command, drawn below #Texture
and #Layer
. #CharBMP
is used for this command.
(This command name is a misspelling of "Pattern".)
Example :
#Patern 1 0203040506070809 // Uses entries #02, #03, #04, #05, #06, #07, #08, and #09
#Texture
The second and most advanced animation command, drawn on top of #Patern
and drawn below #Layer
. #CharTex
is used for this command.
Example :
#Texture 07 101010101010 C0C0C0C0C0C0 00--FFFF--00 00--------80
#Layer
The final animation command, drawn on top of #Patern
and #Texture
. #CharBMP
is used for this command.
Example :
#Layer 06 B0B1B2B3B4B5B6B7 FFFFC4C5C6C7FFFF
Beatoraja Exclusive Commands
Pomyu Chara support was added to beatoraja on Feburary 2018, and with it came a few new commands.
These commands have not been researched, mainly due to a lack of beatoraja skins and characters that make researching these behaviors possible. Everything listed below is speculated behavior.
#SelectCG2P
Color Key: None
Similar to #SelectCG
, but is used for a character's 2P palette.
Example :
#SelectCG2P char-select-2p.bmp
#CharFaceUpperSize / #CharFaceAllSize
Overrides the default, hard-coded rects for #CharFace
.
Example :
#CharFaceUpperSize 0 0 320 320
#CharFaceAllSize 320 0 480 640
#Frame
Alternate command name for #Flame
.
#Pattern
Alternate command name for #Patern
.
Sources
Documentation on the CHP file format, as well as the creation of CHPEditor itself, would not be possible without the previous documentation created several years ago, now preserved by The Internet Archive. There is still more research to be done.
Colorful Canvas Series Portal : https://web.archive.org/web/20231230150503/https://pmcc.nekokan.dyndns.info/
Story of Namidaame - Pomyu Chara Creation Course Part I : https://web.archive.org/web/20220812155722/http://storyof.namidaame.com/yy_pce.htm
Story of Namidaame - Pomyu Chara Creation Course Part II : https://web.archive.org/web/20220812151526/http://storyof.namidaame.com/yy_tec.htm
Yukiiro's Pomyu Chara Webpage : https://web.archive.org/web/20151004013142/http://yukiiro.info/pomu/
beatoraja's Pomyu Chara loader Java file : https://github.com/exch-bms2/beatoraja/blob/master/src/bms/player/beatoraja/skin/PomyuCharaLoader.java