FiveRP: the server from the hosting account, not the earlier one

Wrong server was published before. This is the one that runs on the
hosting account the video was made on: FiveRP - two-step registration
(account, then an identity printed onto a passport), login that returns
you to your resident, and a loading screen driven by the game's own
streaming events.

  resources/[local]/fiverp-auth          NUI + scrypt hashes + oxmysql
  resources/[local]/fiverp-characters    identity, character load, spawn
  resources/[local]/fiverp-loadscreen    loading screen
  sql/schema.sql                         accounts, characters
  docs/DESIGN.md                         the design system every screen follows
  docs/screens/                          shot from the live server

Only our own code is in here. cfx-server-data and oxmysql are fetched by
install.sh instead of being vendored, which keeps the repo at 3.7 MB.

install.sh does the whole box in one command: recommended FXServer
build, cfx-server-data, oxmysql, MariaDB with the schema, resources,
server.cfg (mode 600 - it carries the key and the database password),
boot entry, then it waits for the Cfx registration. Tested end to end on
a spare install root: 29 resources scanned, database and schema created,
and it stopped exactly where a wrong licence key should stop it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Claude Opus 5
2026-08-12 23:42:20 +00:00
co-authored by Claude Opus 5
parent 71856b15e9
commit c857979a55
88 changed files with 3904 additions and 7463 deletions
@@ -0,0 +1,217 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>FiveRP — Passport Office</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="stage" id="stage" aria-hidden="true">
<section class="slab" id="slab" data-view="login">
<!-- ------------------------------------------------------------- form -->
<div class="pane pane-form">
<p class="eyebrow">Los&nbsp;Santos <span class="dot"></span> Passport Office</p>
<div class="rail" id="rail" role="list">
<div class="rail-step is-active" data-step="account" role="listitem">
<span class="rail-mark"></span>
<span class="rail-label">Account</span>
</div>
<span class="rail-line"><i id="railFill"></i></span>
<div class="rail-step" data-step="identity" role="listitem">
<span class="rail-mark"></span>
<span class="rail-label">Identity</span>
</div>
</div>
<!-- Sign in -->
<form class="view" data-view="login" id="formLogin" novalidate>
<h1 class="title">Welcome back</h1>
<p class="sub">Sign in to return to the city.</p>
<label class="field">
<span class="label">Username</span>
<input type="text" name="username" autocomplete="username" spellcheck="false" placeholder="marcus_r">
</label>
<label class="field">
<span class="label">Password</span>
<input type="password" name="password" autocomplete="current-password" placeholder="••••••••">
</label>
<p class="notice" data-notice></p>
<button class="btn" type="submit"><span>Sign in</span></button>
<p class="switch">New to Los Santos? <button type="button" class="link" data-goto="account">Create an account</button></p>
</form>
<!-- Register step 1 -->
<form class="view" data-view="account" id="formAccount" novalidate>
<h1 class="title">Open your file</h1>
<p class="sub">The registry keeps this private. It is how you sign back in.</p>
<label class="field">
<span class="label">Email</span>
<input type="email" name="email" autocomplete="email" spellcheck="false" placeholder="you@example.com">
</label>
<label class="field">
<span class="label">Username</span>
<input type="text" name="username" autocomplete="username" spellcheck="false" placeholder="marcus_r">
<span class="hint">332 characters. Letters, numbers, underscore.</span>
</label>
<label class="field">
<span class="label">Password</span>
<input type="password" name="password" autocomplete="new-password" placeholder="At least 8 characters">
<span class="pwmeter" data-meter><i></i></span>
</label>
<p class="notice" data-notice></p>
<button class="btn" type="submit"><span>Continue</span></button>
<p class="switch">Already registered? <button type="button" class="link" data-goto="login">Sign in</button></p>
</form>
<!-- Register step 2 -->
<form class="view" data-view="identity" id="formIdentity" novalidate>
<h1 class="title">Name your resident</h1>
<p class="sub">This is the name the city will know you by. English letters only.</p>
<div class="row">
<label class="field">
<span class="label">First name</span>
<input type="text" name="firstName" autocomplete="off" spellcheck="false" maxlength="24" placeholder="Marcus">
</label>
<label class="field">
<span class="label">Last name</span>
<input type="text" name="lastName" autocomplete="off" spellcheck="false" maxlength="24" placeholder="Reyes">
</label>
</div>
<p class="notice" data-notice></p>
<button class="btn" type="submit"><span>Issue passport</span></button>
<p class="switch"><button type="button" class="link" data-goto="account">Back to account details</button></p>
</form>
</div>
<!-- ---------------------------------------------------------- passport -->
<div class="pane pane-card" id="pane-card">
<div class="passport" id="permit">
<div class="pp-guilloche" aria-hidden="true"></div>
<div class="pp-sheen" id="sheen" aria-hidden="true"></div>
<header class="pp-head">
<span class="pp-seal" aria-hidden="true">
<svg viewBox="0 0 64 64">
<circle class="ring-out" cx="32" cy="32" r="30"/>
<circle class="ring-in" cx="32" cy="32" r="26"/>
<!-- 13 stars, arced over the shield -->
<g class="stars">
<circle cx="32" cy="14" r="1.5"/>
<circle cx="25" cy="15.3" r="1.5"/><circle cx="39" cy="15.3" r="1.5"/>
<circle cx="19" cy="19" r="1.5"/><circle cx="45" cy="19" r="1.5"/>
<circle cx="15" cy="25" r="1.5"/><circle cx="49" cy="25" r="1.5"/>
</g>
<!-- shield: blue chief over 13 pales -->
<path class="shield-chief" d="M17 28h30v7H17z"/>
<g class="shield-pales">
<path d="M17 35h3v9.5c0 .6.1 1.2.2 1.8H17z"/>
<path d="M23 35h3v13h-3z"/>
<path d="M29 35h3v13h-3z"/>
<path d="M35 35h3v13h-3z"/>
<path d="M41 35h3v13h-3z"/>
</g>
<path class="shield-edge" d="M17 28h30v16.5c0 5.5-6.5 10.5-15 13.5-8.5-3-15-8-15-13.5z"/>
</svg>
</span>
<span class="pp-head-text">
<span class="pp-kind">Passport</span>
<span class="pp-country">United States of America</span>
</span>
<span class="pp-chip" aria-hidden="true">
<svg viewBox="0 0 20 16">
<rect x="0.6" y="0.6" width="18.8" height="14.8" rx="2.4"/>
<path d="M7 .6v15M13 .6v15M.6 5.4h18.8M.6 10.6h18.8"/>
</svg>
</span>
</header>
<div class="pp-body">
<div class="pp-left">
<div class="pp-photo">
<svg class="pp-bust" viewBox="0 0 48 60" aria-hidden="true">
<defs>
<linearGradient id="bust" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#9aa7b8"/>
<stop offset="1" stop-color="#5d6b7e"/>
</linearGradient>
</defs>
<circle cx="24" cy="18" r="11" fill="url(#bust)"/>
<path d="M3 60c0-11.5 9.4-20 21-20s21 8.5 21 20z" fill="url(#bust)"/>
</svg>
<span class="pp-photo-label">Photo</span>
</div>
<div class="pp-sign">
<span class="pp-sign-ink" id="cardSign"></span>
<span class="pp-sign-rule"></span>
<span class="pp-sign-label">Signature</span>
</div>
</div>
<dl class="pp-fields">
<div class="pp-f pp-f--type"><dt>Type</dt><dd>P</dd></div>
<div class="pp-f pp-f--code"><dt>Code</dt><dd>USA</dd></div>
<div class="pp-f pp-f--no"><dt>Passport No.</dt><dd id="cardNo" class="mono"></dd></div>
<div class="pp-f pp-f--wide"><dt>Surname</dt>
<dd class="pp-name" id="cardLast" data-empty="—"></dd></div>
<div class="pp-f pp-f--wide"><dt>Given names</dt>
<dd class="pp-name" id="cardFirst" data-empty="—"></dd></div>
<div class="pp-f pp-f--wide"><dt>Nationality</dt>
<dd>United States of America</dd></div>
<div class="pp-f"><dt>Date of birth</dt><dd class="mono" id="cardDob"></dd></div>
<div class="pp-f"><dt>Sex</dt><dd>X</dd></div>
<div class="pp-f pp-f--wide"><dt>Place of birth</dt><dd>Los Santos, San Andreas</dd></div>
<div class="pp-f"><dt>Date of issue</dt><dd class="mono" id="cardIssue"></dd></div>
<div class="pp-f"><dt>Date of expiration</dt><dd class="mono" id="cardExpiry"></dd></div>
<!-- Spans 4 of 6 columns, leaving the bottom-right corner clear so
the entry stamp lands on paper rather than on top of data. -->
<div class="pp-f pp-f--auth"><dt>Authority</dt>
<dd>United States Department of State</dd></div>
</dl>
<div class="pp-ghost" aria-hidden="true">
<svg viewBox="0 0 48 60">
<circle cx="24" cy="20" r="12"/>
<path d="M2 60c0-12 10-21 22-21s22 9 22 21z"/>
</svg>
</div>
</div>
<div class="pp-mrz mono">
<span id="mrz1">P&lt;USA&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;</span>
<span id="mrz2">&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;USA&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;</span>
</div>
<div class="pp-stamp" id="seal" aria-hidden="true">
<span class="pp-stamp-top">Admitted</span>
<span class="pp-stamp-mid">Los Santos</span>
<span class="pp-stamp-bot" id="stampDate">— — —</span>
</div>
</div>
<p class="pp-caption">Issued once. The city will know you by this name.</p>
</div>
</section>
</div>
<script src="app.js"></script>
</body>
</html>