Skip to content

The amd_assets module

Resolving image://, face:// and ship:// for a document rendered outside the engine.

Overview

media_paths already answers "where does this art live", but through fs.get_mission_dir_filename, which needs an install and a running mission. A static exporter has only a folder, so this mirrors that module's search order against a folder handed to it — the mission's own media/, then each pack story.json pins, then the engine's data/graphics.

Scheme Resolves?
image:// Yes. Including engine built-ins like ball, which live in the install rather than any mission
face:// No file — but it composites. The value names cells of a race atlas, and those atlases are real PNGs. cosmos_dev/mockgui/face.js is the canonical compositor and carries a setSheetResolver hook precisely so another host can use it
ship:// No. The tag names a 3D hull; the .png beside each mesh is its diffuse texture, a near-white sheet that prints as a blank box

A placeholder is a real answer, not a failure: a printed page should say "a ship goes here" rather than closing the gap silently, because art nobody can see is missing is art nobody restores.

API

Resolving image:// art for a document rendered OUTSIDE the engine.

media_paths already answers "where does this logical art path live", but it answers it through fs.get_mission_dir_filename, which needs an Artemis install and a running mission. A static exporter has neither - it has a folder path - so this mirrors that module's SEARCH ORDER against a folder handed to it:

<mission>/media/...                                    the mission's own art
__lib__/media/<pack-name>/...                          each pack it pinned

The pinned packs come out of story.json exactly as media_paths._pinned_packs reads them (resources values plus shared_media, .zip stripped, declaration order), because a document that resolves art differently from the game is a document that shows the wrong picture.

What resolves, and what does not:

  • image:// - a file, once the search includes the ENGINE graphics dir. Keys like ball and test are engine built-ins living in <cosmos>/data/graphics, not in any mission, so a search that stops at the mission folder reports art as missing that is sitting right there.
  • face:// - no file, but not unresolvable either. The value is a face-BUILDER string (arv #ffffff 0 0;arv ...) naming cells of a race ATLAS, and those atlases are real PNGs in the engine graphics dir. The browser mock already composites them (cosmos_dev/mockgui/face.js, which carries a setSheetResolver hook precisely so a second host can), so a document can too - see face_atlases.
  • ship:// - genuinely not resolvable. The tag names a 3D hull, and the .png beside each mesh is its DIFFUSE TEXTURE, not a picture of the ship: ships/tsn_light_cruiser.png is a near-white sheet that would print as a blank box. The browser mock does not draw one either. A placeholder is the honest answer, not a limitation to work around.

A placeholder is a real answer, not a failure: a printed page should say "a ship goes here" rather than closing the gap silently, because art nobody can see is missing is art nobody restores.

MissionAssets

Resolves a media block to something a <img src> can use.

embed=True inlines the bytes as a data: URI, which is what makes the page self-contained and therefore printable from anywhere. embed=False emits a relative path instead: a much smaller file that stops working the moment it is moved, which is the right trade only while iterating.

face_sheets(specs)

{atlas basename: url} for every race the given face strings use.

Only the atlases actually referenced are resolved: a mission whose cast is all Zimni pays 0.44 MB, not the 6.8 MB of all six sheets.

find(name)

The file a logical image name resolves to, or None.

media(block)

The src for one media block, or None to leave a placeholder.

all_face_files(mission_dir=None)

{alias: sheet path} read from the engine's own allFaceFiles.txt.

This file IS the registry - the engine maps a face string's alias to a sheet through it, and it is the only place a MOD can add one, because a mastlib is a zip and cannot write into data/graphics. Its values may point outside the graphics folder (the TNG mod registers ../missions/__lib__/media/<pack>/faces_tng/TNG_Faces_1), so they are resolved against the graphics dir rather than assumed to live in it.

Returns {} when the file or the graphics dir cannot be found, which is the normal case for a checkout with no Cosmos install beside it.

face_alias_table(mission_dir=None)

{alias: atlas basename}.

Prefers the engine's allFaceFiles.txt when a mission dir is given, because that is the only source that knows about MOD sheets - face.js hard-codes the six stock aliases, so a mod atlas (tng1..tng6) rendered as nothing in the mock, the AMD static site and the VS Code preview. Falls back to parsing face.js so a checkout with no Cosmos install beside it still resolves the stock six.

face_aliases_in(spec)

The race aliases one face string references (arv #fff 0 0;arv ...).

face_js_path()

cosmos_dev/mockgui/face.js, or None when cosmos_dev is not installed (it is a dev-only package and never ships inside the .sbslib).

graphics_dir(mission_dir)

The engine's data/graphics, found by walking up from the mission.

fs.get_artemis_graphics_dir answers this at RUNTIME, from an install the engine already located. A static exporter has only a folder, so it looks the way the mock server does - it is handed (or finds) the Cosmos root and reads data/graphics under it. Missions live in <cosmos>/data/missions/<name>, so the graphics folder is a sibling of the missions folder.

media_roots(mission_dir)

Every root a logical media path may resolve against, nearest first.

Mission art wins over engine art, deliberately: a mission that ships its own ball.png means its own.

pinned_packs(mission_dir)

The media packs story.json declares, in declaration order.

Mirrors media_paths._pinned_packs: resources values (unpacked INTO the mission by Mast.expand_resources - not by the engine, which has never heard of story.json) plus shared_media (read from the one shared copy), .zip stripped because the unpacked folder is named for the zip.

png_size(path)

A PNG's (width, height) from its IHDR, or None.

Twelve bytes of header rather than an image library, because nothing in this stack may add a dependency and the only thing an atlas needs is the sheet's dimensions - the cell itself is placed with CSS background-position, which is what the engine does on the GPU anyway.