Web Tiles
| date | 2026-02-09 |
|---|---|
| editors | Robin Berjon <robin@berjon.com> |
| issues | list, new |
| abstract | Tiles are composable web docs and apps that can safely be used in arbitrary contexts and assembled from multiple sources to carry out complex user interface tasks. Their composability, security, and privacy properties make them ideal for use in social media, chat, agents, and malleable software. |
Introduction
The web is a powerful platform that makes it possible to create high-quality content and applications. It would be desirable to be able to use it for social media posts, so that they could feature arbitrary content, and to be able to compose multiple small web apps together by having them talk to one another. Unfortunately, the dominant web security model is a poor fit for such tasks because it makes it way too easy to exfiltrate data, and is generally a privacy nightmare.
Tiles change this by offering an environment in which arbitrary web content can be executed, while protecting against the egress of data by simply locking down the tile to whatever content is pre-listed in its manifest. This makes it possible to embed tiles in social media, chats, LLM interactions, or to compose them with one another.
While the lack of network interaction is limiting, tile execution contexts can then make tiles powerful all the same. For instance, in a chat context all tiles may be able to post and listen on a data channel such that each instance can sync with the others.
Tile Manifests
A tile manifest is simply a MASL document, using the Bundle Mode. The manifest
must have a name and a resources entry, and resources must
include a / entry for the root.
That's all that's needed. How the manifest is obtained depends on the context that the tile is loaded from, as detailed in the following sections.
Tiles on AT Protocol
A key use case for tiles is publishing them on the AT Protocol [at].
Publishing a tile on AT is conceptually simple: every entry in resources must get uploaded
as a blob to the relevant PDS and then the tile itself must be posted to the account's repository as a
record containing the manifest.
The details of the record and the MASL variant used on AT are specified in the relevant appendix.
Please pay particular attention to the details provided there about the manner in which resources
need to point to blobs in order to operate correctly in an AT context.
Tiles in CAR
tk
Tile Execution Contexts
tk
Appendix: Tiles Lexicon
Note that lexica are not flexible enough to be able to describe the resources map.
Importantly, whereas regular MASL uses a CID to reference content, when in an AT record it does
not use the cid type but rather the blob type ([masl], [cid], [at]). This is because a PDS
will not pay particular attention to a CID but will need an uploaded blob to be referenced by
a blob type in a record.
This has important implications with how MASL needs to be used over AT in order to work correctly
with deployed PDSs. An example resources entry for a root HTML document looks as
follows:
{
…
"resources": {
"/": {
"src": {
"$type": "blob",
"ref": { "$link": "bafkreicknles2uzv7sruakcbjtn5pnoc4rqmgkvnavuq4raxexjvcn7osq" },
"size": 20,
"mimeType": "application/octet-stream"
},
"content-type": "text/html"
},
…
}
}
A few things are worth noting in the above:
- The
$typeis required. - The
refis what's used to link to the CID. - The
sizeis required by the PDS and it must be correct (in bytes). -
The
mimeTypeis required by at least some PDS versions and implementations. Note that it doesn't need to match the actualcontent-typethat is provided separately. In fact, in some PDS versions it cannot match it in many cases. It is recommended, wherever possible, to just useapplication/octet-streamthere.
The full lexicon is:
{
"id": "ing.dasl.masl",
"description": "Lexicon for DASL (https://dasl.ing/) types used on AT, notably for Web Tiles.",
"defs": {
"masl": {
"type": "object",
"description": "MASL metadata as defined in https://dasl.ing/masl.html",
"properties": {
"name": {
"type": "string",
"description": "The name for the tile, can be a title or app name",
"maxLength": 1000,
"maxGraphemes": 100
},
"description": {
"type": "string",
"description": "Short overview of the content",
"maxLength": 3000,
"maxGraphemes": 300
},
"categories": {
"type": "array",
"description": "Tags categorising the tile",
"items": {
"type": "string"
}
},
"background_color": {
"type": "string",
"description": "A colour for the background of the tile"
},
"icons": {
"type": "array",
"description": "Icons for the tile",
"items": {
"type": "object",
"required": ["src"],
"properties": {
"src": { type: "string" }, // has to be in resources
"sizes": { type: "string" },
"purpose": { "type": "string" }
}
}
},
"screenshots": {
"type": "array",
"description": "Screenshots, can be used for banner or card images",
"items": {
"type": "object",
"required": ["src"],
"properties": {
"src": { "type": "string" },
"sizes": { "type": "string" },
"label": { "type": "string" }
}
}
},
"sizing": {
"type": "object",
"description": "Requesting sizing properties for the content",
"properties": {
"width": {
"type": "integer",
"mininum": 1
},
"height": {
"type": "integer",
"mininum": 1
}
},
"required": ["width", "height"]
},
"resources": {
"type": "unknown",
"description": "A mapping of path to object with a CID src and HTTP headers"
},
"short_name": {
"type": "string",
"description": "A name, in case the basic name cannot fit"
},
"theme_color": {
"type": "string",
"description": "Theme colour"
},
"prev": {
"type": "cid-link",
"description": "In case there are multiple versions of this tile, this is the CID of the previous one"
},
// CAR compatibility
"version": {
"type": "integer",
"description": "The CAR version — avoid using this",
"const": 1
},
"roots": {
"type": "array",
"description": "The CAR roots — avoid using this",
"items": { "type": "cid-link" }
},
},
"required": ["name", "resources"]
},
"main": {
"type": "record",
"description": "A tile, instantiating MASL metadata into a record",
"key": "tid",
"record": {
"type": "object",
"required": ["cid", "tile", "createdAt"],
"properties": {
"cid": {
"type": "string",
"description": "The DRISL CID of the MASL for the tile",
"format": "cid"
},
"tile": {
"type": "ref",
"description": "The MASL content",
"ref": "ing.dasl.masl#masl"
},
"createdAt": {
"type": "string",
"description": "Timestamp",
"format": "datetime"
}
}
}
}
}
}
References
- [at]
- AT Protocol. URL: https://atproto.com/
- [cid]
- Robin Berjon & Juan Caballero. Content IDs (CIDs). 2026-02-09. URL: https://dasl.ing/cid.html
- [masl]
- Robin Berjon & Juan Caballero. MASL — Metadata for Arbitrary Structures & Links. 2026-02-09. URL: https://dasl.ing/masl.html