Repository navigation
Releases
InsideDev 0.11.0
Faster, safer and easier to drive: the whole tool reviewed line by line
0.11.0 is a review of every part of InsideDev: about 92,000 lines of C#, 14,000 lines of Python, the loader and the
native readback plugin. The goal was a tool that costs nothing while you do not use it, records without slowing the game
or drifting from game time, and that people and AI agents can drive without traps.
Existing commands, MCP tools, config keys and file formats keep working. Where a default changed, it is listed under
"Changed defaults" below, with the key that brings the old behaviour back.
Speed
- Nothing runs while nobody uses the tool. With the editor closed and no client connected, 0.10.0 still scanned the
scene, traced sound events, monitored signals and rebuilt overlay text every frame: 1.2 to 2.8 ms per frame and 17 to
23 garbage collections a minute in our test scene. Now every scanner and monitor sleeps until a panel, a command or a
client needs it, and catches up when it wakes: 0.03 ms per frame and no garbage collection in 95 s in the same scene.
background always(orbackground=alwaysineditor.cfg) brings the old always-on behaviour back. - No more hitch every 10 seconds. While an agent or the editor kept the object database awake, it searched every
root of the scene every 10 s (20 to 30 ms in one frame). It now does that only after a level streams in, and once a
minute as a safety net (db.rootRefresh). - Mods only work in their own level. A mod's operations are grouped by level. They are looked up once when their
level loads, only inside that level, retried a few times for late content, and left alone until the next load. With
three mods enabled and two of their levels not loaded, all mods together cost 0.0016 ms per frame; entering a mod's
level applied it in 2.5 ms, and a respawn applied it again. Extension modules can declare their levels
(IInsideDevLevelScoped) and are then only ticked there;LevelGateis part of the core for mod authors.mod list
andextshow each mod's levels and cost, and the log names an extension whose tick is slow. - Screenshots in a fraction of the time. The MCP screenshot no longer writes a full-size PNG to disk and decodes it
again in managed code: the frame is read once, scaled and encoded by Unity itself. 960 px: 2.25 s before, 0.09 s now;
1920 px: 3.9 s before, 0.31 s now. Newformat: "jpeg": a 1600 px shot is 121 KB in 0.12 s. - Faster calls. One main-thread hop per MCP call instead of two or three, a cached tool list, buffered HTTP. observe
33 ms before, 8 ms now; a console command 18 ms before, 8 ms now; geometry 72 ms before, 8 ms now; find_objects 36 ms
before, 13 ms now. - Recording does not hold the game back.
grecwrites frames straight from the readback buffer and a slow encoder
never blocks the render thread; MultiCam's writer has a bounded wait; the scene recorder scans the scene once at start
and samples only what changed; director holds are hard links instead of copies (500 holds in 0.1 s). With srec and
grec recording, the game held 59.8 fps (vSync 60) against 56.5 before; srec starts and stops in under 0.2 s. - Python tools. Seeking back in a take video 9.9 s to 1.0 s, grade statistics 12.6 s to 2.2 s per 600 frames,
ffmpeg does the scaling, one ffmpeg helper that always cleans up its child.
Recording you can trust
- Video length equals game time. 0.10.0 fixed the file rate once and wrote one frame per grab, so a minute of play
came out about 3.5 s short and the sound no longer lined up. Now frames are placed by game time: a 120 s recording
under load gave 120.13 s of video for 120.10 s of game time. A<file>.times.csvnext to the video gives each frame's
game time for exact audio alignment. - Recording while an agent drives. The time an agent's game stands frozen between calls is left out of the video, and
stepped runs are recorded without lost frames (0.10.0 lost most of them). - The game's own picture, also under other windows.
time {op:"record"}andrec startnow record the game's own
frames. Tested with a window covering the game: none of it in the video. Desktop capture is still there as
source:"desktop"/rec start ... desktop. - A failed ffmpeg (no NVENC, odd window size, full disk) is reported at once and capture stops costing frame time.
- ffmpeg can no longer outlive the game: child processes are tied to the game process.
- A take folder that already holds a recording is not overwritten unless you add
overwrite=on. - The scene recorder stops cleanly on a full disk, checks free space before it starts (
record.minFreeMB), and reports
its state insrec status json. - A level load during a replay no longer freezes the game.
Security
- The MCP server refuses requests from web pages. A page in your browser could send commands to the game while it was
open, through anOrigin: nullrequest. Requests with a foreign Origin, a cross-site fetch, a wrong Host (DNS
rebinding) or a non-JSON MCP body are now refused. Local clients (the stdio launcher,inside_ctl.py, scripts) are not
affected. - No MCP call can start a program of its choice any more: ffmpeg is found by the tool itself (
ffmpeg.pathin
editor.cfg,INSIDEDEV_FFMPEG,_mod\ffmpeg, PATH). reflectcalls go through an allow list; calls that write files, start processes or change the registry are refused.- A deeply nested JSON body can no longer crash the game (tested with 200,000 levels).
- The Mono debugger port of the loader is opt-in (
_mod\debugger.flag).
New commands and tools
| Command / tool | What it does |
|---|---|
doctor [json] |
one self-check of every part: loader, modules, versions, ffmpeg and encoders, disk space, minimized window, time scale, background mode |
help <command> |
usage of one command; help lists every command |
cfg [get / set / reset] [json] |
every config key with its value, default and meaning (103 keys), changeable while the game runs |
background [auto / always / off] |
when the background scanners run |
quit |
closes the game cleanly |
labels types <n / all> |
how many component names a world label shows (the rest as "+N"); labels no longer overlap |
state json, where json, perf json, mod list json, srec status json, acap status json, mcam status json, cam status json |
machine-readable status |
GET /status |
server state without waiting for the game's main thread |
POST /cmds |
several commands in one request and one frame |
film (MCP) |
panorama, game-frame recording and the live director camera with structured results |
observe {detail:"delta"} |
only what appeared, disappeared or changed since the last observation |
act {seq:"R1.2 J R0.4+J"} |
the short input grammar of ctl seq in act |
wait_ready_s on act / move_to / interact |
wait for the game to take input instead of being refused |
checkpoint {op:"goto", name} |
load a checkpoint by name |
restore {dry_run:true} |
what a restore would undo, without doing it |
mcam replay ... resume |
skip camera passes that already finished |
srec load <dir> play, srec reload |
fewer steps for the common loops |
inside_ctl.py wait / snapshot / doctor |
wait until the game is ready, read state, self-check from outside |
mcam_compose.py doctor, --resume |
check ffmpeg and encoders before a compose; skip finished outputs |
InsideMuter status / unmute / stop |
the muter can be asked and stopped; it gives back the sound it muted |
Fixed
- A mod file with a JSON error was replaced by an empty file when you ticked its checkbox; now it is left untouched and
the error names the line and column. - After 400 log lines, file-bridge commands answered with empty text and the Console tab stopped updating.
- The audio catalogue lost rows every 10 seconds of normal play.
- After picking an entry in the command palette, the game's keys stopped working until you clicked the game.
- World labels listed every component on one line, ran off the screen and covered each other.
acap statuscould mute the game; acap's volume rule could end up in a recorded mod.- A scale-only change was recorded up to 8 seconds late.
move_totimers ran several times too fast with vSync off, and a goal inside a gap made the body jump it back and
forth until the step limit.- The observation after an action could miss objects that appeared during it.
- Numbers in replies and files used a decimal comma on non-English Windows (for example
camprinted(1,23, 4,56, ...)). - The stdio launcher dropped
inside_statusfrom its tool list once the game was up. mcam_spec_check.pydisagreed with the game in about 20 rules and did not start on Python 3.9 to 3.11.mcam_audio.py fixcould cut a WAV file short without a backup.
Changed defaults
| What | 0.10.0 | 0.11.0 | Old behaviour |
|---|---|---|---|
| Background scanners | always on | only while the tool is used | background=always |
| Recording into a folder that holds a take | overwritten | refused | overwrite=on |
| Mono debugger port 55555 | on | off | _mod\debugger.flag |
Requests with a foreign or null Origin |
accepted | refused | none (use a local client) |
time {op:"record"} / rec start source |
desktop | game frames | source:"desktop" |
| InsideMuter on exit | leaves sessions muted | un-mutes what it muted | --keep-muted |
reflect call |
deny list | allow list | none |
| World labels | every component | 3 names and "+N" | labels types all |
play.vsync_off=1 |
vSync off from game start | off only while an agent works or the clock is held | play.vsync_off=2 |
| Passive hidden-object scanner | always on | off until the Hidden tab or hidden on |
`hidde... |
InsideDev 0.10.0
A 360 degree panorama command, a much cheaper muter, less garbage per frame
Everything new runs only when you call it, and the game sound is still never muted unless you start InsideMuter yourself. One
built-in limit changed for everyone: a detached MCP job may now run 45 minutes instead of 10.
- 360 degree panorama (
pano, with Play). One console command writes an equirectangular PNG that panorama viewers open
directly, with a JSON file that says where the eye was. Each of the six cube faces is an ordinary game frame, so the picture
is what a screenshot would show there. A 4096x2048 panorama took 2.3 to 2.7 s in all, of which the picture jumps around for
0.2 to 1 s (13 frames at a 2560x1440 game view), tried at places along a long bunker route in a mod scene. - Limits for a first-person camera's free look (
campath mount). Two new optional arguments clamp how far the head may tilt
the view up and down outside the timed looks, for example on a ladder, while a timed look can still reach as far as
pitch_max. Leave them out and nothing changes. - InsideMuter 3. The optional muter costs about 3 % of a core instead of 40 to 60 % (measured without the game, 25 s test:
62 % against 2.7 %), with the same 50 ms mute poll and the same heartbeat. - Less garbage every frame in the core. The main loop keeps its delegates instead of making about 2 KB of new ones per frame,
and the Wwise trace went from 11.9 KB to 0.0-0.2 KB per call in a heavy mod scene. No behaviour changes. - A better profiler.
perfsays how many garbage collections ran sinceperf resetand the longest pause among them, names
the MCP server's parts (mcp.log,mcp.pump,mcp.discovery,mcp.sweep), andperf hide/perf showswitch the renderers
of a part of the scene off and on to measure what they cost. - Long MCP jobs are no longer cut at 10 minutes. A lockstep pass runs below real time on a busy machine: a 431 s take needed
about 660 s of wall clock and was cut at 600 s. The other side: a job that hangs holds the control lane longer;restoreor
jobs {op:"cancel"}ends it at once.
New pitfalls from real filming are in the docs, each marked observed or inferred: the player-side clamp on keyed cameras, holds
under catmull, the plan pass and pinned CPU cores, and first-person flicker with a far clip.
How to use it all, step by step: docs/PLAY.md sections 4.7, 4.8 and 7.8, docs/MCP.md sections 8 and 13.1, docs/AUDIO.md section 11, docs/MULTICAM.md sections 12 and 16.
Everything you need is in the zip: copy bin\InsideDev.dll, bin\InsideDev.Mcp.dll and bin\InsideDev.Play.dll over the old ones in <game>\_mod\ (and tools\mcp\InsideDev.McpStdio.exe if you use the stdio launcher, tools\muter\InsideMuter.exe if you use the muter).
InsideDev 0.9.0
Film a planned camera over live play, from the game's own picture
Two console commands of the Play extension turn a camera plan into a real film of the running game. Both run only when
called and are stopped by restore or a game quit; nothing changes for anyone who does not use them.
- Live director camera (
campath). The main game camera follows a pose path planned in advance (mcam passeswrites
one for every camera of a MultiCam spec, or any script can write the two CSV files) while the game itself plays. Every
frame is the game's own picture: live particles, shaders animated by time, mod effects and temporal anti-aliasing,
which a replay of a recording cannot fully rebuild. The pose goes on the camera inCamera.onPreCull, after the game's
camera script, so the game's camera logic, its culling and the input are untouched. In director mode the plan also
drives the clock: the game is held still during the plan's pauses and runs at the plan's speed otherwise, with the drift
corrected (measured under 0.04 s).campath mountrides the camera on a transform, for example the boy's head for a
first-person pass, with optional smoothing of the head bob, a level horizon and timed looks at points or objects. - Video of the game's own frames (
grec). At the end of every n-th rendered frame the back buffer is copied on the
GPU by the nativeInsideReadbackplugin; a background thread hands the frames to a separate ffmpeg process that
encodes them with NVENC H.265. Windows over the game, focus changes and other programs never reach the file, unlike the
desktop recorder of 0.8.0. 2560x1440 at 30 fps: 3222 frames grabbed, 0 dropped (laptop, RTX 3070 Laptop GPU). - Input tracks wait for the director camera. While
campathholds the game still, aninput_trackplayback no longer
ends asstalled.
Where the work runs. The heavy part of grec runs off the game's main thread: the copy happens on the GPU on the
render thread, the hand-over on a background thread, the encoding in a separate ffmpeg process on the video engine of the
graphics card, so Windows spreads it over other CPU cores and the game keeps its frame time. Anything that touches game
objects (the camera pose, state, input) still runs on the game's main thread, as Unity 5.0 requires. Nothing is pinned to
a particular CPU core.
How to use them: docs/PLAY.md section 4.6 and workflow 7.7.
Everything you need is in the zip: copy bin\InsideDev.dll, bin\InsideDev.Mcp.dll and bin\InsideDev.Play.dll over the old ones in <game>\_mod\ (and tools\mcp\InsideDev.McpStdio.exe if you use the stdio launcher).
InsideDev 0.8.0: the editor and its AI tools no longer slow the game down
the editor and its AI tools no longer slow the game down
InsideDev used to cost the game most of its frame time. Every slowdown was found with measurements, not guesses, and
rewritten at its cause. Same place in the game, fresh start each time, laptop with a Core i7-11370H and an RTX 3070 Laptop
GPU at 2560x1440:
| 0.7.0 | 0.8.0 | |
|---|---|---|
| Game fps with the default overlays (trigger boxes, labels) | 45 to 106 | 146 to 174 |
InsideDev's own time per frame while an AI agent works (perf) |
7.2 ms, peaks 21 ms | 0.57 ms, peaks 6.7 ms |
| Trigger and collider overlay per frame | about 13 to 17 ms | about 3 ms |
| Agent perception scans per frame, for 90 s after every tool call | 6.6 ms | 0.13 ms |
| A 53 s test pass filmed for review | over 15 min (a screenshot every few steps) | 53 s (real-time H.265 video) |
| One screenshot written to a file | 2.0 to 3.1 s | 0.6 s with fast:true |
| vSync | on: a frame a little over 16.7 ms halved the game to about 30 fps | off from the start |
How they were found. The built-in profiler (console perf) splits InsideDev's time per subsystem, and the Play
extension's ticks now appear in it one by one (play.perception, play.stepper, play.changelog ...). Every overlay was
switched off and on alone on a fresh start, and every fix was measured again in the game.
What was wrong, and the fix:
- Agent perception scanned the whole scene one game type at a time, every other frame. For 90 s after any MCP call
the caches behindobserveranFindObjectsOfTypefor one of about 40 game types every other frame, and every such call
walks all ~25 000 objects of the loaded levels: 6.6 ms of every frame, plus a garbage collection every few seconds on a
450 MB heap with pauses up to 0.8 s. Now oneFindObjectsOfType(MonoBehaviour)pass fills every type at once (each
concrete class is matched to the tracked types once and remembered), and nothing runs in the background:observe
refreshes what is stale when it is called, while the game waits for the agent anyway. - The trigger and collider overlay was rebuilt from nothing every frame. For every collider of every loaded level it
asked the engine, every frame, whether the object was active and enabled and where its bounds were, then projected each
box with 24Camera.WorldToScreenPointcalls (120 for a sphere), and it re-read every collider's components every 10 s.
Now each collider keeps its object, shape, world corners and bounds and asks the engine only every 8 frames, staggered;
frustum culling and the projection run in C# from one view-projection matrix per frame, and a rescan classifies new
colliders only. The same projection now draws savepoints, links and hidden markers. - vSync halved the frame rate. A frame a little longer than 16.7 ms waited for the next screen refresh, so the game
sat at 30 to 37 fps. InsideDev is a development tool, so it keeps vSync off from the start (play.vsync_off=0in
editor.cfggives the game its own vSync back). - Screenshots were the filming method. Every one is a PNG the game encodes on its main thread and the server decodes
again to check for a black frame. Passes are now filmed as video instead, and a single shot can skip the decode.
New:
- Real-time recorder:
time {op:"record"}and{op:"record_stop", review_fps}, consolerec start/rec stop.
ffmpeg'sddagrab(DXGI Desktop Duplication: the graphics card copies the screen) and NVENC H.265 (preset p6,
tune hq,cq 16, about 18 Mbit/s at 2560x1440 30 fps) film the game window, so the game's main thread does no capture
work. The window and its monitor are found from inside the game;raiselifts the window to the top without taking
focus;record_stopcan cut JPG review frames. No library was added to the tool: ffmpeg 6.1 or later is an external
program (onPATH, in<game>\_mod\ffmpeg\or atINSIDEDEV_FFMPEG), and the encoder needs an NVIDIA GPU. - Frame meter:
time {op:"state"}reportsfpsandframe_ms_max, the longest frame of the last second. - vSync switch: console
vsync off|on|status,time {op:"vsync"}. - Fast screenshots:
screenshot {mode:"path", fast:true}returns once the file is written.
Install
Copy bin\InsideDev.dll, bin\InsideDev.Mcp.dll, bin\InsideDev.Play.dll into <game>\_mod\ and tools\mcp\InsideDev.McpStdio.exe over the 0.7.0 files. For the recorder, put ffmpeg.exe (6.1 or later, with ddagrab) on PATH, in <game>\_mod\ffmpeg\ or point INSIDEDEV_FFMPEG at it.
InsideDevTool-0.8.0.zip sha256: 6bc5c424d71dc9ce1b55737a8a537aa46bf804109a1fa9056038fc7ddb2e8bed
InsideDev 0.7.0
Everything new is off until you use it; an existing install behaves as before after the update (the game sound is never muted, nothing records, no new hotkey acts unless you copy the module that has it).
What's new
- MCP character control (
InsideDev.Play.dll, optional): an AI assistant plays INSIDE through MCP. It sees the scene as JSON (the boy, nearby objects with ids and actions, hazards, the checkpoint), presses the game's controls for exact logic steps, walks to points, uses objects, waits for conditions, handles checkpoints and menus, reads playbooks and records input tracks. Needs only the MCP server. Connect tohttp://127.0.0.1:47811/mcp/play - MCP server: play / dev / all profiles (
/mcp/play,/mcp=/mcp/dev,/mcp/all), jobs with progress and cancel, one JSON result shape, tool allowlist and token, plainPOST /cmd,GET /state,GET /pingfor scripts, automatic restore of the game 600 s after the last tool call. Existing clients keep the same address and tool names - Scene recorder (
srec): records what moves in a scene into a take folder; the viewer holds the frozen scene at any time of the recording while you fly the free camera - MultiCam (
mcam): films one scene with many cameras at once, or records it once and films every camera from the recording; example specs inspecs\; optionalInsideReadback.dllfor faster replay grabs - Game audio capture (
acap): the game's sound to WAV with sync markers; plays normally by default. The optionalInsideMuter.exemutes the game in Windows while it runs and is only for silent captures - Lab modules (
InsideDev.ReplayLab.dll,InsideDev.Det.dll, optional): engine measurements for recording and replay, input replay determinism test - Python tools (
tools\*.py): command-line control, recording reader, MultiCam spec checker, compositor and QA, audio alignment; guide playbooks (guide\) for the MCPguidetool - Docs:
docs\AGENTS.mdis the entry page for AI agents; full references indocs\
Install
- Copy
bin\version.dllnext toINSIDE.exeandbin\InsideDev.dll(plusbin\InsideDev.Mcp.dllfor MCP) to<game>\_mod\ - Optional:
bin\InsideDev.Play.dllandguide\(to<game>\_mod\guide\) for character control, the lab DLLs to<game>\_mod\,bin\InsideReadback.dllto<game>\INSIDE_Data\Plugins\ - Start the game; F1 opens the editor; MCP clients: see
tools\mcp\clients\and the README
SHA-256
| File | SHA-256 |
|---|---|
bin\version.dll (unchanged) |
5b195e16022f7011be3f4fb891294630120dbbe70197382ad93a2d8ba34272f6 |
bin\InsideDev.dll |
81c642d32325072ed4b451e8db015789d5b735ea4dbf7305bd8dda0bc2e9bd23 |
bin\InsideDev.Mcp.dll |
55a3a3dabdc0680a260aa30a8aee30ec48da62acbe8d8c3f7699bcac20cf06ba |
bin\InsideDev.Play.dll |
eb8fa4a912691811bf3a7a8cdaf887144300a8ead07dc788fe9044fd93dc0168 |
bin\InsideDev.ReplayLab.dll |
e313f2f419b1c311943ea2c4382a5f8bb14ac11d469254ffe2afee01dc70f81d |
bin\InsideDev.Det.dll |
f76a88e192fec3ea3fb057aac75b30030c174730412dcef1d736bd64f1d17f00 |
bin\InsideReadback.dll |
bae87e0b2692ddf2831d62d458ce275fc24c36a48756992b2116dd043d425373 |
tools\mcp\InsideDev.McpStdio.exe |
276744733eebf6dafec0d5d11a36a0e48b631a6a73b07ac585a7905ce8ddb7e9 |
tools\muter\InsideMuter.exe |
1a1e9889dec08b2a38a3981165060888cbd015508a09c1772c9c83a505e11461 |
Everything you need is in the zip.
InsideDev 0.6.0
Everything you need is in the zip.
First release
Drag and drop version.dll to the game root folder (INSIDE), meaning next to the INSIDE.EXE, create a folder called _mod also in the root and paste InsideDev.dll and start the game, the tool should create the _mod folder by itself if you launch it without InsideDev.dll
Your antivirus may flag version.dll, whitelist it if it does so.
InsideDev.dll:
https://www.virustotal.com/gui/file/4578e7b6985f2b4fcb1f22b45f148c70ec3d5119c2e10e98ab6f3c2d7bc7eb16
Version.dll:
https://www.virustotal.com/gui/file/5b195e16022f7011be3f4fb891294630120dbbe70197382ad93a2d8ba34272f6