{
  "url": "https://bloxx.page/bloxx-markdown",
  "title": "Bloxx Markdown: the page language that writes its own schema",
  "description": "Prose is ordinary Markdown. Components are directives that expand to optimised HTML and emit their own JSON-LD. Grammar, catalogue and the honest limits.",
  "lang": "en-GB",
  "headings": [
    {
      "level": 1,
      "text": "Bloxx Markdown"
    },
    {
      "level": 2,
      "text": "Why a language and not a template"
    },
    {
      "level": 2,
      "text": "Grammar"
    },
    {
      "level": 2,
      "text": "The component catalogue"
    },
    {
      "level": 2,
      "text": "What it compiles to"
    },
    {
      "level": 2,
      "text": "The honest limits"
    },
    {
      "level": 2,
      "text": "Build a page with it"
    }
  ],
  "links": [
    {
      "text": "See the catalogue",
      "href": "#catalogue"
    },
    {
      "text": "Formats reference",
      "href": "/formats"
    },
    {
      "text": "/bloxx-markdown",
      "href": "/bloxx-markdown"
    },
    {
      "text": ".md",
      "href": "/bloxx-markdown.md"
    },
    {
      "text": ".txt",
      "href": "/bloxx-markdown.txt"
    },
    {
      "text": ".json",
      "href": "/bloxx-markdown.json"
    },
    {
      "text": ".schema",
      "href": "/bloxx-markdown.schema"
    },
    {
      "text": "Email hello@itsbloxx.com",
      "href": "mailto:hello@itsbloxx.com"
    },
    {
      "text": "Formats reference",
      "href": "/formats"
    }
  ],
  "text": "Bloxx Pages\n\n  14 components, one page of grammar\n\n  Bloxx Markdown\n\n  Prose is ordinary Markdown. Structure comes from directives that expand to pre-built, already-optimised HTML, and the structured ones emit their own JSON-LD. This page is written in it.\n\n  See the catalogueFormats reference\n\n  This page, in four machine formats\n\n  /bloxx-markdown.md.txt.json.schema\n\n  The .md view is close to the source that produced this page, which is the point of having both directions run through one compiler.\n\nWhy a language and not a template\n\nThree problems, one answer.\n\nToken cost. A model emitting :::hero{title=\"...\" cta=\"...\"} spends a fraction of the tokens of forty lines of hero HTML. Across nav, footer, form, pricing and FAQ that is the difference between an agent maintaining a whole site cheaply and burning its context on boilerplate. Worth being honest: this argument is real today and gets weaker every time output prices fall.\n\nConsistency. Components expand to known-good HTML, so every page inherits the same structure and styling without a model reinventing a hero each time.\n\nSchema by construction. This is the durable one. A pricing block becomes a Product with an Offer. An FAQ block becomes a FAQPage. A steps block becomes a HowTo. Nobody writes JSON-LD by hand, so nobody forgets it, and the structured data cannot drift away from the visible content because both come from the same source.\n\nGrammar\n\nOne grammar, borrowed rather than invented. It is the CommonMark generic-directives shape that MDX, Docusaurus and Astro already use, so models have seen it.\n\nThe whole grammarbloxx-markdown\n---\ntitle: Optional frontmatter\ndescription: Feeds the meta description and og:description\nlang: en-GB\n---\n\n:::hero{title=\"Block directive with attributes\" cta=\"Start\" href=\"/signup\"}\n\n## Ordinary markdown prose in between\n\n- lists, **bold**, *italic*, `code`, [links](/x)\n- pipe tables\n\n:::faq\n- Q: Body content is markdown. A: Yes, for components that take a body.\n:::\n\n::leaf{key=\"value\"}\n\n- Block directive: :::name{attrs} with an optional body, closed by :::.\n\n- Leaf directive: ::name{attrs}, no body.\n\n- Attributes: key=\"value\", plus #id shorthand.\n\n- Fences are variable length. A block opened with four colons closes on four, so ::::code can contain a :::hero{} example verbatim. That is how this page shows its own source.\n\n- Unclosed directives are forgiving. A one-line :::hero{...} with no closing fence is treated as bodyless rather than swallowing the rest of the page. This was a real bug found by building this site, and it is the single most likely thing a model gets wrong.\n\n- Unknown components fail soft: emitted as an HTML comment, the page still compiles.\n\n- Heading anchors: ## Title {#id} sets the id, so in-page nav resolves.\n\nThe component catalogue\n\nDirectiveRendersEmits\n:::hero{eyebrow title sub cta href cta2 href2}Centred hero sectionfeeds WebPage\n:::nav{brand links cta href}Sticky header, hoisted out of <main>\n:::footer{tagline links}Footer, hoisted after <main>\n:::pricing{plan price cta href} + feature listPricing cardProduct + Offer\n:::faq with - Q: ... A: ... itemsAccordionFAQPage\n:::steps{title} with - Label: bodyNumbered stepsHowTo\n:::cards{cols} with - Label: bodyCard grid\n:::stats with - value: labelStat row\n:::formats{url label note formats}The machine-format strip\n:::code{title lang}Verbatim code block\n:::cta{title sub cta href cta2 href2}Dark call-to-action band\n:::noteCallout\n:::form{title fields submit}Styled lead form\n\nEvery page also gets a WebPage node. Prices parse currency and period, so $29/mo becomes an Offer of 29 USD.\n\nWhat it compiles to\n\ncompile_bmd(source, url) returns one self-contained HTML document: framework CSS inlined, JSON-LD @graph assembled from whichever components were used, Open Graph and Twitter tags derived from the frontmatter, and correct landmark structure with the header and footer outside <main>.\n\nThe stylesheet is tree-shaken against the rendered page, so a document ships only the rules it actually uses. On this site that is roughly a 28% saving on every request, which matters because Mode-0 pages are self-contained by design.\n\nCompile and publishbash\npython3 scripts/bloxx_markdown.py page.bmd --url https://bloxx.page/page\npython3 scripts/bloxx_publish.py page.bmd --slug page\n\nThe honest limits\n\nBloxx Markdown is a page language, permanently. It is not becoming an app language, because that road ends at a worse MDX.\n\nThere are no conditionals, no loops and no render-time data binding, and there will not be. The moment a language needs those it is re-implementing MDX with no IDE support, no type system and no plugin ecosystem, which is strictly worse than adopting MDX. If you need a component tree, use MDX or Markdoc; they are good, and Markdoc in particular is the same idea aimed at a different target.\n\nData-driven pages are handled at publish time instead: a CSV becomes rows of static components when the page is compiled, not a template evaluated on every request. Same output, no language to maintain.\n\nSo what is actually different here? Not the syntax, which is deliberately borrowed. The difference is the compile target: an optimised page, plus its JSON-LD, plus machine formats at the same URL, plus hosting, from one source an agent can write cheaply.\n\nIs the grammar stable?The four original components and the grammar above are stable. Components added since are additive, and unknown directives fail soft, so a page written today keeps compiling.\n\nCan I share components between pages?Site-scoped saved components are the next step, pinned by version into each page at publish time rather than included live, so editing one component cannot silently change pages you were not looking at. There is no public registry and no marketplace planned.\n\nDoes it work without the hosting?The compiler is a standalone Python script that emits a self-contained HTML file. You can publish that anywhere; you just lose the format views, which are a property of the renderer.\n\nWhy not just write HTML?You can, and a full HTML document publishes as-is with the same format views and edge caching. The language is for when an agent is doing the writing and you want schema correctness by default.\n\n  Build a page with it\n\n  The compiler and the publish loop are in daily use across 27+ domains. If you want to try the connector, get in touch.\n\n  Email hello@itsbloxx.comFormats reference\n",
  "schema": [
    {
      "@context": "https://schema.org",
      "@graph": [
        {
          "@type": "WebPage",
          "name": "Bloxx Markdown: the page language that writes its own schema",
          "description": "Prose is ordinary Markdown. Components are directives that expand to optimised HTML and emit their own JSON-LD. Grammar, catalogue and the honest limits.",
          "url": "https://bloxx.page/bloxx-markdown"
        },
        {
          "@type": "FAQPage",
          "mainEntity": [
            {
              "@type": "Question",
              "name": "Is the grammar stable?",
              "acceptedAnswer": {
                "@type": "Answer",
                "text": "The four original components and the grammar above are stable. Components added since are additive, and unknown directives fail soft, so a page written today keeps compiling."
              }
            },
            {
              "@type": "Question",
              "name": "Can I share components between pages?",
              "acceptedAnswer": {
                "@type": "Answer",
                "text": "Site-scoped saved components are the next step, pinned by version into each page at publish time rather than included live, so editing one component cannot silently change pages you were not looking at. There is no public registry and no marketplace planned."
              }
            },
            {
              "@type": "Question",
              "name": "Does it work without the hosting?",
              "acceptedAnswer": {
                "@type": "Answer",
                "text": "The compiler is a standalone Python script that emits a self-contained HTML file. You can publish that anywhere; you just lose the format views, which are a property of the renderer."
              }
            },
            {
              "@type": "Question",
              "name": "Why not just write HTML?",
              "acceptedAnswer": {
                "@type": "Answer",
                "text": "You can, and a full HTML document publishes as-is with the same format views and edge caching. The language is for when an agent is doing the writing and you want schema correctness by default."
              }
            }
          ]
        }
      ]
    },
    {
      "@context": "https://schema.org",
      "@type": "Person",
      "name": "Charlie Bailey",
      "jobTitle": "Founder, Bloxx Pages",
      "url": "https://www.linkedin.com/in/charliebaileyy/",
      "sameAs": [
        "https://www.linkedin.com/in/charliebaileyy/",
        "https://x.com/joinsidequester"
      ]
    }
  ]
}
