Highport orbital control
Using a tile on your site
Somebody else did the design; you supply the words and the pictures. The version you dock is the version you keep, and nothing its author does afterwards reaches your page.
A tile is a finished design, the HTML and the stylesheet and the images, published by somebody else with a short list of things it asks you to fill in. You pick one, you type your name and pick your picture, and your domain serves it. Attaching one to your site is called binding it, and you need nobody's permission to do it.
The first thing to know is what you are agreeing to when you pick one, because it is less than it sounds.
Nothing changes under you
Your site record does not store the tile's name, or a link to "the latest version". It stores the exact bytes you chose, identified by their content. That single fact is what the rest of this page rests on.
| What the tile's author does | What happens to your site |
|---|---|
| Publishes a new version | Nothing. You are told a newer version exists, in the editor. You move when you decide to |
| Changes their mind about the design entirely | Nothing. You are still serving the version you picked |
| Deletes the tile record | Nothing. We hold the bytes; your page goes on answering |
| Loses the original files, or moves their account | Nothing. The bytes were fetched and stored when you published, and serving your page does not go back to their account for anything |
An author cannot change your live page and cannot take it away from you. There is no version of this where you wake up to a redesign.
A tile's author has no route to your page. It is not a policy we enforce. It is a road that was never built.
The one thing that does not survive is a tile an operator takes down for abuse, which stops serving everywhere at once. That is the takedown mechanism, and it is the only lever on a tile that reaches a site already serving.
Finding a tile
Two places, and both list the same thing: every published tile we report as ready. If your site already has one on it that you never picked, it came with the address, and your first site covers that.
The picker, in your site editor. Open https://hub.highport.space/sites/{your domain}/edit, choose Start from a ready-made tile, and the picker is underneath, headed Choose a tile. Each card carries the tile's icon, its name, who made it, the description, and a sentence saying what it will want from you. That is either Nothing to fill in. or something like 3 details to fill in: name (required), tagline, avatar. A search box filters by name and description, and by the author's DID, the account identifier a handle resolves to, and not by the handle the card shows, although the box is labelled name, description or author. A radio switches between Everything published and Only mine.
The picker loads one page of a hundred tiles and the search filters that page instead of asking us again. Where more than a hundred are published, the rest are visible in the directory but cannot be chosen here.
The directory, at https://hub.highport.space/explore/tiles, twenty at a time, no sign-in needed. A tile's own page adds three things the picker does not have: the full parameter table, with name, type, required and description; a Technical details disclosure carrying the version you would be binding; and a list of the sites already using it. That list shows your own by domain and everybody else's as a number, so you can see how many people are relying on it without getting a directory of strangers' addresses.
The tile page's Use this tile button takes you to the page where you register a domain. It does not carry the tile through. You register the domain, then choose the tile again in the editor.
Neither place offers you a tile that is not ready. Both listings ask for ready tiles only, Only mine included, so a tile you published a minute ago is not choosable until we have finished reading its files. Its own page in the directory does show it, with its state in plain words: Still loading its files, or Missing files — not safe to use. The Use this tile button there is not disabled, because it only takes you to the address form. Binding a version in either state is refused in the editor, under the names in the table at the end of this page. Tiles explains what those states mean, and tiles, from the outside is the page to send somebody who wants to know why a stranger's design is safe to visit.
What binding does to your record
Your site record has a source. Unbound, that is a manifest listing your own files. Bound, it becomes a reference to the tile, its address and its exact version, plus a parameters object holding what you filled in. The identifiers below are made up; the field names are exact:
{
"$type": "space.highport.sites.site",
"source": {
"$type": "com.atproto.repo.strongRef",
"uri": "at://did:plc:z72i7hdynmk6r22z27h6tvur/space.highport.sites.tile/3kabcdefghij2",
"cid": "bafkreia5bhg4r3uf45nfb5rubqxcqexzx7rypi3pbf3wsb37fgi2vaw5ju"
},
"parameters": {
"name": "Mattie",
"links": ["Bluesky|https://bsky.app/profile/mattie.example"]
}
}
Nothing else in the record moves. The record key is still your hostname, and redirects, notFound and wellKnown are yours whichever source you use, so a bound site can still redirect old addresses onto the tile's pages. See the site record for those fields.
Once a tile is bound, the editor shows a panel headed Using {the tile's name}, with the author underneath and the address and version tucked inside a Technical details disclosure. That disclosure is worth opening exactly once, when somebody asks you which version you are on.
Filling in the details
Under the heading Your details, the editor builds a form from the tile's own declaration. One field per thing it asks for, in the order the author declared them, with the author's description as the help text under each. That description is all the guidance there is, so a good tile has good ones.

Required fields are marked. Optional ones you leave empty are left out of the record entirely. Not sent as empty text, not sent as null. There are no defaults anywhere in the system: when a value is absent, the tile falls back to whatever its own code does without it, and the author's description is the only place that gets said. A checkbox you deliberately turned off, or a number you deliberately set to 0, is a value and is kept.
A tile may ask for at most 32 things.
What a tile can ask for
| Kind | What you supply | What the form gives you |
|---|---|---|
| Text | Typed text | A text box. Or a dropdown when the tile lists a fixed set of choices, a date-and-time picker, a URL box, or a box with suggestions, depending on what the author declared |
| A whole number | A number | A number box carrying the tile's minimum and maximum. Whole numbers only; there are no fractions in this data model |
| Yes or no | A checkbox | A checkbox |
| A file | A file you upload | A file chooser limited to the types the tile accepts. The file is uploaded to your own account and stays yours |
| A list | Repeated rows of any of the above | Add item and Remove per row, stopped at the tile's limit, with a live count |
| A record | Something already in your account, your profile for instance | Two tabs: By reference, the default, which lists the things you already have of the kind it wants; and Inline (advanced), which takes one typed out by hand |
Two shapes the form cannot actually fill in: a list of files, and a list of records. The rows appear, and what they produce is refused as ParameterTypeMismatch. No first-party tile asks for either.
A field asking for somebody's handle resolves it as you type and stores the settled form. If it will not resolve, what you typed is kept and the check will judge it.
A record reference pins a version, exactly like a tile does. Pick your profile record and we store its address and the version it has right now. Editing that record later does not change your page until you come back and pick it again. That is the point of pinning. By reference is also the tab you land on, and the other one carries something worth knowing before you use it: a record you type out by hand is read as your own, so any picture inside it is fetched from your account, and a record copied from somebody else names files your account does not hold.
Everything you fill in, resolved, must come to 65,536 bytes of JSON or less. Files you upload count against your site's total size instead. See limits and quotas.
When a value does not fit
The editor checks as you type and shows the problem under the field once you have left it. Each one carries the same error name the server uses, so the problem the editor names is the problem the server would have named.
| What is wrong | What the field says |
|---|---|
| A required field is empty | This tile requires a value here. |
| Text is too long in bytes | At most {n} bytes; this is {m}. |
| Text is too long in characters | At most {n} characters; this is {m}. |
| The value is not one of the tile's choices | Must be one of: a, b, c. |
| A number is out of range | Minimum {n}. / Maximum {n}. |
| A number is not whole | Whole numbers only — the data model has no floats. |
| The wrong kind of value | This parameter takes text. / …a whole number. / …yes or no. / …an uploaded file. / …a list. |
| A file of the wrong type | The tile accepts a, b; this file is c. |
| A file that is too big | At most {n} bytes; this file is {m}. |
| A list with too many rows | At most {n} items; this has {m}. |
| An empty row inside a list | Remove this row or give it a value. |
Where a length is declared in both bytes and characters, the counter under the field shows one budget, whichever is closer to full, and shows both only once you are over one of them.
These checks are a courtesy so you learn about a limit while typing. The authority is the check we run over the whole composed record, which returns what it found under two headings in the editor: Fix these before publishing for the record, Fix these in your details above for the values. See validate before you write for what that check does.
When there is a newer version
We tell you, and then we wait for you.
When the author has published something newer, the Using {name} panel gains one paragraph, reading "The author has published a newer version. Nothing changes on your live page until you publish, and anything the new version needs from you appears below." Beside it is a Use the newer version button.
Pressing it changes the version in your draft and nothing else. The form re-reads the new version's declaration, your existing answers are carried across by name, anything the new version dropped is simply not written, and anything newly required shows up as an empty required field. Your live page is untouched until you press Publish.
Three things follow. A field whose name survived but whose meaning changed keeps your old text, so read the form after an upgrade instead of publishing straight through. The picker has no way back: it offers the newest version of each tile, so once you have moved you cannot choose an older one from the interface. The version itself stays bindable, and pinning an older version is how to put one back into the record by hand. And the button offers whatever the newest version is, which is not always one we can serve. If the check then answers TileInvalid or TileSuspended, publishing stays disabled and the page you already have goes on serving.
The same signal is public. Anything that asks us about your site can see that a newer version of its tile exists, which is how a dashboard you did not write can tell you the same thing.
Changing your mind
| What you want | What to do | What it costs |
|---|---|---|
| Change what you filled in | Open the editor, edit the fields, Get it ready, Publish | Nothing. Same tile, same version, new details |
| Use a different tile | Pick another one in the picker | Any answer whose name matches carries over; the rest are dropped |
| Go back to your own files | Choose Upload files for this page only and publish | The parameters are dropped from the record. Your details are still on screen until you leave the page, so switching back and forth costs nothing until you publish |
| Stop serving the page | Delete the site record | The page stops answering. No files are deleted, and your domain, its DNS and its certificate all survive. See editing, deleting and moving on |
There is no unbind button, because there is nothing to unbind from. Choosing another source and publishing is all there is to it. The tile's files are stored once, for the tile, and are not copied into your site. But they are what your domain serves, so they count toward how large one site may be and the traffic they carry is yours. See limits and quotas.
When a tile cannot be used
Every one of these appears in the editor before you publish, with the name shown beside the explanation. The first five are listed under Fix these before publishing, the last three under Fix these in your details above. Publishing stays disabled until they clear.
| Name | What it means | What to do |
|---|---|---|
TileNotReady |
We know that version only as something prepared, never as a published record. The tile's own commit has not reached us yet | Wait, then press Get it ready again. This is the ordinary answer in the minute or two after a tile is published |
TileVersionUnavailable |
The version your record names is not one we hold. The message names the version we do hold | Pick the tile again in the picker, which pins the version we hold |
TileNotFound |
We hold no version of that tile at all | Pick another tile |
TileSuspended |
An operator has stopped this version taking new bindings | Pick another tile. A site already bound to it goes on serving |
TileInvalid |
The tile's own files or its declaration are broken. It is also the answer for a version we are still reading, and the message names which | Wait, if the message says the version is still indexing. Otherwise use the newer version if there is one, or pick another tile. Only its author can fix a broken one |
MissingParameter |
The tile requires a value you have not supplied | Fill the field in |
UnknownParameter |
Your record supplies something the tile does not ask for | Only reachable if you wrote the record by hand; remove it |
ParametersTooLarge |
Your details together exceed 65,536 bytes | Shorten the longest text, or move it into a file |
If you publish a site that names a tile whose own record has not reached us yet, which is what publishing both in the same minute does, the job waits. It retries for ten minutes before answering TileNotReady and stopping, which is long enough for the ordinary case where two records arrive in the wrong order. If you build a tile inside the site editor, the editor does that waiting for you. It holds the binding until the tile has finished loading its files, so your site never names a tile we cannot yet serve.
One failure arrives after you publish instead of before. If a file belonging to the tile turns out to be missing when we fetch it, the failure is BlobUnavailable, and the status panel adds: "This file belongs to the design you picked, so re-uploading will not help — its author has to publish it again." That is not a brush-off. The file is the tile's and not yours, and only a fresh publication from its author puts it back. Tell them, or pick another tile.
Where to go next
Tiles is the real treatment: how binding by content works, what a tile may and may not do at runtime, and who is allowed to publish one. Read it if you are curious about the design you just picked, or if you are thinking of writing one.
Site owners · 6 of 12