feat: add About page with detailed game mechanics and links
Build Images and Deploy / Update-PROD-Stack (push) Successful in 1m51s

This commit is contained in:
2026-03-20 20:49:18 -04:00
parent 5020f38090
commit cd8e23747b
3 changed files with 231 additions and 1 deletions
+214
View File
@@ -0,0 +1,214 @@
import Link from 'next/link'
import { BookOpen, TrendingUp, TrendingDown, Coins, Shuffle, RotateCcw, Building2, ExternalLink, Github } from 'lucide-react'
export const metadata = {
title: 'About — HashEx',
description: 'How HashEx works: rules, features, and quirks of the hashtag stock market.',
}
function Section({ title, icon: Icon, children }: { title: string; icon: React.ElementType; children: React.ReactNode }) {
return (
<section className="space-y-3">
<div className="flex items-center gap-2 border-b border-surface-border pb-2">
<Icon className="h-5 w-5 text-indigo-400 shrink-0" />
<h2 className="text-lg font-semibold">{title}</h2>
</div>
{children}
</section>
)
}
function Rule({ label, children }: { label: string; children: React.ReactNode }) {
return (
<div className="flex gap-3 text-sm">
<span className="text-indigo-400 font-medium shrink-0 w-32">{label}</span>
<span className="text-slate-300">{children}</span>
</div>
)
}
export default function AboutPage() {
return (
<div className="max-w-2xl mx-auto space-y-10 py-4">
{/* Header */}
<div>
<div className="flex items-center gap-3 mb-2">
<BookOpen className="h-7 w-7 text-indigo-400" />
<h1 className="text-3xl font-bold">About HashEx</h1>
</div>
<p className="text-slate-400">
HashEx is a stock-market simulation game where the &quot;stocks&quot; are Mastodon hashtags.
Prices update automatically based on real post activity. Start with{' '}
<span className="text-white font-medium">$2,000</span> and see how much you can grow it.
</p>
</div>
{/* Getting started */}
<Section title="Getting Started" icon={TrendingUp}>
<div className="space-y-2 text-sm text-slate-300">
<p>
Every new account starts with <span className="text-white font-medium">$2,000</span> in play money and{' '}
<span className="text-white font-medium">1 research point</span>.
</p>
<p>
Use research points to unlock hashtags. Each point lets you search for a tag on Mastodon if it has
activity, it gets added to the exchange with a live price. You earn more points each day based on your
account balance.
</p>
<div className="bg-surface-card border border-surface-border rounded-lg p-3 space-y-1 mt-2">
<p className="text-xs text-slate-500 uppercase tracking-wider mb-1">Daily research points</p>
<div className="grid grid-cols-2 gap-x-4 text-xs">
<span className="text-slate-400">Balance under $10k</span><span>1 pt / day</span>
<span className="text-slate-400">$10k+</span><span>2 pts / day</span>
<span className="text-slate-400">$100k+</span><span>3 pts / day</span>
<span className="text-slate-400">$1M+</span><span>5 pts / day</span>
</div>
</div>
</div>
</Section>
{/* Pricing */}
<Section title="How Prices Work" icon={Coins}>
<div className="space-y-2 text-sm text-slate-300">
<p>
Every hashtag has a price calculated from its post rate on Mastodon:
</p>
<div className="bg-surface-card border border-surface-border rounded-lg px-4 py-3 font-mono text-center text-indigo-300">
price = max($0.25, posts_per_hour × $0.25)
</div>
<p>
Prices update on a regular cycle. A hashtag that goes completely quiet for long enough will be
automatically <span className="text-orange-400">deactivated</span> you&apos;ll get a warning on the
home page if any of your positions are at risk. Research it again to reactivate it.
</p>
</div>
</Section>
{/* Trade types */}
<Section title="Trade Types" icon={TrendingUp}>
<div className="space-y-3">
<Rule label="Buy Long">
Bet the price goes <span className="text-emerald-400">up</span>. You buy shares and profit when the
price rises above your average buy price.
</Rule>
<Rule label="Sell Long">
Close or reduce a long position. Profit = (current price avg buy price) × shares.
</Rule>
<Rule label="Buy Short">
Bet the price goes <span className="text-red-400">down</span>. You put up collateral and profit when
the price falls below your entry.
</Rule>
<Rule label="Sell Short">
Close a short. Profit = (avg entry current price) × shares. If the price rose above your entry you
take a loss and your balance <span className="text-red-400">can go negative</span>.
</Rule>
</div>
<p className="text-xs text-slate-500 mt-2">
All trades are validated server-side. You cannot buy more than your balance, sell more shares than you hold,
or trade a hashtag you haven&apos;t researched.
</p>
</Section>
{/* Short selling specifics */}
<Section title="Short Selling — Quirks & Risks" icon={TrendingDown}>
<div className="space-y-2 text-sm text-slate-300">
<p>
Shorts use a <span className="text-white font-medium">collateral model</span>. When you buy short, the
cost is <code className="text-xs bg-surface-card px-1 py-0.5 rounded">price × shares</code>. When you
close, you receive back <code className="text-xs bg-surface-card px-1 py-0.5 rounded">(2 × entry current) × shares</code>.
</p>
<p>
This means losses are <span className="text-red-400">uncapped</span>. If the price doubles, your
payout is zero. If it triples, your balance goes negative.
</p>
<p>
A <span className="text-red-400">negative balance</span> isn&apos;t game-over you can still trade, but
your total portfolio value will show in red. You can reset your account at any time from your profile page.
</p>
</div>
</Section>
{/* Hedge Funds */}
<Section title="Hedge Funds" icon={Building2}>
<div className="space-y-2 text-sm text-slate-300">
<p>
Admins can create <span className="text-white font-medium">Hedge Funds</span> shared pools of capital
that multiple players can manage together.
</p>
<p>
As a fund manager you trade on behalf of the fund by appending{' '}
<code className="text-xs bg-surface-card px-1 py-0.5 rounded">?fund=[slug]</code> to any hashtag page
(there are quick links on the fund page). A banner confirms you&apos;re in Fund Mode.
</p>
<p>
Outside investors can buy and sell <span className="text-white font-medium">fund shares</span> from the
fund&apos;s page. The NAV (net asset value) per share is calculated live from the fund&apos;s total
portfolio. Fund investments show up in your Holdings and Trade History.
</p>
<p className="text-slate-500 text-xs">
Fund shares are stored to 6 decimal places. Fund accounts cannot sign in directly and do not earn
research points or play the lottery.
</p>
</div>
</Section>
{/* Account reset */}
<Section title="Account Reset" icon={RotateCcw}>
<div className="space-y-2 text-sm text-slate-300">
<p>
You can reset your account from your profile page at any time. All positions are closed and your
balance returns to $2,000.
</p>
<Rule label="Keep history">
Your trade log is preserved. A{' '}
<span className="text-purple-400">Donation</span> entry is recorded if you were in profit, or a{' '}
<span className="text-red-400">Bankruptcy</span> if you were in the red, followed by an{' '}
<span className="text-emerald-400">Account Open</span>.
</Rule>
<Rule label="Erase history">
All trade records are deleted along with the reset.
</Rule>
</div>
</Section>
{/* Lucky Dip */}
<Section title="Lucky Dip" icon={Shuffle}>
<p className="text-sm text-slate-300">
Once per day you can open the Lucky Dip lottery. Pick a box most are empty, but a few hold cash prizes.
Winnings are added directly to your balance.
</p>
</Section>
{/* Links */}
<section className="bg-surface-card border border-surface-border rounded-xl p-5 space-y-3">
<h2 className="text-sm font-semibold text-slate-300 uppercase tracking-wider">Links</h2>
<div className="space-y-2">
<a
href="https://mastodon.nervesocket.com/@ThaMunsta"
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 text-sm text-indigo-400 hover:text-indigo-300 transition-colors"
>
<ExternalLink className="h-4 w-4 shrink-0" />
@ThaMunsta on Mastodon questions, feedback, bug reports
</a>
<a
href="https://git.dev.nervesocket.com/ThaMunsta/hashex"
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 text-sm text-indigo-400 hover:text-indigo-300 transition-colors"
>
<Github className="h-4 w-4 shrink-0" />
Source code contribute or run your own instance
</a>
</div>
</section>
<div className="text-center">
<Link href="/" className="text-sm text-indigo-400 hover:text-indigo-300">
Back to the exchange
</Link>
</div>
</div>
)
}
+13
View File
@@ -0,0 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<!-- dark indigo rounded background -->
<rect width="32" height="32" rx="7" fill="#1e1b4b"/>
<!-- # symbol — slightly angled vertical bars, two horizontal bars -->
<!-- left vertical bar (slants slightly: top-right to bottom-left) -->
<line x1="12" y1="6" x2="10" y2="26" stroke="#a5b4fc" stroke-width="2.8" stroke-linecap="round"/>
<!-- right vertical bar -->
<line x1="20" y1="6" x2="18" y2="26" stroke="#a5b4fc" stroke-width="2.8" stroke-linecap="round"/>
<!-- upper horizontal bar -->
<line x1="6" y1="13" x2="26" y2="13" stroke="#a5b4fc" stroke-width="2.8" stroke-linecap="round"/>
<!-- lower horizontal bar -->
<line x1="5" y1="20" x2="25" y2="20" stroke="#a5b4fc" stroke-width="2.8" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 809 B

+4 -1
View File
@@ -102,7 +102,10 @@ export default async function HomePage() {
</h1> </h1>
<p className="text-slate-400 max-w-xl mx-auto"> <p className="text-slate-400 max-w-xl mx-auto">
Trade hashtags like stocks. Prices are driven by real-time activity on Mastodon. Trade hashtags like stocks. Prices are driven by real-time activity on Mastodon.
Research a tag to unlock it, then buy long or short. Research a tag to unlock it, then buy long or short.{' '}
<Link href="/about" className="text-indigo-400 hover:text-indigo-300 underline underline-offset-2">
Learn more
</Link>
</p> </p>
<div className="flex justify-center gap-4 mt-6"> <div className="flex justify-center gap-4 mt-6">
{session ? ( {session ? (