Interface
A Site and an App are each an Interface of a Product; a rendering is one output format of a record, and an Interface has several.
An Interface is how a person or an Agent reaches a Product: an API, MCP server, CLI, SDK, Site, or App.Interface startupbuilder.dev
A Site and an App each extend Interface on startupbuilder.dev. mdxui renders a Site's pages today, one renderPage call per record, with site() for a whole Site written as Spec; the App's design is open.
Interface and rendering
The two words never trade places:
| Interface | Rendering | |
|---|---|---|
| Is | How a person or an agent reaches a Product | One output format of one record |
| Belongs to | A Product | A record |
| Examples | A Site, an App, an API, a CLI | HTML, JSON, Markdown, a share image, an email |
| On this site | Site | Renderings |
What mdxui renders
One page of one Site Interface, in two renderings. The Preview tab is the HTML a person reads; the Record tab is the JSON an agent reads and writes.
{
"$schema": "https://next.mdxui.dev/schema.json",
"theme": "quaypoint",
"template": "api-product",
"title": "Harbor tides: every berth, every tide",
"description": "Tide tables for every berth in the harbor, as one API: heights, times and the window your keel clears.",
"frame": "none",
"sections": [
{
"kind": "nav",
"shell": { "inset": "bleed", "density": "none", "surface": "glass", "sticky": true },
"block": {
"type": "nav",
"menu": "none",
"brand": { "href": "/", "text": "Harbor tides", "mark": "waves" },
"links": [
["/pricing", "Pricing"],
["/integrations", "Integrations"],
["/blog", "Blog"]
],
"cta": { "href": "/contact", "label": "Talk to the harbor" }
}
},
{
"kind": "hero",
"shell": { "inset": "contained", "density": "hero" },
"block": {
"type": "hero",
"layout": "centered",
"stack": 560,
"title": "Every berth, every tide.",
"lede": "One call returns the tide table for any berth in the harbor: the times, the heights and the window your keel clears.",
"actions": [
{ "href": "/pricing", "label": "See the plans", "kind": "solid" },
{ "href": "/contact", "label": "Talk to the harbor", "kind": "ghost" }
],
"fine": ["1,000 calls a month free", "Heights to the chart datum"]
}
},
{
"kind": "band",
"shell": { "inset": "contained", "density": "compact" },
"block": { "type": "command-row", "command": "npm i @example/harbor-tides", "note": "Node.js 22 or later" }
},
{
"kind": "section",
"shell": { "inset": "contained", "density": "section" },
"block": {
"type": "feature-grid",
"cellHead": "icon",
"head": { "eyebrow": "One call returns", "title": "The whole tide, per berth." },
"items": [
{ "icon": "waves", "title": "High and low water", "text": "Times and heights for 14 days, at the berth itself." },
{ "icon": "anchor", "title": "Keel clearance", "text": "The hours a given draft clears, from the charted depth." },
{ "icon": "map-pin", "title": "Datum named", "text": "Every height names its chart datum." }
]
}
},
{
"kind": "section",
"shell": { "inset": "contained", "density": "section", "surface": "plate" },
"block": {
"type": "api-call",
"method": "GET",
"path": "/v1/berths/{berth}/tides",
"note": "One berth, 14 days",
"examples": [
{
"label": "Pier 4, today",
"request": "curl https://api.harbor-tides.example/v1/berths/pier-4/tides?days=1",
"status": "200 OK",
"response": "{\n \"berth\": \"pier-4\",\n \"datum\": \"chart datum\",\n \"tides\": [\n { \"at\": \"04:12\", \"type\": \"low\", \"m\": 0.6 },\n { \"at\": \"10:31\", \"type\": \"high\", \"m\": 4.1 },\n { \"at\": \"16:40\", \"type\": \"low\", \"m\": 0.8 },\n { \"at\": \"22:58\", \"type\": \"high\", \"m\": 3.9 }\n ]\n}"
}
]
}
},
{
"kind": "section",
"shell": { "inset": "contained", "density": "section" },
"block": {
"type": "endpoints",
"head": { "eyebrow": "The API", "title": "Four routes, one shape." },
"rows": [
{ "method": "GET", "path": "/v1/berths", "text": "Every berth in a harbor, with its charted depth" },
{ "method": "GET", "path": "/v1/berths/{berth}/tides", "text": "High and low water for one berth" },
{ "method": "GET", "path": "/v1/berths/{berth}/window", "text": "The hours a given draft clears" },
{ "method": "POST", "path": "/v1/alerts", "text": "A webhook before a window closes" }
]
}
},
{
"kind": "section",
"shell": { "inset": "contained", "density": "section" },
"block": {
"type": "feature-split",
"head": { "eyebrow": "For the bridge", "title": "Plan the passage, not the math." },
"items": [
{ "icon": "clock", "title": "Windows, not tables", "text": "Ask for a draft and get the hours it clears." },
{ "icon": "bell", "title": "Alerts before the turn", "text": "A webhook fires an hour before a window closes." },
{ "icon": "shield-check", "title": "One source per berth", "text": "Each answer names its station and its datum." }
],
"specimen": {
"blocks": [
{
"type": "terminal",
"variant": "plain",
"title": "A 3.2 m draft at pier 4",
"lang": "json",
"lines": ["{", " \"draft\": 3.2,", " \"opens\": \"08:05\",", " \"closes\": \"12:50\"", "}"]
}
]
}
}
},
{
"kind": "section",
"shell": { "inset": "contained", "density": "section" },
"block": {
"type": "bento",
"head": { "eyebrow": "Where it runs", "title": "In the tools a crew opens." },
"panels": [
{
"title": "In a script",
"text": "One package, typed.",
"specimen": {
"type": "terminal",
"variant": "plain",
"title": "window.ts",
"lang": "ts",
"lines": ["const w = await tides.window('pier-4', 3.2);"]
}
},
{
"title": "In an agent",
"text": "One prompt, one berth.",
"specimen": {
"type": "agent-prompt",
"label": "Ask an agent",
"lines": ["Fetch the tide window for a 3.2 m draft at pier 4 today."]
}
},
{
"title": "On a chart plotter",
"text": "Through the Chartplot integration.",
"specimen": {
"type": "api-call",
"method": "POST",
"path": "/v1/alerts",
"examples": [
{ "label": "Alert", "request": "{ \"berth\": \"pier-4\", \"draft\": 3.2 }", "status": "201 Created", "response": "{ \"id\": \"al_42\" }" }
]
}
}
]
}
},
{
"kind": "section",
"shell": { "inset": "contained", "density": "section" },
"block": {
"type": "compare",
"head": { "eyebrow": "Against station tables", "title": "The berth, not the nearest station." },
"cons": {
"label": "Station tables",
"items": ["Heights at the station", "One PDF per month", "Datum in the small print", "Math done by hand"]
},
"pros": {
"label": "Harbor tides",
"items": ["Heights at the berth", "Fourteen days per call", "Datum on every height", "The window computed"]
}
}
},
{
"kind": "section",
"shell": { "inset": "contained", "density": "section" },
"block": {
"type": "steps",
"head": { "eyebrow": "How it works", "title": "From berth to window." },
"steps": ["Name the berth", "Give the draft", "Read the window", "Set an alert before it closes"]
}
},
{
"kind": "section",
"shell": { "inset": "contained", "density": "section" },
"block": {
"type": "text-stack",
"layout": "stack",
"head": { "eyebrow": "Where the numbers come from", "title": "Charted, measured, named." },
"items": [
{ "title": "Charted depth", "text": "Each berth carries the depth from the latest harbor survey." },
{ "title": "Measured tide", "text": "Predictions are corrected every 6 minutes from the harbor gauge." },
{ "title": "Named datum", "text": "Every height says which datum it stands on." }
]
}
},
{
"kind": "section",
"shell": { "inset": "contained", "density": "section" },
"block": {
"type": "agent-prompt",
"label": "Paste into your agent",
"lines": ["Install @example/harbor-tides from npm.", "Fetch the tide window for a 3.2 m draft at pier 4 today.", "Print when it opens and when it closes."]
}
},
{
"kind": "closing",
"shell": { "inset": "contained", "density": "closing" },
"block": {
"type": "closing",
"layout": "stack",
"head": { "eyebrow": "Free to start", "title": "Ask for your berth.", "lede": "A harbor master adds any berth in the harbor within one working day." },
"actions": [
{ "href": "/contact", "label": "Talk to the harbor", "kind": "solid" }
]
}
},
{
"kind": "footer",
"shell": { "inset": "contained", "density": "footer" },
"block": {
"type": "footer",
"layout": "row",
"brand": { "href": "/", "text": "Harbor tides", "mark": "waves" },
"blurb": "Tide tables for every berth, as one API.",
"columns": [
{
"title": "Product",
"links": [
["/pricing", "Pricing"],
["/integrations", "Integrations"]
]
},
{
"title": "Harbor",
"links": [
["/blog", "Blog"],
["/contact", "Contact"],
["/terms", "Terms"]
]
}
],
"note": ["Harbor tides is a worked example on mdxui.dev, not a customer.", "Rendered by @mdxui/site. Forms here do not send."]
}
}
]
}
How it maps
startupbuilder.dev's eight Interface kinds. mdxui serves one, the Site, and draws the Site pages that document four more.
| startupbuilder.dev | mdxui today | Status |
|---|---|---|
site | Page records, rendered under one Theme | Alpha: Renders today from the published packages |
api | api-callendpointsDocumented on a Site: a call with its response, and the list of endpoints | Alpha: Renders today from the published packages |
cli | command-rowterminalDocumented on a Site: the install line and a session | Alpha: Renders today from the published packages |
sdk | terminalDocumented on a Site: one call per language, as tabs | Alpha: Renders today from the published packages |
mcp | agent-promptDocumented on a Site: the prompt a reader pastes into an agent | Alpha: Renders today from the published packages |
app | Studied for 13 App types; see App types | Study: App and View territory: studied, not designed |
docs | No docs Interface: these docs run on Fumadocs, beside the renderer | Gap: No counterpart in the record; the intended Noun drafts one |
webhooks | No Section type of its own; endpoints lists webhook paths as rows | Gap: No counterpart in the record; the intended Noun drafts one |
path | Where the host mounts the Site on its Domain | Host: The job of the host that serves the files, not of the renderer |
Status
The Site Interface renders today in two renderings, HTML and JSON. The Markdown, share image and email renderings are Spec, each on its own page under Renderings.