iStabOreos

ToF Profile - New

Sep 15th, 2025
38
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 19.02 KB | None | 0 0
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <title></title>
  6. <meta name="viewport" content="width=430px, user-scalable=no">
  7. <link href="https://fonts.googleapis.com/css2?family=Cinzel+Decorative:wght@700&family=Spectral+SC:wght@300;600&display=swap" rel="stylesheet">
  8. <style>
  9. :root {
  10. --bg: #0a0c12;
  11. --text: #f4f1e7;
  12. --gold: #d6b36a;
  13. --gold-soft: rgba(214, 179, 106, 0.15);
  14. --gold-strong: rgba(214, 179, 106, 0.35);
  15. --ease: cubic-bezier(.22,.61,.36,1);
  16. }
  17. * {
  18. box-sizing: border-box;
  19. margin: 0;
  20. padding: 0;
  21. }
  22. html, body {
  23. width: 100%;
  24. height: 100%;
  25. background: var(--bg);
  26. color: var(--text);
  27. font-family: 'Spectral SC', serif;
  28. overflow-x: hidden;
  29. overflow-y: auto;
  30. scroll-behavior: smooth;
  31. -webkit-font-smoothing: antialiased;
  32. -moz-osx-font-smoothing: grayscale;
  33. text-rendering: optimizeLegibility;
  34. }
  35. body::-webkit-scrollbar {
  36. width: 6px;
  37. }
  38. body::-webkit-scrollbar-thumb {
  39. background: linear-gradient(var(--gold), transparent);
  40. border-radius: 6px;
  41. }
  42. :focus-visible {
  43. outline: 2px solid var(--gold);
  44. outline-offset: 2px;
  45. border-radius: 4px;
  46. transition: outline-color .25s var(--ease);
  47. }
  48. .bg-container {
  49. position: fixed;
  50. inset: 0;
  51. overflow: hidden;
  52. z-index: 0;
  53. pointer-events: none;
  54. perspective: 800px;
  55. contain: strict;
  56. }
  57. .gyroscope {
  58. position: absolute;
  59. transform-style: preserve-3d;
  60. will-change: transform, opacity;
  61. filter: drop-shadow(0 0 4px rgba(214,179,106,0.25));
  62. transition: filter .3s var(--ease), opacity .6s var(--ease);
  63. opacity: 1;
  64. }
  65. .gyroscope:hover {
  66. filter: drop-shadow(0 0 8px rgba(214,179,106,0.6));
  67. }
  68. .gyroscope.fade-out {
  69. opacity: 0;
  70. }
  71. .ring {
  72. position: absolute;
  73. inset: 0;
  74. border: 1px solid rgba(214,179,106,0.1);
  75. border-radius: 50%;
  76. transform-style: preserve-3d;
  77. box-shadow: 0 0 4px rgba(214,179,106,0.15);
  78. transition: box-shadow .3s var(--ease);
  79. will-change: transform;
  80. }
  81. .ring:hover {
  82. box-shadow: 0 0 10px rgba(214,179,106,0.4);
  83. }
  84. .ring1 { animation: spinX 6s linear infinite; }
  85. .ring2 { animation: spinY 8s linear infinite; }
  86. .ring3 { animation: spinZ 10s linear infinite; }
  87. .ring4 { animation: spinX 12s linear infinite; }
  88. .ring5 { animation: spinY 14s linear infinite; }
  89. @keyframes spinX { from { transform: rotateX(0); } to { transform: rotateX(360deg); } }
  90. @keyframes spinY { from { transform: rotateY(0); } to { transform: rotateY(360deg); } }
  91. @keyframes spinZ { from { transform: rotateZ(0); } to { transform: rotateZ(360deg); } }
  92. .container {
  93. max-width: 430px;
  94. margin: 20px auto;
  95. padding: 20px;
  96. background: rgba(10, 12, 18, 0.85);
  97. backdrop-filter: blur(4px);
  98. border: 1px solid var(--gold-soft);
  99. border-radius: 20px;
  100. box-shadow: 0 0 40px var(--gold-soft), inset 0 0 25px rgba(214,179,106,0.08);
  101. position: relative;
  102. z-index: 2;
  103. transition: box-shadow .6s var(--ease);
  104. will-change: box-shadow;
  105. }
  106. .container:hover {
  107. box-shadow: 0 0 60px var(--gold-strong), inset 0 0 30px rgba(214,179,106,0.1);
  108. }
  109. .codex-title {
  110. font-family: 'Cinzel Decorative', cursive;
  111. text-align: center;
  112. font-size: 28px;
  113. color: var(--gold);
  114. text-shadow: 0 0 12px var(--gold-strong);
  115. margin-bottom: 16px;
  116. }
  117. .codex-img {
  118. width: 100%;
  119. height: auto;
  120. border-radius: 12px;
  121. box-shadow: 0 0 10px rgba(255,255,255,0.05);
  122. border: 1px solid rgba(255,255,255,0.06);
  123. margin-bottom: 10px;
  124. transition: transform .6s var(--ease), box-shadow .6s var(--ease);
  125. will-change: transform;
  126. transform: translateZ(0);
  127. }
  128. .codex-img:hover {
  129. transform: scale(1.02) translateZ(0);
  130. box-shadow: 0 0 16px rgba(255,255,255,0.08);
  131. }
  132. .codex-quote {
  133. font-style: italic;
  134. text-align: center;
  135. font-size: 13px;
  136. color: var(--gold);
  137. margin-bottom: 12px;
  138. padding: 0 10px;
  139. text-shadow: 0 0 6px rgba(214,179,106,0.2);
  140. }
  141. .tab-controls {
  142. display: flex;
  143. justify-content: space-around;
  144. margin: 12px 0;
  145. gap: 6px;
  146. }
  147. .tab {
  148. background: rgba(255,255,255,0.02);
  149. padding: 6px 12px;
  150. border-radius: 6px;
  151. color: var(--gold);
  152. cursor: pointer;
  153. font-size: 13px;
  154. border: 1px solid rgba(255,255,255,0.06);
  155. transition: background .3s var(--ease), color .3s var(--ease), box-shadow .3s var(--ease), transform .2s var(--ease);
  156. user-select: none;
  157. font-family: inherit;
  158. font-style: normal;
  159. font-weight: 600;
  160. will-change: transform;
  161. }
  162. .tab:hover, .tab.active {
  163. background: var(--gold-soft);
  164. color: var(--text);
  165. box-shadow: 0 0 10px var(--gold-strong);
  166. }
  167. .tab:active {
  168. transform: translateY(1px);
  169. }
  170. .tab-panel {
  171. display: none;
  172. margin-top: 14px;
  173. animation: fadeIn .6s var(--ease) forwards;
  174. }
  175. .tab-panel.active {
  176. display: block;
  177. }
  178. .section {
  179. margin-bottom: 14px;
  180. }
  181. .section-title {
  182. font-weight: 600;
  183. font-size: 13px;
  184. color: var(--gold);
  185. margin-bottom: 4px;
  186. }
  187. .section-content {
  188. font-size: 13px;
  189. line-height: 1.5;
  190. color: #eae7dd;
  191. }
  192. .scrollbox {
  193. max-height: 150px;
  194. overflow-y: auto;
  195. padding-right: 4px;
  196. border-left: 2px solid var(--gold-strong);
  197. padding-left: 8px;
  198. scroll-behavior: smooth;
  199. }
  200. .scrollbox::-webkit-scrollbar {
  201. width: 4px;
  202. }
  203. .scrollbox::-webkit-scrollbar-thumb {
  204. background: var(--gold);
  205. border-radius: 3px;
  206. }
  207. .audio-controls {
  208. text-align: center;
  209. margin-top: 14px;
  210. display: flex;
  211. justify-content: center;
  212. align-items: center;
  213. gap: 10px;
  214. opacity: .3;
  215. transition: opacity .3s var(--ease);
  216. }
  217. .audio-controls:hover {
  218. opacity: 1;
  219. }
  220. .volume-slider {
  221. width: 100px;
  222. accent-color: var(--gold);
  223. transition: filter .25s var(--ease);
  224. filter: drop-shadow(0 0 0 rgba(0,0,0,0));
  225. }
  226. .volume-slider:focus-visible {
  227. filter: drop-shadow(0 0 6px rgba(214,179,106,0.35));
  228. }
  229. .audio-button {
  230. cursor: pointer;
  231. font-size: 14px;
  232. background: none;
  233. color: var(--gold);
  234. border: none;
  235. font-family: inherit;
  236. font-style: normal;
  237. font-weight: 600;
  238. transition: transform .2s var(--ease), text-shadow .3s var(--ease);
  239. }
  240. .audio-button:active {
  241. transform: scale(.98);
  242. }
  243. @keyframes fadeIn {
  244. 0% { opacity: 0; transform: translateY(10px); }
  245. 100% { opacity: 1; transform: translateY(0); }
  246. }
  247. @media (prefers-reduced-motion: reduce) {
  248. .ring1, .ring2, .ring3, .ring4, .ring5 { animation: none !important; }
  249. .tab-panel { animation: none; }
  250. .codex-img { transition: none; }
  251. .container { transition: none; }
  252. .audio-controls { transition: none; }
  253. }
  254. .volume-slider::-webkit-slider-runnable-track {
  255. height: 4px;
  256. background: linear-gradient(to right, var(--gold-strong), rgba(255,255,255,0.06));
  257. border-radius: 999px;
  258. }
  259. .volume-slider::-webkit-slider-thumb {
  260. -webkit-appearance: none;
  261. appearance: none;
  262. width: 14px;
  263. height: 14px;
  264. border-radius: 50%;
  265. background: var(--gold);
  266. border: 1px solid rgba(0,0,0,0.25);
  267. margin-top: -5px;
  268. box-shadow: 0 0 8px var(--gold-strong);
  269. }
  270. .volume-slider::-moz-range-track {
  271. height: 4px;
  272. background: linear-gradient(to right, var(--gold-strong), rgba(255,255,255,0.06));
  273. border-radius: 999px;
  274. }
  275. .volume-slider::-moz-range-thumb {
  276. width: 14px;
  277. height: 14px;
  278. border-radius: 50%;
  279. background: var(--gold);
  280. border: 1px solid rgba(0,0,0,0.25);
  281. box-shadow: 0 0 8px var(--gold-strong);
  282. }
  283. .volume-slider::-ms-track {
  284. height: 4px;
  285. background: transparent;
  286. border-color: transparent;
  287. color: transparent;
  288. }
  289. .volume-slider::-ms-fill-lower, .volume-slider::-ms-fill-upper {
  290. background: linear-gradient(to right, var(--gold-strong), rgba(255,255,255,0.06));
  291. border-radius: 999px;
  292. }
  293. .volume-slider::-ms-thumb {
  294. width: 14px;
  295. height: 14px;
  296. border-radius: 50%;
  297. background: var(--gold);
  298. border: 1px solid rgba(0,0,0,0.25);
  299. box-shadow: 0 0 8px var(--gold-strong);
  300. }
  301. #overview .section-content strong {
  302. color: var(--gold);
  303. text-shadow: 0 0 4px var(--gold-strong);
  304. letter-spacing: 0.3px;
  305. font-variant-caps: small-caps;
  306. }
  307. </style>
  308. </head>
  309. <body>
  310. <div class="bg-container" id="bg-container" aria-hidden="true"></div>
  311. <div class="container">
  312. <h1 class="codex-title">Unnamed Soul</h1>
  313. <img class="codex-img" src="(IMAGE_PLACEHOLDER)" loading="lazy" decoding="async">
  314. <p class="codex-quote">"..."</p>
  315. <div class="tab-controls" role="tablist" aria-label="Profile sections">
  316. <button class="tab active" role="tab" aria-selected="true" aria-controls="overview" id="tab-overview" tabindex="0" data-tab="overview">Overview</button>
  317. <button class="tab" role="tab" aria-selected="false" aria-controls="history" id="tab-history" tabindex="-1" data-tab="history">History</button>
  318. <button class="tab" role="tab" aria-selected="false" aria-controls="achievements" id="tab-achievements" tabindex="-1" data-tab="achievements">Achievements</button>
  319. </div>
  320. <section class="tab-panel active" id="overview" role="tabpanel" aria-labelledby="tab-overview">
  321. <div class="section">
  322. <div class="section-title">Codex Identification</div>
  323. <div class="section-content">
  324. <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 12px;">
  325. <div><strong>Race</strong><br>(RACE_PLACEHOLDER)</div>
  326. <div><strong>Class</strong><br>(CLASS_PLACEHOLDER)</div>
  327. <div><strong>Age</strong><br>(AGE_PLACEHOLDER)</div>
  328. <div><strong>Height</strong><br>(HEIGHT_PLACEHOLDER)</div>
  329. <div><strong>Weight</strong><br>(WEIGHT_PLACEHOLDER)</div>
  330. <div><strong>Eye Color</strong><br>(EYE_COLOR_PLACEHOLDER)</div>
  331. <div style="grid-column: 1 / -1; text-align: center;"><strong>Hair Color</strong><br>(HAIR_COLOR_PLACEHOLDER)</div>
  332. </div>
  333. </div>
  334. </div>
  335. <hr style="border: 0; border-top: 1px solid var(--gold-soft); margin: 14px 0;">
  336. <div class="section">
  337. <div class="section-title">Affiliation</div>
  338. <div class="section-content">
  339. <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 12px;">
  340. <div><strong>Order</strong><br>(ORDER_PLACEHOLDER)</div>
  341. <div><strong>Division</strong><br>(DIVISION_PLACEHOLDER)</div>
  342. </div>
  343. <div style="text-align: center; margin-top: 10px;"><strong>Current Rank</strong><br>(CURRENT_RANK_PLACEHOLDER)</div>
  344. </div>
  345. </div>
  346. </section>
  347. <section class="tab-panel" id="history" role="tabpanel" aria-labelledby="tab-history">
  348. <div class="section">
  349. <div class="section-title">Recorded Past</div>
  350. <div class="section-content scrollbox">
  351. <p>(HISTORY_PLACEHOLDER)</p>
  352. </div>
  353. </div>
  354. </section>
  355. <section class="tab-panel" id="achievements" role="tabpanel" aria-labelledby="tab-achievements">
  356. <div class="section">
  357. <div class="section-title">Recognized Achievements</div>
  358. <div class="section-content scrollbox">
  359. <ul style="padding-left: 18px;">
  360. <li>(ACHIEVEMENT_1)</li>
  361. <li>(ACHIEVEMENT_2)</li>
  362. <li>(ACHIEVEMENT_3)</li>
  363. <li>(ACHIEVEMENT_4)</li>
  364. </ul>
  365. </div>
  366. </div>
  367. </section>
  368. <div class="audio-controls">
  369. <button class="audio-button" id="audio-toggle" aria-label="Play or pause ambient music">▶</button>
  370. <input type="range" min="0" max="1" step="0.01" class="volume-slider" id="volume" aria-label="Volume" value="0.4">
  371. </div>
  372. </div>
  373. <audio id="ambient" preload="auto" loop>
  374. <source src="https://od.lk/s/ODBfNTg4NTM5NTFf/The%20Night%20Unfurls.mp3" type="audio/mpeg">
  375. </audio>
  376. <script>
  377. const audio = document.getElementById('ambient');
  378. const volInput = document.getElementById('volume');
  379. const toggleBtn = document.getElementById('audio-toggle');
  380. const savedVol = localStorage.getItem('codex_volume');
  381. if (savedVol !== null) volInput.value = savedVol;
  382. let volumeTween = null;
  383. function reflectBtn() { toggleBtn.textContent = audio.paused ? '▶' : '⏸'; }
  384. function rampVolume(target, ms) {
  385. if (volumeTween) cancelAnimationFrame(volumeTween.raf);
  386. const start = audio.volume;
  387. const delta = target - start;
  388. const startTime = performance.now();
  389. function step(now) {
  390. const t = Math.min(1, (now - startTime) / ms);
  391. audio.volume = start + delta * (t * (2 - t));
  392. if (t < 1) volumeTween = { raf: requestAnimationFrame(step) }; else volumeTween = null;
  393. }
  394. volumeTween = { raf: requestAnimationFrame(step) };
  395. }
  396. async function tryAutoplay() {
  397. audio.volume = Number(volInput.value);
  398. try { await audio.play(); } catch (_) {}
  399. reflectBtn();
  400. }
  401. function toggleAudio() {
  402. if (audio.paused) {
  403. rampVolume(Number(volInput.value), 120);
  404. audio.play();
  405. } else {
  406. rampVolume(0, 120);
  407. setTimeout(() => { audio.pause(); reflectBtn(); audio.volume = Number(volInput.value); }, 130);
  408. }
  409. reflectBtn();
  410. }
  411. function setVolume(value) {
  412. const v = Number(value);
  413. audio.volume = v;
  414. localStorage.setItem('codex_volume', value);
  415. }
  416. toggleBtn.addEventListener('click', toggleAudio, { passive: true });
  417. volInput.addEventListener('input', e => setVolume(e.target.value), { passive: true });
  418. document.addEventListener('visibilitychange', () => {
  419. if (document.hidden && !audio.paused) {
  420. audio.pause();
  421. reflectBtn();
  422. }
  423. }, { passive: true });
  424. window.addEventListener('load', tryAutoplay, { passive: true });
  425. const tabs = Array.from(document.querySelectorAll('[role="tab"]'));
  426. const panels = Array.from(document.querySelectorAll('[role="tabpanel"]'));
  427. function activateTab(tab) {
  428. tabs.forEach(t => {
  429. const selected = t === tab;
  430. t.classList.toggle('active', selected);
  431. t.setAttribute('aria-selected', selected);
  432. t.tabIndex = selected ? 0 : -1;
  433. });
  434. panels.forEach(p => {
  435. const isTarget = p.id === tab.getAttribute('aria-controls');
  436. p.classList.toggle('active', isTarget);
  437. p.setAttribute('aria-hidden', String(!isTarget));
  438. if (isTarget) {
  439. p.style.animation = 'none';
  440. void p.offsetWidth;
  441. p.style.animation = '';
  442. }
  443. });
  444. tab.focus();
  445. }
  446. tabs.forEach(tab => {
  447. tab.addEventListener('click', () => activateTab(tab), { passive: true });
  448. tab.addEventListener('keydown', e => {
  449. const idx = tabs.indexOf(tab);
  450. if (e.key === 'ArrowRight') {
  451. e.preventDefault();
  452. activateTab(tabs[(idx + 1) % tabs.length]);
  453. } else if (e.key === 'ArrowLeft') {
  454. e.preventDefault();
  455. activateTab(tabs[(idx - 1 + tabs.length) % tabs.length]);
  456. } else if (e.key === 'Home') {
  457. e.preventDefault();
  458. activateTab(tabs[0]);
  459. } else if (e.key === 'End') {
  460. e.preventDefault();
  461. activateTab(tabs[tabs.length - 1]);
  462. } else if (e.key === 'Enter' || e.key === ' ') {
  463. e.preventDefault();
  464. activateTab(tab);
  465. }
  466. });
  467. });
  468. const container = document.getElementById('bg-container');
  469. const rmQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
  470. let reducedMotion = rmQuery.matches;
  471. let gyros = [];
  472. const POOL = [];
  473. const MAX_GYROS = 60;
  474. const SPAWN_INTERVAL = 260;
  475. let lastSpawn = 0;
  476. let animRAF = null;
  477. rmQuery.addEventListener?.('change', e => {
  478. reducedMotion = e.matches;
  479. if (reducedMotion) clearScene();
  480. });
  481. function makeGyroEl() {
  482. const el = document.createElement('div');
  483. el.className = 'gyroscope';
  484. return el;
  485. }
  486. function buildGyro(el, rings) {
  487. el.replaceChildren();
  488. let parent = el;
  489. for (let i = 1; i <= rings; i++) {
  490. const ring = document.createElement('div');
  491. ring.className = `ring ring${i}`;
  492. parent.appendChild(ring);
  493. parent = ring;
  494. }
  495. }
  496. function spawnGyro() {
  497. if (reducedMotion || gyros.length >= MAX_GYROS) return;
  498. const size = 15 + Math.random() * 15;
  499. const rings = 2 + Math.floor(Math.random() * 4);
  500. const x = Math.random() * window.innerWidth;
  501. const y = window.innerHeight + 30;
  502. const el = POOL.pop() || makeGyroEl();
  503. buildGyro(el, rings);
  504. el.style.width = size + 'px';
  505. el.style.height = size + 'px';
  506. container.appendChild(el);
  507. gyros.push({ el, x, y, vx: 0, vy: -0.3 - Math.random() * 0.3, size, alive: true });
  508. }
  509. function recycle(g) {
  510. g.alive = false;
  511. g.el.classList.add('fade-out');
  512. setTimeout(() => {
  513. g.el.remove();
  514. g.el.classList.remove('fade-out');
  515. POOL.push(g.el);
  516. }, 250);
  517. }
  518. function clearScene() {
  519. gyros.forEach(g => recycle(g));
  520. gyros = [];
  521. }
  522. function tick(now) {
  523. animRAF = requestAnimationFrame(tick);
  524. if (document.hidden || reducedMotion) return;
  525. if (!lastSpawn) lastSpawn = now;
  526. if (now - lastSpawn > SPAWN_INTERVAL) {
  527. spawnGyro();
  528. lastSpawn = now;
  529. }
  530. for (let i = gyros.length - 1; i >= 0; i--) {
  531. const g = gyros[i];
  532. if (!g.alive) {
  533. gyros.splice(i, 1);
  534. continue;
  535. }
  536. g.y += g.vy;
  537. g.x += g.vx * 0.98;
  538. g.el.style.transform = `translate3d(${g.x}px, ${g.y}px, 0)`;
  539. if (g.y + g.size <= -50) {
  540. recycle(g);
  541. gyros.splice(i, 1);
  542. }
  543. }
  544. }
  545. function start() {
  546. if (!animRAF) animRAF = requestAnimationFrame(tick);
  547. }
  548. function stop() {
  549. if (animRAF) cancelAnimationFrame(animRAF);
  550. animRAF = null;
  551. }
  552. window.addEventListener('resize', () => { clearScene(); }, { passive: true });
  553. document.addEventListener('visibilitychange', () => {
  554. if (document.hidden) stop();
  555. else start();
  556. }, { passive: true });
  557. start();
  558. </script>
  559. </body>
  560. </html>
Advertisement
Add Comment
Please, Sign In to add comment