Every coin is a mosaic.
Tessera reads a Solana coin from three public sources, runs sixteen written checks on the answers, and lays the result out as 256 tiles of the coin's own logo. Clean checks sit in gold, flagged ones crack, unanswered ones fall out of the wall.
Everything happens in your browser. There is no Tessera server between you and the data, no key, no account. The same rulebook ships as one small module, tessera.js, which you can import straight from this site.
Quick start
Import the module from this site and pass it a mint. You get a report object back.
import { analyze } from "SITE/lib/tessera.js";
const r = await analyze("DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263");
console.log(r.symbol, r.integrity + "%", r.verdict);
// Bonk 75% A few cracks# the three questions tessera.js asks, by hand
MINT=DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263
curl -s "https://api.dexscreener.com/tokens/v1/solana/$MINT"
curl -s "https://api.rugcheck.xyz/v1/tokens/$MINT/report"
curl -s "https://lite-api.jup.ag/tokens/v2/search?query=$MINT"<script type="module">
import { analyze } from "SITE/lib/tessera.js";
const r = await analyze(location.hash.slice(1));
document.body.textContent = r.symbol + ": " + r.integrity + "% " + r.verdict;
</script>fetch). The palette() and render() helpers need a canvas, so they are browser only.Try it
This box imports the same module as the code above and runs it live.
// press ReadHow a mosaic is laid
Four steps, the same ones the home page replays.
- Find the mint. The input must look like a Solana address (base58, 32 to 44 characters). If none of the three sources has heard of it, Tessera stops and says so instead of drawing an empty wall.
- Ask the sources. DexScreener, RugCheck and Jupiter are queried in parallel, each with a 9 second timeout. A source that fails is recorded as silent; it does not stop the others.
- Run the checks. Sixteen checks, each with one written rule and one named source. Pools and lockers are removed from the holder list before anything is counted.
- Lay the tiles. The coin's logo is shrunk to 16 × 16 pixels. Each of the 256 tiles is assigned to one check, sixteen tiles per check, scattered by a shuffle seeded from the mint. Then each tile takes the state of its check.
Tile states
Three states. A check is always exactly one of them.
| State | Means | Drawn as | Counts toward integrity |
|---|---|---|---|
| clean | The source answered and the answer passed the rule. | The logo pixel, washed in gold leaf | Yes |
| cracked | The source answered and the answer broke the rule. | Tinted terracotta, tilted, with a crack through it | No |
| missing | No source answered this question. | An empty socket with a dashed outline | No |
Integrity and verdicts
Integrity is the share of tiles that sit in place, rounded to a whole percent.
integrity = round(clean / 16 * 100) // every check weighs the same: 16 tiles| Condition | Verdict |
|---|---|
| 6 or more checks missing | Too many gaps to read |
| Integrity 85% and up | Whole picture |
| 60% to 84% | A few cracks |
| 35% to 59% | Badly cracked |
| Below 35% | Mostly rubble |
The verdict is a label for the picture, not a rating of the coin. Big, old, well-loved coins often land on A few cracks because of a mutable metadata field or a concentrated top ten.
Sources
Three open APIs and one image proxy. All are called from your browser.
| Source | Endpoint | Gives |
|---|---|---|
| DexScreener | api.dexscreener.com/tokens/v1/solana/{mint} | Every pool: price, liquidity, 24h volume, buys and sells, pair age, image, socials |
| RugCheck | api.rugcheck.xyz/v1/tokens/{mint}/report | Mint and freeze authority, metadata, transfer fee, top holders, known pool accounts, insider networks, LP locks |
| Jupiter | lite-api.jup.ag/tokens/v2/search?query={mint} | Holder count, top 10 share, deployer wallet, deployer balance, deployer launches |
| wsrv.nl | wsrv.nl/?url={logo}&w=64&h=64 | The logo, resized and served with CORS so a canvas can read its pixels |
When two sources could answer the same field, the order is fixed: price and liquidity come from DexScreener first, holder count from Jupiter first, deployer balance from Jupiter and then from RugCheck's creator balance.
All sixteen checks
The whole rulebook. These are the exact thresholds in CHECKS.
| Section | Check | Gold when | Source |
|---|
Market
Is anyone actually trading it?
All pools for the mint are added up. Liquidity is the sum of pool liquidity in USD. Age is measured from the oldest pair. Volume is the 24h total across pools. Sells happen cracks when a coin has buys and zero sells in 24 hours, the classic shape of a coin you cannot sell.
Why 72 hours
Most coins that disappear do it inside their first three days. After that the age tile turns gold; it says nothing about week two.
Holders
Who owns the supply?
Before counting, every address that RugCheck lists in knownAccounts (pools, lockers, program vaults) is removed from the top holder list. Largest holder is then the first wallet left. Top 10 hold comes from Jupiter's audit field. Insider network cracks when RugCheck finds wallets funded from a shared source.
Deployer
What did the creator do?
Deployer holds is the share of supply still in the wallet that launched the coin. Deployer launches counts how many coins that wallet has created. A wallet with hundreds of launches is usually a bot or a launch service, and the tile cracks to say the creator is not a one-coin team.
Authority
Can anyone change the rules?
| Field | If active |
|---|---|
| Mint authority | Someone can print more supply at any time. |
| Freeze authority | Someone can freeze any wallet's balance. |
| Mutable metadata | The name, ticker and logo can be changed. |
| Transfer fee | A Token-2022 fee is taken on every transfer. |
The report page also prints RugCheck's own risk list under this section, word for word, so you can compare readings.
Liquidity and community
Can the pool be pulled, and does anyone stand behind it?
LP locked or burned is a value-weighted average over every pool RugCheck knows: a big locked pool and a tiny unlocked one read as mostly locked. It cracks below 80%. Socials listed counts the websites and social links on DexScreener's token profile.
tessera.js
One file, about 13 KB, served from /lib/tessera.js with open CORS.
| Export | Signature | Returns |
|---|---|---|
analyze | (mint, { onStep, fetch }) | Promise of a report. Throws if the mint is invalid or no source knows it. |
grade | (checks) | { counts, integrity, verdict } |
layout | (mint, n = 256) | Array: tile index → check index |
palette | (imageUrl, cols = 16, mint) | Promise of [[r,g,b], …], cols × cols |
render | (ctx, { size, colors, map, status, t, hover, seed }) | Draws one frame on a 2D canvas |
tileAt | (x, y, size) | Tile index under a point, or -1 |
isMint, usd, pct, short | helpers | Validation and formatting |
CHECKS, SOURCES, SECTIONS, TILES | constants | The rulebook |
Progress
onStep is called with short strings as sources answer, which is how the report page prints its live log.
import { analyze } from "SITE/lib/tessera.js";
const r = await analyze("EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm", {
onStep: (s) => console.log(s), // "DexScreener answered", "Jupiter answered", ...
});
r.checks.filter((c) => c.status === "cracked").forEach((c) => console.log(c.label, c.value));Report format
What analyze() resolves to. Unknown numbers are null, never zero.
{
"mint": "DezXAZ8z…B263", "chain": "solana", "name": "Bonk", "symbol": "Bonk",
"image": "https://…", "url": "https://dexscreener.com/solana/…",
"market": { "price": 0.0000031, "change24h": 3.7, "liquidity": 312275, "mcap": 272181688,
"volume24h": 162400, "buys": 3365, "sells": 4365, "pairs": 12, "ageHours": 33288 },
"holders": { "count": 1027372, "top10": 30.5, "largest": 8.83, "insiders": 48, "list": [ … ] },
"deployer": { "wallet": "9AhK…bkw", "holdsPct": 0, "launches": 10 },
"authority":{ "mint": null, "freeze": null, "mutable": true, "fee": 0 },
"lpLocked": 16.0, "links": [ … ], "rugcheckRisks": [ … ],
"sources": { "dexscreener": true, "rugcheck": true, "jupiter": true },
"checks": [ { "id": "liquidity", "section": "Market", "label": "Liquidity",
"rule": "at least $10,000 in pools", "source": "DexScreener",
"value": "$312,275", "status": "clean" }, … ],
"counts": { "clean": 12, "cracked": 4, "missing": 0 },
"integrity": 75, "verdict": "A few cracks", "at": "2026-10-28T09:00:00.000Z"
}Layout and palette
Why the same coin always cracks in the same places.
layout(mint) shuffles the 256 tile positions with a xorshift generator seeded from an FNV hash of the mint, then hands them out sixteen at a time in check order. The cracks look scattered, like a real wall, but a given coin always gets the same pattern, so two people looking at the same mosaic see the same picture.
palette() asks wsrv.nl for the logo at 64 × 64, draws it onto a 16 × 16 canvas and reads the pixels. If the logo cannot be loaded, the colours are generated from the mint instead, so the wall is never blank.
Embed a mosaic
A self-contained page that draws any coin's wall.
<canvas id="m" width="512" height="512"></canvas>
<script type="module">
import { analyze, palette, layout, render } from "SITE/lib/tessera.js";
const r = await analyze("JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN");
const colors = await palette(r.image, 16, r.mint), map = layout(r.mint);
const ctx = document.getElementById("m").getContext("2d"), t0 = performance.now();
(function frame() {
const t = (performance.now() - t0) / 1000;
render(ctx, { size: 512, colors, map, status: r.checks.map((c) => c.status), t, seed: r.mint });
if (t < 4) requestAnimationFrame(frame);
})();
</script>Limits
What a mosaic cannot tell you.
- Solana only. Every check is written for SPL and Token-2022 mints.
- Three opinions, not the chain. Tessera trusts its sources. If DexScreener misses a pool or RugCheck mislabels a wallet, the tile inherits the mistake. The source is printed on every tile so you know whom to blame.
- Snapshots. A report is the state at the moment you pressed Read. Holders move, locks expire, authorities get revoked.
- Wallets are not people. Nothing here identifies who controls a wallet.
- Rate limits. The public endpoints throttle heavy use. If you read dozens of coins in a loop, expect missing tiles.
$TESSERA
The coin behind the mosaic.
| Field | Value |
|---|---|
| Chain | Solana |
| Ticker | $TESSERA |
| Supply | 1,000,000,000 |
| Contract | soon |
Once it is live, the home page reads $TESSERA's own mint in the "Live from a real mosaic" card instead of BONK. If it shows up cracked, everyone sees it first.
FAQ
Does Tessera store what I read?
Only in your own browser. The last twenty reports go to localStorage so the home page can list them under "Recently read". Nothing is sent anywhere except the three source APIs and the image proxy.
Why does RugCheck's score differ from integrity?
RugCheck weights its own risks. Integrity weighs sixteen checks equally and counts missing answers against the coin. The two answer different questions.
My coin launched five minutes ago and half the wall is missing.
The sources have not indexed it yet. Read it again in a few minutes; missing tiles fill in as answers arrive.
Will other chains come?
The module is written so a chain is just a different set of three questions. Solana comes first because that is where most new coins are minted.