# nsite-clay > A self-editable nsite. One HTML file holds a page's markup, styling, content > and state, and republishes itself: the browser serialises the document, stores > it on Blossom, and publishes a Nostr event saying which bytes are now the page. > Relays hold the pointer, Blossom holds the bytes, and there is no server in > between. This file is the brief for an agent. If you are building someone a website with nsite-clay, read all of it before you start. It is long on purpose: it tells you what the thing is, what to ask for, which template to begin from, and what will go wrong. It links the documentation rather than restating it. - The guide, with screenshots, for the person you are building it for: https://nsite-clay.cypherpunk.today/guide.html - The publisher, if they would rather do it themselves in a browser: https://nsite-clay.cypherpunk.today/deploy.html - Templates, browsable: https://nsite-clay.cypherpunk.today/templates.html - The block composer template, the one to read before writing a block library: https://nsite-clay.cypherpunk.today/t/cms/ - What a template must do: https://github.com/jooray/nsite-clay/blob/main/templates/_shared/CONTRACT.md - Runtime reference: https://github.com/jooray/nsite-clay/blob/main/docs/RUNTIME-API.md - Where state lives: https://github.com/jooray/nsite-clay/blob/main/docs/state.md - Source: https://github.com/jooray/nsite-clay - What an nsite is, from the people who built the idea: https://nsite.run --- ## 1. What an nsite is An nsite is web hosting on Nostr. Not long-form notes rendered as a blog: whole HTML files, with their CSS, their images and their JavaScript. Three pieces, and none of them is a server you rent: **Blossom** stores bytes and names them by their own SHA-256. Upload a file, get back its hash. Ask any Blossom server for that hash and you get exactly those bytes or nothing, because the name *is* the checksum. Content-addressed storage, so a file cannot be quietly swapped for a different one. **A Nostr event** maps paths to hashes. `/index.html` is this hash, `/about.html` is that one. The event is signed by the site owner's key, and it is *replaceable*, meaning a newer one from the same key supersedes it. Publishing a new one is the deploy. This is [NIP-5A](https://github.com/nostr-protocol/nips/blob/master/5A.md), kind 15128 for a key's main site and 35128 for a named one. **A gateway** is an ordinary HTTP server that reads the manifest, fetches the blobs, checks the bytes hash to what the manifest claims, and serves them. Any gateway can serve any site, because they all read the same public events. ### Why this works, and why it is not just a fashion The address is derived from a key, so nobody assigns it and nobody can revoke it. `https://.nsite.lol/` is yours because you hold the key, not because an account exists somewhere. Nothing is tied to one host. Six public gateways serve the same events today: nsite.lol, nsite.run, nosto.re, nwb.tf, nsite.cloud, shakespeare.to. If one is down, change the hostname. If all of them are down, run one yourself; the repo ships one that fits in a file. There is no account, no password reset, no billing relationship, and no terms of service between a person and their own page. ### What nsite-clay adds An nsite, on its own, is deployed from a terminal like any static site. nsite-clay makes the page edit and republish *itself*, so the content management system is inside the static HTML rather than behind it. You change the DOM. Click around the page and edit text, or open your browser's inspector and change it there; the page does not care which. The new version is uploaded to Blossom and one replaceable event is republished saying which hash `/` now points to. Any gateway renders it. The idea and the editing model come from [HyperClay](https://hyperclay.com) and [ClayJS](https://clayjs.com). This is that model with Nostr underneath instead of a hosting platform. --- ## 2. The philosophy, briefly **The document is the database.** There is no separate store. A checklist's state is checkboxes in the markup, a board's cards are elements, a theme is an attribute. Save the page and open the file in a text editor: everything is right there, in HTML, readable by a person. **The file at rest is the state.** No hydration step, no build. `curl` returns the page as a reader sees it, which means crawlers index it and agents can read it without executing anything. **Ownership is a keypair.** "Who may edit this page" is a signature check, not a row in somebody's users table. **One key writes the document.** There is no shared editing, no per-visitor content, and no conflict resolution. Two devices editing at once will lose one side's work. Say this early rather than building toward it. ### Two places to put things Relays are also a database, and confusing the two is the main way a page goes wrong. The rule, in full at [docs/state.md](https://github.com/jooray/nsite-clay/blob/main/docs/state.md): **The document holds what the page is.** Layout, copy, settings, application state. A kanban board is the page; it has no life anywhere else. **Relays hold what you published.** A blog post, a note, a photo: things with an identity of their own that belong in every Nostr client, not only on this page. Put a post only in the markup and Habla, njump and the rest never see it. **A post can be both**, and usually should be. Publish the event, then bake a rendered copy into the page with `nc.compose.bake(event)`. The markup carries `nc:from="naddr1…"`, so the page is self-contained and readable with no JavaScript and no relay, while the post stays a first-class Nostr object. `nc.compose.refreshBaked()` pulls the copies back in line after an edit elsewhere. **Neither** holds a draft, a filter or a scroll position. That is what the tab is doing, not state. Serialisation captures attributes, so anything you put in `dataset` is published to everyone, forever. --- ## 3. What you are actually building One `index.html`. It links three files from the site root and nothing else: ```html ``` Your job is the markup, the styling and the words. Sign-in, saving, versions, media upload, feeds and the post composer already exist. Writing your own is the commonest mistake; check the runtime reference before implementing anything. Never copy `nsite-clay.js` or `nsite-clay-base.css` into the site. They live at the root so one upgrade fixes every page. And the part that is easiest to leave out: the page has to be one they can *add* to, not only one they can retype. Every list on it needs a way to put another item in, every page needs the content form, and a page that grows needs a block library. That is §8, it is not optional, and it is the difference between a site somebody owns and a picture of one. --- ## 4. Start from a template Do not start from a blank file. ```bash npx nsite-clay init mysite --template=blog --npub=npub1… npx nsite-clay deploy mysite --sec=nsec1… ``` Pick by what the page is *for*, then redesign it. The template gives you a working page with the chrome wired up; the design is yours to change. Ten of the twelve carry a block library, so an owner can add sections you did not think of. `gallery` and `irc` do not, on purpose. Check yours with `node tools/template-blocks.mjs `. | Template | For | Look | |---|---|---| | `cms` | a page assembled from blocks rather than a fixed design | warm paper, one column, generous air; the owner adds and reorders blocks in the browser | | `personal` | one person: who you are, what you write | deep blue-black, gold accent, articles as cards and notes as a timeline | | `blog` | someone who already writes on Nostr | black, lunar, slow glow; articles in the main column, notes in a sidebar | | `project` | a piece of software | warm paper and clay-red, numbered bands, terminal cards for the commands | | `event` | a meetup, a gathering, a date and a place | black and white, poster-scale date and venue, downloadable calendar file | | `links` | one page holding everything you publish | a contents page with numbered rows and printed destinations, not a stack of buttons | | `gallery` | photographs | four rooms over one set: a canvas you drag, a sparse hang, a constellation, a plain column | | `terminal` | a project, for people who like terminals | a shell session, phosphor green, readable top to bottom without pressing anything | | `phrack` | a long technical write-up | a text file: monospace, 79 columns, ASCII rules, two colours | | `brutal` | a manifesto, a zine, a loud event | thick borders, hard shadows, oversized type, flat colour | | `eco` | an essay or a small studio | system fonts, almost no images, measures and prints its own page weight | | `irc` | a log someone keeps adding to: notes, a journal, a changelog | a channel transcript, monospace, with a composer that appends a line and saves it | Each is a complete page you can read for the pattern. Their rules are in [CONTRACT.md](https://github.com/jooray/nsite-clay/blob/main/templates/_shared/CONTRACT.md), which is short and binding: shared stylesheet from the root, `nc:edit-gate="hash"`, the standard toolbar markup, CSS variables as the styling hook, no CDN links, no autosave. ### Choosing when they are not sure Ask what the page replaces. "My Linktree" is `links`. "My blog" is `blog` if they post to Nostr already and `personal` if they mostly want an about page. "Our project's site" is `project`, or `terminal` if the audience lives in one. "A poster for a thing happening" is `event`. If they want to show pictures, `gallery`. If they are a writer who cares about typography and hates decoration, `phrack` or `eco`. ### Always ask - **Their npub.** Required: it goes in `nc:owner` and it is the only key that can ever change the page. Without a Nostr key nothing works. - **What the page is for.** This picks the template. - **What should come from Nostr**, if anything: their notes, their articles, their photos, somebody else's. - **What a stranger should do after thirty seconds.** Read something, come to a thing, hire them, follow them, zap them. - **What they do not want.** Most people have a strong opinion about at least one thing they hate on websites, and it is cheaper to hear it now. Also tell them, without being asked, that one key writes the document: there is no shared editing and no second account. ### Ask as well, for a personal homepage - Whether the page pulls their notes, their long-form posts, or both. Fetch a sample first and design for what is actually there rather than what you assumed: someone posting twice a day in two languages needs a different layout from someone publishing an essay a month. - What is at the top: a photo, a sentence, a list of what they are doing now. - Which links matter, and whether they want a Lightning address on the page. Take the picture, banner, name, about line, website and Lightning address from their kind-0 profile rather than asking again. Everything above is judgement they have and you do not. --- ## 4b. When they already have a page Sometimes nobody wants a template. They have a page: a hand written one, an export from a static site generator, a landing page somebody built them years ago. Do not rebuild it from a template and do not talk them out of the design they have. Convert it, and leave them something they can add to on their own. The design is the easy half. The half that decides whether this was worth doing is §8: a converted page where the owner can fix a typo but cannot add next month's event is a screenshot of their old site, not a site. ### First, whether it can be converted at all Say so early rather than halfway through. - **A page a framework renders at runtime.** React, Vue, Svelte and anything else that builds its DOM from JavaScript on load. A save serialises the rendered DOM, so what gets published is a snapshot of one render, and on the next load the framework re-renders over it and the edits are gone. These are not candidates. Their build output usually is, if it is genuinely static HTML. - **Anything that redraws itself on a timer.** A carousel, a clock, a widget that polls. Whatever it happens to be showing at the moment of the save is what gets published. Fine for a page where that region is decoration; not fine where it is the content. - **Assets on somebody else's server.** Fonts from a CDN, an analytics script, an image hotlinked from elsewhere. They keep working, and they also mean the page is only as durable as those hosts, which is the thing an nsite exists to avoid. Download them into the directory you are going to deploy, or inline them. Google Fonts in particular should be replaced with a system stack. The analytics and the cookie banner that existed to declare it can both go. - **A ` ``` Not from a CDN, and not pasted into the document. They are files in their site, uploaded to Blossom and named in their manifest like everything else. The stylesheet is only needed for the runtime's own dialogs and rails. Their CSS is untouched by it; it defines variables and styles elements whose names all start with `nc-`. **Three. The toolbar**, copied verbatim from [CONTRACT.md](https://github.com/jooray/nsite-clay/blob/main/templates/_shared/CONTRACT.md) near the end of ``. Without it there is no way to sign in or save from the page, and a person who cannot find the save button has not been given a self-editable site. Keep the `data-nc-cms` button in it: the shared stylesheet hides that one until the page has an `nc:cms` block, so it costs nothing on a page that does not yet have one and appears by itself when it does. **Four. `editable` on everything a person would change.** §8, layer one. On a converted page this is the bulk of the typing and none of the thinking: walk the document top to bottom and mark every heading, paragraph, caption, list row, button label, date, price and address. Twenty is a low count for a home page. Do not stop after the hero. **Five. Every list becomes a list they can add to.** §8, layer two, and the step that separates a conversion from a screenshot. Whatever the source page repeats is a shape that needs Add, Duplicate, Delete and reorder: the events, the posts, the people, the links, the opening hours. You have the shapes in front of you, so there is nothing to invent. **Six. The content form.** An `nc:cms` rules block covering the whole page, with a card list for every repeating shape. §8 again. Do this on every conversion rather than only on the ones that look like a CMS, because the person who inherits the page did not write it and will not know where to click. **Seven. Blocks.** A converted page usually already contains its own library: the sections that repeat are the shapes. Wrap the region that should grow in `nc:blocks`, give each existing section an `nc:block-type`, and lift one of each distinct shape into a `