scene-builder — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited scene-builder (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
A judgment layer over the scene tools — it maps "here's a map, make it playable" into the right create-scene / update-scene calls with sensible dnd5e defaults and a couple of confirmable mood choices. It adds NO new mechanics; the tools hold all correctness (v14 field paths, fog/grid enum mapping, weather validation against the live CONFIG.weatherEffects, playlist/journal name→id resolution, and auto-detecting scene dimensions from the image).
Tools used: create-scene, update-scene, list-scenes, list-assets, upload-asset, list-playlists, list-journals / search-journals. To build a new playlist or journal to attach, hand off to the `playlist-builder` / `journal-builder` skill — scene-builder wires the link onto the scene; those skills author the content.
A scene without a background is rarely what the user wants. If no image was given:
upload-asset → returns a Data-relative path), orlist-assets on the maps folder, e.g. worlds/<world>/assets/maps).Ask for the path/file if you don't have one. The background must be a Data-relative path (what upload-asset returns and list-assets shows).
Battlemaps very often ship a sidecar JSON next to the image — a map.jpg with a map.json (or <mapname>.json) beside it — carrying pre-built walls and ambient lights so the map is playable on arrival. Whenever a local map file is given, check its folder for a sidecar before creating the scene:
cavern.jpg → cavern.json), then anysingle .json in the same directory.
create-scene handle the **Foundry scene-exportsidecar: a top-level object with `walls` (entries shaped `{ c:[x0,y0,x1,y1], move, sense, sound, door }`) and/or `lights` (entries shaped `{ x, y, dim, bright, tintColor, tintAlpha }`), plus scene fields like `width`, `height`, `grid`, `gridDistance`, `gridUnits`, `padding`, `gridColor`, `gridAlpha`, `globalLight`, `darkness`. Both the legacy and the modern (v14 `sight`/`light`, `config{}`) field shapes are accepted — the tool normalizes either to v14. This is exactly what Dungeon Alchemist's "legacy" Foundry export (and similar map packs) produce.**
menu (and the Dungeon Alchemist help page that recommends it) is stale for Foundry v14: v14 removed the legacy-field migration, so importing this shape natively silently DROPS the data — every wall falls back to NORMAL vision (wrong for limited/secret/none walls) and lights collapse to 0-radius with no tint. create-scene does the legacy→v14 conversion the native path no longer does (verified live, 2026-06-26).
walls and lights arrays straight into create-scene (walls: / lights:).Don't transform the coordinates — they're absolute canvas pixels and the tool writes them verbatim. The tool reports how many walls/lights it placed.
.uvtt / .dd2vtt / .df2vtt, or a JSON withresolution/pixels_per_grid/line_of_sight/portals and a base64 image) uses grid-unit coordinates and a different schema — create-scene does not convert that yet. Don't feed it in raw (the coordinates would be wrong); tell the user it isn't supported yet rather than mangle it.
Normally do NOT compute or ask for width/height — create-scene auto-detects the image's pixel size when you omit width/height. But when you're importing a sidecar's walls/lights, pass the sidecar's own `width`, `height`, `gridSize` (its `grid`), `padding`, `gridDistance`, and `gridUnits` explicitly. The wall/light coordinates were authored against that exact canvas, so reproducing it 1:1 keeps them aligned. (The tool reports the size it used.)
Ask this once, because it flips two settings:
on, fog individual, square grid 100px = 5 ft.
tokenVision: false and globalLight: true (and consider fogMode: "disabled"); the grid is cosmetic.
If it's obvious from context, state your assumption instead of asking.
Read the image file (it renders to you) and offer at most 2–3 mood suggestions as confirmable choices, not silent defaults. Keep it to broad strokes:
| What you see | Suggest |
|---|---|
| Snow / ice / tundra | weather: "snow" (heavy → "blizzard") |
| Swamp / bog / misty / dark forest | weather: "fog", darkness: 0.3–0.5 |
| Dungeon / cave / crypt / windowless interior | globalLight: false, darkness: 0.75–1 |
| Bright outdoor day / lit town | globalLight: true (or darkness: 0) |
| Night exterior / moonlit | darkness: 0.6–0.8, globalLight: false |
| Rain / storm sky | weather: "rain" (heavy → "rainStorm") |
Don't stack five effects. Pick the one or two that define the scene and confirm. Weather keys are validated live by the tool — if you guess wrong, its error lists the valid keys; case doesn't matter.
list-playlists, offer to set playlist: "<name or id>". It auto-plays **on sceneactivation (not on view), so pair it with an offer to activate. To build a NEW playlist to attach, hand off to the playlist-builder** skill, then set playlist to it here.
list-journals / search-journals, offer to set journal: "<name or id>" (e.g. theread-aloud / GM notes for this location).
Both are plain scene-document links; pass the name and the tool resolves it (and errors on an ambiguous duplicate name — pass the id then).
Make a single create-scene call with the assembled params, then report the scene id/name, the detected dimensions, and what mood/links you set. Offer to activate it if the user wants it live now (or pass activate: true when they've already said so).
Typical call (defaults already cover grid 5ft / vision on / fog individual / daylight, so only pass what's special):
create-scene {
name: "Frostspire Pass",
backgroundPath: "worlds/<world>/assets/maps/frostspire.webp",
weather: "snow", // from the map
darkness: 0.3, // dusk
playlist: "Winter Winds", // if attaching
activate: false
}With a sidecar (walls + lighting from map.json), pass its placeables and its canvas fields so the coordinates line up — report back the wall/light counts the tool placed:
create-scene {
name: "Eerie Temple",
backgroundPath: "worlds/<world>/assets/maps/eerie-temple.jpg",
width: 13050, height: 6450, // from the sidecar
gridSize: 150, // sidecar `grid`
gridDistance: 5, gridUnits: "ft",
padding: 0, gridColor: "#000000", gridAlpha: 0.2,
globalLight: true, darkness: 0.3, // sidecar lighting
walls: [ /* sidecar.walls verbatim */ ],
lights: [ /* sidecar.lights verbatim */ ],
activate: false
}To adjust an existing scene later, use update-scene with the same fields (and "" to clear a playlist/journal link). update-scene is document-only — it does not add walls/lights, so import those at create-scene time.
create-scene auto-detect them, except when importing asidecar: then pass the sidecar's own width/height/grid/padding so wall/light pixels stay aligned.
walls/lights verbatim (don'trescale coordinates). Decline Universal VTT (.uvtt/.dd2vtt) sidecars cleanly — not yet supported.
hand-authors or moves placeables. If a tool returns a refusal or reason (e.g. unknown weather, ambiguous link name, skipped walls), surface it rather than working around it.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.