Working in the App¶
The App has three tabs: Projects, Graphics assets and Maps. The words they use, project, bundle, attachment, group, release, are defined in Projects, bundles, releases.
Projects¶
The list of my projects; for the chosen project: its files (create, upload, delete, never main.lua), its attached bundles (view, edit, which opens the Graphics assets tab, detach, attach), publish, download, delete. A third panel shows the content of the chosen bundle, read-only.
Graphics assets¶
The RAW library (upload, view, delete) and the bundles: create one, add assets to it and remove them with their settings (alpha in additive / translucent / dithered / threshold, "behind the background"), Compute the palette, which produces the palette, the atlas and the indexed pages; edit one (reopen the recipe, recompute); delete one if it is attached nowhere. Then the variants and the backgrounds.
The library receives sprites only: an animated sprite is one animation row per upload. Backgrounds and tilesets come from the Maps tab, which is their only producer. The flow "continuous image, then clustering" happens only through the computation of a bundle.
Importing a sheet. A sheet laid out as an N×M grid is detected automatically and becomes an animation strip.
Maps¶
A mini Tiled: you draw 8×8 tiles there (RGBA, tile 0 is the hole) and paint them onto a world within the console's bounds (from 80×60 to 256×128 tiles, 704 tiles at most). The map is the source, editable at will; "Send as background" flattens it into an image and deposits it in the library as a background asset of the same name (the deposit replaces). The chain of bundles is unchanged and finds the drawn tiles again on its own, since they repeat. Deleting the map does not delete the sent asset.
Above 8×8, the stamps (16, 24, 32): grids of base tile ids, the model of metatiles. The world remains a grid of 8×8 ids, and everything downstream ignores the stamps. A stamp is composed in the workshop by painting its grid with a smaller brush, placed at 8 px steps (and cropped at the edges); the same paint engine serves the world, where the brush is a tile or a stamp of any side. Painting at the pixel is reserved for 8×8, the source of truth: retouching a base tile propagates to every stamp and to the whole map.
"Import a sheet" (_T.png, T ∈ {8, 16, 24, 32}) decomposes it into deduplicated base tiles, importing 24 also fills the 8×8 bar, and into stamps; an import that would overflow the 704 is refused with the count, before writing anything.
Each tile carries a solid tag; "Write <map>.mask" generates the collision mask in a project of the account, next to the code that will call phy.map("<map>"). One cell of the mask = one tile (8×8): the geometry of the mask is exactly that of the drawing. One geometry, drawn once: the scenery and the mask can no longer contradict each other.
The recipe of a bundle¶
A bundle reopens: the editor gets back what was kept, the assets in order, the name seen by the game, the alpha mode (additive / translucent / dithered / threshold), the outline (none / fade / dark), "behind the background", and the animation in three states: auto (the App's measurement decides, this is the default), yes (one animation, one row), no (distinct sprites, one row each). The plan of the rows belongs to the bundle.
"Compute the palette" replays everything in the browser, with the simulator's engine. "Save" posts the pieces and the recipe, and replaces the bundle under the same name: a bundle does not rename, another name would be another bundle.
A bundle attached to projects says so, and names them: recomputing it changes what they will publish next time, and it cannot be deleted as long as it is attached. An asset used by a bundle cannot be deleted either.
The \"recalculate\" banner
A bundle is a compiled product: redepositing an asset in the library does not recompute it. The App flags a bundle that is behind its recipe, and it stays behind until you recompute it.
Backgrounds¶
A background is an asset of kind background: the whole world in one RGBA image, dimensions multiples of 8, 2048×1024 at most (the board's tile map is 256×128 tiles); the transparent pixels are the hole. In the recipe of a bundle it has no setting: it is quantised with the sprites of the group (a single palette, that is the whole reason it is there), then tiled: distinct 8×8 tiles by decreasing frequency, tile 0 is the hole, 704 at most; beyond that, clustering by similarity (k-means in colour, the mean of each cluster reprojected onto the indices in use): a continuous image becomes a soft mosaic instead of a brutal replacement, and the loss is counted. Outside the atlas, outside the pool.
It produces two pieces, kept under its short name (grotte): the text map and the tile sheet (an indexed PNG, 32 tiles per row). On output they take the prefix of the group: niveau1-grotte.map and niveau1-grotte-tiles.png in a release (the name of the attachment), caverne-… in the bundle's zip (the bundle's own name), because gfx.bundle() links a background to its group by this prefix. The game writes gfx.background("niveau1-grotte").
Variants¶
A variant, <group>.<variant>.pal, is the same indices with other colours: day/night, a flash; no image, and gfx.palette("<group>.<name>") switches in real time.
In the App, a variant is defined by its settings (hue, saturation, lightness applied to the bundle's palette) and the derived .pal; the page re-derives the colours at each "Compute the palette", so recomputing a bundle never desynchronises its variants. The blend modes stay those of the bundle: a variant never changes the rows, that is its definition, and the App refuses it. The preview "on the console" can be displayed in a variant. On output, the prefix is the group's: niveau1.nuit.pal in the release, caverne.nuit.pal in the bundle's zip.