Pages for Businesses, not pixels.
Render a page from a record, wear it in a Business's Theme, and hand the next one to your agent.
pnpm add @mdxui/site@7.0.0-alpha.0
{
"$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 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 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.", "Rendered by @mdxui/site."]
}
}
]
}
Harbor tides is a worked example, not a customer · API product · its own Theme is quaypoint
Tasks
StartRender your first pageInstall the pinned pair, write one record, render it under two Themes.ShowcaseStart from a worked SiteOpen the Business closest to yours and copy its records.ThemesPick a ThemeFive Brands, each tokens plus four render policies.AgentsHand it to your agentThe fetches, the prompt and the fix loop an agent runs.SectionsFind a Section typeTwenty-seven types by job, each in every Theme.AppsStudy an App typeThirteen App types, studied before any is defined.
Build a…
Each kind of Business has a worked Site: real records, one Theme, a 404 and a contact flow. Open the one closest to yours and copy its records.
What ships
Every page carries one badge. Alpha ships on npm, Spec is written ahead of the package, and Study defines nothing.
| Alpha: Ships on npm at 7.0.0-alpha.0 | @mdxui/site | On npm at 7.0.0-alpha.0: the schema, the renderer and 27 Section types |
| Alpha: Ships on npm at 7.0.0-alpha.0 | @mdxui/themes | On npm at 7.0.0-alpha.0: the Theme contract and 5 Themes |
| Alpha: Ships on npm at 7.0.0-alpha.0 | HTML and JSON | renderPage, and the record served beside every page |
| Spec: Written ahead of the package | Markdown, share image, email | Renderings written ahead of the package |
| Spec: Written ahead of the package | Theme playground | compileTheme runs; a whole page in your own Theme does not |
| Study: A study of the work. Defines nothing. | App, View, Dashboard | Thirteen App types studied; no App package |
For agents
An agent reads the same docs as text, starts from a record that parses and checks its work against the schema.