Instantly share code, notes, and snippets.
Created
February 27, 2026 21:04
-
Star
1
(1)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
-
Save EncodeTheCode/90c4c7205e18d3c39c7c3c40443addc3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!doctype html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8" /> | |
| <meta name="viewport" content="width=device-width,initial-scale=1" /> | |
| <title>PS Classic Menu — Fixed Options Enter</title> | |
| <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script> | |
| <style> | |
| :root{ --selected-size:200px; } | |
| html,body{height:100%;margin:0;background:radial-gradient(circle at center,#111 0%,#000 100%);color:#eee;font-family:system-ui, -apple-system, "Segoe UI", Roboto, Arial;} | |
| .stage{position:relative;width:100%;height:100%;display:flex;align-items:center;justify-content:center;overflow:hidden;} | |
| .carousel{position:relative;width:900px;height:500px;pointer-events:none;will-change:transform;} | |
| .game{ | |
| --size:100px; | |
| position:absolute; left:50%; top:50%; | |
| transform:translate(-50%,-50%); | |
| width:var(--size); height:var(--size); | |
| display:flex; align-items:center; justify-content:center; | |
| pointer-events:auto; cursor:pointer; | |
| border-radius:0.35em; overflow:hidden; | |
| border:1px solid rgba(255,255,255,0.06); | |
| background:linear-gradient(180deg,#151515,#0b0b0f); | |
| box-shadow:0 8px 20px rgba(0,0,0,0.65); | |
| transition: | |
| transform 420ms cubic-bezier(.25,.8,.25,1), | |
| width 420ms cubic-bezier(.25,.8,.25,1), | |
| height 420ms cubic-bezier(.25,.8,.25,1), | |
| opacity 260ms ease, | |
| box-shadow 260ms ease, | |
| border-color 200ms ease; | |
| } | |
| .game img{ | |
| width:100%; height:100%; | |
| object-fit:cover; | |
| display:block; | |
| border-radius:inherit; | |
| pointer-events:none; | |
| } | |
| .game.front{ | |
| border:1px solid #fff; | |
| box-shadow: | |
| 0 14px 36px rgba(0,0,0,0.6), | |
| 0 0 18px rgba(255,255,255,0.06); | |
| } | |
| .game.single{ z-index:9999!important; } | |
| .controls{position:absolute;top:16px;left:50%;transform:translateX(-50%);color:#ddd;font-size:13px;background:rgba(255,255,255,0.02);padding:8px 12px;border-radius:8px;border:1px solid rgba(255,255,255,0.03);display:flex;gap:12px;align-items:center;pointer-events:auto;} | |
| .arrowBtn{background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.04);color:#ddd;padding:8px 10px;border-radius:8px;cursor:pointer;} | |
| .game-title{position:absolute;bottom:86px;left:50%;transform:translateX(-50%);color:#bfbfbf;font-size:18px;letter-spacing:1.6px;text-transform:uppercase;text-align:center;width:min(900px,94vw);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;opacity:0.98;} | |
| </style> | |
| </head> | |
| <body> | |
| <div class="stage"> | |
| <div class="carousel" id="carousel"></div> | |
| <div class="controls"> | |
| <div id="menuTitle">Main Menu</div> | |
| <div style="display:flex;gap:10px;"> | |
| <button class="arrowBtn" id="btnLeft">A / ←</button> | |
| <button class="arrowBtn" id="btnRight">D / →</button> | |
| </div> | |
| </div> | |
| <div class="game-title" id="gameTitle"></div> | |
| </div> | |
| <script> | |
| /* ================= MENU DATA ================= */ | |
| const mainGames = [ | |
| { title: 'Crash Bandicoot', color: '#b2362f', image: 'images/crash.jpg' }, | |
| { title: 'Spyro the Dragon', color: '#2f6fb2' }, | |
| { title: 'Tekken 3', color: '#2fb280' }, | |
| { title: 'Final Fantasy VII', color: '#b28b2f' }, | |
| { title: 'Metal Gear Solid', color: '#8a2fb2' }, | |
| { title: 'Options', color: '#4c6fb2' } | |
| ]; | |
| const optionsGames = [ | |
| { title: 'Display Settings', color: '#3f7fb2' }, | |
| { title: 'Audio Settings', color: '#5fb27f' }, | |
| { title: 'Controls', color: '#b27f3f' }, | |
| { title: 'Back', color: '#4c6fb2' } | |
| ]; | |
| /* ================= STATE ================= */ | |
| let menuData = mainGames.slice(); | |
| let currentMenu = 'main'; | |
| let selected = 0; | |
| let nodes = []; | |
| let animating = false; | |
| const $carousel = $('#carousel'); | |
| /* ================= SVG FALLBACK ================= */ | |
| function escapeForSVG(s){ | |
| return String(s).replace(/&/g,'&'); | |
| } | |
| function makeSVGData(title,color){ | |
| const safe = escapeForSVG(title); | |
| const svg = ` | |
| <svg xmlns='http://www.w3.org/2000/svg' width='400' height='400'> | |
| <defs> | |
| <linearGradient id='g' x1='0' x2='1'> | |
| <stop offset='0' stop-color='${color}'/> | |
| <stop offset='1' stop-color='#111'/> | |
| </linearGradient> | |
| </defs> | |
| <rect width='100%' height='100%' fill='url(#g)'/> | |
| <text x='50%' y='50%' font-size='30' | |
| fill='white' | |
| dominant-baseline='middle' | |
| text-anchor='middle' | |
| font-family='Arial'>${safe}</text> | |
| </svg>`; | |
| return 'data:image/svg+xml;utf8,' + encodeURIComponent(svg); | |
| } | |
| /* ================= BUILD MENU ================= */ | |
| function buildMenu(menuArray){ | |
| $carousel.empty(); | |
| nodes = []; | |
| menuArray.forEach((g,i)=>{ | |
| const el = document.createElement('div'); | |
| el.className = 'game'; | |
| el.dataset.index = i; | |
| const img = document.createElement('img'); | |
| img.alt = g.title.replace(/&/g,'&'); | |
| // ===== IMAGE SUPPORT ADDED HERE ===== | |
| if(g.image){ | |
| img.src = g.image; | |
| img.onerror = function(){ | |
| this.onerror = null; | |
| this.src = makeSVGData( | |
| g.title.replace(/&/g,'&'), | |
| g.color || '#444' | |
| ); | |
| }; | |
| } else { | |
| img.src = makeSVGData( | |
| g.title.replace(/&/g,'&'), | |
| g.color || '#444' | |
| ); | |
| } | |
| // ===================================== | |
| el.appendChild(img); | |
| $carousel.append(el); | |
| nodes.push(el); | |
| el.addEventListener('click', ()=>{ | |
| selected = i; | |
| updatePositions(); | |
| }); | |
| }); | |
| updatePositions(); | |
| } | |
| /* ================= POSITIONING ================= */ | |
| function updatePositions(){ | |
| const total = nodes.length; | |
| const rX = 320; | |
| const rY = 180; | |
| nodes.forEach((node,i)=>{ | |
| let offset = i - selected; | |
| if(offset > total/2) offset -= total; | |
| if(offset < -total/2) offset += total; | |
| const angle = (offset/total) * Math.PI * 2; | |
| const x = Math.sin(angle) * rX; | |
| const y = Math.cos(angle) * rY + 40; | |
| node.style.transform = | |
| `translate(-50%,-50%) translate(${x}px, ${y}px)`; | |
| node.classList.toggle('front', offset === 0); | |
| }); | |
| document.getElementById('gameTitle').textContent = | |
| menuData[selected].title.replace(/&/g,'&'); | |
| } | |
| /* ================= NAVIGATION ================= */ | |
| function moveLeft(){ | |
| selected = (selected - 1 + menuData.length) % menuData.length; | |
| updatePositions(); | |
| } | |
| function moveRight(){ | |
| selected = (selected + 1) % menuData.length; | |
| updatePositions(); | |
| } | |
| function handleEnter(){ | |
| const title = menuData[selected].title.replace(/&/g,'&'); | |
| if(title === "Options"){ | |
| menuData = optionsGames.slice(); | |
| currentMenu = 'options'; | |
| selected = 0; | |
| buildMenu(menuData); | |
| } | |
| else if(title === "Back"){ | |
| menuData = mainGames.slice(); | |
| currentMenu = 'main'; | |
| selected = 0; | |
| buildMenu(menuData); | |
| } | |
| } | |
| $(window).on('keydown', e=>{ | |
| if(e.key === 'ArrowLeft' || e.key === 'a') moveLeft(); | |
| if(e.key === 'ArrowRight' || e.key === 'd') moveRight(); | |
| if(e.key === 'Enter') handleEnter(); | |
| }); | |
| $('#btnLeft').on('click', moveLeft); | |
| $('#btnRight').on('click', moveRight); | |
| /* ================= INIT ================= */ | |
| buildMenu(menuData); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment