Hey Skaruts, I'm not sure what you are trying to do with Love2D, but I thought this might interest you so I'll paste it here.
It's a demo using the Love API via the Lua VM: # main.nim # -- a bunch of glue code to get lua working -- type luacfunc = proc(luaState: pointer): cint luaL_reg = object name: cstring function: luacfunc luaL_reg_ref = ref luaL_reg luaL_reg_list = array[3, luaL_reg] proc reg(name: cstring, function: luacfunc): luaL_reg_ref = new result result.name = name result.function = function const luaGlobalsIndex = -10002 const luaRegistryIndex = -10000 var luaState: pointer proc luaL_ref(lua_State: pointer, t: cint): cint {.importc: "luaL_ref".} proc luaL_openlib(luaState: pointer, name: cstring, lib: luaL_reg_list, someval: cint) {.importc: "luaL_openlib".} proc lua_settop(luaState: pointer, index: cint) {.importc: "lua_settop".} proc rawgeti(luaState: pointer, index1, index2: cint) {.importc: "lua_rawgeti".} proc pop(luaState: pointer, index: cint) = lua_settop(luaState,-(index)-1) proc getfield(luaState: pointer, a: cint, name: cstring) {.importc: "lua_getfield".} proc setfield(luaState: pointer, a: cint, name: cstring) {.importc: "lua_setfield".} proc luaPcall(luaState: pointer, a, b, c: cint): cint {.importc: "lua_pcall".} proc luaToString(luaState: pointer, index: cint, size: cint): cstring {.importc: "lua_tolstring".} proc luaToNumber(luaState: pointer, index: cint): cdouble {.importc: "lua_tonumber".} proc luaToBool(luaState: pointer, index: cint): cint {.importc: "lua_toboolean".} proc pushNumber(luaState: pointer, number: cdouble) {.importc: "lua_pushnumber".} proc pushString(luaState: pointer, s: cstring) {.importc: "lua_pushstring".} proc pushCClosure(luaState: pointer, function: pointer, a: cint) {.importc: "lua_pushcclosure".} proc pushFunction(luaState: pointer, function: pointer) = luaState.pushCClosure(function, 0) proc pullString(luaState: pointer, index: cint): string = $luaToString(luaState, index, 0) proc pullNumber(luaState: pointer, index: cint): float = luaToNumber(luaState, index) proc pullBool(luaState: pointer, index: cint): bool = return luaToBool(luaState, index) == 1 proc loveFunc(moduleName, funcName: string) = getfield(luaState, luaGlobalsIndex, "love") getfield(luaState, -1, moduleName) getfield(luaState, -1, funcName) # -- api wrapper -- type Image = distinct cint proc newImage(filename: string): Image = loveFunc("graphics", "newImage") luaState.pushString(filename) if luaPcall(luaState, 1, 1, 0) != 0: echo "proc newImage failed on the lua side ->", luaState.pullString(-1) quit 1 let res = luaState.luaL_ref(luaRegistryIndex).Image luaState.pop(1) return res proc getWidth(self: Image): float = luaState.rawgeti(luaRegistryIndex, self.cint) getfield(luaState, -1, "getWidth") luaState.rawgeti(luaRegistryIndex, self.cint) if luaPcall(luaState, 1, 1, 0) != 0: echo "proc getWidth failed on the lua side ->", luaState.pullString(-1) quit 1 let res = luaState.pullNumber(-1) luaState.pop(1) return res proc getHeight(self: Image): float = luaState.rawgeti(luaRegistryIndex, self.cint) getfield(luaState, -1, "getHeight") luaState.rawgeti(luaRegistryIndex, self.cint) if luaPcall(luaState, 1, 1, 0) != 0: echo "proc getHeight failed on the lua side ->", luaState.pullString(-1) quit 1 let res = luaState.pullNumber(-1) luaState.pop(1) return res proc draw( image: Image, x: float, # The position to draw the object (x-axis). y: float, # The position to draw the object (y-axis). r: float, # Orientation (radians). sx: float, # Scale factor (x-axis). Can be negative. sy: float, # Scale factor (y-axis). Can be negative. ox: float, # Origin offset (x-axis). (A value of 20 would effectively move your drawable object 20 pixels to the left.) oy: float, # Origin offset (y-axis). (A value of 20 would effectively move your drawable object 20 pixels up.) kx: float, # Shearing factor (x-axis). ky: float # Shearing factor (y-axis). ) = loveFunc("graphics", "draw") luaState.rawgeti(luaRegistryIndex, image.cint) luaState.pushNumber(x) luaState.pushNumber(y) luaState.pushNumber(r) luaState.pushNumber(sx) luaState.pushNumber(sy) luaState.pushNumber(ox) luaState.pushNumber(oy) luaState.pushNumber(kx) luaState.pushNumber(ky) if luaPcall(luaState, 10, 0, 0) != 0: echo "proc draw failed on the lua side ->", luaState.pullString(-1) quit 1 proc quitLove = loveFunc("event", "quit") if luaPcall(luaState, 0, 0, 0) != 0: echo "proc quit failed on the lua side ->", luaState.pullString(-1) quit 1 # -- app code below -- var image: Image proc loadCallback = image = newImage("sprite.png") echo "Image width (should be 300): ", image.getWidth() echo "Image height (should be 205): ", image.getHeight() proc drawCallback = draw(image, 10, 10, 0, 1, 1, 0, 0, 0, 0) proc keypressedCallback(key, scancode: string, isrepeat: bool) = if key == "escape": quitLove() # -- init -- proc drawWrapper(state: pointer): cint = luaState = state drawCallback() proc loadWrapper(state: pointer): cint = luaState = state loadCallback() proc keypressedWrapper(state: pointer): cint = luaState = state let key = state.pullString(1) let scancode = state.pullString(2) let isrepeat = state.pullBool(3) keypressedCallback(key, scancode, isrepeat) proc load(L: pointer): cint {.dynlib, exportc: "luaopen_libmain".} = {.emit: """NimMain();""".} luaState = L echo "lua opened nim lib" var mylib: luaL_reg_list = [ reg(nil, nil)[], reg(nil, nil)[], reg(nil, nil)[] ] luaL_openlib(L, "libmain", mylib, 0) pushFunction(L, drawWrapper) setfield(L, luaGlobalsIndex, "draw") pushFunction(L, keypressedWrapper) setfield(L, luaGlobalsIndex, "keypressed") pushFunction(L, loadWrapper) setfield(L, luaGlobalsIndex, "load") return 1 Run -- main.lua require "libmain" function love.load () load() end function love.draw () draw() end function love.keypressed (key, scanCode, isRepeat) keypressed(key, scanCode, isRepeat) end Run Compile and run: nim c --app:lib main.nim && love . Run Result: You would think that interacting with the engine by going [Nim]-->[Lua]-->[C++] would be slow but it actually doesn't seem to incur much overhead compared to just [Lua]-->[C++]