Json encode / decode questions

Apologies for such a basic question. This is the first time I’ve used the json.encode / json.decode functions, and I’ve clearly missed something basic. Though the help document indicates that the encode statement will take any object that implements the metamethod, it gives no example of how to do so. I’ve searched Jason on the forum, and also did not see an example.

I tried implementing as I have simple things like a change in _index, but it doesn’t seem to be effective as I’m still getting an error stating encode won’t that “user data.”

So, someone give me a smack and explain the blindingly obvious thing I missed. Thanks.

Oh I see. You mean adding json encode/decode support to, say, a vec2? Can you be more specific about which objects you want to encode?

These are classes I created in the current application (in this case, a class called “Location” which is actually a work location within an office / work site and contains a number of fields, including a series of coordinates).

However, just an example of how to implement __tojson so that it supports json.encode would be fine. Even on something like a Vec2. All I can find is the notation in the help file that indicates .encode supports any object that implements the metamethod __json encode, but I can’t find any examples here or elsewhere showing what that implementation looks like.

Thanks.

So you’re trying to encode the instances of the location class? If they’re held in a table, you can encode that table, unless it contains “user data” (ie vectors, matrices etc). I’d also like to know how to implement json encoding for vectors etc. Do you know specifically within the location class, what part of it is causing the “user data” error? What I’m saying is, I don’t think you need to implement a custom json encode for your location class as such, you just need json encoding for the objects contained within it (from your description, vectors).

Eg. Instances of this class can be encoded, as long as they don’t contain “user data” (vectors).


--# Main
-- Json Test

-- Use this function to perform your initial setup
function setup() --cant use vec2s

    objects={
    MyClass(17), MyClass(23), MyClass(9)
    }
    
    tabSave()
    tabLoad()
end

function tabLoad()
    str=readProjectTab("Test")
    tab=json.decode(string.sub(str,3,-3))
    for k,v in pairs(tab) do
        print(v)
    end
   -- tab[1]:draw() --doesnt work
end

function tabSave()
     str=json.encode(objects)
    saveProjectTab("Test", "--"..str.."--")
end

--# MyClass
MyClass = class()

function MyClass:init(x)
    -- you can accept and set parameters here
    self.foo = "bar"
    self.x=x
    -- self.pos=vec2(50,50) --vec2 cant be used with json
end

function MyClass:draw()
    print (self.foo)
end

function MyClass:touched(touch)
    -- Codea does not automatically call this method
end

--# Test
--[{"x":17,"foo":"bar"},{"x":23,"foo":"bar"},{"x":9,"foo":"bar"}]--

I’m not sure the encode, decode works properly, or else I’m wrong in what I’m expecting. In the example below, table tab1 is created. I encode it and print the result. I then decode it into table tab2. I encode it and print the result so I can compare it to the original table. The results are the same, but maybe out of order which shouldn’t matter. I can print values from tab1, but I get errors when I try to print it from tab2.

function setup()
    tab1={a=123,b=456,{3,4,5}}
    z=json.encode(tab1)
    print(z)
    
    tab2=json.decode(z)
    z=json.encode(tab2)
    print(z)
    
    print("\
tab1 --------")
    for a,b in pairs(tab1) do
        print(a,b)
    end
    
    print("\
tab2 --------")
    for a,b in pairs(tab2) do
        print(a,b)
    end
 
    print("\
tab1 --------")
    print(tab1[1])
    print(tab1[1][1],tab1[1][2],tab1[1][3])
    
    print("\
tab2 --------")
    print(tab2[1])
    print(tab2[1][1],tab2[1][2],tab2[1][3])    
end    

My entry to the gamejam uses json for saving levels. Have a look at the Level IO tab in this:

https://gist.github.com/Utsira/8a364a35f397f26aefad

@yojimbo2000 Thanks, but it looks as if you’re encoding simple tables. That works fine for me, as well. My question is implementing the __tojson method within a complex object so that it can properly encoded. I can turn the object into the save string I’ve been using to file them away, or a set of key-value pairs and encode that, but there must be a neater way. After all, that seems like the work I expect out of encode / decode.

@dave1707, tab2 doesn’t have an integer key 1, but a string “1”. That’s because JSON only allows string keys, so when you encode/decode tab1 into tab2, the [1] = {3,4,5} becomes: [“1”] = {3,4,5}. You can see that in the first print of z.

@dave1707 mixing key-values with an array is a terrible idea IMO. You shouldn’t expect to be able to index it by number.

@Mark instead of adding the tojson method to whatever object you need encoding, how about using the “exception” field to catch the parts of the class that are causing json to fall over. If it’s just vec2s that should be quite straight forward. Can you show us the code for the class whose instances you’re trying to encode?

@Mark here’s my example from above, but using the “exception” field to catch the vec2s and convert them into a table/json object: "pos":{"x":9.0,"y":50.0}. I haven’t worked out how to do the equivalent decode though yet. I need to work out how to indictate that this is a type vec2.

Edit: v1.2 more elegant jsonException class, now indicates that table-object is a vec2 "pos":{"vec2":{"x":9.0,"y":50.0}}. No decoding of vec2s yet.

--# Main
-- Json Test

-- Use this function to perform your initial setup
function setup() 

    objects={
    MyClass(17), MyClass(23), MyClass(9)
    }
    
    tabSave()
    tabLoad()
end

function tabLoad()
    local str=readProjectTab("Test")
    local tab=json.decode(string.sub(str,3,-3))
    tabIterate(tab, "")
   -- tab[1]:draw() --doesnt work
end

function tabIterate(tab, indent)
    for k,v in pairs(tab) do
        if type(v)=="table" then print(indent..k.."=") tabIterate(v, indent.."  ") else print(indent..k,v) end
    end
end

function tabSave()
     str=json.encode(objects, {exception = jsonException})
    saveProjectTab("Test", "--"..str.."--")
end

function jsonException(reason, v, state, message)
    if v.x and v.y and not v.z then --vec2
        return json.encode({vec2={x=v.x,y=v.y}})
    end
end

--# MyClass
MyClass = class()

function MyClass:init(x)
    -- you can accept and set parameters here
    self.foo = "bar"
    self.x=x
    self.pos=vec2(x,50) --vec2 cant be used with json without an exception class
end

function MyClass:draw()
    print (self.foo)
end

function MyClass:touched(touch)
    -- Codea does not automatically call this method
end

--# Test
--[{"pos":{"vec2":{"x":17.0,"y":50.0}},"foo":"bar","x":17},{"pos":{"vec2":{"x":23.0,"y":50.0}},"foo":"bar","x":23},{"pos":{"vec2":{"x":9.0,"y":50.0}},"foo":"bar","x":9}]--

Here’s a version that attempts to decode the vec2s. It’s not particularly elegant, as there’s no corresponding equivalent to the exception function in json.decode (this is where implementing the __tojson meta method might be the way to go, as @Mark said in his original enquiry).

Edit: here’s a working version of the code

--# Main
-- Json Test

-- Use this function to perform your initial setup
function setup()
    
    objects={
    MyClass(17), MyClass(23), MyClass(9)
    }
    
    tabSave()
    tabLoad()
end

function tabLoad()
    local str=readProjectTab("Test")
    local result=json.decode(string.sub(str,4,-2))
    result=tabIterate(result)
    result=tabIterate(result) --re-iterate to see if decoding has stuck
end

function tabSave()
    str=json.encode(objects, {exception = jsonException, indent = true})
    saveProjectTab("Test", "--["..str.."]")
end

local underscore = {"=","~","-","."} --underscore characters indicate table depth

function tabIterate(tab, i)
    local new = {}
    local i = i or 0
    local indent = string.rep(" ", i*3) --depth of indentation
    for k,v in pairs(tab) do
        if type(v)=="table" then
            if v.vec2 then --convert back to vec2
                new[k] = vec2(v.x, v.y)
                print (indent..k..": decoding vec2"..tostring(new[k]))
            else
                local under = string.rep(underscore[math.min(#underscore, i+1)], string.len(k))
                print(indent..k.."\
"..indent..under)
                new[k]=tabIterate(v, i+1) --increase indent upon recursion
            end
        else
            if type(v)=="userdata" and v.x and v.y then --check whether vec2 decoding has worked
                print(indent..k..": vec2"..tostring(v))
            else
                print(indent..k..": "..v)
            end
            new[k]=v
        end
    end
    return new
end

function jsonException(reason, v, state, message)
    if v.x and v.y and not v.z then --vec2
        return json.encode({x=v.x,y=v.y,vec2=true}) --set a vec2 flag
    end
end

--# MyClass
MyClass = class()

function MyClass:init(x)
    -- you can accept and set parameters here
    self.foo = "bar"
    self.x=x
    self.pos=vec2(x,50) --vec2 cant be used with json without an exception class
end

function MyClass:draw()
    print (self.foo)
end

function MyClass:touched(touch)
    -- Codea does not automatically call this method
end

--# Test
--[[{
    "foo":"bar",
    "pos":{"vec2":true,"y":50.0,"x":17.0},
    "x":17
  },{
    "foo":"bar",
    "pos":{"vec2":true,"y":50.0,"x":23.0},
    "x":23
  },{
    "foo":"bar",
    "pos":{"vec2":true,"y":50.0,"x":9.0},
    "x":9
  }]]

here is how to implement _toJjson to vec2


--# Main
-- Json Test

-- Use this function to perform your initial setup
function setup() --cant use vec2s
    objects={
    MyClass(17), MyClass(23), MyClass(9)
    }
    Vec2ToJson()
    tabSave()
    out = tabLoad()
    setmetatable(out,{__tostring = function(obj)
        return json.encode(obj,{indent=true}) 
        end})
    print(out)
end

function Vec2ToJson()
    local meta = getmetatable(vec2())
    meta.__tojson = function(t)
        local a = {x=t.x,y=t.y}
        return json.encode(a)
    end
end

function tabLoad()
    local str=readProjectTab("Test")
    str = string.sub(str,4,-4)
    return json.decode(str)
end

function tabSave()
     local str=json.encode(objects,{indent=true})
    saveProjectTab("Test", "--["..str.."]--")
end


--# MyClass
MyClass = class()

function MyClass:init(x)
    -- you can accept and set parameters here
    self.foo = "bar"
    self.x=x
    self.pos=vec2(50,50) --vec2 cant be used with json
end

function MyClass:__tostring()
    return json.encode(self,{indent=true}) 
end



--# Test
--[[{
    "foo":"bar",
    "pos":{"x":50.0,"y":50.0},
    "x":17
  },{
    "foo":"bar",
    "pos":{"x":50.0,"y":50.0},
    "x":23
  },{
    "foo":"bar",
    "pos":{"x":50.0,"y":50.0},
    "x":9
  }]]--

@Jmv38 that’s awesome, thanks. Though might I suggest adding a vec2=true flag to the json-vec2 so that the decode process can convert it back to a genuine vec2 (rather than leaving it as a pseudo-vec2 table)? Unless someone can think of a more elegant way to handle the decode?

@yojimbo2000 i agree. I had not enough time to rework and post your last version, so i just posted this one to show you how to use __toJason (as you asked for it earlier). Thanks.

Ok, here’s my version using @Jmv38 's meta methods. It now supports vec2, vec3, vec4, matrix, with support for conversion back to the proper types. In the code below I show it recreating the instances of the class in the objects table from the saved code.


--# Main
-- Json Test

-- Use this function to perform your initial setup
function setup()
    VecToJson() --establish metamethods for encoding vec2, vec3, vec4, matrix as json objects
    objects={
    MyClass{pos=vec3(17,18,19), angle=45, foo="bar"}, 
    MyClass{pos=vec4(123,124,127,1), angle=0, marzipan="tasty", foo="boo"}, 
    MyClass{pos=vec3(257,263,278), angle=-90, boolean=true, foo="bah"}
    }
    
    for i=1,2 do --do this twice to check back-conversion
        tabSave(objects, "Test")
        result=tabLoad("Test")
        result=tabIterate(result) --decode json objects back to vec2, vec3, vec4
        result=tabIterate(result) --re-iterate to see if decoding has stuck
        objects = {} --clear objects
        for i,v in ipairs(result) do
            objects[i]=MyClass(v) --recreate them from loaded table
        end
    end --rinse and repeat
end

function VecToJson()
    local meta = getmetatable(vec2())
    meta.__tojson = function(t)
        return json.encode({x=t.x,y=t.y,vec2=true})
    end
    meta = getmetatable(vec3())
    meta.__tojson = function(t)
        return json.encode({x=t.x,y=t.y,z=t.z,vec3=true})
    end
    meta = getmetatable(vec4())
    meta.__tojson = function(t)
        return json.encode({x=t.x,y=t.y,z=t.z,w=t.w,vec4=true})
    end
    meta = getmetatable(matrix())
    meta.__tojson = function(t)
        return json.encode({values={t[1],t[2],t[3],t[4], t[5],t[6],t[7],t[8], t[9],t[10],t[11],t[12], t[13],t[14],t[15],t[16]},mat=true}) --a matrix.unpack function would've been handy here!
    end
    
end

function tabSave(tab, loc)
    local str=json.encode(tab, {indent = true}) --exception = jsonException, 
    saveProjectTab(loc, "--["..str.."]")
end

function tabLoad(loc)
    local str=readProjectTab(loc)
    return json.decode(string.sub(str,4,-2))
end

local underscore = {"=","~","-","."} --underscore characters indicate table depth

function tabIterate(tab, i)
    local new = {}
    local i = i or 0
    local indent = string.rep(" ", i*3) --depth of indentation
    for k,v in pairs(tab) do
        if type(v)=="table" then
            if v.vec2 then --convert back to vec2
                new[k] = vec2(v.x, v.y)
                print (indent..k..": decoding vec2"..tostring(new[k]))
            elseif v.vec3 then --convert back to vec3
                new[k] = vec3(v.x, v.y, v.z)
                print (indent..k..": decoding vec3"..tostring(new[k]))
            elseif v.vec4 then --convert back to vec4
                new[k] = vec4(v.x, v.y, v.z, v.w)
                print (indent..k..": decoding vec4"..tostring(new[k]))
            elseif v.mat then --convert back to matrix
                new[k] = matrix(table.unpack(v.values)) 
                print (indent..k..": decoding matrix"..tostring(new[k]))
            else --genuine table
                local under = string.rep(underscore[math.min(#underscore, i+1)], string.len(k))
                print(indent..k.."\
"..indent..under)
                new[k]=tabIterate(v, i+1) --increase indent upon recursion
            end
        else
            print(indent..k..": "..tostring(v))         
            new[k]=v
        end
    end
    return new
end

--[[ --not needed when using meta-methods
function jsonException(reason, v, state, message)
    if v.x and v.y and not v.z then --vec2
        return json.encode({x=v.x,y=v.y,vec2=true}) --set a vec2 flag
    end
end
  ]]

--# MyClass
MyClass = class()

function MyClass:init(t)
    for k,v in pairs(t) do
        self[k]=v
    end
    self:draw()
end

function MyClass:draw() --some pseudo drawing
    translate(self.pos.x, self.pos.y, self.pos.z)
    rotate(self.angle)
    self.matrix=modelMatrix()
    print(self.foo)
    resetMatrix()
end

--# Test
--[[{
    "angle":45,
    "foo":"bar",
    "pos":{"y":18.0,"x":17.0,"vec3":true,"z":19.0},
    "matrix":{"values":[0.70710676908493,0.70710676908493,0.0,0.0,-0.70710676908493,0.70710676908493,0.0,0.0,0.0,0.0,1.0,0.0,17.0,18.0,19.0,1.0],"mat":true}
  },{
    "foo":"boo",
    "angle":0,
    "matrix":{"values":[1.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,1.0,0.0,123.0,124.0,127.0,1.0],"mat":true},
    "pos":{"y":124.0,"x":123.0,"w":1.0,"vec4":true,"z":127.0},
    "marzipan":"tasty"
  },{
    "pos":{"y":263.0,"x":257.0,"vec3":true,"z":278.0},
    "angle":-90,
    "foo":"bah",
    "boolean":true,
    "matrix":{"values":[-4.3711388286738e-08,-1.0,0.0,0.0,1.0,-4.3711388286738e-08,0.0,0.0,0.0,0.0,0.99999994039536,0.0,257.0,263.0,278.0,1.0],"mat":true}
  }]]

you are faster than me! I was preparing this: a version to manage any class with “Class” keyword. How do you like it?


--# Main
-- Json Test

-- Use this function to perform your initial setup
function setup() --cant use vec2s
    objects={
    MyClass(17), MyClass(23), MyClass(9)
    }
    Vec2ToJson()
    Vec3ToJson()
    tabSave()
    out = tabLoad()
    setmetatable(out,{__tostring = function(obj)
        return json.encode(obj,{indent=true}) 
        end})
    print(out[1].pos)
    print(out[1].mis)
end

function Vec2ToJson()
    local meta = getmetatable(vec2())
    meta.__tojson = function(t)
        local a = {Class="vec2",x=t.x,y=t.y}
        return json.encode(a)
    end
end
function Vec3ToJson()
    local meta = getmetatable(vec3())
    meta.__tojson = function(t)
        local a = {Class="vec3",x=t.x,y=t.y,z=t.z}
        return json.encode(a)
    end
end

function tabLoad()
    local str=readProjectTab("Test")
    str = string.sub(str,4,-4)
    local t = json.decode(str)
    t = checkForClass(t)
    return t
end

function checkForClass(t)
    if type(t) ~= "table" then
        return t
    end
    for key,val in pairs(t) do
        if type(val) == "table" then
            t[key] = checkForClass(val)
        end
        local Class = t["Class"] 
        if Class then
            local obj = _G[Class]()
            for k,v in pairs(t) do
                if k~="Class" then
                    obj[k] = v
                end
            end
            t = obj
        end
    end
    return t
end

function tabSave()
     local str=json.encode(objects,{indent=true})
    saveProjectTab("Test", "--["..str.."]--")
end


--# MyClass
MyClass = class()

function MyClass:init(x)
    -- you can accept and set parameters here
    self.foo = "bar"
    self.x=x
    self.pos=vec2(50,50) 
    self.mis =vec3(1,2,3) 
end

function MyClass:__tostring()
    return json.encode(self,{indent=true}) 
end



--# Test
--[[{
    "x":17,
    "mis":{"x":1.0,"y":2.0,"z":3.0,"Class":"vec3"},
    "pos":{"x":50.0,"y":50.0,"Class":"vec2"},
    "foo":"bar"
  },{
    "x":23,
    "mis":{"x":1.0,"y":2.0,"z":3.0,"Class":"vec3"},
    "pos":{"x":50.0,"y":50.0,"Class":"vec2"},
    "foo":"bar"
  },{
    "x":9,
    "mis":{"x":1.0,"y":2.0,"z":3.0,"Class":"vec3"},
    "pos":{"x":50.0,"y":50.0,"Class":"vec2"},
    "foo":"bar"
  }]]--

i found this more general than vec2=true.

@Jmv38 Ok. Actually, I think my preferred method would be, rather than a keyword, nesting the data in a sub table with an appropriate key, eg a vec3 called pos looks like this: "pos":{"vec3":{"y":18.0,"x":17.0,"z":19.0}}. Edit, added exception method, has feature parity with meta-method:



--# Main
-- Json Test

-- Use this function to perform your initial setup
function setup()
   -- VecToJson() --establish metamethods for encoding vec2, vec3, vec4, matrix as json objects
    objects={
    MyClass{pos=vec3(17,18,19), angle=0, foo="bar"}, 
    MyClass{pos=vec2(123,124), angle=-45, marzipan="tasty", foo="boo"}, 
    MyClass{pos=vec3(257,263,278), angle=-90, boolean=true, foo="bah"}
    }
    
    for i=1,2 do --do this twice to check back-conversion
        tabSave(objects, "Test")
        local loadBack=tabLoad("Test")
        loadBack=tabIterate(loadBack) --decode json objects back to vec2, vec3, vec4
        print("---------------------\
DECODING COMPLETE, CHECKING\
---------------------")
        loadBack=tabIterate(loadBack) --re-iterate to see if decoding has stuck
        print("=====================\
RECREATING OBJECTS FROM DECODED DATA, CHECKING\
=====================")
        objects = {} --clear objects
        for i,v in ipairs(loadBack) do
            objects[i]=MyClass(v) --recreate them from loaded table
        end
    end --rinse and repeat
end

--meta-methods
function VecToJson()
    local meta = getmetatable(vec2())
    meta.__tojson = function(t)
       return json.encode({vec2={x=t.x,y=t.y}})
    end
    meta = getmetatable(vec3())
    meta.__tojson = function(t)
       return json.encode({vec3={x=t.x,y=t.y,z=t.z}})
    end
    meta = getmetatable(vec4())
    meta.__tojson = function(t)
        return json.encode({vec4={x=t.x,y=t.y,z=t.z,w=t.w}})
    end
    meta = getmetatable(matrix())
    meta.__tojson = function(t)
    return json.encode({mat4={t[1],t[2],t[3],t[4], t[5],t[6],t[7],t[8], t[9],t[10],t[11],t[12], t[13],t[14],t[15],t[16]}}) --a matrix.unpack function would've been handy here!
    end   
end

 --encode exception func can be used instead of meta-methods
function jsonException(reason, t, state, message)
    if t.x and t.y and t.z and t.w then --vec4
        return json.encode({vec4={x=t.x,y=t.y,z=t.z,w=t.w}})
    elseif t.x and t.y and t.z then --vec3
        return json.encode({vec3={x=t.x,y=t.y,z=t.z}})
    elseif t.x and t.y then --vec2
        return json.encode({vec2={x=t.x,y=t.y}})
    elseif t[16] then --matrix, presumably. nb #t not allowed. what other "userdata" types are there?     
        return json.encode({mat4={t[1],t[2],t[3],t[4], t[5],t[6],t[7],t[8], t[9],t[10],t[11],t[12], t[13],t[14],t[15],t[16]}}) --a matrix.unpack function would've been handy here!    
    end
end

function tabSave(tab, loc)
    local str=json.encode(tab, {indent = true, exception = jsonException}) 
    saveProjectTab(loc, "--["..str.."]\
")
end

function tabLoad(loc)
    local str=readProjectTab(loc)
    return json.decode(string.sub(str,4,-3))
end

local underscore = {"=","~","-","."} --underscore characters indicate table depth

function tabIterate(tab, i)
    local new = {}
    local i = i or 0
    local indent = string.rep(" ", i*3) --depth of indentation
    for k,v in pairs(tab) do
        if type(v)=="table" then --check first whether its a pseudo-table representing a vec2, vec3, vec4, mat4
            if v.vec2 then --convert back to vec2
                local vec = v.vec2
                new[k] = vec2(vec.x, vec.y)
                print (indent..k..": decoding vec2"..tostring(new[k]))
            elseif v.vec3 then --convert back to vec3
                local vec = v.vec3
                new[k] = vec3(vec.x, vec.y, vec.z)
                print (indent..k..": decoding vec3"..tostring(new[k]))
            elseif v.vec4 then --convert back to vec4
                local vec = v.vec4
                new[k] = vec4(vec.x, vec.y, vec.z, vec.w)
                print (indent..k..": decoding vec4"..tostring(new[k]))
            elseif v.mat4 then --convert back to matrix
                new[k] = matrix(table.unpack(v.mat4)) 
                print (indent..k..": decoding matrix"..tostring(new[k]))
            else --genuine table
                local under = string.rep(underscore[math.min(#underscore, i+1)], string.len(k))
                print(indent..k.."\
"..indent..under)
                new[k]=tabIterate(v, i+1) --increase indent upon recursion
            end
        else
            print(indent..k..": "..tostring(v))         
            new[k]=v
        end
    end
    return new
end

--# MyClass
MyClass = class()

function MyClass:init(t)
    for k,v in pairs(t) do
        self[k]=v
    end
    self:draw()
end

function MyClass:draw() --some pseudo drawing
    translate(self.pos:unpack()) --(self.pos.x, self.pos.y, self.pos.z)
    rotate(self.angle)
    self.matrix=modelMatrix()
    print(self.foo)
    resetMatrix()
end

--# Test
--[[{
    "pos":{"vec3":{"y":18.0,"z":19.0,"x":17.0}},
    "angle":0,
    "matrix":{"mat4":[1.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,1.0,0.0,17.0,18.0,19.0,1.0]},
    "foo":"bar"
  },{
    "foo":"boo",
    "matrix":{"mat4":[0.70710676908493,-0.70710676908493,0.0,0.0,0.70710676908493,0.70710676908493,0.0,0.0,0.0,0.0,1.0,0.0,123.0,124.0,0.0,1.0]},
    "pos":{"vec2":{"y":124.0,"x":123.0}},
    "angle":-45,
    "marzipan":"tasty"
  },{
    "foo":"bah",
    "angle":-90,
    "boolean":true,
    "pos":{"vec3":{"y":263.0,"z":278.0,"x":257.0}},
    "matrix":{"mat4":[-4.3711388286738e-08,-1.0,0.0,0.0,1.0,-4.3711388286738e-08,0.0,0.0,0.0,0.0,0.99999994039536,0.0,257.0,263.0,278.0,1.0]}
  }]]