Files
redl-gamepanel/resources/[rp]/rp_ui/html/index.html
T
Claude Opus 5andClaude Opus 5 71856b15e9 The server itself: repo now mirrors the machine it runs on, plus install.sh
The repository carried two different servers side by side - the early
`justrp` prototype with its Python auth API, and a snapshot of the real
one under `server-code/`. Only the second one is a server anyone should
start from, so the prototype is gone and the real one moved to the root.

Taken from the live box, so the UI is the finished version (the tokens,
the county-records sheets and the variable fonts landed after the last
snapshot was pushed):

  resources/[rp]/   rp_db, rp_core, rp_session, rp_loading, rp_ui,
                    rp_selftest, rp_dbtest
  bin/              supervise.sh (keep-alive + console FIFO), rcon, init script
  etc/schema.sql    accounts, characters, transactions, inventory, vehicles
  assets/fonts/     the bundled subsets
  docs/SERVER.md    how it is put together, resource by resource

install.sh turns a clean Ubuntu/Debian box into this server in one
command: recommended FXServer build, MariaDB with the schema, resources,
server.cfg + a generated database password, boot entry (systemd or
init.d), then it waits for the Cfx registration. --name/--port/--db-name
let a second server live on the same machine. Tested end to end on a
spare install root: build 25770 fetched, schema applied, boot entry
written, FXServer started and stopped exactly where a wrong licence key
should stop it.

No secrets travel with it: the licence key and the database password live
in data/secrets.cfg on the machine, and .gitignore now names it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 23:23:33 +00:00

295 lines
12 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Los Santos RP</title>
<link rel="stylesheet" href="tokens.css">
<link rel="stylesheet" href="app.css">
</head>
<body class="hidden">
<div class="edge" aria-hidden="true"></div>
<div class="grain" aria-hidden="true"></div>
<!-- ======================= persistent chrome ======================= -->
<header class="topbar">
<div class="mark">
<svg class="seal" viewBox="0 0 100 100" aria-hidden="true">
<circle cx="50" cy="50" r="46" class="seal-ring"/>
<circle cx="50" cy="50" r="37" class="seal-ring thin"/>
<circle cx="50" cy="50" r="41.5" class="seal-ticks"/>
<path class="seal-star" d="M50 30 L54.7 43.8 L69.4 44 L57.6 52.7 L62 66.6
L50 58.2 L38 66.6 L42.4 52.7 L30.6 44 L45.3 43.8 Z"/>
</svg>
<span class="mark-lines">
<span class="mark-name" id="markName">LOS SANTOS</span>
<span class="mark-tag" id="markTag">ROLEPLAY</span>
</span>
</div>
<!-- A real sequence: you cannot be placed before you have an identity, and you
cannot have an identity before the file exists. Printed as a routing box. -->
<nav class="stages" aria-label="Application progress">
<button class="stagechip" data-stage="auth" type="button" disabled>
<em>01</em><span>Credentials</span>
</button>
<i class="stagelink" aria-hidden="true"></i>
<button class="stagechip" data-stage="characters" type="button" disabled>
<em>02</em><span>Identity</span>
</button>
<i class="stagelink" aria-hidden="true"></i>
<button class="stagechip" data-stage="spawn" type="button" disabled>
<em>03</em><span>Placement</span>
</button>
</nav>
<div class="filetag">
<span class="filetag-k">File</span>
<span id="fileSerial">0000-000000</span>
</div>
</header>
<!-- ======================= 01 / auth ======================= -->
<section class="screen" id="screen-auth" hidden>
<div class="rail">
<div class="rail-scrim" aria-hidden="true"></div>
<div class="letterhead">
<div class="lh-dept">
<span class="lh-city">City of Los Santos</span>
<span class="lh-office">Office of Vital Records</span>
</div>
<div class="lh-form data">VR&#8209;1</div>
</div>
<div class="rail-inner">
<h1 class="head" id="authTitle">Open a file</h1>
<p class="sub" id="authSub">
Everything you do in this city is recorded against this file. Choose a name you will
remember and a password you will not share.
</p>
<form class="form" id="authForm" novalidate>
<div class="field" data-field="username">
<label for="username">Username</label>
<input id="username" name="username" type="text" autocomplete="username"
spellcheck="false" maxlength="20" placeholder="dlarue">
<p class="hint" id="hint-username">3&ndash;20 characters. Letters, numbers and underscore.</p>
</div>
<div class="field" data-field="password">
<label for="password">Password</label>
<div class="withbtn">
<input id="password" name="password" type="password" autocomplete="current-password"
maxlength="72" placeholder="&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;">
<button class="reveal-btn" id="revealPw" type="button" aria-label="Show password">Show</button>
</div>
<p class="hint" id="hint-password">At least 8 characters, with a letter and a number.</p>
</div>
<!-- only present while registering; height animates, nothing reloads -->
<div class="collapse" id="confirmWrap" aria-hidden="true">
<div class="collapse-inner">
<div class="field" data-field="confirm">
<label for="confirm">Repeat password</label>
<input id="confirm" name="confirm" type="password" autocomplete="new-password"
maxlength="72" placeholder="&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;">
<p class="hint" id="hint-confirm">Both entries must match.</p>
</div>
</div>
</div>
<p class="formerror" id="authError" role="alert" aria-live="assertive" hidden></p>
<button class="btn primary" id="authSubmit" type="submit">
<span class="btn-label">Open the file</span>
<span class="btn-spin" aria-hidden="true"></span>
</button>
</form>
<p class="switch">
<span id="switchText">Already have a file?</span>
<button class="linkbtn" id="switchMode" type="button">Sign in instead</button>
</p>
</div>
</div>
</section>
<!-- ======================= 02 / characters ======================= -->
<section class="screen" id="screen-characters" hidden>
<div class="rail wide">
<div class="rail-scrim" aria-hidden="true"></div>
<div class="letterhead">
<div class="lh-dept">
<span class="lh-city">City of Los Santos</span>
<span class="lh-office">Register of Persons</span>
</div>
<div class="lh-form data">VR&#8209;4</div>
</div>
<div class="rail-inner">
<h1 class="head">Who are you today?</h1>
<div class="kicker">
<span class="eyebrow">Registered identities</span>
<span class="hair" aria-hidden="true"></span>
<span class="data" id="charCount">0 / 3</span>
</div>
<ul class="charlist" id="charList"></ul>
<p class="formerror" id="charError" role="alert" aria-live="assertive" hidden></p>
<div class="charactions">
<button class="btn primary" id="charEnter" type="button" disabled>
<span class="btn-label">Enter the city</span>
<span class="btn-spin" aria-hidden="true"></span>
</button>
<button class="btn ghost danger" id="charDelete" type="button" disabled>Delete</button>
</div>
</div>
</div>
</section>
<!-- ======================= 03 / creator ======================= -->
<section class="screen" id="screen-creator" hidden>
<div class="rail wide">
<div class="rail-scrim" aria-hidden="true"></div>
<div class="letterhead">
<div class="lh-dept">
<span class="lh-city">City of Los Santos</span>
<span class="lh-office">Application for Identity</span>
</div>
<button class="linkbtn danger" id="creatorCancel" type="button">Discard</button>
</div>
<nav class="tabs" id="creatorTabs" aria-label="Editor sections">
<button class="tab is-on" data-section="heritage" type="button">Heritage</button>
<button class="tab" data-section="face" type="button">Face</button>
<button class="tab" data-section="hair" type="button">Hair</button>
<button class="tab" data-section="body" type="button">Body</button>
<button class="tab" data-section="clothing" type="button">Clothing</button>
<button class="tab" data-section="identity" type="button">Identity</button>
</nav>
<div class="rail-inner creator">
<div class="panes" id="creatorPanes">
<div class="pane is-on" data-section="heritage"></div>
<div class="pane" data-section="face"></div>
<div class="pane" data-section="hair"></div>
<div class="pane" data-section="body"></div>
<div class="pane" data-section="clothing"></div>
<div class="pane" data-section="identity"></div>
</div>
</div>
<p class="formerror" id="creatorError" role="alert" aria-live="assertive" hidden></p>
<div class="creator-foot">
<button class="btn ghost" id="creatorPrev" type="button">Back</button>
<button class="btn primary" id="creatorNext" type="button">
<span class="btn-label">Next</span>
<span class="btn-spin" aria-hidden="true"></span>
</button>
</div>
</div>
<!-- The plate the subject is photographed against. It is also the drag
surface, so the frame you aim at is the thing that turns. -->
<div class="turntable" id="turntable" title="Drag to turn">
<span class="plate-corner tl" aria-hidden="true"></span>
<span class="plate-corner tr" aria-hidden="true"></span>
<span class="plate-corner bl" aria-hidden="true"></span>
<span class="plate-corner br" aria-hidden="true"></span>
<div class="plate-cap">
<span class="plate-cap-k">Subject</span>
<span class="turnhint"><span class="turnicon" aria-hidden="true"></span>Drag to turn</span>
</div>
</div>
</section>
<!-- ======================= 04 / spawn ======================= -->
<section class="screen" id="screen-spawn" hidden>
<div class="rail">
<div class="rail-scrim" aria-hidden="true"></div>
<div class="letterhead">
<div class="lh-dept">
<span class="lh-city">City of Los Santos</span>
<span class="lh-office">Notice of Placement</span>
</div>
<div class="lh-form data">VR&#8209;9</div>
</div>
<div class="rail-inner">
<h1 class="head">Where does the day start?</h1>
<p class="sub" id="spawnSub">Pick a district. You can move once you are on the ground.</p>
<ul class="spawnlist" id="spawnList"></ul>
<p class="formerror" id="spawnError" role="alert" aria-live="assertive" hidden></p>
<button class="btn primary" id="spawnConfirm" type="button" disabled>
<span class="btn-label">Place me here</span>
<span class="btn-spin" aria-hidden="true"></span>
</button>
</div>
</div>
<!-- A plan sheet from the same office: a drawing of the county, not a screenshot. -->
<div class="chart" id="chart">
<div class="chart-paper" aria-hidden="true"></div>
<svg viewBox="0 0 1000 1000" preserveAspectRatio="xMidYMid meet" aria-hidden="true">
<defs>
<pattern id="grid" width="50" height="50" patternUnits="userSpaceOnUse">
<path d="M50 0 L0 0 0 50" fill="none" stroke="rgba(25,28,24,.10)" stroke-width="1"/>
</pattern>
<pattern id="grid10" width="250" height="250" patternUnits="userSpaceOnUse">
<path d="M250 0 L0 0 0 250" fill="none" stroke="rgba(25,28,24,.18)" stroke-width="1"/>
</pattern>
</defs>
<rect width="1000" height="1000" fill="url(#grid)"/>
<rect width="1000" height="1000" fill="url(#grid10)"/>
<rect class="chart-frame" x="30" y="30" width="940" height="940"/>
<path class="chart-ticks"
d="M30 92 L30 30 L92 30 M908 30 L970 30 L970 92
M970 908 L970 970 L908 970 M92 970 L30 970 L30 908"/>
<path id="landmass"
d="M318 62 L470 44 L604 74 L712 66 L806 128 L858 248 L872 372
L842 468 L868 556 L826 664 L742 742 L648 812 L560 872
L462 918 L392 902 L342 836 L296 742 L262 640 L240 528
L206 424 L196 320 L232 196 L272 108 Z"/>
<!-- the western coastline is the one edge worth drawing emphatically -->
<path id="coastline"
d="M262 640 L240 528 L206 424 L196 320 L232 196 L272 108 L318 62"/>
</svg>
<div class="pins" id="pins"></div>
<!-- every drawing from this office carries a title block -->
<div class="titleblock">
<div class="tb-row tb-main">
<span class="tb-k">Sheet</span>
<span class="tb-v">Los Santos County</span>
</div>
<div class="tb-row">
<span class="tb-k">Scale</span><span class="tb-v">Not to scale</span>
<span class="tb-k">Sheet</span><span class="tb-v">1 of 1</span>
</div>
</div>
</div>
</section>
<!-- the one bold moment: the city stamps your file -->
<div class="stamp" id="stamp" aria-hidden="true">
<span class="stamp-word" id="stampText">Filed</span>
<span class="stamp-sub">Office of Vital Records</span>
</div>
<script src="app.js"></script>
</body>
</html>