Files
code_of_conquest_dnd/mockups/Pause Menu.dc.html
Phillip Tarrant 49bc6b22c0 docs(mockups): add the UI/systems bible (11 screens + README)
High-fidelity HTML/CSS/JS design references for the tactical-CRPG direction —
title, character creation, character sheet, inventory, world map, quest log,
shop, pause/settings, dialogue, combat HUD, main exploration window. README is
the handoff spec (visual system, per-screen state models, Godot translation
notes). Not production code — the source of truth for the game's look + systems.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 16:06:23 -05:00

205 lines
12 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet data-dc-atomics>
<link href="https://fonts.googleapis.com/css2?family=Architects+Daughter&display=swap" rel="stylesheet">
<style>
body{margin:0;background:#0f0d0b;font-family:system-ui,sans-serif}
a{color:#8f3a34}a:hover{color:#6f2b26}
input[type=range]{-webkit-appearance:none;appearance:none;width:230px;height:6px;border-radius:4px;background:#cbb684;outline:none;cursor:pointer}
input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:20px;height:20px;border-radius:50%;background:#8f6a2a;border:2px solid #5a4326;cursor:pointer}
input[type=range]::-moz-range-thumb{width:18px;height:18px;border-radius:50%;background:#8f6a2a;border:2px solid #5a4326;cursor:pointer}
select{font-family:ui-monospace,monospace;font-size:13px;color:#3a2f1c;background:#f6efdd;border:1px solid #a99464;border-radius:8px;padding:9px 12px;outline:none;cursor:pointer;min-width:200px}
</style>
</helmet>
<div style="width:1920px;height:1080px;position:relative;display:flex;align-items:center;justify-content:center;background:repeating-linear-gradient(135deg,#26221c 0 16px,#221e18 16px 32px)">
<!-- dim -->
<div style="position:absolute;inset:0;background:rgba(8,6,4,.72);backdrop-filter:blur(2px)"></div>
<!-- panel -->
<div style="position:relative;width:1560px;height:920px;display:flex;border:8px solid #1a1512;border-radius:16px;box-shadow:0 30px 80px rgba(0,0,0,.6);overflow:hidden">
<div style="position:absolute;inset:8px;border:1.5px solid #a9843f;border-radius:9px;pointer-events:none;opacity:.5;z-index:2"></div>
<!-- ===== LEFT RAIL ===== -->
<div style="width:400px;flex:none;background:repeating-linear-gradient(135deg,#211d17 0 16px,#1d1914 16px 32px);box-sizing:border-box;padding:44px 38px;display:flex;flex-direction:column;position:relative">
<div style="position:absolute;inset:0;background:radial-gradient(120% 50% at 50% 0%,rgba(0,0,0,0) 50%,rgba(0,0,0,.5) 100%);pointer-events:none"></div>
<div style="position:relative">
<div style="font:13px ui-monospace,monospace;letter-spacing:.24em;color:#8a7f6c">THE WORLD WAITS</div>
<div style="font:600 54px 'Architects Daughter',cursive;color:#e8d9b6;line-height:1;margin-top:6px">Paused</div>
<div style="font:13px ui-monospace,monospace;letter-spacing:.06em;color:#a9843f;margin-top:10px">CHAPTER II · THE LOWER WARD</div>
</div>
<div style="position:relative;display:flex;flex-direction:column;gap:12px;margin-top:44px">
<div style="padding:16px 20px;border:1.5px solid #8f3a34;border-radius:10px;background:linear-gradient(180deg,#a5423a,#7a2f29);color:#f4e6cf;font:600 18px system-ui;letter-spacing:.04em;cursor:pointer" style-hover="background:linear-gradient(180deg,#b8524a,#8f3a34)">▸ Resume</div>
<div style="padding:15px 20px;border:1px solid #4a4238;border-radius:10px;background:rgba(30,26,20,.7);color:#d8ccb2;font:600 16px system-ui;cursor:pointer" style-hover="border-color:#a9843f">Save Game</div>
<div style="padding:15px 20px;border:1px solid #4a4238;border-radius:10px;background:rgba(30,26,20,.7);color:#d8ccb2;font:600 16px system-ui;cursor:pointer" style-hover="border-color:#a9843f">Load Game</div>
<div style="padding:15px 20px;border:1px solid #4a4238;border-radius:10px;background:rgba(30,26,20,.7);color:#caa39c;font:600 16px system-ui;cursor:pointer" style-hover="border-color:#8f3a34">Quit to Title</div>
</div>
<div style="position:relative;margin-top:auto;font:12px ui-monospace,monospace;line-height:1.9;color:#7a7060">
<div>PLAYTIME · <span style="color:#c9bda3">14:22:07</span></div>
<div>AUTOSAVED · <span style="color:#c9bda3">6 min ago</span></div>
<div style="color:#8f6a5a;margin-top:6px;font-family:'Architects Daughter',cursive;font-size:13px">Permadeath is on. Be careful out there.</div>
</div>
</div>
<!-- ===== RIGHT: SETTINGS ===== -->
<div style="flex:1;min-width:0;background:linear-gradient(180deg,#ece2ca,#e4d8bd);box-sizing:border-box;padding:38px 46px;display:flex;flex-direction:column;gap:22px">
<div style="display:flex;align-items:flex-end;justify-content:space-between;border-bottom:2px solid #bfa878;padding-bottom:16px">
<div style="font:600 30px 'Architects Daughter',cursive;letter-spacing:.04em;color:#5a4326">Settings</div>
<div style="font:11px ui-monospace,monospace;color:#a99464;border:1px solid #cbb684;border-radius:6px;padding:6px 10px;cursor:pointer" style-hover="background:#e6d9b8">RESTORE DEFAULTS</div>
</div>
<!-- tabs -->
<div style="display:flex;gap:8px">
<sc-for list="{{ tabs }}" as="t" hint-placeholder-count="4">
<div onClick="{{ t.onSelect }}" style="font:12px ui-monospace,monospace;letter-spacing:.1em;padding:9px 18px;border-radius:8px;border:1px solid {{ t.border }};background:{{ t.bg }};color:{{ t.fg }};cursor:pointer">{{ t.label }}</div>
</sc-for>
</div>
<!-- controls -->
<div style="flex:1;overflow-y:auto;display:flex;flex-direction:column">
<sc-for list="{{ controls }}" as="c" hint-placeholder-count="6">
<div style="display:flex;align-items:center;gap:20px;padding:16px 4px;border-bottom:1px solid #d9cba6">
<div style="flex:1;min-width:0">
<div style="font:600 17px system-ui;color:#3a2f1c">{{ c.label }}</div>
<sc-if value="{{ c.hasDesc }}" hint-placeholder-val="{{ false }}"><div style="font:13px/1.4 Georgia,serif;font-style:italic;color:#7a684a;margin-top:2px">{{ c.desc }}</div></sc-if>
</div>
<div style="flex:none;display:flex;align-items:center;gap:14px">
<sc-if value="{{ c.isSlider }}" hint-placeholder-val="{{ false }}">
<span style="font:600 14px ui-monospace,monospace;color:#8f6a2a;width:52px;text-align:right">{{ c.valueLabel }}</span>
<input type="range" min="{{ c.min }}" max="{{ c.max }}" step="1" value="{{ c.def }}" onInput="{{ c.onChange }}" />
</sc-if>
<sc-if value="{{ c.isToggle }}" hint-placeholder-val="{{ false }}">
<div onClick="{{ c.onToggle }}" style="width:50px;height:28px;border-radius:15px;background:{{ c.trackBg }};border:1px solid #8a7748;position:relative;cursor:pointer;transition:background .15s"><div style="position:absolute;top:2px;left:2px;width:22px;height:22px;border-radius:50%;background:#f6efdd;box-shadow:0 1px 2px rgba(0,0,0,.3);transform:{{ c.knobShift }};transition:transform .15s"></div></div>
</sc-if>
<sc-if value="{{ c.isSelect }}" hint-placeholder-val="{{ false }}">
<select onChange="{{ c.onChange }}" value="{{ c.current }}">
<sc-for list="{{ c.options }}" as="o" hint-placeholder-count="3">
<option value="{{ o.value }}">{{ o.label }}</option>
</sc-for>
</select>
</sc-if>
<sc-if value="{{ c.isKeybind }}" hint-placeholder-val="{{ false }}">
<div style="display:flex;gap:6px">
<sc-for list="{{ c.keys }}" as="k" hint-placeholder-count="1">
<span style="font:600 13px ui-monospace,monospace;color:#4a3f2c;background:#f6efdd;border:1px solid #a99464;border-bottom-width:3px;border-radius:6px;padding:6px 11px;min-width:14px;text-align:center">{{ k }}</span>
</sc-for>
</div>
</sc-if>
</div>
</div>
</sc-for>
</div>
</div>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props="{&quot;$preview&quot;:{&quot;width&quot;:1920,&quot;height&quot;:1080}}">
class Component extends DCLogic {
state = {
tab: 'gameplay',
s: {
master: 80, music: 60, sfx: 75, ambience: 50, subtitles: true,
windowMode: 'fullscreen', resolution: '1920x1080', brightness: 55, motionBlur: false, vsync: true, damageFlash: true,
difficulty: 'bastard', permadeath: true, tutorial: true, gore: true, textSpeed: 70, autosave: 'camp',
mouseSens: 50, invertY: false,
},
};
set(key, val) { this.setState(st => ({ s: { ...st.s, [key]: val } })); }
slider(key, label, desc) {
return {
isSlider: true, label, desc: desc || '', hasDesc: !!desc,
min: 0, max: 100, def: this.state.s[key],
valueLabel: this.state.s[key] + '%',
onChange: (e) => this.set(key, +e.target.value),
};
}
toggle(key, label, desc) {
const on = this.state.s[key];
return {
isToggle: true, label, desc: desc || '', hasDesc: !!desc,
trackBg: on ? '#8f6a2a' : '#c9b78a',
knobShift: on ? 'translateX(22px)' : 'translateX(0)',
onToggle: () => this.set(key, !on),
};
}
select(key, label, options, desc) {
return {
isSelect: true, label, desc: desc || '', hasDesc: !!desc,
current: this.state.s[key],
options: options.map(o => ({ value: o[0], label: o[1] })),
onChange: (e) => this.set(key, e.target.value),
};
}
keybind(label, keys) { return { isKeybind: true, label, hasDesc: false, keys }; }
renderVals() {
const tab = this.state.tab;
const tabs = [
{ id: 'gameplay', label: 'GAMEPLAY' },
{ id: 'video', label: 'VIDEO' },
{ id: 'audio', label: 'AUDIO' },
{ id: 'controls', label: 'CONTROLS' },
].map(t => ({
label: t.label,
onSelect: () => this.setState({ tab: t.id }),
bg: t.id === tab ? '#8f3a34' : '#efe6cf',
fg: t.id === tab ? '#f1e8d2' : '#6a5a3a',
border: t.id === tab ? '#8f3a34' : '#cbb684',
}));
let controls = [];
if (tab === 'gameplay') {
controls = [
this.select('difficulty', 'Difficulty', [['cutthroat', 'Cutthroat — story'], ['bastard', 'Bastard — normal'], ['nightmare', 'Nightmare — hard'], ['ironblood', 'Ironblood — brutal']]),
this.toggle('permadeath', 'Permadeath', 'When you die, the save dies with you.'),
this.toggle('gore', 'Gore & Wounds', 'Blood, infection, and the state bodies get into.'),
this.toggle('tutorial', 'Tutorial Hints', 'The DM explains the rules as you go.'),
this.slider('textSpeed', 'Narration Speed', 'How fast the DM writes the world.'),
this.select('autosave', 'Autosave', [['scene', 'Every scene'], ['camp', 'At camp only'], ['manual', 'Manual only']]),
];
} else if (tab === 'video') {
controls = [
this.select('windowMode', 'Window Mode', [['fullscreen', 'Fullscreen'], ['borderless', 'Borderless'], ['windowed', 'Windowed']]),
this.select('resolution', 'Resolution', [['2560x1440', '2560 × 1440'], ['1920x1080', '1920 × 1080'], ['1600x900', '1600 × 900'], ['1280x720', '1280 × 720']]),
this.slider('brightness', 'Brightness', 'The Margreave is meant to be dark. A little.'),
this.toggle('vsync', 'VSync', ''),
this.toggle('motionBlur', 'Motion Blur', ''),
this.toggle('damageFlash', 'Damage Flash', 'The screen reddens when you take a hit.'),
];
} else if (tab === 'audio') {
controls = [
this.slider('master', 'Master Volume', ''),
this.slider('music', 'Music', ''),
this.slider('sfx', 'Effects', ''),
this.slider('ambience', 'Ambience', 'Rain, rats, and distant screaming.'),
this.toggle('subtitles', 'Subtitles', 'Show the DM\u2019s narration as text.'),
];
} else {
controls = [
this.keybind('Move', ['W', 'A', 'S', 'D']),
this.keybind('Interact', ['E']),
this.keybind('Attack', ['LMB']),
this.keybind('End Turn', ['↵']),
this.keybind('Inventory', ['I']),
this.keybind('Character', ['C']),
this.keybind('Quest Log', ['J']),
this.keybind('World Map', ['M']),
this.slider('mouseSens', 'Mouse Sensitivity', ''),
this.toggle('invertY', 'Invert Y-Axis', ''),
];
}
return { tabs, controls };
}
}
</script>
</body>
</html>