STATUS · Built and tested locally. The launch chain has no public node; a public devnet, pointcast-devnet-2, is open (no value is promised; it may reset, and a reset is dated and recorded, never silent). Mainnet anchoring waits on a funded key. First Mints mint on the devnet once its edition is open; the art certificates are rehearsals.

CHAIN · CHECKPOINT BLOOMS · PUBLIC DEVNET-2 · NO VALUE · MAY RESET, NEVER SILENTLY

Checkpoint Blooms: the chain, drawn.

Every tenth block of the PointCast devnet is a checkpoint, and witness keys sign them. A bloom is an abstract drawing of one checkpoint’s hash: the same hash always draws the same SVG, to the byte, and you can recompute it yourself in twenty lines. Where keys have signed, thin rings outside the bloom count them.

devnet · no value · may reset. This is pointcast-devnet-2. One server runs it and it can reset; a reset is dated and recorded, never silent. The last one was on 2026-10-08, and devnet-1 is kept as a recording you can replay at /chain/yard/devnet-1/. Blooms are free to look at, have no price and are not tokens.

today’s bloomthe gridhow it is drawnwhat it is notfor developers

The devnet was reset on 2026-10-08. devnet-1 (#1–#1465, 2026-10-03 → 2026-10-08) is recorded and checkable here →

01 · TODAY’S BLOOM · THE LATEST CHECKPOINT · READ LIVE FROM THE DEVNET, IN YOUR BROWSER

Today’s bloom

This section reads the devnet from your browser after the page loads. Until it answers, the picture is the genesis bloom, drawn from pointcast-devnet-2’s genesis hash. It is not a checkpoint.

GENESIS BLOOM · NOT A CHECKPOINT

Genesis bloom: drawn from the hash of pointcast-devnet-2’s first state, shown until the latest checkpoint is read.

Checkpoint
—
Block hash
—
Sealed (UTC)
—
Your clock
—
Witnessed
—

not read yet

02 · THE LAST 120 CHECKPOINTS · GROUPED BY UTC DAY · READ AS YOU SCROLL

Every tenth block, drawn.

Each tile is one checkpoint, newest first, grouped by the UTC day its block was sealed. A thin gold ring outside a bloom means a witness key signed that checkpoint; the number says how many distinct keys. Press a tile for the large view.

Checkpoints load as this section nears the screen, 24 at a time and six requests at a time, from the devnet.

03 · HOW A BLOOM IS DRAWN · NOTHING HIDDEN

A hash goes in; a drawing comes out.

The block hash is the only input. There is no random number, no clock and no server in the drawing: only the hash, the chain’s own blake2b, and arithmetic. Open any bloom for the exact twenty lines and a copy button.

  1. Seeds. The chain’s own hash, blake2b-512, runs over the 32 bytes of the block hash plus a counter byte, for counters 0, 1 and 2. That is 192 seed bytes. Two bytes at a time become a number between 0 and 1.
  2. Palette. Colours are chosen in OKLCH: one hue anywhere on the wheel, a near-white ink, a deep ground tinted like the site’s ink, and three petal colours with the chroma the channel ramps use. They are written as sRGB hex so every viewer agrees.
  3. Petals. Five to thirteen petals in three layers: long and outer, shorter and offset, short and doubled. Length, width and how sharp the tip is come from the next numbers.
  4. Rings and arcs. Three to six thin rings at hash-chosen radii, some dashed, and three to five signal arcs with round ends that start and sweep where the hash says.
  5. Grain. A calm stipple: 120 tiny dots along a spiral, nudged by the seed bytes.
  6. Witness rings. Not part of the recipe. If keys signed the checkpoint, one thin gold ring per distinct key is added outside the bloom, at radius 390 + 7 × k. Up to 14 are drawn; the text says the real count.

The SVG has no text, no image, no script and no link of any kind: only rect, circle, path and g. The page checks that for every SVG it shows or offers, and its tests run the same audit on a thousand different hashes.

04 · WHAT A BLOOM IS NOT

A drawing, not a promise.

  • Free to look at, free to download. There is no price and no sale.
  • Not tokens. A bloom is a drawing of a checkpoint, not a record on any chain and not a claim on anything.
  • Not proof. A witness ring is one more accountable claim, tied to a free key, that the key replayed the chain and got this hash. Nothing checks that it did; strikes only catch disagreement with this server.
  • Not permanent. This is devnet-2, one server runs it, and it may reset. A reset is dated and recorded: devnet-1 is kept as a recording you can replay at /chain/yard/devnet-1/. After a reset the old hashes are gone from the live chain and these drawings would no longer match it.

devnet · no value · may reset. pointcast-devnet-2 may reset; a reset is dated and recorded, as devnet-1’s was on 2026-10-08 (the recording).

05 · FOR DEVELOPERS

Import it, draw it, audit it.

/chain/apps/bloom.js is a plain ES module with no DOM and no network. It exports bloomSvg(hash, { witnesses, drift }), bloomOgSvg(hash) (a 1200 × 630 variant for cards, with the whole bloom centred and three faint halo rings), auditSvg(svg) and geometryFingerprint(svg). Block hashes come from GET https://pointcast-devnet.mhoydich.workers.dev/block/<height>; the witness list for a checkpoint is GET https://pointcast-devnet.mhoydich.workers.dev/checkpoints/<height>/witnesses.

METHOD

Checkpoints are every 10th block of pointcast-devnet-2; their hashes, times and witness lists are read from the devnet in your browser, and names, notes and addresses are shown as plain text. The drawing itself never touches the devnet. The recipe printed in the large view is read from the shipped file at build time, and a test runs it against the module for two hundred hashes. Filed by Claude Code.

CHECKPOINT BLOOM · LARGE VIEW · devnet · no value · may reset

Checkpoint

Block height
…
Block hash
…
Sealed (UTC)
…
Your clock
…
Chain
…
Parent link
…

The hash is as the devnet reports it (GET /block/<height>); the parent link above is the devnet agreeing with itself. Nothing on this page replays the chain. The Block Yard does, and a witness key is a claim that someone did.

Witnessed

…

    A witness is an accountable claim, not proof of truth: a public claim, tied to a free key, that the key replayed the chain and got this block hash. Nothing checks that it did. Counts are keys, not people.

    Block Yard, Witness lens

    The Block Yard replays the devnet in your browser and rings the checkpoints keys signed. It has no link to a single block, so look for the height above on its track.

    RECOMPUTE IT YOURSELF · 20 LINES · SAME HASH, SAME BYTES

    Recompute it yourself

    This is the whole recipe: the same 20 lines bloomSvg() in /chain/apps/bloom.js runs, plus the one import it needs. Run it as a module (a <script type="module"> on any page works, because the SDK is served with CORS open), or in Node 20 or newer: save the SDK next to your file and change the import path to ./pointcast-chain.js. Call it with the block hash above. With no witness keys on the checkpoint, the SVG it returns is the file you can download, byte for byte.

    1. Seeds. The chain’s own hash, blake2b-512, runs over the 32 bytes of the block hash plus a counter byte, for counters 0, 1 and 2. That is 192 seed bytes. Two bytes at a time become a number between 0 and 1.
    2. Palette. Colours are chosen in OKLCH: one hue anywhere on the wheel, a near-white ink, a deep ground tinted like the site’s ink, and three petal colours with the chroma the channel ramps use. They are written as sRGB hex so every viewer agrees.
    3. Petals. Five to thirteen petals in three layers: long and outer, shorter and offset, short and doubled. Length, width and how sharp the tip is come from the next numbers.
    4. Rings and arcs. Three to six thin rings at hash-chosen radii, some dashed, and three to five signal arcs with round ends that start and sweep where the hash says.
    5. Grain. A calm stipple: 120 tiny dots along a spiral, nudged by the seed bytes.
    6. Witness rings. Not part of the recipe. If keys signed the checkpoint, one thin gold ring per distinct key is added outside the bloom, at radius 390 + 7 × k. Up to 14 are drawn; the text says the real count.
    import { blake2b, hexToBytes } from 'https://pointcast.xyz/chain/sdk/pointcast-chain.js';
    export function bloom(hash) {
      const B = [0, 1, 2].flatMap((c) => [...blake2b([hexToBytes(hash), [c]], 64)]); let i = 0; // 192 seed bytes: the chain's own hash, three counters
      const u = (a, b) => a + (b - a) * ((B[i++] << 8) | B[i++]) / 65536, R = (x) => Math.round(x * 10) / 10, P = (r, t) => `${R(500 + r * Math.sin(t))} ${R(500 - r * Math.cos(t))}`; // u: next two bytes as a number in [a, b)
      const T = (n, a, k = '') => `<${n} ${Object.entries(a).map(([x, v]) => `${x}="${v}"`).join(' ')}${k ? `>${k}</${n}>` : '/>'}`; // one SVG tag; every value is a number or a hex colour
      const hex = (L, C, H) => { const [a, b] = [Math.cos, Math.sin].map((f) => C * f(H * Math.PI / 180)), g = (v) => (v <= .0031308 ? 12.92 * v : 1.055 * v ** (1 / 2.4) - .055);
        const [l, m, s] = [[.3963, .2158], [-.1056, -.0639], [-.0895, -1.2915]].map(([p, q]) => (L + p * a + q * b) ** 3); // OKLCH -> OKLab -> linear sRGB -> hex
        return '#' + [[4.0767, -3.3077, .231], [-1.2684, 2.6098, -.3413], [-.0042, -.7034, 1.7076]].map(([p, q, r]) => Math.round(255 * Math.min(1, Math.max(0, g(p * l + q * m + r * s)))).toString(16).padStart(2, '0')).join(''); };
      const h0 = u(0, 360), ink = hex(.94, .02, h0), bg = hex(u(.17, .25), u(.02, .06), h0 + 190); // palette: a hue, a near-white ink, a deep ground
      const c = [hex(u(.7, .88), u(.08, .14), h0), hex(u(.62, .78), u(.1, .16), h0 + u(25, 70)), hex(u(.82, .93), u(.05, .1), h0 - u(20, 60)), hex(u(.74, .86), u(.1, .15), h0 + u(150, 210))];
      const n = Math.floor(u(5, 14)), len = u(280, 340), wide = u(.35, .8), tip = u(.35, 1), ratio = u(.55, .8); // petals: count, length, width, tip, inner ratio
      const petals = [0, 1, 2].map((j) => { const m = n * (1 + (j > 1)), L = len * [1, ratio, ratio * .6][j], x = L * wide / 2; // three layers of petals, drawn as paths
        const d = `M500 500C${R(500 - x)} ${R(500 - L * .35)} ${R(500 - x * tip)} ${R(500 - L * .9)} 500 ${R(500 - L)}C${R(500 + x * tip)} ${R(500 - L * .9)} ${R(500 + x)} ${R(500 - L * .35)} 500 500Z`;
        return Array.from({ length: m }, (_, k) => T('path', { d, transform: `rotate(${R((k + [0, .5, .25][j]) * 360 / m)} 500 500)`, fill: c[j], 'fill-opacity': [.8, .7, .9][j] })).join(''); }).join('');
      const rings = Array.from({ length: Math.floor(u(3, 7)) }, () => T('circle', { cx: 500, cy: 500, r: R(u(60, 372)), fill: 'none', stroke: ink, 'stroke-opacity': .6, 'stroke-width': R(u(1, 3)), ...(u(0, 1) > .5 && { 'stroke-dasharray': `${R(u(2, 10))} ${R(u(4, 16))}` }) })).join('');
      const arcs = Array.from({ length: Math.floor(u(3, 6)) }, (_, k) => { const r = u(90, 372), t = u(0, 6.2832), s = u(.5, 3.4); // signal arcs: radius, start angle, sweep
        return T('path', { d: `M${P(r, t)}A${R(r)} ${R(r)} 0 ${+(s > Math.PI)} 1 ${P(r, t + s)}`, fill: 'none', stroke: c[k % 2 ? 3 : 1], 'stroke-width': R(u(4, 10)), 'stroke-linecap': 'round', 'stroke-opacity': .95 }); }).join('');
      const grain = T('path', { d: Array.from({ length: 120 }, (_, k) => `M${P(Math.sqrt((k + .5) / 120) * 480, k * 2.39996 + B[k] / 40)}h0`).join(''), stroke: ink, 'stroke-width': 2.2, 'stroke-linecap': 'round', 'stroke-opacity': .2 }); // calm grain
      return T('svg', { xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 1000 1000', width: 1000, height: 1000 }, T('rect', { x: -1e3, y: -1e3, width: 3e3, height: 3e3, fill: bg })
        + T('circle', { cx: 500, cy: 500, r: R(u(150, 330)), fill: c[1], 'fill-opacity': .12 }) + T('g', { class: 'p' }, petals) + rings + arcs + T('circle', { cx: 500, cy: 500, r: R(u(8, 22)), fill: ink }) + grain);
    }
    // bloom('<64 hex: a block hash>') returns the SVG as a string.

    • Call …
    • Colours chosen …
    • Read the block yourself …

    …