Compare commits

...

1 Commits

Author SHA1 Message Date
Your Name 261c99f46e start doc work 2026-06-14 03:26:18 -04:00
35 changed files with 1604 additions and 7 deletions
+1 -1
View File
@@ -24,7 +24,7 @@
<section class="hero hero--slim" aria-label="Phantasy Star Online artwork"><div class="hero-image" role="img" aria-label="PSO Peeps hero artwork"></div></section>
<nav class="nav-bar" aria-label="Primary navigation">
<a href="https://circlewithadot.gitbook.io/psopeeps/connection-guide/connection-guide" target="_blank" rel="noopener noreferrer">Connection Guide</a><a href="leaderboards.html">Leaderboards</a><a href="drops.html">Drops</a><a href="bestiary.html">Bestiary</a><a href="account-ready.html">Account</a>
<a href="guide.html">Connection Guide</a><a href="leaderboards.html">Leaderboards</a><a href="drops.html">Drops</a><a href="bestiary.html">Bestiary</a><a href="account-ready.html">Account</a>
</nav>
<main class="account-layout">
+1 -1
View File
@@ -30,7 +30,7 @@
</section>
<nav class="nav-bar" aria-label="Primary navigation">
<a href="https://circlewithadot.gitbook.io/psopeeps/connection-guide/connection-guide" target="_blank" rel="noopener noreferrer">Connection Guide</a>
<a href="guide.html">Connection Guide</a>
<a href="leaderboards.html">Leaderboards</a>
<a href="drops.html">Drops</a>
<a href="bestiary.html">Bestiary</a>
+1 -1
View File
@@ -28,7 +28,7 @@
</section>
<nav class="nav-bar" aria-label="Primary navigation">
<a href="https://circlewithadot.gitbook.io/psopeeps/connection-guide/connection-guide" target="_blank" rel="noopener noreferrer">Connection Guide</a>
<a href="guide.html">Connection Guide</a>
<a href="leaderboards.html">Leaderboards</a>
<a href="drops.html">Drops</a>
<a href="bestiary.html">Bestiary</a>
+1 -1
View File
@@ -24,7 +24,7 @@
<section class="hero hero--slim" aria-label="Phantasy Star Online artwork"><div class="hero-image" role="img" aria-label="PSO Peeps hero artwork"></div></section>
<nav class="nav-bar" aria-label="Primary navigation">
<a href="https://circlewithadot.gitbook.io/psopeeps/connection-guide/connection-guide" target="_blank" rel="noopener noreferrer">Connection Guide</a><a href="leaderboards.html">Leaderboards</a><a href="drops.html">Drops</a><a href="bestiary.html">Bestiary</a><a href="account-ready.html">Account</a>
<a href="guide.html">Connection Guide</a><a href="leaderboards.html">Leaderboards</a><a href="drops.html">Drops</a><a href="bestiary.html">Bestiary</a><a href="account-ready.html">Account</a>
</nav>
<main class="placeholder-layout">
@@ -0,0 +1,24 @@
# Common Problems
Common connection and setup problems.
## Server addresses
- US Server: `108.175.11.140`
- EU Server: `65.21.79.231`
## Overview
TODO: Fill in the converted guide content for this page.
## Requirements
TODO
## Setup
TODO
## Notes
TODO
@@ -0,0 +1,24 @@
# Flycast BBA
Connect Flycast using the broadband adapter style setup.
## Server addresses
- US Server: `108.175.11.140`
- EU Server: `65.21.79.231`
## Overview
TODO: Fill in the converted guide content for this page.
## Requirements
TODO
## Setup
TODO
## Notes
TODO
@@ -0,0 +1,24 @@
# Flycast Dialup
Connect Flycast using the dialup/modem style setup.
## Server addresses
- US Server: `108.175.11.140`
- EU Server: `65.21.79.231`
## Overview
TODO: Fill in the converted guide content for this page.
## Requirements
TODO
## Setup
TODO
## Notes
TODO
@@ -0,0 +1,48 @@
# V2 - Dreamcast
Most Dreamcast PSO V2 versions can likely connect. PSO Peeps officially supports:
Version 2 Final Revision US
This support statement includes PSO Peeps patches; patches are built and tested against that version. Direct support for Version 2 Final Revision JP is planned.
## Network settings
Use the PSO Peeps server address:
65.21.79.231 (EU)
108.175.11.140 (US)
---
## What you need
- A real Dreamcast
- A normal retail PSO Ver.2 disc
- A working Dreamcast online setup, such as DreamPi or another working modem/BBA setup
## Retail disc + DNS method
Some Dreamcast setups can connect with a normal retail PSO Ver.2 disc by setting the Dreamcast DNS server to PSO Peeps.
Set the Dreamcast DNS to:
Primary DNS: 65.21.79.231 (EU) or 108.175.11.140 (US)
Secondary DNS: 0.0.0.0 / blank / your normal fallback DNS
Use automatic IP settings unless your Dreamcast network setup requires manual values.
## Steps
1. Confirm your Dreamcast online setup works.
2. Boot the normal retail PSO Ver.2 disc.
3. Open the Dreamcast/PSO network settings.
4. Set the primary DNS to:
65.21.79.231 (EU) or 108.175.11.140 (US)
5. Save the network settings.
6. Select your character.
7. Choose **Online Game**.
8. Connect to PSO Peeps.
9. Select the PSO Peeps ship/destination.
@@ -0,0 +1,24 @@
# Dolphin
Connect through Dolphin.
## Server addresses
- US Server: `108.175.11.140`
- EU Server: `65.21.79.231`
## Overview
TODO: Fill in the converted guide content for this page.
## Requirements
TODO
## Setup
TODO
## Notes
TODO
@@ -0,0 +1,24 @@
# GameCube Hardware BBA
Connect a real GameCube using a broadband adapter.
## Server addresses
- US Server: `108.175.11.140`
- EU Server: `65.21.79.231`
## Overview
TODO: Fill in the converted guide content for this page.
## Requirements
TODO
## Setup
TODO
## Notes
TODO
@@ -0,0 +1,24 @@
# Nintendont
Connect through Nintendont.
## Server addresses
- US Server: `108.175.11.140`
- EU Server: `65.21.79.231`
## Overview
TODO: Fill in the converted guide content for this page.
## Requirements
TODO
## Setup
TODO
## Notes
TODO
+54
View File
@@ -0,0 +1,54 @@
# Connection Guide
This guide explains how to connect to PSO Peeps Online Live from Dreamcast, GameCube, PC V2, Blue Burst, Flycast, Dolphin, and Nintendont. Android via Winlator is on the roadmap and has its own section.
## Server addresses
- **US Server:** `108.175.11.140`
- **EU Server:** `65.21.79.231`
Characters on US and EU servers cannot play together. However, you can easily switch servers by updating your DNS settings for your client or console and retain your saves for V2 and V3 if you ever need to.
## Main supported versions
- Dreamcast PSO Ver.2
- PC PSO Ver.2
- GameCube Episode I & II
- GameCube Episode III
- Blue Burst
PSO Peeps supports crossplay between supported client versions. Some features and behavior can differ by client version because Dreamcast V2, PC V2, GameCube, Episode III, and Blue Burst are not identical games. See the Crossplay sections for more.
---
## Before you start
Do not use a client that is still configured for Sylverant, Schtserv, Ephinea, Ultima, or another server.
Do not publicly post your serial number, access key, guild card, or account credentials.
## Supported discs and clients
PSO Peeps officially supports the following versions for direct support:
Dreamcast - Version 2 Final Revision US
PC - Version 2 with our patched exe files tracked by the PC patch server
GameCube - V1.2 Plus US
Blue Burst - Tethella Ver12513_Multi with our patched exe files tracked by the BB patch server
All PSO discs and clients are supported for connection to PSO Peeps. We cannot offer direct support on versions outside the list above.
If you are using a pre-patched disc from another server, such as Sylverant, Schtserv, Ephinea, or Ultima, we cannot support issues related to that disc. We can only support issues related to our own patches. Convert to the PSO Peeps client or disc before requesting support.
If an issue is specific to newserv, Sylverant Patcher, or services like Nintendont, refer to those services and communities to open issues or get help.
## Reporting connection issues
If you are reporting a connection issue, always include:
Game version:
Hardware/emulator:
Client/disc used:
Ship selected:
Approximate time of the issue:
What happened:
@@ -0,0 +1,24 @@
# Blue Burst on Linux
Connect the Blue Burst client on Linux.
## Server addresses
- US Server: `108.175.11.140`
- EU Server: `65.21.79.231`
## Overview
TODO: Fill in the converted guide content for this page.
## Requirements
TODO
## Setup
TODO
## Notes
TODO
@@ -0,0 +1,24 @@
# Blue Burst on Windows
Connect the Blue Burst client on Windows.
## Server addresses
- US Server: `108.175.11.140`
- EU Server: `65.21.79.231`
## Overview
TODO: Fill in the converted guide content for this page.
## Requirements
TODO
## Setup
TODO
## Notes
TODO
+24
View File
@@ -0,0 +1,24 @@
# PSO PC on Linux
Connect the original PSO PC client on Linux.
## Server addresses
- US Server: `108.175.11.140`
- EU Server: `65.21.79.231`
## Overview
TODO: Fill in the converted guide content for this page.
## Requirements
TODO
## Setup
TODO
## Notes
TODO
@@ -0,0 +1,24 @@
# PSO PC on Windows
Connect the original PSO PC client on Windows.
## Server addresses
- US Server: `108.175.11.140`
- EU Server: `65.21.79.231`
## Overview
TODO: Fill in the converted guide content for this page.
## Requirements
TODO
## Setup
TODO
## Notes
TODO
@@ -0,0 +1,24 @@
# Phantasy Star Portable
Phantasy Star Portable connection notes.
## Server addresses
- US Server: `108.175.11.140`
- EU Server: `65.21.79.231`
## Overview
TODO: Fill in the converted guide content for this page.
## Requirements
TODO
## Setup
TODO
## Notes
TODO
@@ -0,0 +1,22 @@
# Quick Reference
Fast connection reference for PSO Peeps.
## Server addresses
- US Server: `108.175.11.140`
- EU Server: `65.21.79.231`
## Guide sections
- Dreamcast: Hardware, Flycast Dialup, Flycast BBA
- PC: PSO PC on Windows/Linux, Blue Burst on Windows/Linux
- GameCube: Hardware BBA, Dolphin, Nintendont
- Xbox
- Phantasy Star Portable
- Server-side saves
- Common problems
## Notes
TODO: Add ports, DNS/proxy notes, account/key requirements, and client-specific quirks here.
@@ -0,0 +1,24 @@
# Server-side Saves
How PSO Peeps server-side saves work.
## Server addresses
- US Server: `108.175.11.140`
- EU Server: `65.21.79.231`
## Overview
TODO: Fill in the converted guide content for this page.
## Requirements
TODO
## Setup
TODO
## Notes
TODO
+24
View File
@@ -0,0 +1,24 @@
# Xbox
Xbox connection notes.
## Server addresses
- US Server: `108.175.11.140`
- EU Server: `65.21.79.231`
## Overview
TODO: Fill in the converted guide content for this page.
## Requirements
TODO
## Setup
TODO
## Notes
TODO
+24
View File
@@ -0,0 +1,24 @@
# Hardcore Brutal Peeps
Brutal Peeps information for Hardcore.
## Server addresses
- US Server: `108.175.11.140`
- EU Server: `65.21.79.231`
## Overview
TODO: Fill in the converted guide content for this page.
## Requirements
TODO
## Setup
TODO
## Notes
TODO
@@ -0,0 +1,24 @@
# Hardcore Getting Started
Start here for Hardcore Peeps.
## Server addresses
- US Server: `108.175.11.140`
- EU Server: `65.21.79.231`
## Overview
TODO: Fill in the converted guide content for this page.
## Requirements
TODO
## Setup
TODO
## Notes
TODO
@@ -0,0 +1,24 @@
# Meseta and Bank Limits
Hardcore meseta and bank limits.
## Server addresses
- US Server: `108.175.11.140`
- EU Server: `65.21.79.231`
## Overview
TODO: Fill in the converted guide content for this page.
## Requirements
TODO
## Setup
TODO
## Notes
TODO
+24
View File
@@ -0,0 +1,24 @@
# Points System
Hardcore points system information.
## Server addresses
- US Server: `108.175.11.140`
- EU Server: `65.21.79.231`
## Overview
TODO: Fill in the converted guide content for this page.
## Requirements
TODO
## Setup
TODO
## Notes
TODO
+24
View File
@@ -0,0 +1,24 @@
# Hardcore Progression
Hardcore progression rules and expectations.
## Server addresses
- US Server: `108.175.11.140`
- EU Server: `65.21.79.231`
## Overview
TODO: Fill in the converted guide content for this page.
## Requirements
TODO
## Setup
TODO
## Notes
TODO
+24
View File
@@ -0,0 +1,24 @@
# Brutal Peeps
Brutal Peeps information for normal play.
## Server addresses
- US Server: `108.175.11.140`
- EU Server: `65.21.79.231`
## Overview
TODO: Fill in the converted guide content for this page.
## Requirements
TODO
## Setup
TODO
## Notes
TODO
+24
View File
@@ -0,0 +1,24 @@
# Crossplay Rooms
How crossplay rooms work on PSO Peeps.
## Server addresses
- US Server: `108.175.11.140`
- EU Server: `65.21.79.231`
## Overview
TODO: Fill in the converted guide content for this page.
## Requirements
TODO
## Setup
TODO
## Notes
TODO
+24
View File
@@ -0,0 +1,24 @@
# Peeps Getting Started
Start here for normal PSO Peeps play.
## Server addresses
- US Server: `108.175.11.140`
- EU Server: `65.21.79.231`
## Overview
TODO: Fill in the converted guide content for this page.
## Requirements
TODO
## Setup
TODO
## Notes
TODO
+24
View File
@@ -0,0 +1,24 @@
# XP Periods
XP period information for PSO Peeps.
## Server addresses
- US Server: `108.175.11.140`
- EU Server: `65.21.79.231`
## Overview
TODO: Fill in the converted guide content for this page.
## Requirements
TODO
## Setup
TODO
## Notes
TODO
+1 -1
View File
@@ -24,7 +24,7 @@
<section class="hero hero--slim" aria-label="Phantasy Star Online artwork"><div class="hero-image" role="img" aria-label="PSO Peeps hero artwork"></div></section>
<nav class="nav-bar" aria-label="Primary navigation">
<a href="https://circlewithadot.gitbook.io/psopeeps/connection-guide/connection-guide" target="_blank" rel="noopener noreferrer">Connection Guide</a><a href="leaderboards.html">Leaderboards</a><a href="drops.html">Drops</a><a href="bestiary.html">Bestiary</a><a href="account-ready.html">Account</a>
<a href="guide.html">Connection Guide</a><a href="leaderboards.html">Leaderboards</a><a href="drops.html">Drops</a><a href="bestiary.html">Bestiary</a><a href="account-ready.html">Account</a>
</nav>
<main class="placeholder-layout">
+112
View File
@@ -0,0 +1,112 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Guide - PSO Peeps</title>
<meta name="description" content="PSO Peeps connection and gameplay guides.">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css?v=local-guide-20260614-7">
<script src="app.js?v=saves-synced-20260609-2" defer></script>
</head>
<body>
<div class="site-shell">
<header class="site-header site-header--accountline" aria-label="Site header">
<a class="brand" href="index.html" aria-label="PSO Peeps home">
<span class="brand-logo brand-logo--text" aria-hidden="true">P</span>
<span class="brand-name">PSO PEEPS</span>
</a>
<div class="top-account-status"><span class="status-dot" aria-hidden="true"></span><a href="account-ready.html">Signed in as chuudoku</a></div>
</header>
<section class="hero hero--slim" aria-label="Phantasy Star Online artwork">
<div class="hero-image" role="img" aria-label="PSO Peeps hero artwork"></div>
</section>
<nav class="nav-bar" aria-label="Primary navigation">
<a href="guide.html">Connection Guide</a><a href="leaderboards.html">Leaderboards</a><a href="drops.html">Drops</a><a href="bestiary.html">Bestiary</a><a href="account-ready.html">Account</a>
</nav>
<main class="placeholder-layout guide-layout">
<section class="card placeholder-control-card guide-control-card">
<h1 class="section-title">Guide</h1>
<p class="guide-intro">
Use this guide to connect to PSO Peeps, learn the normal Peeps setup, or review Hardcore Peeps rules and progression.
Both ships are available below.
</p>
<div class="guide-server-grid" aria-label="Server addresses">
<div class="guide-server-card">
<span>US Server</span>
<strong>108.175.11.140</strong>
</div>
<div class="guide-server-card">
<span>EU Server</span>
<strong>65.21.79.231</strong>
</div>
</div>
<form class="placeholder-form guide-controls">
<div class="guide-control">
<label for="guide-level-0">Guide</label>
<select id="guide-level-0"></select>
</div>
<div class="guide-control" id="guide-level-1-wrap" hidden>
<label for="guide-level-1">Section</label>
<select id="guide-level-1"></select>
</div>
<div class="guide-control" id="guide-level-2-wrap" hidden>
<label for="guide-level-2">Platform</label>
<select id="guide-level-2"></select>
</div>
<div class="guide-control" id="guide-level-3-wrap" hidden>
<label for="guide-level-3">System</label>
<select id="guide-level-3"></select>
</div>
</form>
</section>
<section class="card placeholder-results-card">
<div class="blank-data-box guide-box" id="guide-content">Guide content will load here.</div>
</section>
</main>
<footer class="footer-bar">
<div class="social-links" aria-label="Social links">
<a href="#" aria-label="Discord">
<img src="icons/discord.png" alt="" width="24" height="24">
<span>Discord</span>
</a>
<a href="#" aria-label="Mastodon">
<img src="icons/mastodon.png" alt="" width="24" height="24">
<span>Mastodon</span>
</a>
<a href="#" aria-label="Bluesky">
<img src="icons/bluesky.png" alt="" width="24" height="24">
<span>Bluesky</span>
</a>
</div>
<div class="footer-legal" aria-label="Site license and software credits">
<p>
All content on this website is licensed under
<a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank" rel="noopener noreferrer">CC BY-NC-SA 4.0</a>.
</p>
<p>
PSO Peeps uses a modified version of
<a href="https://github.com/fuzziqersoftware/newserv" target="_blank" rel="noopener noreferrer">newserv</a>
from fuzziqersoftware.
<a href="https://github.com/fuzziqersoftware/newserv/blob/master/LICENSE" target="_blank" rel="noopener noreferrer">LICENSE</a>
</p>
</div>
</footer>
</div>
<script src="guide.js?v=local-guide-20260614-7" defer></script>
</body>
</html>
+492
View File
@@ -0,0 +1,492 @@
(() => {
"use strict";
const SERVER_INFO = {
us: "108.175.11.140",
eu: "65.21.79.231",
};
const GUIDE_TREE = {
connection: {
label: "Connection Guide",
children: {
overview: {
label: "Overview",
doc: "docs/guide/connection/overview.md",
},
dreamcast: {
label: "Dreamcast",
children: {
hardware: {
label: "Hardware",
doc: "docs/guide/connection/dreamcast/hardware.md",
},
flycastDialup: {
label: "Flycast (Dialup)",
doc: "docs/guide/connection/dreamcast/flycast-dialup.md",
},
flycastBba: {
label: "Flycast (BBA)",
doc: "docs/guide/connection/dreamcast/flycast-bba.md",
},
},
},
pc: {
label: "PC",
children: {
pc: {
label: "PC",
children: {
windows: {
label: "Windows",
doc: "docs/guide/connection/pc/pc-windows.md",
},
linux: {
label: "Linux",
doc: "docs/guide/connection/pc/pc-linux.md",
},
},
},
blueBurst: {
label: "Blue Burst",
children: {
windows: {
label: "Windows",
doc: "docs/guide/connection/pc/blue-burst-windows.md",
},
linux: {
label: "Linux",
doc: "docs/guide/connection/pc/blue-burst-linux.md",
},
},
},
},
},
gamecube: {
label: "GameCube",
children: {
hardwareBba: {
label: "Hardware (BBA)",
doc: "docs/guide/connection/gamecube/hardware-bba.md",
},
dolphin: {
label: "Dolphin",
doc: "docs/guide/connection/gamecube/dolphin.md",
},
nintendont: {
label: "Nintendont",
doc: "docs/guide/connection/gamecube/nintendont.md",
},
},
},
xbox: {
label: "Xbox",
doc: "docs/guide/connection/xbox.md",
},
psp: {
label: "Phantasy Star Portable",
doc: "docs/guide/connection/phantasy-star-portable.md",
},
serverSideSaves: {
label: "Server-side saves",
doc: "docs/guide/connection/server-side-saves.md",
},
commonProblems: {
label: "Common problems",
doc: "docs/guide/connection/common-problems.md",
},
quickReference: {
label: "Quick reference",
doc: "docs/guide/connection/quick-reference.md",
},
},
},
peeps: {
label: "Peeps Guide",
children: {
gettingStarted: {
label: "Getting Started",
doc: "docs/guide/peeps/getting-started.md",
},
crossplayRooms: {
label: "Crossplay Rooms",
doc: "docs/guide/peeps/crossplay-rooms.md",
},
xpPeriods: {
label: "XP Periods",
doc: "docs/guide/peeps/xp-periods.md",
},
brutalPeeps: {
label: "Brutal Peeps",
doc: "docs/guide/peeps/brutal-peeps.md",
},
},
},
hardcore: {
label: "Hardcore Peeps Guide",
children: {
gettingStarted: {
label: "Getting Started",
doc: "docs/guide/hardcore/getting-started.md",
},
progression: {
label: "Progression",
doc: "docs/guide/hardcore/progression.md",
},
mesetaAndBankLimits: {
label: "Meseta and Bank Limits",
doc: "docs/guide/hardcore/meseta-and-bank-limits.md",
},
pointsSystem: {
label: "Points System",
doc: "docs/guide/hardcore/points-system.md",
},
brutalPeeps: {
label: "Brutal Peeps",
doc: "docs/guide/hardcore/brutal-peeps.md",
},
},
},
};
const qs = (sel) => document.querySelector(sel);
const selects = [
qs("#guide-level-0"),
qs("#guide-level-1"),
qs("#guide-level-2"),
qs("#guide-level-3"),
];
const wrappers = [
null,
qs("#guide-level-1-wrap"),
qs("#guide-level-2-wrap"),
qs("#guide-level-3-wrap"),
];
const labels = [
null,
qs('label[for="guide-level-1"]'),
qs('label[for="guide-level-2"]'),
qs('label[for="guide-level-3"]'),
];
const box = qs("#guide-content");
let pendingPath = null;
let loadingPath = "";
const mdCache = new Map();
function esc(value) {
return String(value ?? "")
.replaceAll("&", "&amp;")
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;")
.replaceAll('"', "&quot;")
.replaceAll("'", "&#039;");
}
function nodeChildren(node) {
return node && node.children ? Object.entries(node.children) : [];
}
function fillSelect(select, children, preferredValue) {
if (!select) return "";
const entries = Object.entries(children || {});
const previous = preferredValue || select.value;
select.innerHTML = "";
for (const [key, child] of entries) {
const opt = document.createElement("option");
opt.value = key;
opt.textContent = child.label;
select.appendChild(opt);
}
if (entries.some(([key]) => key === previous)) {
select.value = previous;
} else if (entries.length) {
select.value = entries[0][0];
}
return select.value;
}
function setStatus(message, kind = "") {
if (!box) return;
box.innerHTML = `<div class="guide-status ${kind ? `guide-status--${esc(kind)}` : ""}">${esc(message)}</div>`;
}
function pathLabels(path) {
let node = { children: GUIDE_TREE };
const out = [];
for (const key of path) {
const next = node.children?.[key];
if (!next) break;
out.push(next.label);
node = next;
}
return out;
}
function safeHref(raw) {
const href = String(raw || "").trim();
if (/^(https?:|mailto:|#|\/|\.\/|\.\.\/)/i.test(href)) return href;
if (!/^[a-z][a-z0-9+.-]*:/i.test(href)) return href;
return "#";
}
function inlineMarkdown(raw) {
const codeSpans = [];
let text = String(raw ?? "").replace(/`([^`]+)`/g, (_, code) => {
const token = `@@CODE${codeSpans.length}@@`;
codeSpans.push(`<code>${esc(code)}</code>`);
return token;
});
let html = esc(text);
html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_, label, href) => {
return `<a href="${esc(safeHref(href))}">${label}</a>`;
});
html = html
.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>")
.replace(/\*([^*]+)\*/g, "<em>$1</em>");
codeSpans.forEach((span, index) => {
html = html.replaceAll(`@@CODE${index}@@`, span);
});
return html;
}
function renderMarkdown(markdown) {
const lines = String(markdown || "").replace(/\r\n/g, "\n").split("\n");
const out = [];
let paragraph = [];
let list = [];
let orderedList = [];
let code = [];
let inFence = false;
const fence = String.fromCharCode(96, 96, 96);
function flushParagraph() {
if (!paragraph.length) return;
out.push(`<p>${inlineMarkdown(paragraph.join(" "))}</p>`);
paragraph = [];
}
function flushList() {
if (!list.length) return;
out.push(`<ul>${list.map((item) => `<li>${inlineMarkdown(item)}</li>`).join("")}</ul>`);
list = [];
}
function flushOrderedList() {
if (!orderedList.length) return;
out.push(`<ol>${orderedList.map((item) => `<li>${inlineMarkdown(item)}</li>`).join("")}</ol>`);
orderedList = [];
}
function flushCode() {
if (!code.length) return;
out.push(`<pre><code>${esc(code.join("\n"))}</code></pre>`);
code = [];
}
function flushTextBlocks() {
flushParagraph();
flushList();
flushOrderedList();
}
for (const line of lines) {
const trimmed = line.trim();
if (trimmed.startsWith(fence)) {
flushTextBlocks();
if (inFence) {
flushCode();
inFence = false;
} else {
inFence = true;
code = [];
}
continue;
}
if (inFence) {
code.push(line);
continue;
}
if (/^ {4,}/.test(line)) {
flushTextBlocks();
code.push(line.replace(/^ {4}/, ""));
continue;
}
if (code.length && trimmed === "") {
flushCode();
continue;
}
if (code.length) {
flushCode();
}
if (!trimmed) {
flushTextBlocks();
continue;
}
if (/^(-{3,}|\*{3,}|_{3,})$/.test(trimmed)) {
flushTextBlocks();
out.push("<hr>");
continue;
}
const heading = trimmed.match(/^(#{1,5})\s+(.+)$/);
if (heading) {
flushTextBlocks();
const level = Math.min(heading[1].length + 1, 6);
out.push(`<h${level}>${inlineMarkdown(heading[2])}</h${level}>`);
continue;
}
const bullet = line.match(/^\s*[-*]\s+(.+)$/);
if (bullet) {
flushParagraph();
flushOrderedList();
list.push(bullet[1]);
continue;
}
const ordered = line.match(/^\s*\d+\.\s+(.+)$/);
if (ordered) {
flushParagraph();
flushList();
orderedList.push(ordered[1]);
continue;
}
paragraph.push(trimmed);
}
flushTextBlocks();
flushCode();
return `<div class="guide-doc">${out.join("\n")}</div>`;
}
async function loadDoc(node, path) {
if (!node.doc) {
setStatus("Choose a guide page from the menus above.");
return;
}
const pathKey = path.join("/");
loadingPath = pathKey;
setStatus(`Loading ${pathLabels(path).join(" ")}...`);
try {
let markdown = mdCache.get(node.doc);
if (!markdown) {
const response = await fetch(node.doc, { cache: "no-cache" });
if (!response.ok) {
throw new Error(`Unable to load ${node.doc} (${response.status})`);
}
markdown = await response.text();
mdCache.set(node.doc, markdown);
}
if (loadingPath !== pathKey) return;
const breadcrumb = pathLabels(path).join(" ");
box.innerHTML = `
<div class="guide-breadcrumb">${esc(breadcrumb)}</div>
${renderMarkdown(markdown)}
`;
} catch (err) {
if (loadingPath !== pathKey) return;
setStatus(err?.message || "Unable to load guide page.", "error");
}
}
function updateHash(path) {
const next = `#${path.join("/")}`;
if (window.location.hash !== next) {
history.replaceState(null, "", next);
}
}
function readHashPath() {
const raw = window.location.hash.replace(/^#/, "").trim();
if (!raw) return null;
return raw.split("/").filter(Boolean);
}
function syncGuide(changedLevel = -1) {
if (!box || selects.some((select) => !select)) return;
if (changedLevel >= 0) {
for (let i = changedLevel + 1; i < selects.length; i += 1) {
selects[i].value = "";
}
}
let node = { children: GUIDE_TREE };
const path = [];
for (let level = 0; level < selects.length; level += 1) {
const select = selects[level];
if (!node.children) {
for (let hideLevel = level; hideLevel < wrappers.length; hideLevel += 1) {
if (wrappers[hideLevel]) wrappers[hideLevel].hidden = true;
}
break;
}
const preferred = pendingPath?.[level] || select.value;
const selected = fillSelect(select, node.children, preferred);
if (wrappers[level]) wrappers[level].hidden = false;
const current = node.children[selected];
path.push(selected);
node = current;
if (labels[level]) {
labels[level].textContent =
level === 1 && path[0] === "connection" ? "Platform" :
level === 1 ? "Topic" :
level === 2 && path[0] === "connection" && path[1] === "pc" ? "Client" :
level === 2 && path[0] === "connection" ? "Setup" :
level === 3 ? "System" :
"Option";
}
}
pendingPath = null;
for (let level = 1; level < wrappers.length; level += 1) {
const parent = path.slice(0, level).reduce((cur, key) => cur?.children?.[key], { children: GUIDE_TREE });
if (!parent?.children && wrappers[level]) wrappers[level].hidden = true;
}
updateHash(path);
loadDoc(node, path);
}
document.addEventListener("DOMContentLoaded", () => {
pendingPath = readHashPath();
selects.forEach((select, index) => {
select?.addEventListener("change", () => syncGuide(index));
});
syncGuide();
});
})();
+1 -1
View File
@@ -37,7 +37,7 @@
</section>
<nav class="nav-bar" aria-label="Primary navigation">
<a href="https://circlewithadot.gitbook.io/psopeeps/connection-guide/connection-guide" target="_blank" rel="noopener noreferrer">Connection Guide</a>
<a href="guide.html">Connection Guide</a>
<a href="leaderboards.html">Leaderboards</a>
<a href="drops.html">Drops</a>
<a href="bestiary.html">Bestiary</a>
+1 -1
View File
@@ -24,7 +24,7 @@
<section class="hero hero--slim" aria-label="Phantasy Star Online artwork"><div class="hero-image" role="img" aria-label="PSO Peeps hero artwork"></div></section>
<nav class="nav-bar" aria-label="Primary navigation">
<a href="https://circlewithadot.gitbook.io/psopeeps/connection-guide/connection-guide" target="_blank" rel="noopener noreferrer">Connection Guide</a><a href="leaderboards.html">Leaderboards</a><a href="drops.html">Drops</a><a href="bestiary.html">Bestiary</a><a href="account-ready.html">Account</a>
<a href="guide.html">Connection Guide</a><a href="leaderboards.html">Leaderboards</a><a href="drops.html">Drops</a><a href="bestiary.html">Bestiary</a><a href="account-ready.html">Account</a>
</nav>
<main class="placeholder-layout">
+341
View File
@@ -1915,3 +1915,344 @@ button.inline-link,
}
}
/* Local guide page */
.guide-layout {
gap: 12px;
}
.guide-control-card {
display: block;
}
.guide-intro {
max-width: 920px;
margin: 0 0 18px;
color: var(--muted-text);
line-height: 1.55;
}
.guide-server-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px;
margin: 0 0 18px;
}
.guide-server-card {
border: 1px solid var(--panel-border);
border-radius: 10px;
padding: 14px 16px;
background: rgba(0, 0, 0, 0.22);
}
.guide-server-card span {
display: block;
margin-bottom: 6px;
color: var(--muted-text);
font-size: 0.72rem;
font-weight: 800;
letter-spacing: 0.12em;
text-transform: uppercase;
}
.guide-server-card strong {
color: var(--text);
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
font-size: 0.95rem;
}
.placeholder-form.guide-controls {
display: grid;
grid-template-columns: repeat(4, minmax(150px, 1fr));
gap: 12px;
margin: 0;
}
.guide-control {
min-width: 0;
}
.guide-box.blank-data-box {
display: block;
min-height: 360px;
padding: 28px 32px;
text-align: left;
}
.guide-status {
color: var(--muted-text);
}
.guide-status--error {
color: #ffb4b4;
}
.guide-breadcrumb {
margin-bottom: 18px;
color: var(--muted-text);
font-size: 0.78rem;
font-weight: 800;
letter-spacing: 0.08em;
}
.guide-doc {
max-width: 880px;
margin: 0 auto;
color: var(--text);
line-height: 1.65;
}
.guide-doc h2,
.guide-doc h3,
.guide-doc h4,
.guide-doc h5 {
margin: 1.35em 0 0.55em;
color: var(--text);
}
.guide-doc h2:first-child {
margin-top: 0;
}
.guide-doc p {
margin: 0 0 1em;
}
.guide-doc ul {
margin: 0 0 1em 1.4em;
padding: 0;
}
.guide-doc li {
margin: 0.3em 0;
}
.guide-doc code {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
}
.guide-doc pre {
overflow-x: auto;
padding: 12px;
border-radius: 10px;
background: rgba(0, 0, 0, 0.45);
}
@media (max-width: 900px) {
.placeholder-form.guide-controls {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 640px) {
.guide-server-grid,
.placeholder-form.guide-controls {
grid-template-columns: 1fr;
}
.guide-box.blank-data-box {
padding: 22px;
}
}
/* Guide markdown readability fixes */
.guide-box.blank-data-box {
align-items: stretch;
justify-content: flex-start;
font-size: 1rem;
font-weight: 400;
letter-spacing: normal;
text-transform: none;
}
.guide-box .guide-breadcrumb {
text-align: left;
}
.guide-doc {
font-weight: 400;
letter-spacing: normal;
text-transform: none;
}
.guide-doc h2 {
font-size: 1.55rem;
font-weight: 800;
}
.guide-doc h3 {
font-size: 1.15rem;
font-weight: 800;
}
.guide-doc p,
.guide-doc li {
color: var(--text);
font-weight: 400;
}
.guide-doc strong {
font-weight: 800;
}
.guide-doc hr {
margin: 24px 0;
border: 0;
border-top: 1px solid var(--panel-border);
}
.guide-doc pre {
margin: 12px 0 22px;
white-space: pre;
}
.guide-doc pre code {
display: block;
color: var(--text);
font-weight: 400;
line-height: 1.45;
}
/* Guide Markdown polish */
.guide-box.blank-data-box {
align-items: stretch !important;
justify-content: flex-start !important;
text-align: left !important;
font-size: 1rem !important;
font-weight: 400 !important;
letter-spacing: normal !important;
text-transform: none !important;
}
.guide-doc {
max-width: 880px;
margin: 0 auto;
color: var(--text);
line-height: 1.65;
font-size: 1rem;
font-weight: 400 !important;
letter-spacing: normal !important;
text-transform: none !important;
}
.guide-doc h2 {
margin: 0 0 18px;
font-size: 1.8rem;
line-height: 1.2;
font-weight: 800;
}
.guide-doc h3 {
margin: 28px 0 12px;
font-size: 1.25rem;
line-height: 1.3;
font-weight: 800;
}
.guide-doc p {
margin: 0 0 18px;
color: var(--text);
font-weight: 400;
}
.guide-doc ul {
margin: 0 0 20px 1.35rem;
padding: 0;
}
.guide-doc li {
margin: 7px 0;
color: var(--text);
font-weight: 400;
}
.guide-doc li::marker {
color: #e6adc1;
}
.guide-doc strong {
font-weight: 800;
}
.guide-doc hr {
margin: 28px 0;
border: 0;
border-top: 1px solid rgba(230, 173, 193, 0.25);
}
.guide-doc pre {
display: block;
box-sizing: border-box;
width: 100%;
margin: 12px 0 24px;
padding: 16px 18px;
overflow-x: auto;
white-space: pre;
border: 1px solid rgba(230, 173, 193, 0.28);
border-radius: 10px;
background: rgba(70, 35, 48, 0.28);
}
.guide-doc pre code {
display: block;
color: var(--text);
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
font-size: 0.92rem;
line-height: 1.45;
font-weight: 400;
}
.guide-doc code {
padding: 0.08rem 0.25rem;
border: 1px solid rgba(230, 173, 193, 0.25);
border-radius: 4px;
background: rgba(70, 35, 48, 0.28);
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
}
.guide-doc pre code {
padding: 0;
border: 0;
background: transparent;
}
/* Guide Markdown neutral site-color override */
.guide-doc li::marker {
color: var(--muted-text) !important;
}
.guide-doc hr {
border-top-color: var(--panel-border) !important;
}
.guide-doc pre {
border-color: var(--panel-border) !important;
background: rgba(0, 0, 0, 0.24) !important;
}
.guide-doc code {
border-color: var(--panel-border) !important;
background: rgba(0, 0, 0, 0.24) !important;
color: var(--text) !important;
}
.guide-doc pre code {
border: 0 !important;
background: transparent !important;
color: var(--text) !important;
}
/* Guide ordered-list support */
.guide-doc ol {
margin: 0 0 20px 1.35rem;
padding: 0;
}
.guide-doc ol li {
margin: 7px 0;
padding-left: 0.25rem;
}
.guide-doc ol li::marker {
color: var(--muted-text);
}