Publish a folder from the Vulpine wallet and it lives in the BSV blockchain: no server, no hosting bill, no host to switch it off. Change one file later and only that file goes up again. Every version is kept.
A small site costs a fraction of a cent to publish, paid from your wallet as you publish it. The site has nothing to renew.
Change one file and publish: the new version shows under the same address. Any earlier version can be put back with one press.
A public site anyone can open, or a .void site sealed with a key that only its link carries.
Point a .fox name you hold at your site, and it follows every update.
About two minutes, start to finish.
.html page; pick the one it opens on, usually index.html. Links between your files keep working on chain.In Sites, press Manage on your site. Edit a page right there, replace or remove a file, add files, start a new text file, or update the whole thing from a folder or a .zip. Then Publish the update.
Only the files that changed go on chain, so an update usually costs less than the first publish. The site's address stays the same, and everyone who opens it sees the new version.
Versions lists each version of your site and what changed in it. Make live puts any of them back: that is a new version too, so nothing is ever lost. On a computer, Download .zip gives you the files of any version.
Everything you publish stays on chain. A newer version replaces what people see, but older versions can still be read by anyone who has the site's link. Publish nothing you would need to take back.
Anyone can open it, by its address or by a .fox name pointed at it. Its files and its name are on chain in the open.
Unlisted and sealed. Every file is encrypted before it goes on chain, and the key is part of the site's link: whoever has the link can open it, and nobody else can, us included.
Hold a .fox name? In Sites, Manage your public site, then under .fox names press Point here. From then on yourname.fox opens your site, and every update shows under it by itself. It takes about a minute to reach everyone. Unpoint it any time.
You pay the network to store your site, from your wallet, when you publish. The wallet shows the exact price before you pay.
| For example | Sats | In dollars |
|---|---|---|
| A one-page site, 20 KB | 2,130 | … |
| A small site: 10 files, 500 KB | 50,580 | … |
| A big site: 60 files, 5 MB | 503,080 | … |
| An update: one 10 KB page changed | 1,190 | … |
.html page.A site opens in Vulpine's browser, in a sealed frame. That is what makes it safe to open anyone's site, and it shapes how you build one:
<link href="style.css">, url(img/bg.png), <script src="app.js">), and the wallet puts them in place.<a href="about.html">.fetch('data/posts.json') is answered from the site itself, up to 1 MB a file and 8 MB in all.api.whatsonchain.com and junglebus.gorillapool.io are open to it. If a read fails, the wallet tries again and falls back from one service to the other, answering in the shape you asked for.ordinals.gorillapool.io is open too, so a picture or a video can come straight from its inscription: <video src="https://ordinals.gorillapool.io/content/<txid>_<vout>">. An older Vulpine doesn't allow this, so fall back to reading the inscription's transaction, as Btube on chain does.parent.postMessage({ type: 'open-link', url }, '*'), and Vulpine asks the person once for each site before opening it.A .void page gets window.VOID: { key, board, read }, the site's key, its board's address on chain, and the services it may read. It reads posts from the board's address, opening each with the key. To post, the page seals the post with the key and hands it to the wallet:
parent.postMessage({ type: 'void-post', box, id }, '*')
// the wallet answers, once it is sent:
{ type: 'void-posted', txid, hex, id } // hex: the transaction, so the page can show the post at once
{ type: 'void-error', message, id }
The person is asked once, while the site is open, before their posting pocket pays for anything.
Every public board on the network (4chain's /FG/, /POL/, any other) is an address on chain: the key is sha256('vulpine-board:' + SLUG), so any page can work it out from the board's name. Every post on the board pays one sat there, so a page reads the board by reading that address's history, with no server in between. Each post is an OP_RETURN of Vulpine, fwetch-post and the post as JSON ({ p, b, t, reply, img, board, tr }). The network also writes two records there: board-index, which lists older posts, and board-hide, which lists what the moderators took down. Believe them only when house 0's key signed an input of their transaction. 4chain on chain is one page that does all this, and it is a site itself, so you can read its source: open chain:1d4019489f5332a924c7776bfbfde10c45d60155bc07c21977ea1812f8a0f5d8_0 in Vulpine's Browser.
To post on a board, a page hands the post to Vulpine. The network writes it anonymously, the way it writes every anonymous post:
parent.postMessage({ type: 'board-post', id, post: { board: 'FG', b: 'words', reply, tr, imgData } }, '*')
// the wallet answers, once it is sent:
{ type: 'board-posted', txid, id }
{ type: 'board-error', message, id }
The person is asked once, while the site is open. Nothing is paid from their wallet.
Cregs List is an address too: its key is sha256('vulpine-app:cregs'). Every ad, every change to one and every taking down pays one sat there, so a page reads the classifieds from that address's history. An ad is an OP_RETURN of Vulpine, fwetch-classified and the ad as JSON ({ p, title, body, category, city, location, price, currency, imgs, t, pub, sig }). city names one of the network's cities by its slug (new-orleans-us). Each ad is signed by its poster's identity: the record without pub and sig, keys sorted, as JSON, signed with BRC-42's "anyone" (protocol [0, 'fwetch identity'], key 1), so any page can check who posted it. The network lists older ads there (app-index) and what was taken down (app-hide); believe those only when house 0 signed. Cregs List on chain does all of this, signature checks included, and it is a site itself: chain:d9e56fbc66bbe64e4478e5267395873c9236e19875d5be5186831fae988a2ca8_0.
To post an ad, change one or take one down, a page hands it to Vulpine, which asks the person every time and signs it with their wallet. The network pays:
parent.postMessage({ type: 'classified-post', id, ad: { title, body, category, city, location, price, currency, anon, alias, parent, pub } }, '*')
parent.postMessage({ type: 'classified-remove', id, txid, title, pub }, '*')
parent.postMessage({ type: 'open-listing', id, txid }, '*') // the ad in Vulpine's Cregs List, to reply to its poster
// the wallet answers:
{ type: 'classified-posted', txid, record, id } // record: the signed ad, so the page can show it at once
{ type: 'classified-removed', txid, id }
{ type: 'listing-opened', id }
{ type: 'classified-error', message, id }
A change (with parent) or a taking down is only for an ad this wallet posted: pub is the key that signed it.
Open, and all on chain. Anything that follows it can read a Vulpine site; no Vulpine server is needed to open one by its address.
application/octet-stream.{ "p": "vulpine-site", "v": 1, "id": "<32 hex>", "name": "My site", "index": "index.html",
"files": { "index.html": { "o": "<txid>_<vout>", "t": "text/html", "n": 5120, "h": "<sha256 hex>" } },
"owner": "<public key hex>", "prev": null, "ts": 1791334703 }<txid>_<vout>. A .void site's link carries that and the key.prev names the one before), then sends a version record: 1 sat to the site's record address, P2PKH(sha256('vulpine-site-head:' + secret)), where the secret is the address (or a .void site's key), with an OP_RETURN of Vulpine | site-head | { id, n, m, sig }. For a .void site that payload is sealed too.sig signs vulpine-site-head-v2|id|entry|n|manifest with a key the publisher's wallet makes for that one site; it must match the first manifest's owner. Readers take the highest validly signed n. Making an old version live is a new record with a higher n.https://ordinals.gorillapool.io/content/<txid>_<vout>.fwetch-retarget record whose target is site:<address>.