{	time_max	: 0,
	times		: [ float32Array() ],
	frame_inv	: [ float32Array() ],
	tracks 		: [
		{ type:"rot", joint_idx:0, time_idx:0, lerp:linear, data:float32Array() },
		{ type:"pos", joint_idx:0, time_idx:0, lerp:linear, data:float32Array() },
	]
}

get_animation( frame_inv = true );

let j, i, t, tt;
for( i=0; i < times.length; i++ ){
	t 	= times[i];
	tt 	= new Float32Array( t.length-1 );
	for( j=0; j < t.length-1; j++ ) tt[ j ] = 1 / ( t[j+1] - t[j] ); //  1 / (b - a)

	frame_inv.push( tt );
}

//############################################################################

<skeleton>
[
	{},
]
</skeleton>

<animation name="walk">
time_max:1234
time_0:sadads==
time_1:23424aa==
track_rot_0_0_linear:adadasd2131as==
</animation>


Base64_Mesh
vert:asdasdasd==
idx:asdasdsd==
norm:adsasdad==
uv:asdsdad=
weight:adasdasd=
joint:adasadas==

//############################################################################

// Setup Animation Caching on App.
App.cache.animation 	= new Map();
App.cache.get_animation	= function( key ){
	let x = this.animation.get( key );
	if( !x ){ console.log("Cached Animation Not Found %s", key ); return null; }
	return x;
};
App.cache.animation.set( "walk", data );

//############################################################################

class AnimationMachine{
	constructor(){
		this.current	= null;
		this.cross_to	= null;
		this.cross_t 	= 0;
		this.stack		= {};
	}

	/////////////////////////////////////////////////////////////////
	// 
	/////////////////////////////////////////////////////////////////
		
		// Add a new Animation to the Stack
		set( name, data ){ this.stack[ name ] = { clock:0, anim:data }; return this; }

		// Cross Fade into a new Animation
		to( name ){
			let a = this.stack[ name ];
			if( !a ){ console.log("Animation not found on stack: %s", name); return this; }

			a.clock = 0;
			if( !this.current ){ this.current = a; return this; }

			this.cross_to	= a;
			this.cross_t	= 0;
			return this;
		}


	/////////////////////////////////////////////////////////////////
	// 
	/////////////////////////////////////////////////////////////////

		// Run animation and save results to pose object
		run( dt, pose ){
			let f_times	= this.frame_times( dt, this.current ),
				anim	= this.current.anim,
				v		= [0,0,0,0],
				track, frame;

			for( track of anim.tracks ){
				frame = f_times[ track.time_idx ]; // [ FA_IDX, FB_IDX, NORM_TIME ]

				switch( track.type ){
					case "rot":
						this.quat_buf_blend( track.data, frame[0]*4, frame[1]*4, frame[2], v );
						pose.update_bone( track.joint_idx, v );
						break;
					case "pos":
						this.vec3_buf_lerp( track.data, frame[0]*3, frame[1]*3, frame[2], v );
						pose.update_bone( track.joint_idx, null, v );
						break;
				}
			}
		}

		// Every animation can have multiple shared time tracks.
		// So we incrmement our animation clock, then for each time
		// track we find between which two frames does the time exist.
		// Then we normalized the time between the two frames.
		// Return: [ [ FA_IDX, FB_IDX, NORM_TIME ], ... ];
		frame_times( dt, data ){
			// Move time forward, loop back on overflow.
			anim.clock = (data.clock + dt) % data.animation.time_max;

			// Find the Frames for each group time.
			let j, i, time, fa, fb, ft,
				times	= data.animation.times;
				rtn		= new Array( times.length );

			for( j=0; j < times.length; j++ ){
				time = times[ j ];

				//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
				// Find the first frame that is less then the clock.
				fa = 0;
				for( i=time.length-2; i > 0; i-- )
					if( time[i] < anim.clock ){ fA = i; break; }

				//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
				// Normalize Time Between Frames
				fb = fa + 1;
				ft = ( anim.clock - time[ fa ] ) / ( time[fb] - time[ fa ] );
				//ft = ( anim.clock - time[ fa ] ) * frame_inc[ fa ];
				rtn[ j ] = [ fa, fb, ft ];
			}

			return rtn;
		}


	/*///////////////////////////////////////////////////////////////
	Animation data is saved in a flat array for simplicity & memory sake. 
	Because of that can not easily use Quaternion / Vector functions. So 
	recreate any functions needed to work with a flat data buffer.
	///////////////////////////////////////////////////////////////*/

		// Special Quaternion NLerp Function. Does DOT checking & Fix
		quat_buf_blend( buf, ai, bi, t, out ){
			let a_x = buf[ ai ],	// Quaternion From
				a_y = buf[ ai+1 ],
				a_z = buf[ ai+2 ],
				a_w = buf[ ai+3 ],
				b_x = buf[ bi ],	// Quaternion To
				b_y = buf[ bi+1 ],
				b_z = buf[ bi+2 ],
				b_w = buf[ bi+3 ],
				dot = a_x * b_x + a_y * b_y + a_z * b_z + a_w * b_w,
				ti 	= 1 - t,
				s 	= 1;

		    // if Rotations with a dot less then 0 causes artifacts when lerping,
		    // Can fix this by switching the sign of the To Quaternion.
		    if( dot < 0 ) s = -1;
			out[ 0 ] = ti * a_x + t * b_x * s;
			out[ 1 ] = ti * a_y + t * b_y * s;
			out[ 2 ] = ti * a_z + t * b_z * s;
			out[ 3 ] = ti * a_w + t * b_w * s;

			return out.norm();
		}

		// basic vec3 lerp
		vec3_buf_lerp( buf, ai, bi, t, out ){
			let ti = 1 - t;
			out[ 0 ] = ti * buf[ ai ]		+ t * buf[ bi ];
			out[ 1 ] = ti * buf[ ai + 1 ]	+ t * buf[ bi + 1 ];
			out[ 2 ] = ti * buf[ ai + 2 ]	+ t * buf[ bi + 2 ];
			return out;
		}
}

//############################################################################

class FungiGLTF{
	static $debug( e_name, json, bin, arm_name ){} // Mesh with Armature Preview
	static $( e_name, json, bin ){} // Just the Mesh;
	static $skin( e_name, json, bin, arm_name ){} // Mesh with Armature

	// Armature Preview Only
	static $preview( e_name, arm_name, json ){
		let e		= App.$Draw( e.name ),
			node	= {},
			bones 	= Gltf.getSkin( arm_name, json, node );

		Armature.$( e );
		this.gen_bones( e, bones );
		ArmaturePreview.$( e, "ArmaturePreview", 2 );

		// Set the Entity Transfrom from Armature's Node Transform if available.
		if( node.scl ) e.Node.setScl( node.scl );
		if( node.rot ) e.Node.setRot( node.rot );

		return e;
	}

	/////////////////////////////////////////////////////////////////
	// 
	/////////////////////////////////////////////////////////////////

		// Takes the bones information from gltf and
		// create the Entity Heirarchy of the bones and assign
		// it to the armature.
		static gen_bones( e, bones, def_len=0.3 ){
			let arm = e.Armature;

			//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			// Create Bones
			let i, b, ab, bLen = bones.length;
			for( i=0; i < bLen; i++ ){
				b	= bones[i];
				ab	= arm.add_bone( b.name, 1, null, b.idx );
				if( b.rot ) ab.Node.setRot( b.rot );
				if( b.pos ) ab.Node.setPos( b.pos );
				if( b.scl ) ab.Node.setScl( b.scl );
			}

			//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			// Setting up Parent-Child
			for( i=0; i < bLen; i++ ){
				b	= bones[ i ];
				ab	= arm.bones[ b.idx ];
				
				// Can not have levels updated automaticly, Callstack limits get hit
				// Instead, using the Level from bones to manually set it.
				if( b.p_idx != null ) arm.bones[ b.p_idx ].Node.add_child( ab, false );

				// Manual set node level, Must do it after addChild, else it will get overwritten.
				ab.Node.level = b.lvl; //TODO THIS ISN"T CORRECT ANYMORE, ROOT BONE NOW LIVES UNDER RENDER ENTITY
			}

			Armature.finalize( e );	// This updates World Transforms

			//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			// With the WorldTransforms update, Calculate the Length of each bone.
			// The IK System needs to know the length of each bone.
			for( i=0; i < bLen; i++ ){
				ab = arm.bones[ i ];

				if( ab.Node.children.length == 0 ){
					ab.Bone.length = def_len;
					continue;
				}

				b = ab.Node.children[0].Node.world;					// First Child's World Space Transform
				ab.Bone.length = ab.Node.world.pos.length( b.pos );	// Distance from Parent to Child
			}
		}

}

//############################################################################

GLTF.get_armature_node( arm_name, json ){
	let ji, n = {};
	for( ji of json.nodes ){ 
		if( ji.name == name ){ 
			if( ji.rotation )	n["rot"] = ji.rotation;
			if( ji.scale )		n["scl"] = ji.scale;
			if( ji.position )	n["pos"] = ji.position;
			break;
		}
	}
	return n;
}

//############################################################################
//
build_src( json, bin ){
	let e = FungiGLTF.$preview( "Mesh", "Armature", json );

	gAnimPose = new TPose( e.Armature, false ).set_offset( e.Node.local.rot, null, e.Node.local.scl );
	gSrcTPose = new TPose( e.Armature ).set_offset( e.Node.local.rot, null, e.Node.local.scl ).update_world();

	//~~~~~~~~~~~~~~~~~~~~~~~~~
	let anim = Gltf.get_animation( "Armature|mixamo.com|Layer0", json, bin );
	let AMachine = new AnimationMachine().set( "base", anim );
}

AMachine.run( dt, pose );


//############################################################################

/*
Rig
- Chains

Pose
- Has a Bone Transform Array itself.

TPose
- Has Bind Transform Array
- Offset Transform
- Model and Local Space of Each Bone

 */

class IKRig{
	constructor(){
		this.t_pose;
		this.hip;
		this.head;
		this.chains = {};
			.arm_l
			.arm_r
			.leg_l
			.leg_r
			.spine
	}
}

let b_map = [
	"LeftUpLeg", "LeftUpLeg",
	"LeftLeg", "LeftLeg",
	"LeftArm", "LeftArm",
	"LeftForeArm", "LeftForeArm",
];

class AnimationRetarget{
	constructor( from, to ){
		this.from_t_pose	= from;
		this.to_t_pose		= to;
		this.bone_map		= new Array();

		this.hip 			= null; //{ from_idx:null, to_idx:null, max_height:null, scale:1 };
		this.hip_y_only		= true;

		/*
			{ 
				from_idx	: 0,
				from_pworld_q : ; // From TPose's Parent Bone Rotation in Model Space
				dot_chk_q	:  // From TPose Bone Rotation in Model Space Rotation
				to_idx		: 0,
				shift_q		: new Quat() // TPoseA.Rot.Invert * TPoseB.Rot
				to_local_q	: new Quat() // Parent World Space Rotation Inverted
			}
		*/
	}

	set_hip( from, to, y_only=true ){ return this; }
	
	auto_map( ){ return this; }
	
	load_map( map ){ 
		let i, from_idx, to_idx;

		for( i=0; i < map.length; i+=2 ){
			from_idx	= this.from_t_pose.get_index( map[ i ] );
			to_idx		= this.to_t_pose.get_index( map[ i+1 ] );
			this.mk_map_item( from_idx, to_idx );
		}

		return this;
	}

	mk_map_item( from_idx, to_idx ){
		let i, t_bone, f_bone;

		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		// Initially Need to isolate the retargeted bone, 
		// To do that, we take the Parent Bone's TPose Model Space Rotation
		// then add to it the Src Local Space Rotation. This brings
		// the animated rotation into the "From TPose's" Model Space.
		// Note: Only need to save the reference, So we dont need to do the 
		// root bone testing during retargeting.
		f_bone		= this.from_t_pose.bones[ f_idx ];
		let from_pworld_q = ( f_bone.p_idx == null )? 
			this.from_t_pose.root_offset.rot : 
			this.from_t_pose.bones[ f_bone.p_idx ].world.rot;

		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		// When I have the retargeted rotation in To TPose Model Space,
		// Need to get the parent's Mode Space rotation inverted to
		// convert into the TPose Bone's Local Space.
		// Node : Caching the Inverted Rotation to avoid doing this during
		// retargeting
		t_bone		= this.to_t_pose.bones[ t_idx ];
		let to_local_q = ( t_bone.p_idx == null )? 
			this.to_t_pose.root_offset.rot.clone() : 
			this.to_t_pose.bones[ t_bone.p_idx ].world.rot.clone();
		to_local_q.invert();

		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		// Need a rotation that will shift "From TPose Bone" to be equal to "To TPose Bone"
		let shift_q = Quat.invert( f_bone.world.rot ).mul( t_bone.world.rot );

		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		this.bone_map.push({
			dot_chk_q : f_bone.world.rot, // Just Caching Reference to remove any lookup later.
			from_pworld_q,
			to_local_q,
			shift_q,
			from_idx,
			to_idx,
		});
	}

	retarget( src_pose, to_pose ){
		// Basic Math Flow to Retarget Rotations
		//   shift = from_t.bone.ws.rot.invert * to_t.bone.ws.rot
		//   dif   = from_t.parent_bone.ws.rot * src_pose.bone.ls.rot
		//   dif   *= dot( dif, from_t.bone.ws.rot  ) >= 0 ? shift : -shift;
		//   final_pose.bone.ls.rot = to_t.parent_bone.ws.rot.invert * Dif

		let dif = new Quat(),
			qt 	= new Quat(),
			b;

		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		for( b of this.bone_map ){
			// Isolate each bone change in Model Space TPose.
			// Using the TPose Model Space of the parent, but the local rotation of the bone
			// The idea of having just a whole tpose with only one bone that changed.
			dif.from_mul( p.from_pworld_q, src_pose.bones[ b.from_idx ].local.rot ); 

			// We shift the Src MS bone rotation, Into the Target's MS by
			// using the TPose Rotation Difference. Need to do a dot check
			// else artifacts can show up when the dif is from the opposite dir
			// from the from_tpose model space bone.
			if( Quat.dot( dif, b.dot_chk_q ) < 0 ) 	dif.mul( b.shift_q.negate( qt ) ); 
			else 									dif.mul( b.shift_q );

			dif.pmul( b.to_local_q );				// Move the bone to local space for the target bone
			to_pose.update_bone( b.to_idx, dif );	// Save to Final Pose
		}

		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		// Handle Hip Translation
		if( this.hip ){
			/*
				scale     = Src_Pose.Bone.ModelSpace.Pos / From_TPose.Bone.ModelSpace.Pos; // Normalize Change from Source
				dif_pos   = ( 1 - scale ) * To_TPose.Bone.ModelSpace.Pos;
				final_pos = To_TPose.Bone.LocalSpace.Pos - dif_pose

				Todo, Rethink this.
				scale 	= to_t.ws_pos / from_t.ws_pos;
				pos_dif = ( src.ws.pos - from_t.ws.pos ) * scale;
				final 	= to_t.ls.pos + pos_dif;

			let a_yt 	= from_tpose.bones[ a_idx ].world.pos[1]; 		// Max Height of hip in tpose A
			let a_y 	= from_pose.bones[ a_idx ].world.pos[1];		// Current Height in Model Splace
			let a_scale	= a_y / a_yt;									// Create a scale value

			let b_yt	= to_tpose.bones[ b_idx ].world.pos[1];			// Max Height of hip in tpose B
			let b_y		= ( 1 - a_scale ) * b_yt;						// Calc new Height based on scaled B Max Hight
			
			let pos  	= to_tpose.bones[ b_idx ].local.pos.clone();
			pos[1]		-= b_y;
			to_pose.update_bone( b_idx, null, pos );					// Apply Pos Only

			*/
		}

		return this;
	}
}


//############################################################################

class Pose{
	constructor( arm ){
		this.arm			= arm;				// Reference Back to Armature, Make Apply work Easily
		this.bones			= [];				// Recreation of Bone Hierarchy
		this.root_offset	= new Transform();	// Parent Transform for Root Bone ( Mixamo Skeletons need this to render right )

		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		// Create Bone Transform Hierarchy to do transformations
		// without changing the actual armature.
		let b, pi;
		for( let i=0; i < arm.bones.length; i++ ){
			b	= arm.bones[i];
			pi	= ( b.Node.parent && b.Node.parent.Bone )? b.Node.parent.Bone.order : null;

			this.bones[ i ] = {
				chg_state	: 0,								// If Local Has Been Updated
				idx 		: i,								// Bone Index in Armature
				p_idx 		: pi,								// Parent Bone Index in Armature
				len 		: b.Bone.length,					// Length of Bone
				local		: new Transform( b.Bone.bind ),		// Local Transform, use Bind pose as default
				world		: new Transform(),					// Model Space Transform
			};
		}
	}

	/////////////////////////////////////////////////////////////////
	// Setters / Getters
	/////////////////////////////////////////////////////////////////
		
		set_offset( rot=null, pos=null, scl=null ){ this.root_offset.set( rot, pos, scl ); return this; }
		
		set_bone( idx, rot=null, pos=null, scl=null ){
			let b = this.bones[ idx ];
			b.local.set( rot, pos, scl );

			if( rot ) b.chg_state |= Pose.ROT;
			if( pos ) b.chg_state |= Pose.POS;
			if( scl ) b.chg_state |= Pose.SCL;

			return this;
		}

		get_index( bname ){ return this.arm.map_name[ bname ]; }

	/////////////////////////////////////////////////////////////////
	// Methods
	/////////////////////////////////////////////////////////////////

		update_world(){
			for( let b of this.bones ){
				if( b.p_idx != null )	b.world.from_add( this.bones[ b.p_idx ].world, b.local ); // Parent.World + Child.Local
				else					b.world.from_add( this.root_offset, b.local );
			}
			return this;
		}
		
		apply(){
			let i, 
				pb, // Pose Bone
				ab;	// Armature Bone

			for( i=0; i < this.bones.length; i++ ){
				pb = this.bones[ i ];
				
				if( pb.chg_state == 0 ) continue;
				ab = this.arm.bones[ i ];

				if( pb.chg_state & Pose.ROT ) ab.Node.local.rot.copy( pb.local.rot );
				if( pb.chg_state & Pose.POS ) ab.Node.local.pos.copy( pb.local.pos );
				if( pb.chg_state & Pose.SCL ) ab.Node.local.scl.copy( pb.local.scl );
				
				ab.Node.isModified	= true;
				pb.changeState		= 0;
			}

			this.arm.isModified = true;
			return this;
		}

	/////////////////////////////////////////////////////////////////
	// T Pose Helpers
	/////////////////////////////////////////////////////////////////
		// TODO, Fix this to work without Armature, Use Model Space of Bind Pose
		static align_chain( e, ary, dir, pose ){
			let pt		= new Transform(),			// Parent Transform ( Current Bone's Parent );
				ct		= new Transform(),			// Child Transform ( Current Bone )
				aEnd	= ary.length - 1,			// End Index
				f		= new Vec3(),				// Forward
				u		= new Vec3( dir ),			// Up
				l		= new Vec3(),				// Left
				r		= new Quat(),				// Final Rotation
				q		= new Quat(),				// Temp Rotation
				b 		= e.Armature.get_bone( ary[0] );	// Bone Entity Reference
			
			// Parent Bone's Transform
			b.Node.get_world_transform( pt, false );

			for( let i=0; i <= aEnd; i++ ){
				ct.from_add( pt, b.Bone.bind );		// Calc current bones world transform
				//App.debug
				//	.point( ct.pos, 2 )
				//	.line( ct.pos, Vec3.add( ct.pos, dir), 0 );
				//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
				// Up direction is where we need the bone to point to.
				// We then get the bone's current forward direction, use it
				// to get its left, then finish it off by recalculating
				// fwd to make it orthogonal. Want to try to keep the orientation
				// while ( fwd, lft ) realigning the up direction.
				f.from_quat( ct.rot, Vec3.FORWARD ); 		// Find Bone's Forward World Direction
				l.from_cross( u, f ).norm();				// Get World Left
				f.from_cross( l, u ).norm();				// Realign Forward
				r.from_axis( l, u, f );						// Create Rotation from 3x3 rot Matrix
				
				if( Quat.dot( r, ct.rot ) < 0 ) r.negate();	// Do a Inverted rotation check, negate it if under zero.
				
				r.pmul( q.from_invert( pt.rot ) );			// Move rotation to local space
				pose.update_bone( b.Bone.order, r );		// Update Pose with new ls rotation
				
				//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
				// If not the last bone, take then the new rotation to calc the next parents
				// world space transform for the next bone on the list.
				if( i != aEnd){
					pt.add( r, b.Bone.bind.pos, b.Bone.bind.scl );
					b = e.Armature.get_bone( ary[i+1] );
				}
			}
		}

		static align_foot_forward( e, foot, pose ){
			let pt	= new Transform(),
				ct	= new Transform(),
				v	= new Vec3(),
				q	= new Quat(),
				b	= e.Armature.get_bone( foot );
			
			this.pose_bone_world_parent(  pose, b, pt, ct ); // Get the Parent and Child Transforms. e.Armature,
			
			ct.transformVec( [0,b.Bone.length,0], v );	// Get the Tails of the Bone
			v.sub( ct.pos );							// Get The direction to the tail
			v[1] = 0;									// Flatten vector to 2D by removing Y Position
			v.norm();									// Make it a unit vector
			q	.from_unit_vecs( v, Vec3.FORWARD )		// Rotation needed to point the foot forward.
				.mul( ct.rot )							// Move WS Foot to point forward
				.pmul( pt.rot.invert() );				// To Local Space
			pose.update_bone( b.Bone.order, q );		// Save to Pose
		}

		static pose_bone_world_parent(  pose, b, pt, ct ){ //arm,
			let n	= b.Node,
				ary	= [];
			//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			// Move up the Node Tree
			while( n.parent != null ){
				if( !n.parent.Bone ) break; //Armature root is an entity, can skip it to only get Model Space Transform for pose
				ary.push( n.parent.Bone.order );
				n = n.parent.Node;
			}
			//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			let i 	= ary.length - 1,
				pb	= pose.bones;
			pt.copy( pb[ ary[i] ].local );							// Start the parent Transfrom by coping the first bone
			
			for( i--; i > -1; i-- ) pt.add( pb[ ary[i] ].local );	// Then add all the children bones
			//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			ct.from_add( pt, pb[ b.Bone.order ].local );			// Then add child current local transform to the parent's
		}
}

Pose.ROT = 1;
Pose.POS = 2;
Pose.SCL = 4;


//############################################################################

// Manage loading mesh from a custom data format linked to GLTF Bin File
class FungiMesh{
	/////////////////////////////////////////////////////////////////
	// Different Loading Styles for Meshes.
	/////////////////////////////////////////////////////////////////
		
		// Just the Mesh
		static $( ename, txt, bin, mat, mesh_list=null ){
			let e = App.$Draw( ename );
			this.load_vaos( e, txt, bin, mat, mesh_list );
			return e;
		} 
		
		// Mesh with Armature
		static $skin( ename, txt, bin, mat="ArmatureSkinPhong", mesh_list=null ){
			let e = App.$Draw( ename );
			this.load_vaos( e, txt, bin, mat, mesh_list );
			this.load_bones( e, txt );
			return e;
		}
		
		// Armature Preview Only
		static $preview( ename, txt, mesh_list=null ){
			let e = App.$Draw( ename );
			this.load_bones( e, txt );
			ArmaturePreview.$( e, "ArmaturePreview", 2 );
			return e;
		}

		// Mesh with Armature Preview
		static $debug( ename, txt, bin, mat="ArmatureSkinPhong", mesh_list=null ){
			let e = App.$Draw( ename );
			this.load_vaos( e, txt, bin, mat, mesh_list );
			this.load_bones( e, txt );
			ArmaturePreview.$( e, "ArmaturePreview", 2 );
			return e;
		}


	/////////////////////////////////////////////////////////////////
	// Helper Functions
	/////////////////////////////////////////////////////////////////
		static parse_section( sec, txt ){
			let aPos = txt.indexOf( "<" + sec + ">" ) + sec.length + 2,
				bPos = txt.indexOf( "</" + sec + ">" );

			if( aPos == -1 || bPos == -1 || bPos <= aPos ) return null;

			let tmp	= txt.substring( aPos, bPos );
			
			try{ return JSON.parse( tmp ); }
			catch(err){ console.error( err.message, "\n" , tmp ); }
			
			return null;
		}

		static load_vaos( e, txt, bin, mat, mesh_list ){
			let i, vao, s, spec = this.parse_section( "Vao", txt );

			mesh_list = mesh_list || spec;
			
			for( i of mesh_list ){
				s	= spec[ i ];
				vao	= Vao.standard_by_bin( e.info.name +"_"+ i, s, bin );
				e.Draw.add( vao, mat );
			}
		}

		static load_bones( e, txt ){
			let json = this.parse_section( "Armature", txt );
			Armature.$( e );

			let i, b, ab, bLen = json.length, arm = e.Armature;
			for( i=0; i < bLen; i++ ){
				b	= json[i];
				ab 	= arm.add_bone( b.name, b.len, null, b.idx );
				
				// Can not have levels updated automaticly, Callstack limits get hit
				// Instead, using the Level from bones to manually set it.
				//if( b.p_idx != null ) App.node.addChild( arm.bones[ b.p_idx ], ab, false );
				if( b.p_idx != null ) arm.bones[ b.p_idx ].Node.add_child( ab, false );
				
				// Manual set node level, Must do it after addChild, else it will get overwritten.
				ab.Node.level = b.lvl; //TODO, fix this, Root bone is now parented to render entity
				if( b.rot ) ab.Node.setRot( b.rot );
				if( b.pos ) ab.Node.setPos( b.pos );
				if( b.scl ) ab.Node.setScl( b.scl );
			}

			Armature.finalize( e );	// World Transform and Bind Pose
		}
}