.blend file format of Blender: GraphViz block diagram (.dot) source

Blender is an open source suite for 3D modelling, sculpting, animation, compositing, rendering, preparation of assets for its own game engine and exporting to others, etc. .blend is its own binary format that saves whole state of suite: current scene, animations, all software settings, extensions, etc.

Internally, .blend format is a hybrid semi-self-descriptive format. On top level, it contains a simple header and a sequence of file blocks, which more or less follow typical TLV pattern. Pre-last block would be a structure with code DNA1, which is a essentially a machine-readable schema of all other structures used in this file.

Application

Blender

File extension

blend

KS implementation details

License: CC0-1.0

References

This page hosts a formal specification of .blend file format of Blender using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

GraphViz block diagram source

blender_blend.dot

digraph {
	rankdir=LR;
	node [shape=plaintext];
	subgraph cluster__blender_blend {
		label="BlenderBlend";
		graph[style=dotted];

		blender_blend__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
			<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
			<TR><TD PORT="hdr_pos">0</TD><TD PORT="hdr_size">12</TD><TD>Header</TD><TD PORT="hdr_type">hdr</TD></TR>
			<TR><TD PORT="blocks_pos">12</TD><TD PORT="blocks_size">...</TD><TD>FileBlock</TD><TD PORT="blocks_type">blocks</TD></TR>
			<TR><TD COLSPAN="4" PORT="blocks__repeat">repeat to end of stream</TD></TR>
		</TABLE>>];
		blender_blend__inst__sdna_structs [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
			<TR><TD BGCOLOR="#E0FFE0">id</TD><TD BGCOLOR="#E0FFE0">value</TD></TR>
			<TR><TD>sdna_structs</TD><TD>blocks[(blocks.length - 2)].body.structs</TD></TR>
		</TABLE>>];
		subgraph cluster__dna_struct {
			label="BlenderBlend::DnaStruct";
			graph[style=dotted];

			dna_struct__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
				<TR><TD PORT="idx_type_pos">0</TD><TD PORT="idx_type_size">2</TD><TD>u2le</TD><TD PORT="idx_type_type">idx_type</TD></TR>
				<TR><TD PORT="num_fields_pos">2</TD><TD PORT="num_fields_size">2</TD><TD>u2le</TD><TD PORT="num_fields_type">num_fields</TD></TR>
				<TR><TD PORT="fields_pos">4</TD><TD PORT="fields_size">4</TD><TD>DnaField</TD><TD PORT="fields_type">fields</TD></TR>
				<TR><TD COLSPAN="4" PORT="fields__repeat">repeat num_fields times</TD></TR>
			</TABLE>>];
			dna_struct__inst__type [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">id</TD><TD BGCOLOR="#E0FFE0">value</TD></TR>
				<TR><TD>type</TD><TD>_parent.types[idx_type]</TD></TR>
			</TABLE>>];
		}
		subgraph cluster__file_block {
			label="BlenderBlend::FileBlock";
			graph[style=dotted];

			file_block__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
				<TR><TD PORT="code_pos">0</TD><TD PORT="code_size">4</TD><TD>str(ASCII)</TD><TD PORT="code_type">code</TD></TR>
				<TR><TD PORT="len_body_pos">4</TD><TD PORT="len_body_size">4</TD><TD>u4le</TD><TD PORT="len_body_type">len_body</TD></TR>
				<TR><TD PORT="mem_addr_pos">8</TD><TD PORT="mem_addr_size">_root.hdr.psize</TD><TD></TD><TD PORT="mem_addr_type">mem_addr</TD></TR>
				<TR><TD PORT="sdna_index_pos">...</TD><TD PORT="sdna_index_size">4</TD><TD>u4le</TD><TD PORT="sdna_index_type">sdna_index</TD></TR>
				<TR><TD PORT="count_pos">...</TD><TD PORT="count_size">4</TD><TD>u4le</TD><TD PORT="count_type">count</TD></TR>
				<TR><TD PORT="body_pos">...</TD><TD PORT="body_size">...</TD><TD>switch (code)</TD><TD PORT="body_type">body</TD></TR>
			</TABLE>>];
			file_block__inst__sdna_struct [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">id</TD><TD BGCOLOR="#E0FFE0">value</TD></TR>
				<TR><TD>sdna_struct</TD><TD>_root.sdna_structs[sdna_index]</TD></TR>
			</TABLE>>];
file_block__seq_body_switch [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
	<TR><TD BGCOLOR="#F0F2E4">case</TD><TD BGCOLOR="#F0F2E4">type</TD></TR>
	<TR><TD>&quot;DNA1&quot;</TD><TD PORT="case0">Dna1Body</TD></TR>
</TABLE>>];
		}
		subgraph cluster__dna1_body {
			label="BlenderBlend::Dna1Body";
			graph[style=dotted];

			dna1_body__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
				<TR><TD PORT="id_pos">0</TD><TD PORT="id_size">4</TD><TD></TD><TD PORT="id_type">id</TD></TR>
				<TR><TD PORT="name_magic_pos">4</TD><TD PORT="name_magic_size">4</TD><TD></TD><TD PORT="name_magic_type">name_magic</TD></TR>
				<TR><TD PORT="num_names_pos">8</TD><TD PORT="num_names_size">4</TD><TD>u4le</TD><TD PORT="num_names_type">num_names</TD></TR>
				<TR><TD PORT="names_pos">12</TD><TD PORT="names_size">...</TD><TD>str(UTF-8)</TD><TD PORT="names_type">names</TD></TR>
				<TR><TD COLSPAN="4" PORT="names__repeat">repeat num_names times</TD></TR>
				<TR><TD PORT="padding_1_pos">...</TD><TD PORT="padding_1_size">((4 - _io.pos) % 4)</TD><TD></TD><TD PORT="padding_1_type">padding_1</TD></TR>
				<TR><TD PORT="type_magic_pos">...</TD><TD PORT="type_magic_size">4</TD><TD></TD><TD PORT="type_magic_type">type_magic</TD></TR>
				<TR><TD PORT="num_types_pos">...</TD><TD PORT="num_types_size">4</TD><TD>u4le</TD><TD PORT="num_types_type">num_types</TD></TR>
				<TR><TD PORT="types_pos">...</TD><TD PORT="types_size">...</TD><TD>str(UTF-8)</TD><TD PORT="types_type">types</TD></TR>
				<TR><TD COLSPAN="4" PORT="types__repeat">repeat num_types times</TD></TR>
				<TR><TD PORT="padding_2_pos">...</TD><TD PORT="padding_2_size">((4 - _io.pos) % 4)</TD><TD></TD><TD PORT="padding_2_type">padding_2</TD></TR>
				<TR><TD PORT="tlen_magic_pos">...</TD><TD PORT="tlen_magic_size">4</TD><TD></TD><TD PORT="tlen_magic_type">tlen_magic</TD></TR>
				<TR><TD PORT="lengths_pos">...</TD><TD PORT="lengths_size">2</TD><TD>u2le</TD><TD PORT="lengths_type">lengths</TD></TR>
				<TR><TD COLSPAN="4" PORT="lengths__repeat">repeat num_types times</TD></TR>
				<TR><TD PORT="padding_3_pos">...</TD><TD PORT="padding_3_size">((4 - _io.pos) % 4)</TD><TD></TD><TD PORT="padding_3_type">padding_3</TD></TR>
				<TR><TD PORT="strc_magic_pos">...</TD><TD PORT="strc_magic_size">4</TD><TD></TD><TD PORT="strc_magic_type">strc_magic</TD></TR>
				<TR><TD PORT="num_structs_pos">...</TD><TD PORT="num_structs_size">4</TD><TD>u4le</TD><TD PORT="num_structs_type">num_structs</TD></TR>
				<TR><TD PORT="structs_pos">...</TD><TD PORT="structs_size">...</TD><TD>DnaStruct</TD><TD PORT="structs_type">structs</TD></TR>
				<TR><TD COLSPAN="4" PORT="structs__repeat">repeat num_structs times</TD></TR>
			</TABLE>>];
		}
		subgraph cluster__header {
			label="BlenderBlend::Header";
			graph[style=dotted];

			header__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
				<TR><TD PORT="magic_pos">0</TD><TD PORT="magic_size">7</TD><TD></TD><TD PORT="magic_type">magic</TD></TR>
				<TR><TD PORT="ptr_size_id_pos">7</TD><TD PORT="ptr_size_id_size">1</TD><TD>u1→PtrSize</TD><TD PORT="ptr_size_id_type">ptr_size_id</TD></TR>
				<TR><TD PORT="endian_pos">8</TD><TD PORT="endian_size">1</TD><TD>u1→Endian</TD><TD PORT="endian_type">endian</TD></TR>
				<TR><TD PORT="version_pos">9</TD><TD PORT="version_size">3</TD><TD>str(ASCII)</TD><TD PORT="version_type">version</TD></TR>
			</TABLE>>];
			header__inst__psize [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">id</TD><TD BGCOLOR="#E0FFE0">value</TD></TR>
				<TR><TD>psize</TD><TD>(ptr_size_id == :ptr_size_bits_64 ? 8 : 4)</TD></TR>
			</TABLE>>];
		}
		subgraph cluster__dna_field {
			label="BlenderBlend::DnaField";
			graph[style=dotted];

			dna_field__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
				<TR><TD PORT="idx_type_pos">0</TD><TD PORT="idx_type_size">2</TD><TD>u2le</TD><TD PORT="idx_type_type">idx_type</TD></TR>
				<TR><TD PORT="idx_name_pos">2</TD><TD PORT="idx_name_size">2</TD><TD>u2le</TD><TD PORT="idx_name_type">idx_name</TD></TR>
			</TABLE>>];
			dna_field__inst__type [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">id</TD><TD BGCOLOR="#E0FFE0">value</TD></TR>
				<TR><TD>type</TD><TD>_parent._parent.types[idx_type]</TD></TR>
			</TABLE>>];
			dna_field__inst__name [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">id</TD><TD BGCOLOR="#E0FFE0">value</TD></TR>
				<TR><TD>name</TD><TD>_parent._parent.names[idx_name]</TD></TR>
			</TABLE>>];
		}
	}
	blender_blend__seq:hdr_type -> header__seq [style=bold];
	blender_blend__seq:blocks_type -> file_block__seq [style=bold];
	dna1_body__seq:structs_type -> blender_blend__inst__sdna_structs [color="#404040"];
	dna_struct__seq:fields_type -> dna_field__seq [style=bold];
	dna_struct__seq:num_fields_type -> dna_struct__seq:fields__repeat [color="#404040"];
	dna1_body__seq:types_type -> dna_struct__inst__type [color="#404040"];
	dna_struct__seq:idx_type_type -> dna_struct__inst__type [color="#404040"];
	header__inst__psize:psize_type -> file_block__seq:mem_addr_size [color="#404040"];
	file_block__seq:body_type -> file_block__seq_body_switch [style=bold];
	file_block__seq_body_switch:case0 -> dna1_body__seq [style=bold];
	file_block__seq:code_type -> file_block__seq:body_type [color="#404040"];
	blender_blend__inst__sdna_structs:sdna_structs_type -> file_block__inst__sdna_struct [color="#404040"];
	file_block__seq:sdna_index_type -> file_block__inst__sdna_struct [color="#404040"];
	dna1_body__seq:num_names_type -> dna1_body__seq:names__repeat [color="#404040"];
	dna1_body__seq:num_types_type -> dna1_body__seq:types__repeat [color="#404040"];
	dna1_body__seq:num_types_type -> dna1_body__seq:lengths__repeat [color="#404040"];
	dna1_body__seq:structs_type -> dna_struct__seq [style=bold];
	dna1_body__seq:num_structs_type -> dna1_body__seq:structs__repeat [color="#404040"];
	header__seq:ptr_size_id_type -> header__inst__psize [color="#404040"];
	dna1_body__seq:types_type -> dna_field__inst__type [color="#404040"];
	dna_field__seq:idx_type_type -> dna_field__inst__type [color="#404040"];
	dna1_body__seq:names_type -> dna_field__inst__name [color="#404040"];
	dna_field__seq:idx_name_type -> dna_field__inst__name [color="#404040"];
}