
Defold
Defold is a free, lightweight game engine whose small runtime is a natural fit for instant-loading Games.
Quick Start
Everything happens inside the Defold editor. Nothing else to install, nothing to delete from the template.
Step 1: Get the Template
Install Defold from defold.com (official manuals), then get the starter template: minit-template-defold. Use Code > Download ZIP on GitHub and unzip it, or clone the repo.
Want to see a finished Game first? minit-sample-defold is a bouncy-ball reference Game that works the same way.
Step 2: Open It and Fetch Libraries
In Defold, use Open From Disk and pick the template's game.project (Defold's New Project screen can't use it). Then run Project > Fetch Libraries. There is no other feedback. The minit folder does not appear in your project folder; it shows up under Dependencies in Defold's Assets pane. That is the Minit Games SDK, already listed as a dependency in the template. Quick check: press Ctrl+P and type minit.lua.
Build and run (Project > Build) to try the template.
Step 3: Name Your Game
Set the name in Project Settings > Title (game.project). Players see it, and minit.studio uses it on your first upload only.
Step 4: Import & Use the API
local minit = require("minit.minit")
-- Call once your game has booted and is ready to be shown
minit.loading_done()
-- Read a game-config value from the URL query string, e.g. ?difficulty=hard
local difficulty = minit.get_config_value("difficulty", "normal")
-- Read this player's persisted userData slot (or nil if never written)
local saved = minit.get_user_data()
local score = 1234 -- Replace with the final score from your game's own state
-- When the game ends, report the final score once (higher score = better)
minit.report_result(score)
minit.report_result(): the one call every Game must make. Options and result handling: Reporting Results.minit.loading_done(): optional; holds the host's reveal until your game is playable. Game Ready Signal.minit.get_user_data()/report_result(score, { user_data = ... }): optional per-player persistence (browser storage is unavailable in the sandboxed host). Saving User Data.minit.get_config_value(key, default): reads mod config values off the URL query string; outside the host it returnsdefault(desktop/mobile) or reads the URL directly (standalone HTML5 build). Declaring the keys: Config Values.minit.should_show_tutorial(): gate your first-play tutorial UI on it; it returnsfalseonce the app reports the player has played the Game, andtrueoutside an HTML5 build. Interactive Tutorials.minit.is_viewable()/minit.on_viewable_change(fn): whether the player can see the game right now. Pause When Off-Screen.
Step 5: Fill In meta.json
The template's meta.json is packaged with your build. description, controls and logic are recommended, not required:
controlsandlogic: players see them as Controls and Game Logic under "How to play" in the ⓘ sheet under the Game.description: shown behind "Show more".
minit.studio applies these on your first upload and on any upload that creates a new revision (after your latest revision is locked or has non-draft Posts, such as a scheduled or published Post); an upload that replaces your current draft ignores them, so edit them in minit.studio instead. Details and limits: meta.json reference, Writing your description and Limits & Constraints FAQ.
Step 6: Package and Upload
Run Project > Minit: Package for Upload. It bundles your Game, checks the bundle, and writes dist/<title>.zip with meta.json included. When it finishes, a dialog says the Game is ready to upload (with an Open dist folder button), or lists what failed. The same messages also go to the editor Console. The first run in a session may sit a few seconds without feedback.
The ZIP file name drops emoji and characters file names can't hold; your Game keeps its full title.
The ready-to-upload result also has a Textures: line: compressed as set in <path> or uncompressed (no texture profile in game.project). See Bundle Size.
Then upload dist/<title>.zip at minit.studio. There is no "zip your build folder" step.
Step 7: Test on Your Phone
Before publishing: on the game's page in minit.studio, click the QR button in the Live preview panel, then Generate preview link, and scan the code. With the Minit Games app installed, the Game opens in the app; without it, it plays on a web page with links to download the app. The link works for 15 minutes. Details: Testing Your Game on Device.
Start from a template
- minit-template-defold: minimal skeleton with the SDK wired; the SDK provides the packaging menu item
- minit-sample-defold: finished bouncy-ball example Game, and the reference Game for the Defold game jam
Bundling Manually
Prefer to bundle yourself? These are the Defold-specific requirements the menu item enforces. The menu item also checks the general upload limits and rules in Platform Requirements and Limits & Constraints FAQ, including:
- A script must call
minit.report_result, or packaging fails. No script callingminit.loading_doneonly gets a note. - The ZIP is at most 50 MB and holds at most 2000 files, at most 300 MB uncompressed;
index.htmlis at most 10 MB. meta.jsonconfighas at most 25 entries, each description at most 100 characters.
The licence (meta.json license) is not checked by the menu item: minit.studio checks it when you upload. See Licensing third-party content.
The Defold-specific requirements:
wasm-webis required. A multi-threaded (pthread) build fails in the app.- Use the release variant.
- Set
htmlfile = /minit/minit.htmlunder[html5]ingame.project. This is the Minit HTML shell from the SDK library; with the library dependency there is nothing to copy (without it, see the fallback below). - Keep the shell's audio repair as shipped. Without it the Game is silent in the app.
- Don't touch
localStorageorsessionStorage. The platform forbids web storage; use Saving User Data instead. - The bundle needs
index.html,dmloader.js,<name>.wasm,<name>_wasm.jsandarchive. index.htmlandmeta.jsonat the ZIP root, not nested in a folder.- Add
"title"to the ZIP'smeta.jsonyourself. The template'smeta.jsonhas none (only the menu item adds it), and without it your first upload becomes "Untitled Post". See the meta.json reference.
Also tick Texture compression in Project > Bundle and set the texture profile in game.project (see Bundle Size). The menu item always bundles with texture compression; it doesn't check the profile, it only reports it on the Textures: line.
Adding the SDK to an Existing Project
The template already has the dependency. For your own project, add it in game.project, then Project > Fetch Libraries:
[project]
dependencies = https://github.com/Minit-Games/minit-defold/archive/refs/tags/v1.17.0.zip
Prefer the tag-pinned URL: .../archive/refs/heads/master.zip tracks latest and can change under you. After fetching, minit/ appears as a read-only library folder and require("minit.minit") resolves. No dependencies beyond Defold's built-in html5 and json modules.
The Project > Minit: Package for Upload menu item and the Minit HTML shell come with the dependency.
If your project has editor/minit.editor_script and editor/minit_package.lua from an earlier Minit template, delete those two files — otherwise the menu item appears twice. Keep any other editor scripts.
If your THIRD-PARTY-NOTICES.txt came from an earlier Minit template, remove its Defold and Minit SDK sections — the menu item now adds them.
Fallback (no editor / quick try / offline):
Download the Minit SDK (minit.lua)
Drop the file into your project under a minit/ folder (so it lives at minit/minit.lua). require("minit.minit") resolves the same way.
Also download the shell, minit/minit.html, and put it at minit/minit.html. For texture compression, also download the texture profile, minit/minit.texture_profiles, and put it at minit/minit.texture_profiles. Without the dependency there is no Minit: Package for Upload menu item; bundle manually as described in Bundling Manually.
Display settings for your own project. The template already ships them. For your own project, copy the [display] and [html5] settings from the template's game.project and the layout helper minit_platform/layout.lua, which rebuilds the layout from the live window size. See Screen Layout below.
Minit Games-Specific Tips
Screen Layout
The template has no fixed design resolution. Its layout helper (minit_platform/layout.lua) fits the Game to the actual screen, and the template ships its display and HTML5 settings, so you don't need to set them. Keep your UI positioned relative to the live screen size rather than hardcoded pixel positions.
Pause When Off-Screen
Players swipe past your Game in the feed and background the app mid-run. Pause while the game isn't viewable:
function init(self)
self.unsubscribe = minit.on_viewable_change(function(viewable)
self.paused = not viewable
end)
self.paused = not minit.is_viewable()
end
function update(self, dt)
if self.paused then return end
-- advance gameplay
end
function final(self)
self.unsubscribe()
end
fnfires only when the value changes, up to ~250 ms late (the SDK polls);minit.is_viewable()returns the current value.- Subscribe from a script that lives as long as the subscription, such as your main game script: the poll timer belongs to the script that subscribed most recently.
- Only the Minit app reports feed and focus changes; elsewhere it follows browser tab visibility. Outside an HTML5 build
is_viewable()returnstrueandfnnever fires.
Sound
Sound starts on the first tap. That is intended: browsers block audio until the player interacts, so it doesn't mean audio is broken.
Touch Input
Include the touch action in your input binding file and handle it in on_input. See the Defold input manual.
Bundle Size
Defold's lean runtime keeps web bundles small; the limits live in Platform Requirements. Compress textures with the SDK's texture profile:
[graphics]
texture_profiles = /minit/minit.texture_profiles
- Everything is compressed with BasisU (lossy), without mipmaps.
- Atlases under any
uncompressed/folder stay uncompressed: put the.atlasfile there for pixel art or UI that must stay pixel-exact. The folder of the atlas counts, not the folder of its images. - Without
texture_profilesset, textures stay uncompressed. To change the rules, copy the profile into your project and pointtexture_profilesat your copy.
Text & Fonts on High-DPI Mobile
Don't use the built-in /builtins/fonts/default.font for on-screen UI text: it's baked at size: 14, which renders tiny on high-DPI phones. high_dpi does not change the text height; it only raises rendering sharpness.
Bake a custom .font asset instead: point a .font resource at a TTF (the built-in /builtins/fonts/vera_mo_bd.ttf works) with size set to 40–60, add it to your GUI's font list, and assign it to your text nodes. Increase the baked size rather than scaling the node up: scaling a small glyph adds no detail; Defold's distance-field fonts bake larger at little cost.
Set [display] high_dpi = 1 for crisper text at no cost to layout size.