Veduta

Project Layout

veduta init mygame (or Veduta: New Game) creates:

mygame/
├── main.lua                  the game's code
├── veduta.json               the manifest: name, engine version, defaults
├── card.json                 how the console's dashboard lists the game
├── assets/
│   ├── scenes/main.vscene
│   ├── models/quad.vmodel          a 1 × 1 square, the shape of every sprite
│   └── materials/sprite.vmat       the settings a sprite material needs
├── tests/scenarios/start.vscenario
├── .github/workflows/release.yml   publishes the game when you tag a version
├── .veduta/, .vscode/, .luarc.json editor setup: API definitions and JSON schemas
├── CLAUDE.md, .mcp.json            for an AI agent working on the game (veduta mcp)
├── README.md, CHANGELOG.md, .gitignore

A .git repository is created too. The tool writes what it produces (test runs, renders, fuzz results, and the simulator's saves) under out/, and compiled assets under assets/.cooked/: both are ignored by git and never need editing.

The Project view

In VS Code, the Veduta icon in the activity bar opens the game as a tree: Game (veduta.json, card.json, README, CHANGELOG), Scripts, Scenes, Worlds, Maps, Prefabs, Models, Materials, Textures, Images (the PNG files under assets/) and Scenarios, each with its folders. What the tool writes (out/, assets/.cooked/, the editor files) is not there.

Right-click a section or a folder to make something in it: New Scene…, New Prefab…, New Script… and so on, and New Folder…. You type the name only; the file is written by veduta new, the same as in a terminal, so it builds as it is:

NewIs
scenean empty scene with an orthographic camera
worlda flat world of one biome; the first one also brings the ground material and its tiling texture
mapa 16 × 12 map of one terrain, opened in the map editor; the first one also brings the ground texture
prefaban empty prefab, 1 × 1 m
modela 1 m box standing on its base
materiala light grey material
texturea 32 × 32 grey texture
scenarioa run of 20 ticks from the game's start (or, New Scenario Starting Here… on a scene or world, from there) that checks the invariants
scriptan empty Lua module, with the require that loads it

A scene or a world also has Play from Here, a scenario Run Scenario and Debug Scenario, a texture its preview; every file and folder can be renamed (an asset keeps its extension, and its name stays unique in its kind) and deleted. Renaming an asset does not change what refers to it: the build that follows shows those places in Problems.

Where things go

PathHolds
*.lua anywhere in the projectscripts; main.lua is the entry point, the others are modules loaded with require
assets/scenes/<name>.vscenescenes
assets/models/<name>.vmodelmodels
assets/materials/<name>.vmatmaterials
assets/textures/<name>.vtextextures; PNG files they use can sit anywhere under assets/
assets/worlds/<name>.vworldworlds
assets/maps/<name>.vmaptile maps
assets/prefabs/<name>.vprefabgroups of entities placed by worlds
tests/scenarios/<name>.vscenarioscenarios
tests/golden/the recorded outcome of each scenario, written by veduta test

An asset's name is its file name without the extension: assets/materials/hero.vmat is the material hero. Names are 1 to 64 characters of a-z, 0-9, _ and -, starting with a letter or a digit. Sources can be sorted into folders under their kind's directory (assets/materials/enemies/bat.vmat is still the material bat), so a name must be unique across the folders; scenarios too can sit in folders of tests/scenarios/. veduta move, veduta rename and the Project view in VS Code move and rename sources and change what names them. See Structuring a Large Game.

Every source is a JSON file with the extension of its format (.vscene, .vmodel, .vmat, .vtex, .vworld, .vmap, .vprefab, .vscenario; VS Code opens them as JSON) and starts with a "veduta" header naming its format ("scene/1", "material/1", …). A project made before v2.0.0-rc.8 has crate.model.json and so on: veduta upgrade renames them. Decoding is strict: an unknown field, a duplicate key or a wrong type is an error with its file, line and column, and VS Code underlines it as you type.

veduta.json

{
  "veduta": "project/1",
  "name": "gemcave",
  "title": "Gem Cave",
  "engine": "v2.0.0-rc.5",
  "script": "main.lua",
  "icon": "icon.png"
}
FieldDefaultMeaning
vedutarequired"project/1"
namerequiredlowercase identifier, used for folders and archives
titlethe namewhat players see on the dashboard: spaces and accents allowed
enginerequiredthe engine version the game targets; veduta upgrade changes it
scriptnonethe main Lua file. Its presence is what makes the project a Lua game.
api1the Lua API level the game needs
iconnonea PNG outside assets/, shown beside the title on the dashboard
resolution[320, 240]the frame the game is designed for
tick_rate20ticks per second; the console shows 20 frames a second, keep 20
default_scene"main"the scene the game starts in
default_worldnonea world to start in instead of a scene
default_seed1seed of the random generator when none is given
invariants[]checks run in every test, see Testing
bounds±100 mthe box the within_bounds invariant keeps entities in

The full list is in the project format.

card.json

The console's dashboard reads it to list the game:

{
  "veduta": "card/1",
  "title": "Gem Cave",
  "name": "gemcave"
}

title and name must agree with veduta.json; veduta doctor says when they do not. veduta deploy adds the version and the icon to the copy it puts on the card.

Editor files

.veduta/lua/veduta.d.lua describes the API to the Lua extension (completion, hover, checks), .veduta/schema/ holds the JSON schemas of every format, and .vscode/ and .luarc.json point the editor at them. veduta upgrade refreshes them when the engine changes: do not edit them by hand.

Veduta v2 (Lua games, release candidates). This wiki is built from wiki/ in the engine's repository, where its examples are tested, and published with every engine release on https://veduta.roomve.it/docs/.