Introduction
QUAD file is mainly for 2D sprites on modern 3D graphics engine. Every drawing is a polygon in square, rectangle, or other quadrilaterals (hence the name QUAD).
The major difference from 2D sprite:
-
Instead creating a new drawing for every possible transformation, the sprites can be transform directly using GPU.
-
Two transformation can be interpolate during animation. This creates a new type of sprites with 2D doll-like movement.
-
If the 2D sprite is properly layered, its depth value can be faked, allowing dynamic lighting and shadow calculations later.
-
All indexed color textures will be convert to RGBA true color textures when loading. There are no more palette animations.
-
The texture can be in grayscale to be blended with user selected colors. This can be better than editing palettes that edits only 1 color at a time (and that color can be affecting multiple unrelated layers). Blending the whole layer is a lot more convenient, but cost CPU/GPU processing power.
-
As everything on GPU is measured in
-1.0 to +1.0
or0.0 to 1.0
, rounding error is a very common problem. -
Anti-Alias and Smoothing filters are often used to blend the sharp outer edge of 3D models and background. It may not be suitable for 2D pixel art.
The major difference from 3D model:
-
It is still animated in frames, instead of using delta time. On a normal 60 FPS (frames per seconds) game, 1 frame is 16.67 milliseconds.
-
Z or depth value are not used. It is faked on drawing for perspective correction and drawing order.
-
As every polygons are quadrilateral with 4 unique x,y coordinates, indices are not needed. They are auto-generated when drawing as 2 triangles.
-
No triangulation needed. The 2 triangles never need to be further broken into smaller triangles.
-
Camera Clipping Planes are not used. There are no
near
andfar
in 2D games. Everything within the camera are drawn. Camera is only used for zoom in or out for dramatic effects. -
Full opaque/solid sprites doesn’t exists in 2D. There are always transparent/semi-transparent pixels surrounding the sprite, including GUI elements and textbox.
-
3D technique of reducing GPU overdraw by rendering opaque objects front-to-back order is not applicable. All sprites, regardless of opaque/transparent, is rendered in back-to-front order (Painter’s algorithm).
Basic File Structure

A QUAD file consists of multiple sub objects:
-
keyframe
defines the drawings of a frame. -
hitbox
defines the areas for collusion detection for a frame. -
animation
defines the changes between frames over time. -
skeleton
defines the relationship between frames.
Quad Object
{ "tag" : Tag Object, "keyframe" : [ Keyframe Object, Keyframe Object, ... ], "hitbox" : [ Hitbox Object, Hitbox Object, ... ], "animation" : [ Animation Object, Animation Object, ... ], "skeleton" : [ Skeleton Object, Skeleton Object, ... ], "slot" : [ Slot Object, Slot Object, ... ], "blend" : [ Blend Object, Blend Object, ... ], "link" : [ Link Object, Link Object, ... ], }
Tag Object
It is to define the metadata for current QUAD file.
{ tag : [ any , any ... ], tag : any, }
For reference, here are some suggestions for tag fields.
- MPEG Audio Tag ID3v1 [mp3tag]
-
-
Title
-
Artist
-
Album
-
Year
-
Comment
-
Genre
-
- ISO9660 → The Primary Volume Descriptor [isotag]
-
-
System Identifier
-
Volume Identifier
-
Volume Sequence Number
-
Volume Set Identifier
-
Publisher Identifier
-
Data Preparer Identifier
-
Application Identifier
-
Copyright File Identifier
-
Abstract File Identifier
-
Bibliographic File Identifier
-
Volume Creation Date and Time
-
Volume Modification Date and Time
-
Volume Expiration Date and Time
-
Volume Effective Date and Time
-
Attach Object
Used internally by an object to link with another object.
If invalid, the object is not attached.
{ "type" : string tag, "id" : int id, }
- type (required)
-
-
For linking to other objects in the QUAD file.
-
Valid values are:
-
keyframe
for Keyframe Object -
hitbox
for Hitbox Object -
slot
for Slot Object -
animation
for Animation Object -
skeleton
for Skeleton Object
-
-
- id (required)
-
-
Array index to the object.
-
Slot Object
Used when more than 1 object need to be attach to a frame.
A frame can consist of a sprite, a hitbox and a sound effect.
[ Attach Object, Attach Object, ... ]
Keyframe Object
It is to define a drawing for a frame. The result is an assembled sprite.
{ "debug" : any, "name" : string, "layer" : [ Keyframe Layer Object, Keyframe Layer Object, ... ], "order" : [ int layer_id , int layer_id , ... ], }
- debug
-
-
Additional notes and/or comments.
-
- name
-
-
Custom string to identify this object.
-
If omitted, then it is default to "keyframe %d".
-
- layer (required)
-
-
An array of objects to be drawn for this keyframe.
-
- order
-
-
Drawing order for Keyframe Layer Object, in bottom-to-top order (Painter’s algorithm).
-
All
layer_id
must be unique within the array, or else it is invalid. -
If omitted or invalid, then it is default to:
-
[ 0 , 1 , 2 , … , layer.length - 1 ]
-
-
Keyframe Layer Object
{ "debug" : any, "dstquad" : [ number x1 , number y1 , number x2 , number y2 , number x3 , number y3 , number x4 , number y4 , ], "blend_id" : int id, "fogquad" : [ string rgba1 , string rgba2 , string rgba3 , string rgba4 ], "fogquad" : string rgba, "attribute" : [ string , string , ... ], "attribute" : string, "colorize" : string, "tex_id" : int id, "srcquad" : [ number x1 , number y1 , number x2 , number y2 , number x3 , number y3 , number x4 , number y4 , ], }
- debug
-
-
Additional notes and/or comments.
-
- dstquad (required)
-
-
Accepts 8 numbers array, or 4 pairs of x,y coordinates.
-
Defines the area on the canvas or background to write pixels to.
-
Measured in pixel (px), with +X is right direction, and +Y is down direction.
-
If omitted, then this layer object is invalid and skipped.
-
- blend_id
-
-
Index of Blend Object to use for alpha blending.
-
If Blend Object is invalid or does not exists, then it is skipped.
-
If omitted, then it is default to -1.
-
-1 means disable alpha blending. All pixels, including transparent pixels, will overwrite pixels within
dstquad
.
-
- fogquad
-
-
Accepts 4 RGBA strings for 4 corners of a quad.
-
Can be shorthand to 1 RGBA string when all 4 corners are the same color.
-
-
RGBA string is in "#rrggbbaa" format.
-
If omitted, then it is default to "#ffffffff" (white solid).
-
- attribute
-
-
Accepts a string for only 1 attribute, or a list of string for multiple attributes.
-
Used for character customization.
-
Can be used with enum attributes to form an int of bitflags for faster render.
-
- colorize
-
-
Accepts a string of custom color name.
-
Used for character customization, by adjusting the HSV (Hue Saturation Value) of a grayscale texture to custom color.
-
Custom color is in RGB, default to
rgb(1.0 , 1.0 , 1.0)
.
-
- tex_id
-
-
Required to draw texture.
-
If omitted or it is invalid, then it is default to -1 (draw fog color only)
-
- srcquad
-
-
Required to draw texture.
-
Accepts 8 numbers array, as in 4 pairs of x,y coordinates.
-
Defines the area of texture or foreground to read pixels from.
-
Measured in pixel (px), with +X is right direction, and +Y is down direction.
-
If omitted or it is invalid, then fog color only is drawn.
-
Hitbox Object
It is to define the areas for collusion detection for a frame.
{ "debug" : any, "name" : string, "layer" : [ Hitbox Layer Object, Hitbox Layer Object, ... ], }
- debug
-
-
Additional notes and/or comments.
-
- name
-
-
Custom string to identify this object.
-
If omitted, then it is default to "hitbox %d".
-
- layer (required)
-
-
An array of hitbox with different properties.
-
Hitbox Layer Object
{ "debug" : any, "hitquad" : [ number x1 , number y1 , number x2 , number y2 , number x3 , number y3 , number x4 , number y4 , ], "attribute" : [ string , string , ... ], "attribute" : string, }
- debug
-
-
Additional notes and/or comments.
-
- hitquad (required)
-
-
Accepts 8 numbers array, or 4 pairs of x,y coordinates.
-
Defines the area for collusion detection.
-
Measured in pixel (px), with +X is right direction, and +Y is down direction.
-
If omitted, then this layer object is invalid and skipped.
-
- attribute
-
-
Accepts a string for only 1 attribute, or a list of string for multiple attributes.
-
Can be used with enum attributes to form an int of bitflags for faster collusion detection.
-
Animation Object
It is to define the changes between frames over time.
{ "debug" : any, "name" : string, "timeline" : [ Animation Timeline Object, Animation Timeline Object, ... ], "loop_id" : int id, }
- debug
-
-
Additional notes and/or comments.
-
- name
-
-
Custom string to identify this object.
-
If omitted, then it is default to "animation %d".
-
- timeline (required)
-
-
An array of objects to be drawn in sequence.
-
- loop_id
-
-
Marks the array index for next frame when timeline reaches the end.
-
Value
0
(zero) restarts from the beginning. -
If omitted, then it is default
-1
(no loop).
-
Animation Timeline Object
{ "debug" : any, "time" : int fps, "attach" : Attach Object, "matrix" : [ a,b,c,d , e,f,g,h , i,j,k,l , m,n,o,p ], "color" : string rgba, "matrix_mix" : bool, "color_mix" : bool, "keyframe_mix" : bool, "hitbox_mix" : bool, }
- debug
-
-
Additional notes and/or comments.
-
- time (required)
-
-
Measured in frames. For 60 FPS (frames per second), 1 frame is 16.67 milliseconds.
-
- attach
-
-
If omitted, then nothing is drawn.
-
- matrix
-
-
A 4x4 transformation matrix.
-
If omitted, then it is default to 4x4 identity matrix.
-
- color
-
-
String is in "#rrggbbaa" format.
-
If omitted, then it is default to "#ffffffff" (white solid).
-
- matrix_mix
-
-
Marks if current matrix is interpolated with the next matrix.
-
rate = t / time , t++
-
matrix = (current * (1.0 - rate)) + (next * rate)
-
-
If omitted, then it is default to
0
(false
)
-
- color_mix
-
-
Marks if current color is interpolated with the next color.
-
rate = t / time , t++
-
color = (current * (1.0 - rate)) + (next * rate)
-
-
If omitted, then it is default to
0
(false
)
-
- keyframe_mix
-
-
Marks if current Keyframe Layer Object is interpolated with the next Keyframe Layer Object.
-
Affects
dstquad
andfogquad
.-
rate = t / time , t++
-
layer = (current * (1.0 - rate)) + (next * rate)
-
-
If omitted, then it is default to
0
(false
)-
Mixing is impossible under the following conditions, and this setting is default to
0
(false
).-
If current keyframe layer count is not the same as next keyframe layer count.
-
If current keyframe layer is empty.
-
If next keyframe layer is empty.
-
-
If
false
, only current keyframe layer is used, next keyframe layer is ignored.
-
-
- hitbox_mix
-
-
Marks if current Hitbox Layer Object is interpolated with the next Hitbox Layer Object.
-
Affects
hitquad
.-
rate = t / time , t++
-
layer = (current * (1.0 - rate)) + (next * rate)
-
-
If omitted, then it is default to
0
(false
)-
Mixing is impossible under the following conditions, and this setting is default to
0
(false
).-
If current hitbox layer count is not the same as next hitbox layer count.
-
If current hitbox layer is empty.
-
If next hitbox layer is empty.
-
-
If
false
, only current hitbox layer is used, next hitbox layer is ignored.
-
-
Skeleton Object
It is to define the relationship between frames.
{ "debug" : any, "name" : string, "bone" : [ Skeleton Bone Object, Skeleton Bone Object, ... ], }
- debug
-
-
Additional notes and/or comments.
-
- name
-
-
Custom string to identify this object.
-
If omitted, then it is default to "skeleton %d".
-
- bone (required)
-
-
An array of bones to built the skeleton.
-
Skeleton Bone Object
{ "debug" : any, "name" : string, "attach" : Attach Object, }
- debug
-
-
Additional notes and/or comments.
-
- name
-
-
Custom string to identify this object.
-
If omitted, then it is default to "skeleton bone %d".
-
- attach
-
-
If omitted, then it is invisible bone and drawing is skipped.
-
Blend Object
It is to define alpha blending formula to handle transparency and semi-transparency pixels.
{ "debug" : any, "name" : string, "mode_rgb" : [ string mode , string src_factor , string dst_factor ], "mode_alpha" : [ string mode , string src_factor , string dst_factor ], "color" : string rgba, "logic_op" : [ string opcode_r , string opcode_g , string opcode_b , string opcode_a ], "logic_op" : [ string opcode_rgb , string opcode_a ], "logic_op" : string opcode, }
- debug
-
-
Additional notes and/or comments.
-
- name
-
-
Custom string to identify this object.
-
If omitted, then it is default to "blend %d".
-
- mode_rgb (required)
-
-
Accepts a 3 strings array
-
mode
is enum forblendEquation()
, and string can be case-insensitive.-
FUNC_ADD
is math operationSRC + DST
-
FUNC_SUBTRACT
is math operationSRC - DST
-
FUNC_REVERSE_SUBTRACT
is math operation-SRC + DST
-
MIN
ismin(SRC.r, DST.r)
,min(SRC.g, DST.g)
,min(SRC.b, DST.b)
andmin(SRC.a, DST.a)
-
MAX
ismax(SRC.r, DST.r)
,max(SRC.g, DST.g)
,max(SRC.b, DST.b)
andmax(SRC.a, DST.a)
-
-
src_factor
anddst_factor
are enum forblendFunc()
, and string can be case-insensitive.-
Static value
-
ZERO
is value0.0
-
ONE
is value1.0
-
-
SRC or Foreground (top layer)
-
SRC_COLOR
-
SRC_ALPHA
-
ONE_MINUS_SRC_COLOR
-
ONE_MINUS_SRC_ALPHA
-
-
DST or Background (bottom layer)
-
DST_COLOR
-
DST_ALPHA
-
ONE_MINUS_DST_COLOR
-
ONE_MINUS_DST_ALPHA
-
-
CONSTANT (require
color
below)-
CONSTANT_COLOR
-
CONSTANT_ALPHA
-
ONE_MINUS_CONSTANT_COLOR
-
ONE_MINUS_CONSTANT_ALPHA
-
-
-
-
- mode_alpha
-
-
same format as
mode_rgb
above -
if omitted, then it is the same as
mode_rgb
-
- color
-
-
required only if
src/dst_factor
uses CONSTANT -
String is in "#rrggbbaa" format.
-
If omitted, then it is default to "#ffffffff" (white solid).
-
- logic_op
-
-
Has higher priority than normal blending. Hence when it is set,
mode_rgb
,mode_alpha
andcolor
are ignored. -
Accepts 4 strings array for each RGBA components.
-
Can be shorthand to 2 string for RGB and Alpha components.
-
Can be shorthand to 1 string for all 4 RGBA components.
-
opcode
is enum forlogicOp()
, and string can be case-insensitive.-
CLEAR
as value 0 -
SET
as value 1 -
COPY
as bitwise operationSRC
-
COPY_INVERTED
as bitwise operation~SRC
-
NOOP
as bitwise operationDST
-
INVERT
as bitwise operation~DST
-
AND
as bitwise operationSRC & DST
-
NAND
as bitwise operation~(SRC & DST)
-
OR
as bitwise operationSRC | DST
-
NOR
as bitwise operation~(SRC | DST)
-
XOR
as bitwise operationSRC ^ DST
-
EQUIV
as bitwise operation~(SRC ^ DST)
-
AND_REVERSE
as bitwise operationSRC & ~DST
-
AND_INVERTED
as bitwise operation~SRC & DST
-
OR_REVERSE
as bitwise operationSRC | ~DST
-
OR_INVERTED
as bitwise operation~SRC | DST
-
-
-
Logic Operation can only be used for integer draw buffer. It invalid for floating-point draw buffer.
-
If omitted or invalid, then it is default to
0
(use normal blending).
-
Link Object
It is to connect with another QUAD file, allowing interaction between QUAD files.
{ "list" : pointer, "id" : int id, }
- list (required)
-
-
Pointer to array of QUAD files.
-
- id (required)
-
-
Array index to the QUAD file.
-
Revision History
- v0.5.x
-
-
keyframe_layer_object
: defineblend_id
== -1 as disable alpha blending -
blend_object
: separatemode
intomode_rgb
andmode_alpha
-
blend_object
: addedlogic_op
-
- v0.5 (2024-4-3)
-
-
quad_object
: renamed tolink_object
-
keyframe_layer_object
: addedcolorize
-
keyframe_layer_object
: addedattribute
-
hitbox_layer_object
: addedattribute
-
- v0.4 (2024-1-11)
-
-
keyframe_object
: addedorder
-
skeleton_bone_object
: removedorder
-
skeleton_bone_object
: removedparent_id
-
- v0.3 (2023-11-06)
-
-
animation_timeline_object
: removedmix
-
animation_timeline_object
: addedmatrix_mix
-
animation_timeline_object
: addedcolor_mix
-
animation_timeline_object
: addedkeyframe_mix
-
animation_timeline_object
: addedhitbox_mix
-
- v0.2 (2023-05-11)
-
-
Rewritten from scratch with dynamic
attach_object
system. -
Object keys are standardize to be singular form in
lower_snake_case
. -
Added
hitbox
objects. -
Added
slot
objects. -
Added
skeleton
objects. -
Added
blend
objects. -
animation
object is simplified to one-track only.
-
- v0.1 (2021-03-01)
-
-
Initial release and first draft.
-
Terminology
- SRC
-
-
As in "Source", pixels READ from texture.
-
On image editor, it is the top layer.
-
[U,V] is used when accessing vectors that represent texture coordinates.
-
0,0 is at top-left of texture.
-
+X is right direction, +Y is down direction, and they are measured in px (pixels).
-
For Texture size 320x240, X is 0px (left) to 320px (right) , and Y is 0px (top) to 240px (bottom).
-
It is then normalized to 0.0 to 1.0.
-
- DST
-
-
As in "Destination", pixels WRITE to canvas.
-
On alpha blending operation, pixels are READ and WRITE back to canvas.
-
On image editor, it is the bottom layer.
-
[X,Y] is used when accessing vectors that reporesent canvas points.
-
0,0 is at the center of canvas.
-
+X is right direction, +Y is down direction, and they are measured in px (pixels).
-
For Canvas size 320x240, X is -160px (left) to +160px (right) , and Y is -120px (top) to +120px (bottom).
-
It is then normalized to -1.0 to +1.0.
-
Example
Contributors
- In alphabetical order
-
-
Cloud2333
-
tombmonkey
-
Links
- Online Ver
- Extra Readings