Porto Riviera ↗

Riviera Docs Intro

Riviera · Intro

A multiplayer Mediterranean luxury RPG, played in the browser. Walk a shared harbor, work the marina for Credits, buy a visible upgrade, and surface rare Discoveries. The intro is one harbor and one loop, built end to end before anything else.

Introduction#

Riviera is played in the browser. No download, no install. You arrive at Porto Riviera, a single shared harbor you occupy alongside other real players in real time. You take honest Marina work for the soft currency, Credits, and spend them with the Dealer on a boat or scooter that everyone else can see. Status here is visible, earned, and shared.

At a glance#

GenreIsometric shared-world luxury RPG
PlatformBrowser (desktop), no install
MultiplayerReal-time, server-authoritative
ChainSolana, read-only $RIV balance gate
Intro scopeOne harbor · marina jobs · the Dealer · Discoveries

The core loop#

The intro proves a single loop: work → earn Credits → buy a visible upgrade → be seen, with a rare-find jackpot layered on top. Every outcome is decided by the server, so progression is fair and shared.

New here? Start with the Quickstart, then read Marina work and The Dealer.

Quickstart: the core loop#

You begin with a Used Tender and 40 Credits. From there:

1 · Enter the harbor#

Connect a Solana wallet to pass the token gate, spawn on the quay, and click-to-move around the harbor. You send a target tile; the server walks you there.

2 · Earn Credits#

Stand next to a marina station (wash, fuel, or repair) and start a matching job. A server-owned timer runs; when it finishes, the Credits are yours.

3 · Buy an upgrade#

Visit the Dealer and spend Credits on the next vehicle up the ladder, then equip it. The equipped vehicle is public: everyone in the harbor sees it.

4 · Strike a Discovery#

Each completed job has a small chance to surface a rare Discovery. Sell it to the Dealer for a Credit windfall. The rarest finds are announced to the whole harbor.

Porto Riviera#

The harbor is a single Colyseus room rendered as an isometric diamond of stone quay, promenade, and water. Sprites are low-poly 3D models baked to isometric frames. The look is hand-built, not real-time 3D.

Layout#

The authoritative map is a 48 × 48 square grid. Tiles are walkable or blocked; the server validates every move against that grid. Layers, bottom to top: water, ground (the walkable quay), structures, and overhead (awnings that draw over you).

On the quay#

  • Player spawn: where you appear when you join.
  • Marina stations: wash, fuel, and repair points; stand adjacent to begin work.
  • The Dealer: one storefront where you buy upgrades and sell Discoveries.
  • Berths: slips where an owned boat renders for the harbor to see.

The intro is one room. Additional districts are future rooms. There are no portals in the intro.

Players & presence#

What other players must see is broadcast through the room's shared state. What is yours alone is sent privately to you and never broadcast. The split is a privacy and anti-cheat boundary.

What others see#

Public per-player state lives in the Colyseus schema and is synced to everyone: your name, your grid position, and your equipped vehicle. Light chat keeps the quay social.

What stays yours#

Private state is owner-directed and never placed in the broadcast schema: your Credits, your inventory, and the Discoveries you hold. It is delivered to you alone via direct messages.

Marina work#

Marina work is how every Credit is earned in the intro. Four jobs span three station types. Faster jobs pay less; the long repair pays best.

Job board#

JobidStationDurationPayout
Clean a hullhull_cleanwash6 s12 cr
Refuel a boatrefuelfuel5 s10 cr
Polish the deckdeck_polishwash9 s20 cr
Patch a hullhull_repairrepair14 s38 cr

Rules#

  • You must stand adjacent to a station whose type matches the job.
  • One active job per player at a time.
  • The timer is server-owned. Your client may show a progress bar for feel, but the reward arrives only when the server completes the job.

The client never decides a reward. Payouts and rare-find rolls are settled on the server tick. See Netcode & protocol.

The Dealer#

The Dealer is an NPC menu: buy and sell only, no dialogue. Buying and equipping a vehicle is the whole point of the climb: it is the status everyone in the harbor can see.

The vehicle ladder#

VehicleidTypePrice
Used Tendertender_usedboatowned at start
City Scooterscooter_cityland150 cr
Classic Runaboutrunabout_classicboat600 cr
Sport Cruisercruiser_sportboat2,800 cr

Buying & equipping#

To buy, the server checks the vehicle exists, isn't already owned, and that you hold enough Credits, then deducts and adds it to your inventory. Equipping sets your public equippedVehicleId, which broadcasts to the room. You can also sell a Discovery here for Credits.

Discoveries#

A Discovery (a rare find) is the intro's jackpot. It is the accelerant that can leapfrog you up the ladder, and the screenshot-worthy moment that pulls players in.

Drop rate#

Every completed job carries a flat 3% chance (dropChancePerJob = 0.03) to surface a find. The roll happens server-side on job completion. When a find occurs, the entry is chosen by relative weight.

The find table#

DiscoveryidChance*Sells for
Vintage Brass Compassfind_compass40%220 cr
Lost Designer Watchfind_watch25%650 cr
Black Pearlfind_pearl20%900 cr
Rare License Platefind_plate12%1,500 cr
Diamond Signet Ringfind_ring3%4,200 cr

* Chance that a find is this item, given a find occurred (the weights). Per job, multiply by the 3% drop chance.

A Diamond Signet Ring (4,200 cr) is worth more than the Sport Cruiser itself, and triggers a harbor-wide announcement.

Credits & progression#

Credits are the only currency in the intro. There is no sink and no token economy. You earn, then you spend. $RIV is not used for purchases (see the token gate).

Starting out#

You begin with 40 Credits (startingCredits) and the Used Tender. The first real goal is the City Scooter (150 cr), roughly 6–10 jobs of work.

Tuning#

  • The Sport Cruiser (2,800 cr) is the aspirational target: a long climb, or a lucky-find leapfrog.
  • Discoveries (220–4,200 cr) are the intended accelerant: one good find jumps progression.
  • Selling a Discovery applies rareFindSellMultiplier (1.0 in the intro).

The $RIV gate#

In the intro, $RIV has exactly one role: it gates access to the harbor. Nothing in the game is bought, sold, or settled with the token yet. The full token economy the platform is built toward is described in Tokenomics.

How the gate works#

Entry is a balance read. Hold at least RIVIERA_GATE_MIN of RIVIERA_TOKEN_MINT and you're in. Connection uses Wallet Standard; the balance is read over RPC with gill. There is no transaction, no contract call, and no signature required to enter.

What the token is not (yet)#

  • Not a currency: all in-game value is Credits and the NPC Dealer.
  • No player marketplace, no $RIV settlement or transfers in the intro.
  • No on-chain programs. Private keys and signers never touch client or shared code.

Mint and RPC come from .env (RIVIERA_TOKEN_MINT, SOLANA_RPC_URL, SOLANA_NETWORK). Build on devnet first; swap to a mainnet mint at launch.

Tokenomics#

The access gate is only the first use of $RIV. The platform is designed around the token as its settlement and value layer: as features roll out past the intro, activity on the platform is denominated in $RIV, and a fixed share of that activity is used to buy back and burn the token, while staking locks more supply away. The result is a deflationary flywheel that ties token scarcity to real usage.

Roadmap, not the intro. The intro ships gate-only (see The $RIV gate). The mechanics below describe the economy the platform is built toward. Values shown as [TBD] are placeholders pending finalization.

Where $RIV is used#

  • Access gate (live in the intro): hold the minimum balance to enter.
  • On-platform transactions: marketplace trades, premium items, and services settle in $RIV.
  • Staking: lock tokens to earn a share of platform fees and unlock benefits.
  • Tiers and governance: holdings and stake can unlock higher access tiers, fee discounts, and a say in direction.

The 5% transaction fee#

Every on-platform $RIV transaction carries a 5% protocol fee, and the entire fee feeds the burn. There is no split: 100% of the 5% is used to buy $RIV on the open market and burn it. This is the engine of the flywheel.

ParameterValue*
Transaction fee5%
Allocated to buy-back & burn100%

* The 5% rate is subject to change.

Buy-back-and-burn#

The full 5% fee is used to purchase $RIV on the open market and permanently remove it from circulation. Burns scale with platform activity: the more players transact, the more supply is retired, which makes the token structurally deflationary over time.

Staking#

Holders can stake $RIV to unlock in-platform benefits such as higher access tiers, reduced fees, and, later, governance. Staked tokens are locked, which removes them from circulating supply and reinforces the same scarcity the burn creates. Staking reward details are being finalized.

The flywheel#

The pieces compound into a loop:

  1. More players join and transact on the platform.
  2. Every transaction pays a 5% fee in $RIV.
  3. The entire fee buys back and burns $RIV, permanently shrinking supply.
  4. Staking locks more supply away, and a scarcer token strengthens the incentive to hold and stake.
  5. Aligned holders bring and keep more activity, which returns to step 1.

Parameters#

ParameterValue
NetworkSolana (SPL token)
Contract addressHREUDWzLtmJrMjav48RY9iPRJr9r8KoTBLjWNjdPpump (on pump.fun)
Total supply[TBD]
Transaction fee5% (subject to change)
Fee to buy-back & burn100%
Gate minimum (intro)RIVIERA_GATE_MIN

Mechanics and figures here are design intent, subject to change, and provided for information only. Nothing on this page is financial advice or an offer of any token or security.

Architecture overview#

The prime directive#

All gameplay state and validation run in cartesian integer grid coordinates. The isometric projection exists only on the client, at render time. The authoritative server is projection-blind. It never imports, references, or computes anything isometric. The transform lives in one client file:

// client/src/iso/iso.ts (client only, never on the server)
const cartToIso = (cx, cy) => ({ x: (cx - cy) * HW, y: (cx + cy) * HH });

Client & server#

  • Client: Phaser 3 with native isometric tilemaps. Owns all iso math and rendering; scenes only render and capture input.
  • Server: Colyseus authoritative rooms on a cartesian grid, simulated at 20 Hz.
  • Shared: frozen TypeScript types, constants, and the message protocol. No Phaser, no Colyseus runtime.

Netcode & protocol#

Intent, not position#

The client sends intent: “move to this tile”, “start this job”, “buy this vehicle”. The server validates, resolves, and broadcasts the truth. The client never tells the server where it is; position, Credits, inventory, and every reward are server-owned.

Message protocol#

Public position/name/equipped-vehicle sync via the schema. These messages cover discrete actions and private state.

type ClientMessage =
  | { t: "move"; gridX: number; gridY: number }
  | { t: "start_job"; jobId: string; stationId: string }
  | { t: "buy_vehicle"; vehicleId: string }
  | { t: "equip_vehicle"; vehicleId: string }
  | { t: "sell_find"; findId: string }
  | { t: "chat"; text: string };

type ServerMessage =
  | { t: "credits"; credits: number }
  | { t: "inventory"; ownedVehicleIds: string[]; equippedVehicleId: string; findIds: string[] }
  | { t: "job_done"; payoutCredits: number; find: {...} | null }
  | { t: "announce"; text: string }   // broadcast
  | { t: "chat"; from: string; text: string }
  | { t: "error"; message: string };
MessageDirectionPurpose
moveclient → serverValidate target tile, path the player, update schema.
start_jobclient → serverVerify adjacency + station type, start a server timer.
job_doneserver → ownerPayout + rolled Discovery (or null) on timer completion.
announceserver → allHarbor-wide headline for rare finds.
credits / inventoryserver → ownerPrivate state after any change. Never broadcast.

Tech stack#

LayerTechnology
Client renderPhaser 3, native isometric tilemaps, 2D
ArtLow-poly 3D models baked to isometric sprites
MapsTiled (isometric), JSON export
NetcodeColyseus, authoritative rooms, Schema state
PersistencePostgres + Prisma
SolanaWallet Standard (connect) + gill (read-only RPC)
LanguageTypeScript, strict, end to end

Constants#

Dimensional and timing constants have a single source of truth in shared/constants.ts. They are never inlined elsewhere.

export const GRID_WIDTH = 48;          // harbor tiles, x
export const GRID_HEIGHT = 48;         // harbor tiles, y
export const SERVER_TICK_HZ = 20;      // authoritative sim rate
export const MOVE_TILES_PER_SEC = 4;    // player move speed
export const ISO_TILE_W = 64;          // iso diamond width (px)
export const ISO_TILE_H = 32;          // iso diamond height (px)

Game content (prices, payouts, durations, drop rates) lives in /data JSON, not in constants. See Marina work, The Dealer, and Discoveries.

Roadmap & scope#

Build order#

PhaseDeliversStatus
1 · Iso foundationHarbor map, projection, click/WASD movement, depth sortBuilt
2 · Shared movementColyseus authoritative movement; clients see each otherPlanned
3 · Marina & CreditsServer-authoritative jobs, payouts, rare-find rollsPlanned
4 · The DealerBuy + equip a visible vehicle; sell a DiscoveryPlanned
5 · Token gateWallet connect + $RIV balance gate at joinPlanned

Out of scope (deferred)#

The following are explicitly not in the intro. They wait until the core loop is proven:

  • Player marketplace & $RIV settlement; on-chain programs
  • Racing, diving / underwater recovery, vehicle restoration, luxury logistics
  • Reputation spheres, property / housing, clubs & crews, seasonal events
  • Multiple districts, NPC dialogue trees, mega yachts, mobile / native builds, real-time 3D
Riviera · Intro MVP documentation Content of record: /shared, /data, /docs