I had a similar problem with terrain data not fitting into my target memory spec and had to shrink my 32byte vertex format to 16byte. So, based on that experience:
Position, 3 x 4 bytes.
Normal. 3 x 4 bytes.
Texture coordinates. 2 x 2 bytes
Animation data, 4 x 2 bytes.
2) I definitely need 4 bytes per dimension for position
3) I was hoping to compress each normal to only 4 bytes, meaning I'll save 8 bytes from each vertex (~22% less data per vertex). Is this possible? Packing would be done at load time, but unpacking will be done in the vertex shader, meaning that it'll have to be pretty fast to be a worthwhile trade-off.
1) My format ended up being (2 variants):
* 3x2B - position
* 2x1B - misc material params
* 4x1B - more material data OR 2x2B texcoord
* 4x1B - normal + 1 byte extra data OR quaternion - normal & tangent vectors
2) ... so, I have to challenge this. I use a dangling attribute to move a whole "chunk" of vertexes to where they should be (hence why a full float is not needed to get the exact same precision and range). Understanding how floating point numbers work is a must tho or cracks can appear - when done correctly it is guaranteed to give the exact same end result than when one would have used 4B-floats for positions. Might be worth considering.
3) using bytes has been sufficient for me, might be to you too. Unpacking is just one MAD instruction which is so ridiculously cheap that it wont have any effect on performance at all.
So, i would recommend:
Position, 3 x 4 bytes. => 3x2B (+dangling attribute)
. => 2B padding data for sane alignment
Normal. 3 x 4 bytes. => 4x1B (normal + something else to not completely screw up the alignment)
Texture coordinates. 2 x 2 bytes => 2x2B (if you really-really need it, i generate them in vertex shader based on position)
Animation data, 4 x 2 bytes. => 4x2B (as you said you can not shrink it, sure?)
=> 6+2+4+4+8 = 24B
edit: or use 3x2 normal instead of the 2B padding + 4x1B.