diff --git a/README.md b/README.md index b14f998..2a89b68 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,37 @@ # Wikideck -Wikideck is an experimental, self-hosted RandomX network where each mined block creates a native NFT from a random English Wikipedia article. A page may be minted more than once; each NFT commits its own article and mint-time statistics snapshot, including a Wikimedia-hosted picture. It includes a React interface, a validating node, local P-256 wallets, transfers, atomic trades, a mock-payment marketplace, and current off-chain Wikipedia statistics. The default network is testnet; a separate mainnet candidate is implemented but launch-gated. +Wikideck is an NFT blockchain where mining a block rewards the miner with a collectible card based on a Wikipedia page. Build collections, trade cards with other collectors, or host a peer with its own marketplace. Trading card games (TCGs), including custom games hosted by peers, are planned for a later release. + +Mining uses **RandomX, the proof-of-work algorithm also used by Monero**, designed to keep general-purpose consumer CPUs competitive. Wikideck is an independent blockchain, not part of Monero or its mining/security network. Hardware, total network hashpower and difficulty determine results; no particular mining reward rate or profitability is guaranteed. **This is a local test network, not a public mainnet or an investment product.** No public bootnodes or hosted network are provided. Test NFTs have no promised value. Do not use funds or valuable assets. This project is not affiliated with Wikipedia or the Wikimedia Foundation. +## Collect, trade, and build your own community + +- **Mine Wikipedia cards.** Each accepted block mints a native NFT for the miner from a random illustrated English Wikipedia article. The card records the article snapshot and mint-time statistics. The same page can appear on more than one distinct card. The reward is a card representing a page—not ownership of the page, its copyright, or a payment to Wikipedia. +- **Build collections.** Assemble a broad cabinet of discoveries or focus on a subject, series or theme. Browse public decks and exchange up to eight cards on each side in one atomic trade. +- **Buy and sell in peer-hosted markets.** Running a peer lets you host a market for the shared chain's cards. Your community can be general-purpose or focus on a particular collection. Listings, auctions and orders belong to that market host; card ownership and mined transfers are shared through the blockchain. +- **Support the host and project author.** Sales allocate a configurable hosting fee to the peer's market operator (2.5% by default) and a separate hardcoded **1% author fee** to the project's fixed XMR address. Both are deducted from seller proceeds; the default total is 3.5%. In the intended cryptocurrency settlement model the host retains its fee, while the author allocation is paid separately. Today all payment, fee and payout accounting is simulated. +- **Cryptocurrency checkout.** Market prices are quoted in USD and designed to settle in **Monero (XMR)**. The current testnet checkout is mock-only: no real cryptocurrency is accepted or sent. The SHKeeper integration remains an offline prototype, not live checkout. +- **Play TCGs — planned.** The roadmap is to use these same cards in trading card games and let peers host custom TCG experiences. There is no playable game engine, match system, deck legality or custom rules hosting yet. Current card stats are not a promise of future game balance. + +## Peer ownership and customization + +The project's open-source direction is to give peer operators substantial freedom to adapt their own market: presentation, community focus, curation and future game rules. A collection-focused community can run the current general listing interface today; built-in collection filters, moderation/admission tooling and custom TCG hosting are future work, not existing operator controls. Operators can already configure their hosting fee and run their own local marketplace journal. + +Market customization does not let one peer rewrite shared NFT ownership or unilaterally change consensus for other peers. Compatible peers must follow the same network rules. The author fee is hardcoded in the distributed implementation; it is not a hosting configuration option. Any source modifications and redistribution must respect the eventual project license and third-party licenses. + +**Licensing status:** this checkout does not yet contain a project LICENSE file. Source availability alone does not grant open-source modification/redistribution rights. Publishing an appropriate license is still required before describing those freedoms as legally granted. Wikipedia text/images and dependencies retain their separate licenses; a Wikideck software license would not replace them. + +## What's available now + +| Available in the testnet | Planned / not enabled | +| --- | --- | +| RandomX mining and illustrated Wikipedia NFT rewards | Reviewed production network launch | +| Encrypted local wallets, collections and atomic card trades | Playable TCGs and peer-hosted custom games | +| Per-peer fixed-price listings and timed auctions | Built-in collection-specific curation/admission controls | +| Mock USD-priced/XMR checkout and host/author fee accounting | Real cryptocurrency settlement and production SHKeeper activation | + ## Run the three-node testnet (Docker) Install Docker Desktop with Linux containers and Docker Compose v2. From the repository root, start three connected nodes: @@ -53,9 +81,9 @@ New/migrated local vaults encrypt the key in IndexedDB; the unlocked key remains The current testnet wallet is separate from any wallet used by an older demo. There is no automatic migration. See [consensus, wallets, and operational limits](docs/testnet-consensus.md) and the in-app backup warnings for more detail. -## Mine only by explicit choice +## Mine Wikipedia cards with RandomX -Mining uses the native CPU RandomX engine. The browser page never mines or launches a native program. First build the engine, download an encrypted wallet backup, then run the CLI from an interactive terminal and enter the password at its hidden prompt: +Mining uses the native CPU RandomX engine. First build the engine, download an encrypted wallet backup, then run the CLI from an interactive terminal and enter the password at its hidden prompt: ```sh npm run miner -- --wallet "path/to/encrypted-backup.json" --consent --node http://127.0.0.1:3101 --blocks 3 @@ -73,7 +101,7 @@ Light mode needs a 256 MiB cache plus scratchpad and process overhead. `--fast` - **My collection** shows NFTs owned by the active local wallet on the connected node's canonical chain. - **Block explorer** distinguishes block IDs, NFT token IDs, and RandomX proof hashes. A submitted transfer is pending until a block confirms it. Reorganizations can change canonical ownership and confirmations. - **Trade decks** lets you look up another public wallet by receive address, select up to eight cards on each side, prepare a signed offer, and accept another player's offer. Offers are shared as JSON for the other player to review; they are not submitted until accepted. The two parties sign the same card list, and validators apply the whole bundle atomically or reject it entirely. Offers are not reservations: before acceptance the app re-checks ownership, maturity, sequences, and pending activity; stale offers must be recreated. -- **Marketplace** supports persistent fixed-price listings, timed auctions, USD prices and mock XMR checkout. Seller fees include configurable hosting (default 2.5%) plus a hardcoded additional 1% to a fixed XMR recipient (3.5% total by default). Buyers simulate payment, sellers sign real card delivery, and simulated seller-net/additional-fee payouts happen automatically after canonical delivery confirmations. **Never send real XMR: no payable checkout address or live processor is enabled.** Listings/orders are local to the selected marketplace node, not gossiped; listing does not lock a card on-chain. See [marketplace setup, fee recipient, rules and SHKeeper boundary](docs/marketplace.md). +- **Marketplace** is the connected peer's market: fixed-price listings, timed auctions, USD prices and mock XMR checkout. Sales allocate a configurable fee to the hosting operator (default 2.5%) and a hardcoded 1% author fee (3.5% total by default). Buyers simulate payment, sellers sign real card delivery, and simulated seller-net/author-fee payouts happen after canonical delivery confirmations. **Never send real XMR: no payable checkout address or live processor is enabled.** Listings/orders are local to the selected market host, not gossiped; listing does not lock a card on-chain. See [peer markets, fees and payment status](docs/marketplace.md). - Each minted card shows current Wikipedia statistics alongside its immutable at-mint snapshot: pageviews, article size, language links, revision, and derived scores. Current values may change; at-mint values are committed to the block. Missing pageview data stays unavailable, not zero. - The appearance selector offers Catppuccin Mocha, Macchiato, Frappé, and Latte themes. diff --git a/docs/marketplace.md b/docs/marketplace.md index 63785c3..87ccbec 100755 --- a/docs/marketplace.md +++ b/docs/marketplace.md @@ -1,4 +1,16 @@ -# Marketplace sandbox +# Peer-hosted markets + +Every Wikideck peer can host its own market for cards on the shared NFT blockchain. A host can serve collectors broadly or build a community around a particular collection, theme or subject. Card ownership and confirmed transfers follow the shared chain; each host keeps its own listings, bids and order journal. Buyers and sellers must use the same host to complete a sale. + +The current market provides fixed-price sales and timed auctions. Running a collection-focused community is possible today, but built-in collection-specific admission, moderation and curation controls are not implemented. Peer-hosted custom trading card games are also planned, not available yet. Operators can adapt the source and presentation subject to licensing; the project still needs a published software license before open-source reuse rights can be claimed. See [project direction and licensing](../README.md#peer-ownership-and-customization). + +## Cryptocurrency payments and the two sale fees + +The intended settlement currency is **Monero (XMR)**, with USD-priced listings and an XMR amount quoted at checkout. Mining and payments are separate: RandomX secures Wikideck's own blockchain, while XMR payments would settle on Monero. + +Each sale allocates a configurable hosting fee to the peer's market operator (default **2.5%**) plus a hardcoded **1% author fee** to the project author's fixed XMR address. Both are deducted from the seller's gross proceeds, not compounded or secretly added to the buyer price. At the default rates the seller keeps 96.5% before any future disclosed processor/network-fee policy. The host retains the hosting allocation; the author allocation is a separate payout. **All allocations and payouts are currently simulated.** + +## Current testnet sandbox Open **Marketplace** in the interface. Prices are **USD**; checkout amounts, fees, refunds, and automatic seller payouts are simulated in **XMR**. There is no payable address, payment processor connection, or movement of real Monero in this release. The displayed exchange rate is a deterministic simulation fixture, not a market quote. **Signing delivery transfers the actual card on the selected chain**, even though payment is mocked. @@ -37,9 +49,9 @@ The single-node and three-node testnet Compose configurations pass these setting Money is stored as integer USD cents and calculated in integer Monero atomic units (12 decimal places). Gross XMR is rounded up to an atomic unit; each fee is rounded down separately; seller net is exactly gross minus both fees. Maximum listing/bid price is $1,000,000.00. -## Fixed additional 1% fee +## Hardcoded 1% project author fee -Every new marketplace sale (fixed price or winning auction) includes a **hardcoded additional 1% seller fee**, on top of the configurable hosting fee. Both fees are calculated independently on the gross sale proceeds, not compounded. At the default 2.5% hosting fee the combined deduction is **3.5%**. Setting the hosting fee to zero does **not** disable the additional 1%. +Every new marketplace sale (fixed price or winning auction) includes a **hardcoded 1% project author fee**, on top of the configurable fee for the hosting peer's operator. Both fees are calculated independently on gross sale proceeds, not compounded. At the default 2.5% hosting fee the combined deduction is **3.5%**. Setting the hosting fee to zero does **not** disable the author fee. The fixed public XMR payout recipient is: diff --git a/docs/randomx-native.md b/docs/randomx-native.md index af9aa8f..9a023b0 100644 --- a/docs/randomx-native.md +++ b/docs/randomx-native.md @@ -1,8 +1,8 @@ # Native RandomX engine -This is the CPU proof engine used by the Wikideck testnet node and explicit opt-in -native miner. Mining runs only when the operator starts the native CLI; the browser -does not mine or launch native programs. The Docker image builds this pinned +Wikideck's native CPU proof engine uses RandomX, the algorithm also used by Monero, +designed to keep general-purpose consumer CPUs competitive. Mining a Wikideck block +rewards its miner with a Wikipedia NFT card on Wikideck's independent chain. The Docker image builds this pinned implementation and runs its known-vector test. There is no GPU path, simulated hash, or production fallback hash. diff --git a/index.html b/index.html index 3d46879..1cd184d 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ - + Wikideck — Mine knowledge. diff --git a/src/App.css b/src/App.css index b36ddc1..8701e44 100644 --- a/src/App.css +++ b/src/App.css @@ -1,3 +1,4 @@ +.project-pillars{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:18px;margin:24px 0 36px}.project-pillars article{padding:24px;border:1px solid var(--theme-border);background:var(--ctp-mantle);border-radius:12px;display:flex;flex-direction:column;align-items:flex-start}.project-pillars article>svg{color:var(--theme-accent);margin-bottom:18px}.project-pillars .section-eyebrow{font-size:8px;line-height:1.7}.project-pillars h2{font-size:21px;line-height:1.3;letter-spacing:-.5px;margin:12px 0}.project-pillars p{font-size:12px;line-height:1.85;color:var(--ctp-subtext0);margin:0 0 18px}.project-pillars button{margin-top:auto;text-align:left}@media(max-width:1000px){.project-pillars{grid-template-columns:1fr}.project-pillars article{padding:22px}.project-pillars p{max-width:680px}} .app-shell{min-height:100vh}.sidebar{position:fixed;inset:0 auto 0 0;width:224px;background:#151918;color:#f1f4ef;padding:34px 19px 22px;display:flex;flex-direction:column;z-index:20}.brand{display:flex;align-items:center;font-size:27px;letter-spacing:-1.3px;font-weight:750;padding:0 12px;gap:10px}.brand-dot{color:#d0ed9b;margin-left:-10px}.brand-mark{position:relative;display:grid;place-items:center;background:#d2ef9c;color:#1d2618;border-radius:9px;width:33px;height:36px;font-family:Georgia,serif;font-size:28px;font-weight:bold;letter-spacing:-4px;padding-right:4px}.brand-mark>span{position:absolute;font-size:12px;right:3px;top:0;letter-spacing:0}.sidebar-label{color:#737b74;font-size:9px;letter-spacing:1.7px;margin:53px 13px 19px}.nav-item{display:flex;align-items:center;gap:12px;width:100%;padding:14px 14px;margin:4px 0;border-radius:7px;background:transparent;color:#a1aaa3;font-size:12px;font-weight:500;text-align:left}.nav-item.active{color:#d7efaa;background:#2a3427}.nav-item:hover{background:#242d25}.nav-count{margin-left:auto;display:grid;place-items:center;min-width:20px;height:19px;border:1px solid #424b40;border-radius:4px;font-size:10px}.sidebar-note{margin:auto 4px 51px;border:1px solid #343d31;background:linear-gradient(135deg,#212a20,#1a211c);border-radius:10px;padding:19px 16px}.tiny-spark{font-size:27px;color:#c1dc95}.sidebar-note h3{font-size:17px;font-weight:500;line-height:1.5;letter-spacing:-.4px;margin:12px 0 9px}.sidebar-note p{font-size:11px;line-height:1.8;color:#97a18f}.sidebar-note button{display:flex;align-items:center;justify-content:space-between;width:100%;color:#d3e5b8;background:transparent;padding:17px 0 1px;font-size:11px}.sidebar-bottom{display:flex;align-items:center;gap:8px;font-size:10px;color:#adb6a9;border-top:1px solid #2c322c;padding:22px 10px 18px}.network-dot{display:inline-block;height:6px;width:6px;border-radius:50%;background:#83ae5f;box-shadow:0 0 0 3px #83ae5f12;flex-shrink:0}.disconnected{background:#c79a5b}.prototype{font-size:8px;letter-spacing:.8px;background:#293127;color:#a8bd90;border:1px solid #3b4735;border-radius:3px;padding:3px 5px;margin-left:auto}.help-link{display:flex;align-items:center;gap:9px;background:none;color:#8d978b;font-size:11px;padding:9px 10px}.help-link svg:last-child{margin-left:auto}.main-shell{margin-left:224px}.topbar{height:79px;border-bottom:1px solid #e7eae2;display:flex;align-items:center;justify-content:space-between;padding:0 43px;background:#fcfdfb}.breadcrumbs{display:flex;align-items:center;gap:12px;color:#8c9289;font-size:11px}.breadcrumbs span{color:#3d4639}.top-actions{display:flex;align-items:center;gap:24px}.network-pill{font-size:10px;color:#7b8574;display:flex;align-items:center;gap:8px}.wallet-button{display:flex;align-items:center;gap:10px;border:1px solid #e1e5dc;border-radius:6px;padding:7px 9px;background:#fff;font-size:10px;font-weight:600;letter-spacing:.2px}.wallet-avatar{display:grid;place-items:center;width:24px;height:24px;border-radius:4px;color:#566740;background:#e8efde}.wallet-button>svg{color:#8f9788;margin-left:6px}main{max-width:1540px;margin:0 auto;padding:35px 42px 0}.hero{min-height:367px;display:grid;grid-template-columns:1.15fr 1fr;position:relative;isolation:isolate;background:#edf1e7;border:1px solid #e6ebde;border-radius:12px;overflow:hidden}.hero-copy{padding:39px 0 36px 34px;z-index:3}.eyebrow{display:flex;align-items:center;gap:8px;font-size:8px;font-weight:650;letter-spacing:1.3px;color:#667459;margin-bottom:23px}.eyebrow>span{width:5px;height:5px;background:#6e8c4c;border-radius:50%}.hero h1{font-size:clamp(30px,3.05vw,49px);font-weight:600;line-height:1.18;letter-spacing:-1.8px;color:#263323;position:relative;white-space:nowrap}.hero h1>span{font-family:Georgia,'Times New Roman',serif;font-style:italic;font-weight:400;color:#6b8258}.hero-copy>p{max-width:365px;font-size:12px;line-height:1.85;color:#7b8372;margin:18px 0 23px}.hero-actions{display:flex;align-items:center;gap:18px}.button{display:inline-flex;align-items:center;justify-content:center;gap:10px;padding:12px 16px;border-radius:6px;font-size:11px;font-weight:600;white-space:nowrap;min-height:40px}.button.dark{background:#273320;color:#f3f8ea}.button.dark:hover{background:#374a2b}.button.dark svg:last-child{margin-left:8px}.text-button{font-size:11px;display:inline-flex;align-items:center;gap:11px;padding:8px 0;background:none;white-space:nowrap}.hero-foot{display:flex;gap:18px;color:#8a9580;font-size:9px;margin-top:20px}.hero-foot>span{display:flex;align-items:center;gap:4px}.hero-visual{position:relative;min-height:360px}.orbit{border:1px solid #c7d3ba80;border-radius:50%;width:340px;height:340px;position:absolute;left:4%;top:12px;transform:rotate(-25deg)}.orbit-two{height:235px;width:450px;left:-12%;top:65px;transform:rotate(-36deg)}.orbit-spark{position:absolute;color:#879b66}.spark-one{top:55px;left:14%;font-size:38px}.spark-two{bottom:58px;right:9%;font-size:31px;font-weight:200}.hero-card{position:absolute;width:196px}.hero-card .wiki-card{box-shadow:0 12px 25px #3a4d2d2b}.hero-card .card-art{height:135px}.hero-card .card-content{padding:13px 12px 10px}.hero-card .card-content p{font-size:8px;line-height:1.6;min-height:27px;-webkit-line-clamp:2}.hero-card .card-title h3{font-size:16px}.hero-card .card-stats{margin-top:10px;padding-top:9px}.hero-card .card-stats span{font-size:9px}.hero-card .card-bottom{font-size:6px;padding:9px 10px}.hero-card .card-top{font-size:7px;padding:9px}.hero-card .card-category{font-size:7px;padding:4px 7px}.front-card{top:57px;left:34%;transform:rotate(12deg);z-index:2}.back-card{top:34px;left:3%;transform:rotate(-13deg);z-index:1}.floating-label{display:flex;align-items:center;gap:8px;position:absolute;background:#ffffffeb;box-shadow:0 3px 12px #3644290c;border:1px solid #e4eadd;border-radius:5px;font-size:9px;padding:10px 13px;z-index:4;white-space:nowrap;color:#536249}.label-top{top:22px;right:6%;transform:rotate(5deg)}.label-bottom{bottom:22px;left:5%;transform:rotate(-5deg)}.label-bottom svg:first-child{color:#788f59}.metrics{display:grid;grid-template-columns:repeat(4,1fr);padding:25px 0;margin:0 0 4px;gap:8px}.metrics>div{display:flex;gap:12px;align-items:center;padding:0 15px;border-right:1px solid #e3e7dd}.metrics>div:first-child{padding-left:3px}.metrics>div:last-child{border:0}.metric-icon{height:38px;width:38px;display:grid;place-items:center;border-radius:9px;background:#edf0e8;color:#778366}.metrics>div>div>span{color:#89907f;font-size:10px;display:block;margin-bottom:4px}.metrics strong{font-size:22px;font-weight:600;letter-spacing:-.6px;display:flex;align-items:baseline;gap:9px}.metrics small{font-size:9px;font-weight:400;letter-spacing:0;color:#909684;white-space:nowrap}.metrics strong.algorithm{font-size:18px;flex-direction:column;gap:1px}.leaf{color:#88a761;background:#edf2e5}.mining-panel{display:grid;grid-template-columns:1.25fr 1fr;gap:35px;padding:27px 28px;background:#fff;border:1px solid #e4e8df;border-radius:10px;margin:10px 0 36px;position:relative}.section-eyebrow{display:flex;align-items:center;gap:7px;color:#8a937f;font-size:8px;letter-spacing:1.5px;font-weight:600;margin-bottom:10px}.idle-dot{height:5px;width:5px;border-radius:50%;background:#a5b295}.mining-description{display:flex;flex-direction:column;justify-content:center}.mining-description h2{font-size:22px;font-weight:550;letter-spacing:-.7px;margin:4px 0 11px}.mining-description p{max-width:380px;font-size:11px;line-height:1.9;color:#87907e}.mining-meta{display:flex;gap:16px;margin-top:24px;font-size:8px;color:#8e9684}.mining-meta>span{display:flex;align-items:center;gap:5px}.miner-controls{border-left:1px solid #edf0e7;padding-left:30px}.miner-display{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:13px}.miner-display>div:first-child{min-width:0}.miner-display span{font-size:8px;letter-spacing:1.2px;color:#8f9884;display:block;margin-bottom:6px}.miner-display strong{font-size:13px;font-weight:550;display:block;max-width:225px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.signal-bars{display:flex;align-items:center;gap:2px;height:36px}.signal-bars i{width:3px;border-radius:2px;background:#cbd9ba}.signal-bars i:nth-child(3n){background:#a7bd8b}.running i{animation:equalize .75s infinite alternate}.intensity{display:flex;align-items:center;justify-content:space-between;gap:5px;font-size:9px;color:#87917b;margin-bottom:11px}.intensity select{border:1px solid #e4e9dd;border-radius:4px;padding:4px 6px;font-size:9px;background:#fafcf7;color:#63734e}.consent{font-size:9px;color:#6d795f;display:flex;align-items:center;gap:6px;margin:8px 0 11px}.consent input{accent-color:#6c8748;margin:0;width:12px;height:12px}.lime{background:#d2eca7;color:#334723;width:100%;font-weight:650}.lime:hover{background:#c3e58c}.lime svg:last-child{margin-left:auto}.lime svg:first-child{margin-right:auto}.miner-footnote{display:block;font-size:8px;color:#a0a795;text-align:center;margin-top:8px}.mining-stop{width:100%;background:#edf2e4;border:1px solid #d9e3cb;color:#4a6334;margin-top:12px}.hash-line{font-family:Consolas,monospace;font-size:10px;color:#7b8f65;padding:11px 9px;background:#f4f7f0;border-radius:5px}.section-heading{display:flex;justify-content:space-between;align-items:center;gap:15px;margin-bottom:22px}.section-heading h2{font-size:23px;font-weight:550;letter-spacing:-.7px;display:flex;align-items:center;gap:9px}.section-heading p{font-size:11px;color:#929887;margin-top:7px;line-height:1.6}.section-heading>.text-button{color:#718260;font-size:10px}.count-badge{font:500 10px 'Segoe UI',sans-serif;color:#8a967b;border:1px solid #dfe5d7;border-radius:5px;padding:4px 6px;letter-spacing:0;display:inline-flex;vertical-align:middle}.filter-bar{display:flex;align-items:center;justify-content:space-between;gap:15px;padding:0 0 18px;border-bottom:1px solid #e9ece2;margin-bottom:22px}.category-tabs{display:flex;gap:4px;flex-wrap:wrap}.category-tabs button{background:transparent;color:#8e9684;font-size:10px;padding:7px 12px;border-radius:5px;white-space:nowrap}.category-tabs button.selected{color:#3b4e29;background:#e8eedf;font-weight:600}.category-tabs button:hover{background:#eef2e8}.search-input{display:flex;align-items:center;gap:7px;border:1px solid #e3e8db;border-radius:5px;padding:8px 10px;color:#97a08a;background:#fcfdfb;max-width:178px}.search-input input{border:0;outline:0;min-width:0;width:100%;background:transparent;font-size:9px;color:#58634d}.search-input input::placeholder{color:#a1a993}.card-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:20px}.wiki-card{display:block;position:relative;background:#fff;border:1px solid #dce4d3;border-radius:9px;overflow:hidden;text-align:left;width:100%;padding:0;box-shadow:0 3px 4px #202e1810;transition:transform .2s,box-shadow .2s}.wiki-card:hover{transform:translateY(-5px);box-shadow:0 9px 20px #293b211b}.card-top{display:flex;align-items:center;justify-content:space-between;padding:10px 12px;color:#657b51;background:#f1f5e9;font-size:8px;letter-spacing:.5px}.card-top>span:first-child{display:flex;align-items:center;gap:4px}.card-top>span:last-child{color:#909b83;font-size:7px}.legendary .card-top{background:#f5f0e2;color:#9b8350}.legendary{border-color:#e3d9bd}.epic .card-top{background:#eeebf6;color:#8c78a9}.rare .card-top{background:#eaf1f6;color:#64839c}.card-art{height:183px;position:relative;background:radial-gradient(ellipse at top right,#688b8e,#192929);overflow:hidden;display:flex;align-items:center;justify-content:center;color:#b7cbb3}.card-art img{width:100%;height:100%;object-fit:cover;display:block;transition:transform .4s;mix-blend-mode:normal}.wiki-card:hover .card-art img{transform:scale(1.04)}.art-space{background:#0a1015}.art-space img{object-fit:contain;padding:11px}.art-people{background:#3b3d35}.art-people img{object-position:50% 30%;filter:sepia(.15)}.art-science{background:#e9e8d9}.art-science img{object-fit:contain;padding:12px}.art-nature{background:#224440}.art-nature img{filter:saturate(.65);object-position:45% 50%}.card-art::after{content:'';position:absolute;inset:0;background:linear-gradient(transparent 70%,#16201545);pointer-events:none}.card-category{position:absolute;bottom:10px;left:11px;font-size:8px;padding:4px 8px;color:#f1f5eb;background:#182d2999;backdrop-filter:blur(6px);border:1px solid #ffffff30;border-radius:4px;z-index:1}.card-content{padding:14px 14px 11px}.card-title{display:flex;align-items:center;justify-content:space-between;gap:6px;margin-bottom:8px}.card-title h3{font-family:Georgia,'Times New Roman',serif;font-size:20px;font-weight:400;letter-spacing:-.4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.card-title>svg{color:#a7ad9c;width:13px}.card-content>p{font-size:9px;color:#909684;line-height:1.75;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;min-height:32px}.card-stats{display:flex;align-items:center;justify-content:space-between;border-top:1px solid #eff1e9;margin-top:13px;padding-top:12px;color:#6b785e}.card-stats>span{display:flex;align-items:center;gap:5px;font-size:10px}.card-stats svg{color:#98a489}.card-bottom{display:flex;align-items:center;justify-content:space-between;background:#fafbf7;border-top:1px solid #eff1e9;padding:9px 12px;font-size:6px;letter-spacing:.65px;color:#a0a790}.card-list-caption{display:flex;align-items:center;gap:5px;font-size:8px;color:#a0a891;margin:12px 2px}.card-list-caption>span:first-child{color:#8b967e;margin-right:auto}.caption-dot{height:4px;width:4px;background:#a2b78a;border-radius:50%}.empty-state{text-align:center;padding:58px 20px 65px;background:#f0f4eace;border:1px dashed #dce5d0;border-radius:9px;color:#8e9e7d}.empty-state>svg{margin-bottom:18px;color:#90a273}.empty-state h3{font-size:21px;font-weight:500;letter-spacing:-.5px;color:#4b5d3b}.empty-state p{font-size:12px;margin:11px auto 22px;max-width:410px;line-height:1.7}.explorer-section{min-height:65vh;padding-top:14px}.explorer-section h1{font-size:37px;font-weight:550;letter-spacing:-1.3px}.explorer-section h1>.count-badge{margin-left:12px}.outline{border:1px solid #dfe6d5;background:#fff;color:#647653}.explorer-note{display:flex;align-items:center;gap:13px;border:1px solid #dfe7d6;background:#eff4e8;padding:16px 19px;border-radius:7px;color:#7b8c67;margin:25px 0}.explorer-note p{font-size:11px;line-height:1.7}.table-scroll{overflow:auto;border:1px solid #e4e9de;border-radius:8px}table{border-collapse:collapse;width:100%;text-align:left;background:#fff;white-space:nowrap}th{font-weight:500;color:#98a18b;font-size:9px;letter-spacing:.5px;text-transform:uppercase;padding:16px 18px;background:#f3f6ef}td{border-top:1px solid #edf1e7;padding:19px 18px;font-size:11px;color:#778668}td strong{display:block;color:#3f5031;font-weight:550}td small{display:block;font-size:8px;margin-top:5px;color:#99a28e}tbody tr{cursor:pointer}tbody tr:hover{background:#f6f9f0}.mono{font-family:Consolas,monospace}.rarity-tag{display:inline-block;font-size:9px;padding:5px 8px;background:#edf2e6;color:#6c8352;border-radius:4px}.rarity-tag.legendary{color:#9f854f;background:#f5f0e2}.rarity-tag.epic{color:#8e78a5;background:#f0eaf6}.rarity-tag.rare{color:#63849d;background:#eaf2f7}.transfer-title{font-size:19px;font-weight:500;letter-spacing:-.4px;margin:34px 0 18px}.journal>div{display:flex;align-items:center;gap:18px;font-size:10px;color:#839271;padding:16px;background:#fff;border-bottom:1px solid #e5ecda}.journal>div>svg:last-child{margin-left:auto}.muted{color:#8a9580;font-size:12px;line-height:1.9}.error-banner{display:flex;align-items:center;gap:9px;background:#fcf0e8;border:1px solid #eedace;border-radius:6px;font-size:11px;color:#9f745c;padding:12px 15px;margin-bottom:18px}.error-banner>span{flex:1}.error-banner button{background:none;color:#9e715b;font-size:11px}.transfer-error{color:#ae6850;font-size:12px;line-height:1.7;padding:10px;background:#fff2eb;border-radius:5px}footer{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:12px;border-top:1px solid #e4e9dc;margin-top:37px;padding:24px 0 20px;color:#929c85;font-size:9px}footer>a{display:flex;align-items:center;gap:8px}footer>a>svg{color:#7f8c70}footer>span{display:flex;align-items:center;gap:15px;font-family:Georgia,serif;font-style:italic;font-size:11px}.footer-star{font-size:21px;color:#8b9f71}footer>p{width:100%;font-size:8px;line-height:1.8;color:#a1a993}footer p a{text-decoration:underline;text-underline-offset:2px}.toast{position:fixed;bottom:28px;left:calc(50% + 112px);transform:translateX(-50%);z-index:70;display:flex;align-items:center;gap:12px;padding:15px 17px;background:#263421;color:#e4f0d6;border:1px solid #495a3d;border-radius:8px;box-shadow:0 6px 35px #1b2e252f;font-size:12px;max-width:calc(100% - 35px)}.toast>span{display:grid;place-items:center;background:#3e512f;border-radius:50%;padding:5px;color:#c4e99d}.toast>button{background:transparent;color:#b6c5a9;margin-left:14px}.modal-backdrop{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;background:#131c18a8;backdrop-filter:blur(6px);z-index:50;padding:28px}.modal{position:relative;padding:36px;max-height:90vh;overflow:auto;background:#fbfcf8;border:1px solid #e5ebdc;border-radius:14px;box-shadow:0 20px 70px #0c1a2140;width:505px;max-width:100%;animation:modal-in .2s ease-out}.modal-close{position:absolute;top:14px;right:14px;background:#edf1e7;color:#80936a;border-radius:50%;padding:6px;display:flex;z-index:2}.modal h2{font-size:28px;font-weight:550;letter-spacing:-.9px;line-height:1.3;margin:10px 0 16px}.modal-icon{display:grid;place-items:center;width:48px;height:48px;border-radius:12px;background:#e7efd9;color:#799458;margin-bottom:24px}.guide-steps{margin:25px 0}.guide-steps>div{display:flex;gap:15px;margin-bottom:24px}.guide-steps>div>span{color:#a2b18d;font-size:11px;padding-top:3px}.guide-steps h3{font-size:14px;font-weight:600;margin-bottom:7px}.guide-steps p{font-size:11px;color:#8b977e;line-height:1.9}.info-box{padding:15px 17px;border:1px solid #e1e8d6;background:#eff4e8;border-radius:7px;margin:24px 0}.info-box strong{font-size:11px;color:#687c51;font-weight:600}.info-box p{font-size:10px;line-height:1.9;color:#869473;margin-top:5px}.full{width:100%}.field-label{display:block;font-size:8px;letter-spacing:1.3px;color:#9aa68d;margin:24px 0 9px}.address-box{font-family:Consolas,monospace;font-size:11px;line-height:1.8;overflow-wrap:anywhere;padding:13px;border:1px solid #e0e8d6;background:#f0f5e9;border-radius:6px;color:#72845b;margin-bottom:18px;user-select:all}.wallet-count{display:flex;align-items:center;justify-content:center;gap:8px;color:#7b8d64;font-size:11px}.recipient-input{width:100%;padding:12px;font-size:11px;color:#647c4e;background:#fff;border:1px solid #dce7cf;border-radius:6px}.card-modal{display:grid;grid-template-columns:.8fr 1.2fr;gap:32px;width:850px;padding:42px 36px}.detail-card{align-self:center;pointer-events:none}.detail-card .card-art{height:230px}.detail-copy{align-self:center}.detail-copy>p{font-size:12px;line-height:1.9;color:#839173}.detail-facts{display:flex;justify-content:space-between;gap:10px;border-block:1px solid #e5ebdc;padding:15px 0;margin-top:21px;font-size:9px;color:#95a284}.detail-facts strong{display:block;color:#72865b;font-size:10px;margin-top:5px;font-weight:550}.detail-links{display:flex;flex-wrap:wrap;gap:18px;margin:20px 0 12px}.detail-links a{display:flex;align-items:center;gap:6px;font-size:10px;color:#6f8755}.detail-copy p.attribution{font-size:9px;line-height:1.8;color:#a3af96;margin:14px 0 20px}.detail-copy .field-label{margin-top:17px}.detail-copy .address-box{font-size:9px}.spin{animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}@keyframes equalize{from{transform:scaleY(.5);opacity:.6}to{transform:scaleY(1.2);opacity:1}}@keyframes modal-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}} @media(min-width:1500px){.hero{min-height:415px}.hero-copy{padding:48px 0 40px 45px}.hero-visual{margin-right:20px}.hero-card{width:225px}.hero-card .card-art{height:160px}.front-card{top:68px}.back-card{top:40px}.hero h1{font-size:51px}.hero-copy>p{font-size:13px;max-width:400px}.orbit-one{width:390px;height:390px}.orbit-two{width:500px;height:270px}.label-bottom{bottom:30px}.card-art{height:215px}.card-content>p{font-size:10px}.sidebar{width:235px}.main-shell{margin-left:235px}} @media(max-width:1200px){.sidebar{width:200px;padding-inline:14px}.main-shell{margin-left:200px}main{padding:28px 28px 0}.topbar{padding:0 28px}.hero-copy{padding:31px 0 28px 25px}.hero h1{font-size:36px}.hero-visual{min-height:350px}.hero-card{width:173px}.hero-card .card-art{height:120px}.back-card{left:3%;top:50px}.front-card{left:32%;top:80px}.floating-label{font-size:8px;padding:8px}.label-top{right:7%;top:30px}.label-bottom{bottom:22px;left:1%}.hero-copy>p{max-width:300px}.hero-actions{gap:12px}.hero-actions .text-button{font-size:10px}.hero-actions .button{font-size:10px;padding:11px 12px}.hero-foot{font-size:8px;gap:10px}.eyebrow{font-size:7px}.metrics>div{padding:0 10px;gap:9px}.metrics strong{gap:6px;font-size:20px}.metrics small{font-size:8px}.metric-icon{height:31px;width:31px}.mining-panel{padding:23px;gap:22px}.mining-description h2{font-size:21px}.mining-meta{gap:10px;font-size:7px}.miner-controls{padding-left:23px}.card-grid{gap:14px}.card-art{height:155px}.card-title h3{font-size:18px}.card-content{padding:12px}.section-heading h2{font-size:21px}.filter-bar{align-items:flex-start;flex-wrap:wrap}.search-input{max-width:170px}.category-tabs button{padding:6px 10px}.toast{left:calc(50% + 100px)}} diff --git a/src/App.tsx b/src/App.tsx index 8da716c..685be4b 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -166,7 +166,7 @@ export default function App() { const Icon = [LayoutDashboard, Layers3, Globe2, ArrowLeftRight, ShoppingBag][i]; return ; })} -
✦

A little curiosity.
An independent chain.

Collect knowledge as native NFTs on a sovereign RandomX testnet.

+
✦

Your cards.
Your community.

Mine Wikipedia NFT cards, build collections, and trade in peer-hosted markets.

{peerLabel}{NETWORK_LABEL}
@@ -177,7 +177,7 @@ export default function App() { {error &&
{error}
} {view === 'Discover' && <>
-
KNOWLEDGE, COLLECTED ON ITS OWN CHAIN.

Mine knowledge.
Collect the extraordinary.

Random Wikipedia articles, each with a picture. A chain of new discoveries. Mine native NFTs with an opt-in RandomX miner, and keep the keys to your collection.

Independent testnet No browser mining
+
WIKIPEDIA CARDS. THEIR OWN NFT BLOCKCHAIN.

Mine knowledge.
Collect the extraordinary.

Mine a block. Earn a Wikipedia NFT card. Build collections, trade discoveries, and find your community in peer-hosted markets. Trading card games are next on the roadmap.

Consumer-CPU mining Peer-hosted markets
✳+
Preview cards · not owned
setSelected(samples[2])} />
setSelected(samples[0])} />
A world worth collecting
@@ -187,9 +187,14 @@ export default function App() {
Proof of work{snapshot?.algorithm ?? 'RandomX'}native CPU mining
-
EXPLICIT OPT-IN · OUTSIDE YOUR BROWSER

Native RandomX mining

This page never runs mining code or launches a native program. Build the trusted native binary, download an encrypted wallet backup, then start the miner yourself in an interactive terminal.

One native worker Independent validating peers
Light · default256 MiB cache + scratchpad and overhead.Fast · explicit --fast~2 GiB dataset plus cache; budget over 2.3 GiB per process. Higher CPU, energy and memory use. RandomX is not a promise of ASIC-proof mining.
+
RANDOMX · BUILT FOR GENERAL-PURPOSE CPUS

Mine blocks. Earn cards.

Wikideck uses RandomX, the proof-of-work algorithm also used by Monero, to keep mining competitive on consumer-grade CPUs. Each accepted block rewards its miner with an illustrated Wikipedia NFT card. Results depend on your hardware and network difficulty; Wikideck does not share Monero’s network security.

Consumer hardware Independent validating peers
Light · default256 MiB cache + scratchpad and overhead.Fast · --fast~2 GiB dataset plus cache; budget over 2.3 GiB per process. Mining consumes CPU, memory and energy; RandomX is not a guarantee of ASIC resistance or profitability.
NEXT WIKIPEDIA ARTICLE{snapshot ? 'Chosen when the miner requests work' : 'Waiting for testnet RPC…'}

Each mining template requests a random English Wikipedia article with a Wikimedia picture. Pages may repeat; every minted card carries its own statistics snapshot.

  1. Build wikideck-randomx using the repository’s native build instructions.
  2. Save your encrypted backup and keep its password separate.
  3. Replace <backup.json> with your local file path (quote paths with spaces), then run:
{nativeCommand}

Node: {window.location.origin}. Same-origin RPC, including the development proxy. Use HTTPS for remote nodes. Password entry stays local; never put it in the command. Defaults to one worker and at most one block. Ctrl+C stops the native miner; closing this page does not.

+
+
COLLECT & TRADE

A collection with a story.

Collect Wikipedia pages as cards, swap multiple cards in one trade, or list discoveries at a fixed price or timed auction.

+
HOST YOUR OWN MARKET

Your peer. Your community.

Run a peer and host a market for everyone or a community centered on a collection. Sales allocate a hosting fee to the operator and a hardcoded 1% to the project author. Cryptocurrency checkout is designed for XMR; today payments and fees are simulated.

+
ON THE ROADMAP · NOT PLAYABLE YET

Cards made for more.

Trading card games and peer-hosted custom TCGs are planned. The open-source direction is to let communities adapt markets and games; a software license still needs to be published. Built-in collection curation and custom game hosting are not available yet.

+
} {view === 'Marketplace' ? : view === 'Trade decks' ? : view !== 'Block explorer' ?
{view === 'My collection' ? 'YOUR PERSONAL ENCYCLOPEDIA' : 'AN ENCYCLOPEDIA, REIMAGINED'}

{view === 'My collection' ? 'Your cabinet of curiosities' : 'A world of possible discoveries'}{visibleCards.length}

{view === 'My collection' ? 'Confirmed native NFT ownership. Pending transfers stay here until mined.' : snapshot?.blocks.length ? 'Recent native NFTs on this node’s canonical testnet chain.' : 'Sample previews only; mined NFTs use random Wikipedia pages with pictures. The same page may be minted more than once.'}

{view === 'Discover' && }
@@ -198,7 +203,7 @@ export default function App() {
:
FOLLOW THE CANONICAL CHAIN

Block explorer{snapshot?.blocks.length ?? 0}

Native NFT mints, RandomX proofs, and mined ownership transfers.

View full chain JSON

Sovereign testnet with independently validating peers and cumulative-work chain selection. This network is unbootstrapped, not a public mainnet. Zero peers means an isolated node, not a connected network. Canonical ownership can change during a reorganization.

Cumulative work
{snapshot?.cumulativeWork ?? '—'}
Peer count
{rpcAvailable ? snapshot?.peers ?? '—' : 'Unknown'} · {peerLabel}
Chain ID · pinned genesis
{snapshot?.chainId ?? '—'}
Network
{NETWORK}
Tip block ID
{snapshot?.tip ?? '—'}
Mint maturity
{snapshot?.maturity ?? CONSENSUS.coinbaseMaturity} subsequent blocks at inclusion height
- {snapshot?.blocks.length ?
{[...snapshot.blocks].reverse().map(b => )}
Block / confirmationsDiscoveryBlock ID / NFT token IDConfirmed ownerRandomX proof / rarity
{snapshot.blocks.length - b.height + 1} confirmations{b.article.title}Wikipedia #{b.article.pageId}Block {short(b.hash)}NFT {short(b.tokenId)} {short(testnetOwnerOf(snapshot, b.tokenId) ?? '')}{short(b.powHash)}{rarity(b.powHash)}
:
Wikideck

A new chain. A blank page.

No canonical NFT blocks loaded. Native mining is an explicit, separate step.

} + {snapshot?.blocks.length ?
{[...snapshot.blocks].reverse().map(b => )}
Block / confirmationsDiscoveryBlock ID / NFT token IDConfirmed ownerRandomX proof / rarity
{snapshot.blocks.length - b.height + 1} confirmations{b.article.title}Wikipedia #{b.article.pageId}Block {short(b.hash)}NFT {short(b.tokenId)} {short(testnetOwnerOf(snapshot, b.tokenId) ?? '')}{short(b.powHash)}{rarity(b.powHash)}
:
Wikideck

A new chain. A blank page.

No NFT blocks loaded yet. Mine a block to earn the next Wikipedia card.

}

Mined transfers and trades

{snapshot?.transfers.length ?
{snapshot.transfers.map((tx, i) => isNftTrade(tx) ?
{tx.offered.length} cards {short(tx.proposer)} ⇄ {tx.requested.length} cards {short(tx.counterparty)}Atomic trade · mined #{snapshot.blocks.find(b => b.transactions.some(item => isNftTrade(item) && item.proposerSignature === tx.proposerSignature))?.height ?? '—'}
:
{short(tx.cardHash)}{short(tx.from)} → {short(tx.to)}Sequence {tx.sequence} · mined #{snapshot.blocks.find(b => b.transactions.some(item => !isNftTrade(item) && item.signature === tx.signature))?.height ?? '—'}
)}
:

No mined transfers or trades.

} @@ -206,12 +211,22 @@ export default function App() { ?
{tx.offered.length} cards {short(tx.proposer)} ⇄ {tx.requested.length} cards {short(tx.counterparty)}Atomic trade · awaiting mining
:
{short(tx.cardHash)}{short(tx.from)} → {short(tx.to)}Awaiting mining
)}
} -
Built on the shoulders of Wikipedia.Knowledge, not financial promises.✦

Independent experiment, not affiliated with Wikimedia. Mined article snapshots are selected from Wikipedia; attribution and image licenses appear on each card. Native NFTs are not ERC-721 tokens, fiat, or rights to article content. No promised monetary value.

+
Wikipedia pages. Collectible discoveries.Mine. Collect. Trade.✦

Independent project, not affiliated with Wikimedia or Monero. NFT rewards represent Wikipedia article snapshots, not ownership of Wikipedia pages or their copyright. Attribution and image licenses appear on each card. Current network: experimental testnet; cryptocurrency payments are simulated and TCG play is planned. No promised monetary value.

{toast &&
{toast}
} {(dialog || selected) &&
{ if (e.target === e.currentTarget) close(); }}>
- {dialog === 'guide' ? <>
THE TESTNET FIELD GUIDE

A universe in every card.

01

Mine natively. Only by choice.

No browser mining or automatic native execution. Build the trusted RandomX binary and run the miner yourself with an encrypted wallet backup and explicit --consent. One worker defaults to light mode (256 MiB cache plus overhead); --fast adds a ~2 GiB dataset. Mining uses CPU and energy, may warm your device, and is not guaranteed ASIC-proof. Ctrl+C stops it.

02

A page, a snapshot. A sovereign chain.

Each mining template asks Wikipedia for a random English article with a picture. A page can appear on multiple NFTs; each block commits its own article and mint-time statistics snapshot. Validators verify the snapshot's structure and commitments without contacting Wikimedia during consensus validation. Independent peers validate RandomX work, native NFT mints, and signed transactions, choosing the cumulative-work canonical chain. This testnet is unbootstrapped: there is no public mainnet, and an isolated node has no peer-backed network security.

03

Keep your keys. Trade as a team.

Your P-256 wallet is a local signing identity, not a server login. Download a password-encrypted backup and restore it locally to control your NFTs. Use Trade decks to review a public wallet’s confirmed holdings and prepare a signed multi-card offer. The other player signs before submission; all cards exchange together when the single trade transaction is mined. Offers do not reserve cards and can go stale. A pending transfer or trade does not change confirmed ownership. Mints require two subsequent blocks at inclusion height; reorganizations can change confirmations and ownership.

Native NFTs, not content ownership.

Token IDs identify native assets on this chain, not ERC-721 tokens on another network. RandomX proof hashes determine game rarity and stats; block IDs identify blocks. An NFT does not grant copyright or other intellectual-property rights to Wikipedia text or images. Follow their licenses and attribution. No fiat, financial return, or monetary value is promised.

+ {dialog === 'guide' ? <> +
THE WIKIDECK FIELD GUIDE

Mine. Collect. Make it yours.

+
+
01

Mine a block. Earn a Wikipedia card.

Wikideck is an NFT blockchain: each accepted block rewards its miner with a card based on a random illustrated Wikipedia page and its mint-time statistics. RandomX, also used by Monero, is designed for competitive mining on consumer CPUs. Wikideck is its own network, not part of Monero. Mining uses CPU, memory and energy; rewards depend on hardware and network difficulty.

+
02

Build a collection. Trade your discoveries.

Collect broadly or focus on a theme. Your encrypted local wallet controls your cards. Trade decks lets two players sign a multi-card swap that settles together when mined. Fixed-price sales and timed auctions live in the connected peer’s market. Transfers remain pending until mined, and chain reorganizations can change ownership and confirmations.

+
03

Host a peer. Grow a community.

A peer can host a general-purpose market or a community devoted to a collection. Listings and orders stay with that host, while card ownership follows the shared blockchain. Sales allocate a configurable hosting fee to the operator and a hardcoded 1% author fee. Prices are in USD with XMR cryptocurrency settlement planned; today payments, fees and payouts are simulations only.

+
04

Custom trading card games — coming later.

Playing TCGs with your cards and hosting custom TCGs on a peer are planned, not implemented. The open-source direction is to give operators freedom to adapt their market and future games; publishing the software license is still pending. Built-in collection curation and custom rules hosting are also future work. Shared consensus remains the same across compatible peers.

+
+
Collectible cards, not ownership of Wikipedia.

NFT rewards represent article snapshots, not rights to Wikipedia text or images. Follow each card’s attribution and licenses. This is an experimental testnet, not a launched production network; never send real XMR to its mock checkout. Current stats are not final TCG rules or a promise of financial value.

+ + : dialog === 'wallet' ? <>
YOUR LOCAL TESTNET IDENTITY

A wallet for your wonders.

No server login. This recoverable wallet controls native NFTs through local signatures. It is separate from the original demo wallet.

{wallet?.address ?? 'Wallet unavailable. Enable local browser storage and retry.'}

{owned.length} confirmed native NFTs in your collection

: dialog === 'transfer' ? <>
PASS ON THE CURIOSITY

Send {selected?.article.title}.

Use the recipient’s 64-character testnet wallet address on this same chain. Signing submits a pending transaction; it does not immediately transfer ownership.

{selected?.block?.tokenId}
setRecipient(e.target.value)} placeholder="Paste a 64-character wallet address" autoComplete="off" maxLength={64} />
Review before signing.

Transfers take effect only when mined into the canonical chain. Once confirmed, there is no undo button or recovery for a wrong address. Mints require two subsequent blocks at inclusion height; only one pending transfer per NFT is allowed.

{(!rpcAvailable || transferDisabledReason) &&

{!rpcAvailable ? 'RPC unavailable. Reconnect before signing.' : transferDisabledReason}

}{transferError &&

{transferError}

} : selected && <>
{selected.block ? `MINTED IN BLOCK #${selected.block.height}` : 'EXAMPLE CARD · NOT OWNED'}

{selected.article.title}

{selected.article.extract}

Page ID#{selected.article.pageId}Rarity{rarity(selected.hash)}Content{selected.article.source === 'live' ? `Pinned revision ${selected.article.revisionId}` : 'Sample preview'}
{selected.block && <>
{selected.block.tokenId}
{selected.block.hash}
{selected.hash}

{confirmations} canonical confirmations{!rpcAvailable ? ' · last known state' : ''}. {selectedBlock ? `Confirmed owner: ${selectedOwner}` : 'This mint is not on the loaded canonical chain.'}

{pending &&

Transfer pending mining · confirmed owner unchanged.

}}

{selected.article.source === 'live' ? 'Pinned text by Wikipedia contributors, CC BY-SA 4.0. Excerpt shortened for card display.' : 'Original fixed starter summary, linked to the real Wikipedia article; no live revision captured.'} Stats are game values, not encyclopedia facts. NFT ownership grants no rights to article text or images.

{selected.block && selectedOwner === wallet?.address && <>{transferDisabledReason &&

{transferDisabledReason}

}}
} diff --git a/src/Marketplace.tsx b/src/Marketplace.tsx index 23c2d59..91bea54 100755 --- a/src/Marketplace.tsx +++ b/src/Marketplace.tsx @@ -10,7 +10,7 @@ import './market.css'; type Props = { wallet?: Wallet; snapshot?: TestnetSnapshot; rpcAvailable: boolean; onNotice(message: string): void }; type Page = { listings: MarketListing[]; next: number | null; info: MarketInfo }; const short = (v: string) => `${v.slice(0, 8)}…${v.slice(-5)}`; -const feeDisclosure = (marketBps: number) => `Market fee: ${marketBps / 100}% plus a fixed 1% additional fee (${(marketBps + ADDITIONAL_MARKET_FEE.bps) / 100}% total), both deducted from seller proceeds. Additional fee recipient: ${ADDITIONAL_MARKET_FEE.address}. Payouts are simulated only.`; +const feeDisclosure = (marketBps: number) => `Hosting peer fee: ${marketBps / 100}% plus a hardcoded 1% project author fee (${(marketBps + ADDITIONAL_MARKET_FEE.bps) / 100}% total), both deducted from seller proceeds. Author fee recipient: ${ADDITIONAL_MARKET_FEE.address}. Payouts are simulated only.`; async function api(body?: unknown, offset = 0): Promise { const response = await fetch(body ? '/api/market/command' : `/api/market?offset=${offset}`, { cache: 'no-store', signal: AbortSignal.timeout(15000), @@ -124,10 +124,11 @@ export function Marketplace({ wallet, snapshot, rpcAvailable, onNotice }: Props) }; const disabled = busy || !wallet || !rpcAvailable || !page; return
-
THE COLLECTOR’S EXCHANGE

A new home for
extraordinary finds.

Discover a fixed-price favorite or join a timed auction. Prices in USD, checkout in XMR. Your keys always sign card delivery.

KNOWLEDGE CHANGES HANDS
+
THIS PEER’S COLLECTOR EXCHANGE

Your next find.
Your kind of market.

Buy a fixed-price card or join a timed auction. Every peer can host its own market: a broad exchange or a community centered on a collection. Prices are in USD; cryptocurrency checkout is designed for Monero (XMR), currently simulated.

PEER-HOSTED · COMMUNITY-DRIVEN
+

Sales support the hosting peer’s operator through a configurable fee and the project author through a hardcoded 1% fee. Both are deducted from seller proceeds. Collection-specific curation tools and peer-hosted custom TCGs are planned, not available yet.

Mock payments only · never send real XMR

Quotes, payment confirmations, refunds, fees, and automatic seller payouts are simulated. Card delivery is a real on-chain transfer. There is no payable Monero address. Listings are local to this marketplace node, not shared by peers.

SANDBOX
{(['browse','sell','orders'] as const).map(t=>)}
- {page&&<>
Market fee {page.info.feeBps/100}% + 1% additional · {(page.info.feeBps+ADDITIONAL_MARKET_FEE.bps)/100}% total deducted from sellerDelivery {page.info.deliveryConfirmations} confirmations before mock payoutSimulation rate ${page.info.mockUsdPerXmr}/XMR · not a live quote

Fixed 1% fee recipient · simulated payout only, not a checkout address: {ADDITIONAL_MARKET_FEE.address}

} + {page&&<>
Host {page.info.feeBps/100}% + author 1% · {(page.info.feeBps+ADDITIONAL_MARKET_FEE.bps)/100}% total deducted from sellerDelivery {page.info.deliveryConfirmations} confirmations before mock payoutSimulation rate ${page.info.mockUsdPerXmr}/XMR · not a live quote

Hardcoded project author fee recipient · simulated payout only, not a checkout address: {ADDITIONAL_MARKET_FEE.address}

} {!rpcAvailable&&

Reconnect to the node before using the marketplace.

} {!wallet&&

Open your local wallet to list cards, bid, and check out.

} {error&&

{error}

} @@ -138,7 +139,7 @@ export function Marketplace({ wallet, snapshot, rpcAvailable, onNotice }: Props) const article=snapshot?.blocks.find(b=>b.tokenId===l.cardHash)?.article; return
{l.kind==='auction'?:} {l.kind==='auction'?'Timed auction':'Fixed price'}
BY {short(l.seller)} {mine?'· YOU':''}

{l.title}

{formatUsd(salePrice)}{l.kind==='fixed'?'XMR at checkout':l.highestBid?'Highest bid':'Starting bid'}
{l.kind==='auction'&&

{deadline(l.endsAt!,now)}{ended&&l.highestBid?` · winner ${short(l.highestBid.bidder)}`:''}

} {l.status==='reserved'?

Reserved · awaiting settlement

:mine?:l.kind==='fixed'||ended?:
setBids(v=>({...v,[l.id]:e.target.value}))}/>
} -

{l.feeBps/100}% market + {(l.additionalFee?.bps ?? 0)/100}% additional seller fee · NFT {short(l.cardHash)}

{article&&

Wikipedia · Image & license · NFT metadata

}
; +

{l.feeBps/100}% host + {(l.additionalFee?.bps ?? 0)/100}% author · deducted from seller · NFT {short(l.cardHash)}

{article&&

Wikipedia · Image & license · NFT metadata

}
; })}{!page?.listings.length&&

A discovery worth sharing?

The market is waiting for its first listing. Offer a card from your confirmed collection.

}{page?.next!==null&&page?.next!==undefined&&}} {tab==='sell'&&
MAKE ROOM FOR THE NEXT DISCOVERY

Put a card on the market.

Keep a set price open indefinitely, or let collectors bid until the clock runs out. You retain custody of the card and must return to sign delivery after mock payment.

A listing does not lock a card in consensus. Transfers elsewhere can invalidate it. No cancellation after an auction’s first bid; the winner gets 30 minutes to pay. Seller delivery deadline is 48 hours after mock payment.

{e.preventDefault();create();}}>setPrice(e.target.value)} required/>{kind==='auction'&&<>setHours(e.target.value)} required/>}

Fees: {page?(page.info.feeBps/100)+'% market + 1% additional':'—'} · both subtracted from seller proceeds, never added to the buyer price.

} {tab==='orders'&&
@@ -152,8 +153,8 @@ export function Marketplace({ wallet, snapshot, rpcAvailable, onNotice }: Props)
Sale
{formatUsd(o.priceCents)}
Mock checkout
{o.invoice.amountXmr} XMR
-
Market fee ({o.feeBps/100}%)
{o.feeXmr} XMR
- {o.additionalFee &&
Additional fee ({o.additionalFee.bps/100}%) · simulated
{o.additionalFee.amountXmr} XMR · {o.additionalFee.payout}Recipient: {o.additionalFee.address}
} +
Hosting peer fee ({o.feeBps/100}%) · simulated
{o.feeXmr} XMR
+ {o.additionalFee &&
Project author fee ({o.additionalFee.bps/100}%) · simulated
{o.additionalFee.amountXmr} XMR · {o.additionalFee.payout}Recipient: {o.additionalFee.address}
}
Seller net · simulated
{o.sellerNetXmr} XMR

{o.status==='awaiting-payment'?`Pay by ${new Date(o.payBy).toLocaleString()}`:o.status==='paid'?`Seller signs delivery by ${new Date(o.deliverBy).toLocaleString()}`:`Delivery: ${o.deliveryConfirmations}/${o.requiredConfirmations} confirmations · payout: ${o.payout}`}

diff --git a/tests/project-copy.test.ts b/tests/project-copy.test.ts new file mode 100755 index 0000000..f5e3697 --- /dev/null +++ b/tests/project-copy.test.ts @@ -0,0 +1,25 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { readFile } from 'node:fs/promises'; + +test('project overview distinguishes mining rewards, peer markets, planned TCGs and current payment status',async()=>{ + const readme=await readFile(new URL('../README.md',import.meta.url),'utf8'); + assert.match(readme,/mining a block rewards the miner with a collectible card based on a Wikipedia page/); + assert.match(readme,/algorithm also used by Monero/); + assert.match(readme,/consumer CPUs competitive/); + assert.match(readme,/custom games hosted by peers.*planned/); + assert.match(readme,/configurable hosting fee/); + assert.match(readme,/hardcoded \*\*1% author fee\*\*/); + assert.match(readme,/checkout is mock-only/); + assert.match(readme,/does not yet contain a project LICENSE file/); + assert.doesNotMatch(readme,/## Mine only by explicit choice/); +}); +test('homepage explains the roadmap without opt-in marketing or implying live XMR checkout',async()=>{ + const app=await readFile(new URL('../src/App.tsx',import.meta.url),'utf8'); + assert.match(app,/Mine a block\. Earn a Wikipedia NFT card/); + assert.match(app,/ON THE ROADMAP · NOT PLAYABLE YET/); + assert.match(app,/peer-hosted custom TCGs are planned/); + assert.match(app,/today payments and fees are simulated/); + assert.doesNotMatch(app,/EXPLICIT OPT-IN|opt-in RandomX|No browser mining|Only by choice/); + assert.match(app,/--consent/); // Documentation-only change: runnable miner invocation keeps its existing required flag. +});