Webtiles as view#
An experiment into sharing WebTiles on the AT Protocol wrapped in context which declares the tile as being able to render a given NSID/collection of AT Protocol records.
eg. "This Webtile can render a Bluesky post" or "This Webtile can render a Video game playthrough".
Sketch#
CAUTION
This is highly speculative, something to experiment with so I can explore it and discuss its strengths and weaknesses.
A record published to at://byjp.me/es.webtil.eView/some-key declares that it's intended to render records in the games.gamesgamesgamesgames.experimental.actor.play collection like this one).
It might look like this:
{
// This webtile is intended to render this Atproto collection
"collection": "games.gamesgamesgamesgames.experimental.actor.play",
// This webtile is intended to render records that match *all* of these JSONPath queries
"where": [
"$[?@.game == 'at://did:web:gamesgamesgamesgames.games/games.gamesgamesgamesgames.game/3mghhtroxpn2d']",
],
// Here is the *embedded* webtile
"tile": {
"$type": "ing.dasl.masl",
// The rest of the Webtile
},
}
A site wanting to display a g.gggg.actor.play record would use the <webtile-view> component to:
- Retrieve the record to be displayed
- Retrieve the Webtile View(s) that can display it (open question: discovery?)
- Filter out Webtile Views that have a
whereJSONPath clause marking them as incompatible with the provided record - Render the Webtile
- Send a
postMessage({ kind: "render", record, uri })to the Webtile, and answer the{ kind: "xrpc", … }data requests it posts back - (Optional — for self-sizing tiles such as full-page views) let the Webtile drive its own height with the iframe-resizer v4 wire protocol
Upon which the Webtile will update using the given data. It may request additional records or identity lookups by posting XRPC reads for the host to broker — e.g. postMessage({"kind": "xrpc", "nsid": "com.atproto.repo.getRecord", …}) and postMessage({"kind": "xrpc", "nsid": "com.atproto.repo.describeRepo", …}). The host routes each allowlisted call to the repo's PDS.
A Webtile opts into self-sizing by reporting its height — either by dropping in @iframe-resizer/child or by posting the [iFrameSizer]…:resize message itself. The <webtile-view> element handles the host side automatically, applying the reported height — growing the iframe so the host page scrolls — only when it carries the autoheight attribute.
Potential challenges#
- How do we support discovery of webtile views for a given lexicon?
Architecture#
Three layers. The middle one — <webtile-view> — is the trust and network boundary: it is the only
code that talks to atproto, and the Webtile is sandboxed with no network of its own. The host page just
configures and styles the element; it never sees atproto. (In the DOM the Webtile is an iframe inside
<webtile-view>, which sits in the host page.)
sequenceDiagram
autonumber
participant H as Host page
participant V as <webtile-view>
participant T as Webtile iFrame
participant N as Atproto network
H->>V: Record URI + prioritised webtile sources
V->>N: Resolve identity, fetch record + 'webtile view'
N->>V: identity, records, 'webtile view'
V->>T: render(record, uri)
opt Retrieve blob (eg. image)
T->>N: PDS /xrpc/com.atproto.sync.getBlob
N->>T: Blob
end
opt Retrieving a Record
T->>V: postMessage({"kind": "xrpc", "nsid": "com.atproto.repo.getRecord", …})
V->>T: getRecord response
end
opt Resolving an identity
T->>V: postMessage({"kind": "xrpc", "nsid": "com.atproto.repo.describeRepo", …})
V->>T: describeRepo response (handle, didDoc, …)
end
opt Height negotiation (iframe-resizer v4)
T->>V: [iFrameResizerChild]Ready
V->>T: [iFrameSizer]<config>
T->>V: [iFrameSizer]<id>:<height>:<width>:<type>
Note over V: grows iframe when autoheight is set
end
<webtile-view> picks the first tile whose NSID and where clauses accept the record, sandboxes it,
then brokers each allowlisted XRPC read the tile asks for — so the tile never touches atproto itself.
Blobs are the one exception: the tile loads them straight from the PDS.