Create rich lists and import JSON
Use the same options and reviewed extensions as Tilt’s starter lists.
Start without JSON
- Create a list with at least two items, or paste one item per line. Optional columns are name | image URL or #hex | caption | comma-separated tags. Bullets and numbered lists work too.
- Item fields starts with editable definitions for the item name, image, caption, tags, image style and position. Add up to 30 fields, then open an item’s Details button to fill them in. Item images need a URL hosted elsewhere; you cannot upload them from the editor. Use Preview on an item to see its unsaved comparison card. Use On item cards to choose the single field for each card value and for tag filters. You can also hide captions or set one photo or logo style for the whole list. A list-wide image style hides the per-item choice.
- List details sets the description and comparison question. Player options adds switches, dropdowns, sliders or text. Play behaviour shows the list’s extension source, or lets you add your own code. These sections stay collapsed until you need them.
- Save explicitly. Personal, store, public and group lists use the same format. Personal lists support 300 items; public and group lists support 50. Publishing to the store or public shared section requires a site admin.
Import and export
{
"formatVersion": 1,
"name": "Sea and sand",
"icon": "palette",
"fields": [
{
"id": "colour",
"label": "Colour",
"type": "color"
}
],
"presentation": {
"colour": "colour"
},
"items": [
{
"id": "sea",
"label": "Sea",
"fields": {
"colour": "#488F94"
},
"tags": [
"coast"
]
},
{
"id": "sand",
"label": "Sand",
"fields": {
"colour": "#E9D7BA"
},
"tags": [
"shore"
]
}
],
"extensions": [
{
"name": "My tool",
"description": "An editable tool",
"config": {},
"package": {
"apiVersion": 1,
"capabilities": [],
"surfaces": [
{
"id": "hello",
"label": "My tool",
"slot": "tool",
"height": 100
}
],
"script": "function mount(tilt) { tilt.root.textContent = 'Hello from my list'; }"
}
}
]
}Open List JSON to see the complete current document. Form changes update it automatically. Choose a .json file up to 256 KB or paste JSON, then Preview import. Use imported list replaces only your draft after confirmation. Export JSON downloads the draft without votes or account information.
Use formatVersion 1, name (1–80 characters), icon and items. Optional tagline supports 200 characters and prompt supports 120. Item IDs must be unique lowercase letters, numbers or hyphens, up to 80 characters. Keep IDs stable to preserve their rankings.
Custom fields and presentation
Define up to 30 fields with id, label and type: text, number, color, select, boolean, image, tags or image-position. Select fields need choices containing value and label. Numbers support min and max; required marks a mandatory value. Field values stay in each item’s fields object, keyed by field ID. Text supports 300 characters; colours use #RRGGBB. Existing standard item properties and source fields remain supported for older lists.
The presentation object selects one field ID for each card role: label, colour, caption, image, tags, imageStyleField or imagePosition. hideCaption hides captions; imageStyle sets photo or logo for the whole list and takes priority over imageStyleField. Leaving a role unselected uses the item’s standard property. Use images you have permission to share.
Player options
Define up to 20 options with id, label, description, type and default. Types are toggle (the default), select, range and text. Select uses choices with value and label; range requires min and max and optionally step. Defaults must match the type.
Effects are hide-labels, include-tag (with tag), select-tag, or extension. The first two use switches; select-tag uses a dropdown whose values match tags, with all meaning no filter. Extension settings are passed to the play module by option ID. Filters preserve rankings and must leave two available contenders.
Preferences puts account access near the top. Ranking, home layout and searchable list options live in expandable sections. Quick preferences in the top bar is available on every screen. It includes appearance, voting style and auto-continue, with list options when a list is open. All preferences opens the full settings page.
Extensions during play
Each extension contains name, description, config (up to 8 KB), and its complete package (up to 32 KB). Scripts, capabilities and surfaces are visible and editable in the list. Approval is checked against the package contents; it is never trusted from imported JSON. Unapproved packages stay saved and use standard comparisons.
The Colours list’s embedded Colour studio package adds colour cards with clickable hex codes: click a code to copy it without voting. Explore colours opens a segmented wheel made from the list’s actual shades, with equal sectors and concentric shade rings, where you can add any of its colours. Neutrals appear separately from the hue wheel. Marker numbers are ranking positions, starting with your favourite. Keyboard users can add markers with Add colour, move them up or down with the row buttons or arrow keys, change shades using the Selected shade menu, and remove them with Delete. Save ranking saves the order directly from this tool and estimates scores. Unselected colours are not marked as disliked. Dragging a marker changes its shade; use the ranking controls to change its position.
Colour studio reads the colourField named in config (default: colour), or the item's swatch. The standard animated Tilt card is kept; only its caption becomes a copy button. The same package works on any list with colour fields. Tool drafts last while Play stays mounted; they are not synced. Regular extensions are always available. Use experimental extensions in Preferences is off by default and enables packages marked experimental, including Colour studio. This uses your normal saved preferences. Blind matching remains independent.
Local developers can use /dev/extensions to add seven two-item example lists covering captions, inline controls, popup tools, custom cards, replacement voting, combined surfaces and multiple independent tools. The examples use the public SDK, can be exported as JSON, and are unavailable in production.
Signed-in creators can suggest JavaScript through Play behaviour. Each version is pending until a superadmin approves its exact code digest. Superadmins can preview, reject or revoke submissions in the dashboard. Changed packages need their own approval. An identical copy shares approval, regardless of its list or creator. Revocation applies to every copy of that code.
Custom interfaces (API version 1)
{
"apiVersion": 1,
"capabilities": [
"clipboard.write"
],
"surfaces": [
{
"id": "copy",
"label": "Copy a value",
"slot": "inline",
"height": 60
}
],
"script": "function mount(tilt) { const draw = () => { const item = tilt.context.items.find(i => i.id === tilt.context.pair[0]); const text = String(item.fields?.code || item.label); tilt.root.textContent = 'Keep this value'; tilt.actions([{id:'copy',label:text,title:'Copy to clipboard',command:{type:'clipboard.write',text}}]); }; tilt.onContext(draw); draw(); }"
}Paste a JSON package into the list’s extension source with apiVersion: 1, capabilities, surfaces and script. The script is a function mount(tilt). Signed-in account holders can submit code for review; only a superadmin can approve it. The immutable approval digest covers the entire JSON package, including capabilities. List JSON includes the complete extension object: name, description, config and package. The package contains all source code and capabilities; no module ID or bundled implementation is required. Editing a package changes its review digest.
A surface has a unique id, label, slot and height (60–600 pixels). Slots are tool (opened from a Play button), inline (a panel below the comparison), card-caption (native actions inside the existing card), card (replaces both cards with separate instances), or voting (replaces the entire comparison). Custom surfaces are transparent by default: set appearance to panel for a Tilt container. Set autoHeight to true to fit content within 60–600 pixels. Set experimental: true on the package to require the experimental-extensions preference; omitted or false means regular availability. This flag is covered by the package approval digest. One package can supply up to eight surfaces, but only one of each card, card-caption and voting renderer. When both are present, the voting renderer takes precedence. These are integration points, not a fixed set of widgets: the script can build its own DOM, CSS, canvas, interactions and calculations.
The SDK supplies tilt.root, tilt.context, tilt.surface, tilt.state, tilt.onContext(callback), tilt.setState(JSON), and tilt.actions(array). Card instances receive side: left or right in surface and context. Context has current items, pair, config, options, labelsHidden, interaction (tapToChoose and autoAdvance), disabled, and feedback (selected and the saved vote result, when available). Re-render when context changes, honour disabled and hidden labels, and provide keyboard controls. CSS colours are exposed as --color-ink, --color-ink-soft, --color-surface, --color-cream, --color-line, --color-lavender-deep and related theme variables. The tilt.ui toolkit provides button({label, title, variant, compact, disabled, onClick}), field({label, type, value, min, max, step, choices, onChange}), toggle({label, checked, disabled, onChange}), and layout(row, stack or panel, children). These return DOM nodes to append to your custom UI, using IBM Plex Sans, your text size, colours and shared control styling. Text-size and appearance changes update mounted surfaces without resetting their local state. Field types include text, number, color, range and select. Toolkit callbacks handle local interaction only; saved actions still go through tilt.actions. State is private to that mounted Play experience and surface, survives closing a tool, and is limited to 16 KB; it is not persistent account storage.
Declare only the capabilities you need: clipboard.write, select, vote, pair, arrange, order.save. tilt.actions declares up to eight native Tilt buttons. They appear inside the original card for card-caption surfaces, and below other custom interfaces. Each needs id, label, optional title (tooltip), and command. Set variant to subtle for a flat secondary control, or secondary for a raised Tilt button. Commands are {type:'clipboard.write',text}, {type:'select',value:1..5}, {type:'vote',value:1..5}, {type:'pair',ids:[leftId,rightId]}, {type:'arrange',ids:[ordered item IDs]}, or {type:'order.save',ids:[ordered item IDs]}. Text is limited to 4096 characters. IDs must belong to currently available items. Select follows the player’s auto-advance setting; vote commits an answer directly. Only a user click on a native button executes a command. Clicking a clipboard button never casts a vote. Arrange opens the order editor for review. The separately approved order.save capability saves an order directly after a native button click, for tools that already provide their own ranking editor. Neither can save automatically from extension code. Arrange and order.save are only available for personal lists. Live rankings accept individual votes only.
Interfaces run in nested opaque sandbox frames. App DOM, cookies, account storage, network requests, external frames, forms, popups and external navigation are blocked. Author scripts cannot invoke the host's actions directly. Output is validated and bounded, and invalid messages or startup failures restore standard comparisons. Interactive DOM code has no hard CPU deadline. A successful preview does not prove safe behaviour: superadmins must review code, accessibility, performance, labels and every declared capability before approval. New ideas can use arbitrary interface code, but new privileges or ranking data types still need a reviewed host API addition.
Starter lists belong to you
New libraries start with the public lists selected by Tilt’s superadmins. The selection can include Tilt and community lists, or be empty. Changes apply only to new libraries; existing copies and rankings stay as they are. Tilt’s own store lists are published by @tilt. Community copies retain their creator’s name. You can add more lists from the store. Edit or archive installed copies like any list. Delete an archived copy to remove its rankings; adding the store original again creates a fresh copy. Deleting your copy does not remove the store listing.