Framsticks file and data format specification 

This page describes the format of files used by the Framsticks simulator. The same basic format is used for storing genotypes, scripting extensions and settings. Some constants are also documented here.

General rules for all files

All files used by Framsticks are text-only files, which means that they can be easily viewed (or edited by advanced users) using your favourite text viewer/editor.

A file may contain any number of objects of various classes. Objects contain properties (a.k.a. fields) with names and values. Unlike XML there is no hierarchy nor relation between objects, however the application can interpret the sequence of objects in this way (eg. "GenotypeGroup:" contains "org:").

ClassName:
fieldname:value
fieldname2:value2
...etc

  ← empty line ends the object contents

ClassName2:
somefieldname:somevalue
...etc

Lines starting with "#" (hash) are comments (but not inside multiline fields).
The special #include comment includes the contents of another file at the point where this directive is placed. (This feature is provided to facilitate creating Framsticks script files by users. The Framsticks application itself never generates files with #include, so you can ignore this directive when reading genotype files).

There is an official C++ source for parsing the Framsticks file format: see MultiParamLoader, MiniGenotypeLoader and loadertest.cpp from the SDK.

Examples of some popular classes:

Class Description Most important properties Used in files
org Genotype with recorded performance data name, genotype, info *.gen, *.expt
property Property definition (for scripting) id, name, type *.neuro, *.expdef, *.show, *.style
sim_params Simulator settings expdef *.sim, *.expt
GenotypeGroup Genotype group settings. The "org" objects following a GenotypeGroup object are considered members of the group name, fitness *.gen, *.expt
class Neuron definition name, code *.neuro

Field (property) value syntax

If a field value contains \n (newline character), then the whole value is embedded in ~ signs:

fieldname:~     ← note that the value starts in the next line
a multi-line value here, there may be
many lines of
text~

In the above example, the value will be "a multi-line value here, there may be\nmany lines of\ntext".

If there is a ~ sign within the field value, it must be quoted as \~

Values for properties of simple types (d,s,f) are parsed according to the respective type.

Values for properties of type x (universal fields) can be interpreted as string, integer, float or object, depending on the contents of the property:

  • if it can be parsed as a number, then it becomes an integer or a float (integers can be hexadecimal using the 0x or 0X notation, positive or negative)
  • if it starts with prefix @Serialized:, special handling must be used allowing for object passing and more precise type control:
    • numbers are stored directly
    • strings are enclosed in double quotes " (and special characters (" \n \t) are quoted with backslash)
    • null (without quotes) is a special empty value
    • Vector objects are written as [value1,value2,value3] where each value is encoded using the same serialization algorithm
    • Dictionary objects are written as {key1:value1,key2:value2,key3:value3} (as above, and all keys must be strings)
    • Objects of other classes are serialized by appending a string, vector or dictionary after the object class name (depending on what de/serialization method is available for a given class - toVector(), toDictionary() or toString()). Currently the only classes supporting serialization (besides Vector and Dictionary) are XYZ and Orient and they use vector-type serialization, like this: XYZ[1.0,2.0,3.0] and Orient[1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0]
    • Classes that do not support serialization are serialized by printing the object class name (just as described above) and then <any string> (note angle brackets), which usually is the memory address
    • Vector and Dictionary objects can contain objects (or, strictly speaking, object references), and de/serialization procedure preserves object identities and relations by remembering all emitted objects and placing a special reference instruction ^NUMBER instead of the object being serialized, whenever a previously remembered object is encountered. Objects are uniquely numbered from left to right, starting with 0 (0 being the "root" object). Numeric values, strings, null objects, and nonserializable objects (of the form ClassName) are not numbered.
    • @Serialized should not be used in cases where simple method is sufficient, and it may only be used for property types x and o.
  • else the property value is a string.
Example: (assuming all properties are of type x)
SomeObject:
f1:123                                  (interpreted as integer)
f2:-0x125                               (integer, hexadecimal notation)
f3:12.3e+05                             (floating point number)
f4:-12.3                                (floating point number)
f5:                                     (empty string)
f6:123x                                 (string "123x" - not a number even though it starts with a number)
f7:@Serialized:"123"                    (string, enforced by quotes)
f8:@Serialized:"\""                     (string containing one quote character - but this form should not be used...
f9:"                                    (...because this simple method gives the same string value)
f10:@Serialized:                        (incorrect encoding, the (empty) text following @Serialized:
                                        is not recognized as any known type)
f11:@Serialized:"@Serialized:"          (this string value can't be encoded using the simple method)
f12:@Serialized:[+0X10,null,"abc"]      (Vector object containing a number, null element and string)
f13:@Serialized:{"a":123,"b":[0x7,8,9]} (Dictionary object containing a Vector object as one of the values)
f14:@Serialized:[[[]]]                  (empty Vector in a Vector in a Vector)
f15:@Serialized:["\n\n",""]             (two Vector elements: string containing two newlines and empty string)
f16:@Serialized:Population<0x85f53a8>   (the object that does not support serialization)
#
#  some examples where multiple references to the same object(s) are stored - the ^ char is used:
#
f17:@Serialized:[^0]            (Vector containing a reference to itself (infinite loop))
f18:@Serialized:[44,[^1]]       (Vector containing a value 44 and the self-referencing vector as in
                                 previous example - note the "self reference" is now ^1)
f19:@Serialized:[[100],["abc"],[300,^2]]          (["abc"] is second object (referenced by ^2), numbers
                                                   and string do not count as objects)
f20:@Serialized:[[123,[]],["x",^0],^2]            (root[0][1]==root[2], root[1][1]==root,
                                                   root[1][1][1][1][1][0]=="x")
f21:@Serialized:{"a":[33,44],"b":^1,"c":[33,44]}  ("a" and "b" point to the same object,
                                                   "c" contains the same two numbers but is unrelated)
f22:@Serialized:[null,null,[1,2],null,^1]         (^1 refers to [1,2], null does not count as object)

Defining properties

Properties are very common in Framsticks. You see them in the GUI, you can access them in scripts. A property can be treated as a variable or attribute of some object. In *.expdef, *.show, *.neuro and *.style files you can create properties by adding the "property" objects.

Example:

property:
id:cr_c
name:Constant
type:f -10000 10000
help:Constant value added to total fitness
group:Fitness
The "property" itself has 6 fields:
  • id – internal property name (for scripting)
  • name – user-friendly name (displayed in the user interface where appropriate)
  • type – data type (see below)
  • flags – additional information
  • help – additional description (for a tooltip, or documentation)
  • group – properties with the same group will be displayed together, if feasible.

Property types

The type of a property is defined by a string of the format
  • type[subtype] [min max [default] [~enum1~enum2~enum3]]

  • type is one of the following letters:
    • d (for 32-bit signed integers)
    • f (for 64-bit signed floating points – "double")
    • s (for strings of characters of any length)
    • x (universal type for values of any type)
    • o (objects)
    • p (procedures and functions)
    • l (lists of elements) and e (event source) are only used by the Framsticks server so they only need to be handled by network clients.
  • subtype (optional) can be safely ignored, as it is only for presentation/editing purposes.
    • for type d, the subtype can be 'b' or 'c'. 'b' is a hint for the GUI to present the property as a binary value (i.e. a list of binary on/off switches). 'c' informs that this integer property describes a color as 0x00BBGGRR (for colors, min and max must be defined as "0 16777215").
    • for type f, the subtype can be 't' or 'i'. 't' is a hint for the GUI to present the property as the calendar time. The property value is the number of seconds elapsed since 1970-01-01 0:00 UTC (known as the "unix time"). Subtype 'i' informs that this floating point property describes length of an interval of time, measured in seconds.

The minimum, maximum and default values have the usual meaning for 'd' and 'f' types. If you wanted to define the default value without introducing restrictions on min and max, use "0 -1" for min and max.

The 's' type is slightly different:

  • The minimum value tells if the string is multiline (0 means single line, 1 means multiline),
  • The maximum value defines the maximum allowed length (in characters) of the string (set −1 or do not give any value to allow any length),
  • The default value can contain spaces (so it does not strictly adhere to the general format where spaces separate min/max/default fields), but trailing and leading spaces are stripped,
  • The default value must not contain tilde ~ characters (this would clash with enumeration).

The "enum..." optional part can only be used for types 'd' and 's'. For 's', the enum list can be used by the GUI as a list of suggested string values (but it does not limit in any way strings entered by a user). For 'd', it can be used by the GUI as a list of string choices that are associated with integer values, starting from the minimum value.

Some examples:

  • "d" – an integer property
  • "f −2.3 5.5" – a floating point property, allowed range -2.3..5.5
  • "s" – a single-line string, any length
  • "s 1 500" – a multiline string, up to 500 chars
  • "d -1 3 2 ~unknown~very low~low~medium~high" – an integer of value −1, 0, 1, 2 (default) or 3, with textual labels assigned (and shown by a smart GUI)
  • "dc 0 16777215 255" – a color, blue as default

The 'o' type is used for object values. The syntax is "o[ClassName]".

The 'p' type is used for procedures and functions. The syntax is

p[[ return_type](argument1_type[ argument1_name],argument2_type[ argument2_name])]

where return_type and argument_type is one of the previously mentioned types (d,f,s,o,x), shortened to single letters, except for "o", which can still declare the class name by appending it to "o" (without a space), eg. "oClassName". Argument names are optional.
For maximal compatiblity the parser could assume the following:
  • the word after "p" but before "(" is the return type (if present)
  • anything between "(" and ")" is arguments
  • everything else can be ignored
Examples:
  • "p" means "a procedure with unknown arguments and unknown return type". This is the only valid form of "limited-information-p", any other syntax always define the return value and all argument types.
  • "p()" means "a procedure without arguments that does not return anything". Lack of the return type declaration and argument types no longer means they are undefined - they are just defined as empty. It's the presence of "(" that makes the procedure fully defined.
  • "p oSomething()" is a procedure returning the Something class object.
  • "p(o Something)" procedure accepting a single object argument named Something.
  • "p(oSomething)" procedure accepting a single unnamed argument of class Something.
  • "p oResult(oGeno source genotype)" procedure accepting object of class Geno, returning Result. Note: argument name ("source genotype") may contain spaces.

More examples of property types

d
f
s
o
p
d
d 0 0 ~Default
d 0 1
d 0 -1 0
d 0 1 0
d 0 100000
d 0 1000000 0
d 0 10000000 1000000
d 0 1000000 10000
d 0 1 0 ~MechaStick~ODE
d 0 1 1
d 0 1 ~Cylinder~Box
d 0 1 ~Standard~Server style
d 0 2 0 ~Flat surface~Blocks~Height field
d 0 2 1 ~Don't print (mute)~Print summary~Print details
d 1 100 5
d -1 1 -1
d -1 999999 -1
d 2 50 10
db 0 2147483647 0
db 0 65535 0
dc 0 16777215 15126952
dc 0 16777215
f
f 0.001 1000.0 1.0
f 0.001 1.0 0.05
f 0.001 1.0 0.5
f 0.0 1.0 0.25
f 0.0 1.0 1.0
f 0.01 100.0 1.0
f 0.01 1000 5
f 0.0 4.0 0.4
f 0 0.5 0.01
f 0 0.5 0.5
f 0.05 0.7 0.2
f 0 -1 0
f 0 1 0
f 0 10 0
f 0 100 0
f 0 100 0.02
f 0 100 0.05
f 0 10 5
f 0 1 0.6
f 0 1 1e-5
f 10 10000 20
f 1 10 2
f -20 200 -1
f -2 2 0
ft 0 -1 0
s
s 0
s 0 -1 .
s 0 -1 scene_%04d.jpg
s 0 100
s 0 -1 joint
s 0 -1 neuro
s 0 -1 part
s 0 30
s 0 40
s 0 ~boids~capture-the-flag~dance~deathmatch~dump_creatures
s 1
s 1 -1
s 1 1000
o
oCreature
oCreatureSignals
oDictionary
oExpProperties
oExpState
oFile
oGenePool
oGenePools
oGenMan
oGeno
oInterface
oMechJoint
oMechPart
oModel
oNeuroClass
oNeuroDef
oNeuroProperties
oNeuroSignals
oOrient
oPopulation
oPopulations
oSimulator
oSlaveSimulators
oVector
oWorld
oWorldSignals
oXYZ
p
p()
p d()
p(d break conditions)
p(d break condition,s label)
p(d channel,f value)
p(x Creature object or index)
p d(d)
p d(d genotypes in tournament)
p d(d input)
p d(d item)
p d(d mask)
p d(d num)
p d(f)
p(d Field#,d Column width)
p d(f minimum similarity)
p(d freqency in Hz,d length in milliseconds)
p oCreature(x Genotype object or Geno object or string genotype or CreatureSnapshot object)
p oDictionary(s url,x post data or null,oFunctionReference callback or null)
p f(oMechPart source part,oCreature recipient creature,oMechPart recipient part,f requested_amount_of_energy)
p oGenotype(x Genotype object or Geno object or string genotype)
p(x function name or index,oVector arguments)
p(x genotype object or index)
p(x index or id)
p(x index or id,x value)
p(x index_or_object)
p(x key)
p x(s)
p x(s filename)
p x(s filename,d options,d genepool,d population)
p(x value)
p x(x index or id)
p x(x key)
p x(x key,x value)
p x(x value)
p x(x,x)

Property flags

A flag is a number that is converted to a binary form, and each bit has its own meaning. Therefore you can encode many options in a single number (e.g. 41=32+8+1=binary 101001, so three options are set).
The default value is 0, which means "public".

For properties, the following bits are used:

  • 1 – readonly
  • 16 – user readonly (user should not modify this property)
  • 32 – private (user should not see this property)
    This flag is commonly used in neuron definitions. Neuron properties are by default accessible from genotype level and visible to genetic operators. If you need a private internal variable you should set its flag to "32" (see "delay.neuro" example).

Specific file types and their contents

Neuron definitions (*.neuro)

Contains one "class:" object (which defines the neuron class) and any number of "property:" objects (which define neuron properties).

"class:" has the following properties:

  • name – neuron class name. It is used in genotypes and it must start with the capital letter
  • longname – friendly name (displayed in hints)
  • description – long description (optional)
  • code – contains the neuron script source.
    • function init() – invoked once for each neuron instance (so that you can e.g. initialize some internal state)
    • function go() – called in each simulation step. Should contain the neuron logic (i.e. assign a new output value to Neuro.state)
  • prefinputs is the preferred number of inputs of the neuron. −1 means "any number of inputs is OK".
  • prefoutput should be 1 if the neuron provides meaningful output value, 0 otherwise.
  • preflocation should be 0 if the neuron is not embodied, 1 if it is located on a Part, 2 if it is located on a Joint.
  • shape_types is a bit mask of supported Model ShapeType values, default 3=all shape types supported.
  • joint_shapes is a bit mask of supported Joint Shape values, default 15=all shapes supported.
  • vhints (visual hints) is a bit-field. Create the value by adding the following bits:
    • 1 = Invisible – don't draw neurons of this class
    • 2 = No label – don't draw classname label (below the neuron symbol) for this neuron class
    • 4 = First Part – draw the neuron at the first part when attached to a joint (default is in the middle)
    • 8 = Second Part – draw the neuron at the second part when attached to a joint (default is in the middle)
    • 16 = Effector – use muscle color when drawing this neuron
    • 32 = Sensor – use receptor color when drawing this neuron
    • more values and descriptions in enum Hint in modelparts.h.
  • icon is a neuron icon for use in NN diagrams, encoded as a comma-separated sequence of integer numbers.
    • N = the total number of all numbers following this one
    • NS = the number of line sequences
        repeated NS times:
      • NL = number of line segments (creating a polyline)
      • X,Y (repeated NL+1 times) - subsequent line segment coordinates, each line should fit in a 100x100 square
        - neuron input connections will be drawn at X=25 (varying Y for multiple inputs, Y=50 for a single input)
        - neuron output connection will be drawn at (X=100,Y=50)
      Example:
      17,2,4,25,5040,3060,3075,50100,50,1,40,5060,50
      N = 17 numbers following this oneNS = 2 line sequencesNL = the first sequence has 4 segmentscoordinates for 4 line segments = 5 endpoints = 10 numbersNL = the second sequence has 1 segmentcoordinates for 1 line segment

      See also: a script for creating *.neuro icon from SVG.

Experiment definitions (*.expdef)

Contains one "expdef:" object (the experiment definition), any number of "property:" objects (which define experiment parameters, ExpProperties), and any number of "state:" objects (which are internal state items, ExpState).

"expdef:" has the following properties:

  • name – experiment title (single line)
  • info – experiment description (multiline)
  • neurons – specifies which neuron classes will be available in this experiment. If you developed neurons that require a specific experiment definition, you can put these neuron files in a dedicated directory and declare their location using the neurons property. This way you avoid cluttering other experiment definitions with these neurons (if they require a specific expdef, they would not work with other expdef's anyway).
    Neurons that you want to be available are specified by:
    • neuron file name (relative to the scripts directory)
    • file pattern (as above, but can refer to more files at once by using a single asterisk *)
    • a special word std meaning "standard neurons" (i.e. all built-in neurons)
    Multiple neuron specifications must be separated by a comma (,)
    The default setting is "std,*.neuro" which means "use standard neurons and all scripting neurons from *.neuro files". The default setting illustrates how to use a comma to separate two specifications, and how to use a file pattern to specify all file names ending with .neuro.
  • code – contains the experiment script source.