# Building an Asset Pack

> How to author prefabs, decks, materials, textures and scripts as a publishable Asset pack, and what its published document will and will not carry.

- Source: https://diceytable.com/docs/editor/workflows/build-an-asset-pack
- Last verified: 2026-08-20

An **Asset pack** is a publishable bundle of *pieces* — prefabs, custom decks, the materials and
textures they use, and the scripts that give them behaviour. It has no scene, no room and no
table. Several games can depend on one Asset pack and place its pieces however they like.

> **Naming.** The wire value in `diceytable.mod.json` is `"type": "component-pack"`, but the
> author-facing name is always **Asset pack**. "Component" in DiceyTable means an *engine*
> component — `render`, `rigidbody`, `collision`, `light`, `camera`, `script` — and nothing else.

## Open the Asset Editor

Create one from **Create → Asset pack** in the chooser, or open an existing `component-pack`
project at `/editor/asset/{id}`. See [Editor URLs and Modes](https://diceytable.com/docs/editor/concepts/editor-urls).

The Hierarchy collapses to five rows:

```
Prefabs (12)
Decks (2)
Materials
Textures
Scripts
```

There is no `Room` row, no `Table` row, no `Player Zones` and no `Seat Template` — an Asset pack
owns none of those, and the published document refuses them by name. Nothing in your project is
deleted by opening this editor; those rows simply are not part of this subject.

## Prefabs are definitions, not placements

A prefab carries a kind, a label, a colour, scale, tags, a material and a metadata bag. It
carries **no position and no rotation**, and this is structural rather than a convention: the
schema has no such field, so a placement cannot be saved into one even by hand-editing. The game
that depends on your pack decides where each copy goes.

Two ways to make one:

- Configure a piece on the table, then **Save as prefab** from its context menu. Everything a
  definition owns is copied; the position is not.
- Select the `Prefabs` row and use the Asset Explorer's Prefabs folder.

Selecting a prefab row opens the same prefab inspector the Game Editor uses — name, ID, kind,
colour, the **Script** binding, and **Place copy**.

### Previewing a prefab

The prefab inspector renders the actual model the table would draw for it, resolved the same way
the runtime resolves it (custom model asset, then standard preset, then the first preset for its
kind). **Place copy** puts a real copy on the table so you can look at it in the viewport.

Placed copies are a **preview**. The published document caps placed objects at zero, so a save
reports them and drops them — the `Prefabs` panel warns while any are on the table.

## Attaching a script

Bind a script from a prefab's **Script** field, then press **Edit script** to open it in the
[script editor](https://diceytable.com/docs/editor/item-editors/script) without leaving the mode. Saving there compiles
it; `compiled` is what the sandbox actually runs.

Three rules the published document enforces, all of which the editor shows you first:

| Rule | Why | Where you see it |
|---|---|---|
| Every script must be attached to at least one prefab | An Asset pack has no scene, so an always-on script belongs to no piece and can never run — nor be attributed in the capability disclosure | `orphan` badge on the script row |
| A prefab's script must be shipped **by this pack** | Otherwise the piece would bind to whatever script id happens to exist in the game that installed it | `missing script` badge on the prefab row |
| A script must have a compiled body | A source-only script ships a piece that silently does nothing | `not compiled` badge on the script row |

Your pack must also **declare the capabilities its scripts use** in the manifest. That
declaration is published to every player of every game that depends on you, so publishing refuses
a pack whose declaration does not describe its code — see
[what gets rejected](https://diceytable.com/docs/mods/scanner/what-gets-rejected).

> A script is scanned as its **compiled** body, and comments survive the compile. A bare
> `window`, `fetch` or `eval` **inside a comment** rejects the file.

## Decks

The `Decks` row lists every `.deck.json` in the project. Cards, sheets and layouts are edited in
the [deck editor](https://diceytable.com/docs/editor/item-editors/deck) — selecting a deck row here only tells you
whether the definition **rides inside the published pack**.

Use **Bundle into pack** (or **Bundle all decks** on the `Decks` row) to put a definition in the
document. A bundled deck makes the pack self-contained: a game that depends on you resolves the
deck without reaching back into your repository. A prefab that names a deck the pack does not
bundle is refused.

## Materials, textures and the viewport

`Materials` and `Textures` are shared with every other editor subject rather than owned by this
one — the same library dresses a prefab, a room's floor and a table's model. Selecting a row
opens the shipped material or texture inspector.

The Asset Editor's lighting is an **editor preview setting**. The published document carries a
fixed neutral environment, because ambient, fog and skybox belong to the room pack and the
surface colour to the table pack. Changing the preview never changes what you ship.

## What a save writes

Saving writes a component pack document, not a plain scene. The editor **refuses to save** a
document the schema would reject rather than writing one that publishing would burn an immutable
version on. When something is dropped, it says so — except for the seat and room-settings blocks
the editor backfills on every project and the preview environment, which were never yours to
author here.

## See also

- [Editor URLs and Modes](https://diceytable.com/docs/editor/concepts/editor-urls)
- [The Hierarchy Panel](https://diceytable.com/docs/editor/interface/hierarchy)
- [Building a Deck](https://diceytable.com/docs/editor/workflows/build-a-deck)
- [Scripts](https://diceytable.com/docs/editor/working/scripts)
- [What gets rejected](https://diceytable.com/docs/mods/scanner/what-gets-rejected)
