Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96d12300ee | ||
|
|
3446386ec9 | ||
|
|
522b1fafc6 | ||
|
|
5e5dcec54a | ||
|
|
94ddf2374d | ||
|
|
87c95bf615 | ||
|
|
1522a791f9 | ||
|
|
ce648c2f3d | ||
|
|
b771fb0cf5 | ||
|
|
f90967526b | ||
|
|
94e7fe9fcf | ||
|
|
96840e304d | ||
|
|
c9796ea2a0 | ||
|
|
aa0270b385 | ||
|
|
b3cb653acd | ||
|
|
1d7cb6d43f | ||
|
|
f64b60e1aa | ||
|
|
5369099acf | ||
|
|
f2b12bb164 | ||
|
|
8d476abc17 | ||
|
|
4d0efd3ca5 | ||
|
|
a7f1adbf83 | ||
|
|
f72336ab8c | ||
|
|
9552fb73cc | ||
|
|
c75854203c | ||
|
|
0014c99b52 | ||
|
|
43e1366e73 | ||
|
|
911d0639f0 | ||
|
|
953ac5939e | ||
|
|
d2bb102bd3 | ||
|
|
14e0261e69 | ||
|
|
79976a367a | ||
|
|
2d921a0024 | ||
|
|
385530a6a7 | ||
|
|
977fbf9c5e | ||
|
|
6e857ac79b | ||
|
|
b0512940db | ||
|
|
f533052603 | ||
|
|
19bb73a8ee | ||
|
|
87a0c933dc | ||
|
|
339286fd08 | ||
|
|
9fd4fee2a7 | ||
|
|
efe24e3edf | ||
|
|
8fded353fc |
@@ -116,6 +116,94 @@
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<script src="https://js.puter.com/v2/"></script>
|
||||
<script>
|
||||
let aiChatWindow = null;
|
||||
let chatVisible = false;
|
||||
|
||||
// Detect Shift+T
|
||||
document.addEventListener("keydown", (e) => {
|
||||
if (e.shiftKey && e.key.toLowerCase() === "t") {
|
||||
e.preventDefault();
|
||||
toggleAIChat();
|
||||
}
|
||||
});
|
||||
|
||||
async function toggleAIChat() {
|
||||
if (!chatVisible) {
|
||||
aiChatWindow = document.createElement("div");
|
||||
aiChatWindow.style = `
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
width: 400px;
|
||||
height: 500px;
|
||||
background: #1e1e1e;
|
||||
color: #f0f0f0;
|
||||
border: 2px solid #444;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 0 20px rgba(0,0,0,0.5);
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
font-family: system-ui, sans-serif;
|
||||
`;
|
||||
aiChatWindow.innerHTML = `
|
||||
<div style="background:#222;padding:10px;text-align:center;font-weight:bold;">
|
||||
🎮 Fun Miles AI Chat
|
||||
</div>
|
||||
<div id="chatLog" style="flex:1;overflow-y:auto;padding:10px;"></div>
|
||||
<div style="display:flex;border-top:1px solid #333;">
|
||||
<input id="chatInput" type="text" placeholder="Type a message..."
|
||||
style="flex:1;padding:10px;background:#2a2a2a;color:#fff;border:none;outline:none;">
|
||||
<button id="chatSend" style="padding:10px 15px;background:#444;color:#fff;border:none;">Send</button>
|
||||
</div>
|
||||
`;
|
||||
document.body.appendChild(aiChatWindow);
|
||||
|
||||
const chatLog = aiChatWindow.querySelector("#chatLog");
|
||||
const chatInput = aiChatWindow.querySelector("#chatInput");
|
||||
const chatSend = aiChatWindow.querySelector("#chatSend");
|
||||
|
||||
// Intro message
|
||||
chatLog.innerHTML = `
|
||||
<div style="margin-bottom:10px;">
|
||||
<b>AI:</b> 👋 Hi! I'm the <b>Fun Miles AI</b> — here to answer your <b>gaming questions</b>, chat about mods, or just have fun.
|
||||
Ask me anything!
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Send message handler
|
||||
chatSend.onclick = async () => {
|
||||
const msg = chatInput.value.trim();
|
||||
if (!msg) return;
|
||||
chatLog.innerHTML += `<div><b>You:</b> ${msg}</div>`;
|
||||
chatInput.value = "";
|
||||
|
||||
try {
|
||||
const response = await puter.ai.chat(msg);
|
||||
chatLog.innerHTML += `<div><b>AI:</b> ${response}</div>`;
|
||||
chatLog.scrollTop = chatLog.scrollHeight;
|
||||
} catch (err) {
|
||||
chatLog.innerHTML += `<div style="color:red;"><b>Error:</b> ${err.message}</div>`;
|
||||
}
|
||||
};
|
||||
|
||||
// Enter key sends message
|
||||
chatInput.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter") chatSend.click();
|
||||
});
|
||||
|
||||
chatVisible = true;
|
||||
} else {
|
||||
aiChatWindow.remove();
|
||||
chatVisible = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<h1>404 Not Found</h1>
|
||||
<p>Oops! The page you are looking for does not exist.</p>
|
||||
<p>It might have been removed, had its name changed, or is temporarily unavailable.</p>
|
||||
@@ -134,4 +222,4 @@
|
||||
window.onload = applyDarkMode;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -1,35 +1,64 @@
|
||||
https://forms.fillout.com/t/aWUkWGKkMNus
|
||||
The Best Online Gaming Site You Can Make One Of Your by Hosting
|
||||
<p xmlns:cc="http://creativecommons.org/ns#" xmlns:dct="http://purl.org/dc/terms/"><a property="dct:title" rel="cc:attributionURL" href="https://github.com/mileswolfallen2/fun-miles">fun-miles</a> by <a rel="cc:attributionURL dct:creator" property="cc:attributionName" href="https://github.com/mileswolfallen2">miles Allen and Robert Winberg</a> The Licensed Is Under <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/?ref=chooser-v1" target="_blank" rel="license noopener noreferrer" style="display:inline-block;">Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1" alt=""><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1" alt=""><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/nc.svg?ref=chooser-v1" alt=""><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/sa.svg?ref=chooser-v1" alt=""></a></p>
|
||||
# Moon Gaming
|
||||
|
||||
<h1>How To Make Your Own Verson To Host</h1>
|
||||
To host the “fun-miles” GitHub repository using Render static sites, follow these steps outlined in the flowchart:
|
||||
fun game from stuf
|
||||
Go to: [fun-miles.free.nf](http://fun-miles.free.nf)
|
||||
|
||||
Fork the repository using github
|
||||
Create a Render account and create a new static site, connecting it to your GitHub and then
|
||||
<img src="https://render.com/docs/static/9705deafa360259a1e4342980e6efff5/7a72b/new-static-site.png" alt="Selecting Static Site from the New menu"
|
||||
height="300" width="auto" align=”left”>
|
||||
<img src="https://render.com/docs/static/2c8e1ccdd8cd76c9409ea39a966c501e/2b72d/git-connect.png" alt="Git Connect" height="200" width="auto"/>
|
||||
<img src="https://render.com/docs/static/2b69098df84b4909b0a2336f43542dab/dcb99/github-connect-repo.png" alt="List of GitHub repos in the Render Dashboard"
|
||||
height="200" width="auto"/>
|
||||
---
|
||||
|
||||
Configure the build settings, deploy the site, and then view your live site via the provided URL.
|
||||
## Overview
|
||||
|
||||
Moon Gaming is a fun, web-based game project featuring interactive gameplay and engaging content. The project is primarily written in **HTML** and **JavaScript**, with some additional code in Java and C. You can play it online or view/contribute to the open-source code here.
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
- Interactive web game, easy to play in your browser.
|
||||
- Clean and simple HTML/JavaScript codebase.
|
||||
- Lightweight and fast-loading.
|
||||
- Open source for learning and contributions.
|
||||
|
||||
---
|
||||
|
||||
<h1>To Contribute To The Repository, Please Follow These Steps:</h1>
|
||||
## Getting Started
|
||||
|
||||
Fork The Repository To Your Own GitHub Account.
|
||||
Create A New Branch For Your Project Or Idea.
|
||||
Develop Your Project Or Idea, Ensuring It Aligns With The Repository's Purpose.
|
||||
Commit Your Changes And Push Them To Your Forked Repository.
|
||||
Submit A Pull Request To The Original "Fun-Miles" Repository,
|
||||
By Contributing To The "Fun-Miles" Git Repository, You Can Help Make It A More Diverse And Engaging Collection Of Projects And Ideas, While Also Showcasing Your Own Idea.
|
||||
### Play Online
|
||||
|
||||
Play instantly [here](http://fun-miles.free.nf).
|
||||
|
||||
### Run Locally
|
||||
|
||||
1. **Clone the repository:**
|
||||
```bash
|
||||
git clone https://github.com/mileswolfallen2/moon-gaming.git
|
||||
```
|
||||
2. **Navigate to the project folder:**
|
||||
```bash
|
||||
cd moon-gaming
|
||||
```
|
||||
3. **Open `index.html` in your web browser.**
|
||||
|
||||
---
|
||||
|
||||
## Languages Used
|
||||
|
||||
- **HTML:** 95.6%
|
||||
- **JavaScript:** 4%
|
||||
- **Java:** 0.3%
|
||||
- **C:** 0.1%
|
||||
- **CSS, GLSL:** <0.1%
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
Pull requests are welcome! For major changes, please open an issue first to discuss what you would like to change or add.
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
This project is open-source. See the [LICENSE](LICENSE) file for details.
|
||||
<h1>Notes</h1>
|
||||
|
||||
[render preview]
|
||||
|
||||
|
After Width: | Height: | Size: 10 KiB |
@@ -7,10 +7,10 @@
|
||||
EJS_player = '#game';
|
||||
EJS_core = 'gba';
|
||||
EJS_gameUrl = 'emerald.gba';
|
||||
EJS_pathtodata = 'https://cdn.jsdelivr.net/gh/ethanaobrien/emulatorjs@main/data/';
|
||||
EJS_pathtodata = 'https://cdn.emulatorjs.org/stable/data/';
|
||||
|
||||
</script>
|
||||
<script src='https://cdn.jsdelivr.net/gh/ethanaobrien/emulatorjs@main/data/loader.js'></script>
|
||||
<script src='https://cdn.emulatorjs.org/stable/data/loader.js'></script>
|
||||
|
||||
<style>
|
||||
.game {
|
||||
@@ -30,4 +30,4 @@ EJS_pathtodata = 'https://cdn.jsdelivr.net/gh/ethanaobrien/emulatorjs@main/data/
|
||||
left: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -95,46 +95,4 @@
|
||||
} else {
|
||||
fpsCounter.style.display = 'none'; // Hide FPS counter
|
||||
}
|
||||
</script> let frames = 0;
|
||||
|
||||
function frameLoop() {
|
||||
const now = performance.now();
|
||||
frames++;
|
||||
|
||||
if (now - lastFrameTime >= 1000) {
|
||||
const fps = Math.round(frames / ((now - lastFrameTime) / 1000));
|
||||
fpsCounter.textContent = `FPS: ${fps}`;
|
||||
frames = 0;
|
||||
lastFrameTime = now;
|
||||
}
|
||||
requestAnimationFrame(frameLoop);
|
||||
}
|
||||
frameLoop();
|
||||
}
|
||||
|
||||
calculateFPS(); // Start FPS calculation
|
||||
} else {
|
||||
fpsCounter.style.display = 'none'; // Hide FPS counter
|
||||
}
|
||||
</script> let frames = 0;
|
||||
|
||||
function frameLoop() {
|
||||
const now = performance.now();
|
||||
frames++;
|
||||
|
||||
if (now - lastFrameTime >= 1000) {
|
||||
const fps = Math.round(frames / ((now - lastFrameTime) / 1000));
|
||||
fpsCounter.textContent = `FPS: ${fps}`;
|
||||
frames = 0;
|
||||
lastFrameTime = now;
|
||||
}
|
||||
requestAnimationFrame(frameLoop);
|
||||
}
|
||||
frameLoop();
|
||||
}
|
||||
|
||||
calculateFPS(); // Start FPS calculation
|
||||
} else {
|
||||
fpsCounter.style.display = 'none'; // Hide FPS counter
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
@@ -759,9 +759,65 @@
|
||||
</div>
|
||||
<div class="game">
|
||||
|
||||
<a href="Helios-main/index.html">
|
||||
<a href="/games/idk-yet-but-it-works-this-time-main/index.html">
|
||||
<img src="" alt="test">
|
||||
<div clsaa="game-title">proxy work in progress</div>
|
||||
<div clsaa="game-title">sans hard fight</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="game">
|
||||
|
||||
<a href="games2/game/zombsroyale/index.html">
|
||||
<img src="/WebGames-master/WebGames-master/games2/game/zombsroyale/favicon.ico" alt="test">
|
||||
<div clsaa="game-title">zombsroyale</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="game">
|
||||
|
||||
<a href="games2/game/tiny-fishing/index.html">
|
||||
<img src="/WebGames-master/WebGames-master/games2/game/tiny-fishing/tiny-fishing.png" alt="test">
|
||||
<div clsaa="game-title">tiny-fishing</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="game">
|
||||
|
||||
<a href="games2/game/slope-2/index.html">
|
||||
<img src="WebGames-master/WebGames-master/games2/game/slope-2/webgl-logo.png" alt="test">
|
||||
<div clsaa="game-title">slope-2</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="game">
|
||||
|
||||
<a href="games2/game/run3/index.html">
|
||||
<img src="WebGames-master/WebGames-master/games2/game/run3/favicon.png" alt="test">
|
||||
<div clsaa="game-title">run 3</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="game">
|
||||
|
||||
<a href="games2/game/fireboy-and-watergirl-forest-temple/index.html">
|
||||
<img src="/WebGames-master/WebGames-master/games2/game/fireboy-and-watergirl-forest-temple/icon-60x60.png" alt="test">
|
||||
<div clsaa="game-title">fireboy and watergirl forest temple</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="game">
|
||||
|
||||
<a href="games2/game/draw-the-hill/index.html">
|
||||
<img src="WebGames-master/WebGames-master/games2/game/draw-the-hill/icons/icon-512.png" alt="test">
|
||||
<div clsaa="game-title">draw the hill</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="game">
|
||||
|
||||
<a href="games2/game/madalin-stunt-cars-2/index.html">
|
||||
<img src="WebGames-master/WebGames-master/games2/game/madalin-stunt-cars-2/images (11).jpeg" alt="madalin-stunt-cars-2">
|
||||
<div clsaa="game-title">madalin stunt cars 2</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="game">
|
||||
|
||||
<a href="games2/game/crossyroad/index.html">
|
||||
<img src="WebGames-master/WebGames-master/games2/game/crossyroad/crossyroad.png" alt="crossyroad-png">
|
||||
<div clsaa="game-title">crossyroad</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -996,4 +1052,4 @@
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -564,6 +564,11 @@ const mainContentData = [
|
||||
image: "assets/Super-Scratch-Bros-Beta.jpeg",
|
||||
link: "/WebGames-master/WebGames-master/games2/game/rooftop-snipers/index.html",
|
||||
},
|
||||
{
|
||||
name: "sans hard fight",
|
||||
image: "assets/Super-Scratch-Bros-Beta.jpeg",
|
||||
link: "/games/idk-yet-but-it-works-this-time-main/index.html",
|
||||
},
|
||||
];
|
||||
|
||||
mainContentData.forEach(item => {
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Game Object Formatter</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
.input-area {
|
||||
width: 100%;
|
||||
margin: 20px 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
textarea {
|
||||
width: 100%;
|
||||
height: 120px;
|
||||
font-family: monospace;
|
||||
font-size: 16px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
button {
|
||||
padding: 8px 20px;
|
||||
font-size: 16px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.games-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 24px;
|
||||
}
|
||||
.game {
|
||||
opacity: 0;
|
||||
transform: translateY(-50px);
|
||||
transition: opacity 0.5s, transform 0.5s;
|
||||
margin: 10px;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
width: 175px;
|
||||
background: #faf9f7;
|
||||
box-shadow: 0 2px 7px #0001;
|
||||
}
|
||||
.game img {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.game-title {
|
||||
margin-top: 10px;
|
||||
font-weight: bold;
|
||||
font-size: 1.1em;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Game Object to HTML Formatter</h2>
|
||||
<div class="input-area">
|
||||
<label for="objInput">Paste your JS object(s) or JSON here — array or single object:</label>
|
||||
<textarea id="objInput" placeholder='Try this:
|
||||
[
|
||||
{
|
||||
"name": "Tic-Tac-Toe",
|
||||
"image": "assets/tic-tac-toe.png",
|
||||
"link": "tic-tac-toe/index.html"
|
||||
},
|
||||
{
|
||||
"name": "Chess",
|
||||
"image": "assets/chess.png",
|
||||
"link": "chess/index.html"
|
||||
}
|
||||
]'></textarea>
|
||||
<button onclick="formatGames()">Format!</button>
|
||||
</div>
|
||||
<div class="games-container" id="gamesContainer"></div>
|
||||
|
||||
<script>
|
||||
function formatTitle(str) {
|
||||
return str.replace(/-/g, " ").replace(/\b\w/g, c => c.toUpperCase());
|
||||
}
|
||||
|
||||
function parseUserInput(txt) {
|
||||
// Try parse as JSON
|
||||
try {
|
||||
return JSON.parse(txt);
|
||||
} catch {}
|
||||
// Try parse as JS object(s)
|
||||
try {
|
||||
// add quotes around keys, make valid JSON
|
||||
let fixedTxt = txt.replace(/([{,]\s*)(\w+)\s*:/g, '$1"$2":');
|
||||
return JSON.parse(fixedTxt);
|
||||
} catch {
|
||||
alert("Could not parse input as JSON or JS object array.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function formatGames() {
|
||||
const raw = document.getElementById('objInput').value.trim();
|
||||
const gameData = parseUserInput(raw);
|
||||
const games = Array.isArray(gameData) ? gameData : [gameData];
|
||||
|
||||
const container = document.getElementById('gamesContainer');
|
||||
container.innerHTML = ''; // clear old
|
||||
|
||||
const basePath = "/WebGames-master/WebGames-master/";
|
||||
let idx = 0;
|
||||
for (const game of games) {
|
||||
if (!game || !game.name || !game.image || !game.link) continue;
|
||||
const div = document.createElement('div');
|
||||
div.className = "game";
|
||||
div.style.opacity = "0";
|
||||
div.style.transform = "translateY(-50px)";
|
||||
|
||||
const anchor = document.createElement('a');
|
||||
anchor.href = basePath + game.link;
|
||||
|
||||
const img = document.createElement('img');
|
||||
img.src = "./" + game.image;
|
||||
img.alt = game.name.toLowerCase();
|
||||
|
||||
const titleDiv = document.createElement('div');
|
||||
titleDiv.className = "game-title";
|
||||
titleDiv.textContent = formatTitle(game.name);
|
||||
|
||||
anchor.appendChild(img);
|
||||
anchor.appendChild(titleDiv);
|
||||
div.appendChild(anchor);
|
||||
|
||||
container.appendChild(div);
|
||||
|
||||
// Animate appearance
|
||||
setTimeout(() => {
|
||||
div.style.opacity = "1";
|
||||
div.style.transform = "translateY(0)";
|
||||
}, 40 * idx++);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,91 @@
|
||||
// --- AI Chat Widget ---
|
||||
let aiChatWindow = null;
|
||||
let chatVisible = false;
|
||||
|
||||
// Detect Shift+T
|
||||
document.addEventListener("keydown", (e) => {
|
||||
if (e.shiftKey && e.key.toLowerCase() === "t") {
|
||||
e.preventDefault();
|
||||
toggleAIChat();
|
||||
}
|
||||
});
|
||||
|
||||
async function toggleAIChat() {
|
||||
if (!chatVisible) {
|
||||
aiChatWindow = document.createElement("div");
|
||||
aiChatWindow.style = `
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
width: 400px;
|
||||
height: 500px;
|
||||
background: #1e1e1e;
|
||||
color: #f0f0f0;
|
||||
border: 2px solid #444;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 0 20px rgba(0,0,0,0.5);
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
font-family: system-ui, sans-serif;
|
||||
`;
|
||||
aiChatWindow.innerHTML = `
|
||||
<div style="background:#222;padding:10px;text-align:center;font-weight:bold;">
|
||||
🎮 AI Chat to help with games
|
||||
</div>
|
||||
<div id="chatLog" style="flex:1;overflow-y:auto;padding:10px;"></div>
|
||||
<div style="display:flex;border-top:1px solid #333;">
|
||||
<input id="chatInput" type="text" placeholder="Type a message..."
|
||||
style="flex:1;padding:10px;background:#2a2a2a;color:#fff;border:none;outline:none;">
|
||||
<button id="chatSend" style="padding:10px 15px;background:#444;color:#fff;border:none;">Send</button>
|
||||
</div>
|
||||
`;
|
||||
document.body.appendChild(aiChatWindow);
|
||||
|
||||
const chatLog = aiChatWindow.querySelector("#chatLog");
|
||||
const chatInput = aiChatWindow.querySelector("#chatInput");
|
||||
const chatSend = aiChatWindow.querySelector("#chatSend");
|
||||
|
||||
// Intro message
|
||||
chatLog.innerHTML = `
|
||||
<div style="margin-bottom:10px;">
|
||||
<b>AI:</b> 👋 Hi! I'm the <b>Moon Gaming AI</b> — here to answer your <b>gaming questions</b>, chat about mods, or just have fun.
|
||||
Ask me anything!
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Send message handler
|
||||
chatSend.onclick = async () => {
|
||||
const msg = chatInput.value.trim();
|
||||
if (!msg) return;
|
||||
chatLog.innerHTML += `<div><b>You:</b> ${msg}</div>`;
|
||||
chatInput.value = "";
|
||||
|
||||
try {
|
||||
const response = await puter.ai.chat(msg);
|
||||
chatLog.innerHTML += `<div><b>AI:</b> ${response}</div>`;
|
||||
chatLog.scrollTop = chatLog.scrollHeight;
|
||||
} catch (err) {
|
||||
chatLog.innerHTML += `<div style="color:red;"><b>Error:</b> ${err.message}</div>`;
|
||||
}
|
||||
};
|
||||
|
||||
// Enter key sends message
|
||||
chatInput.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter") chatSend.click();
|
||||
});
|
||||
|
||||
chatVisible = true;
|
||||
} else {
|
||||
aiChatWindow.remove();
|
||||
chatVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Dark Mode Logic ---
|
||||
function applyDarkMode() {
|
||||
const isDarkMode = localStorage.getItem('darkMode') === 'true';
|
||||
document.body.classList.toggle('dark-mode', isDarkMode);
|
||||
}
|
||||
window.onload = applyDarkMode;
|
||||
@@ -0,0 +1,268 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Puter.js Sora2 Video Generator</title>
|
||||
<!-- Load Puter.js SDK - REQUIRED -->
|
||||
<script src="https://js.puter.com/v2/"></script>
|
||||
|
||||
<style>
|
||||
/* Base Styling & Responsiveness */
|
||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&display=swap');
|
||||
body {
|
||||
font-family: 'Inter', sans-serif;
|
||||
background-color: #0d1117;
|
||||
color: #c9d1d9;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 1rem;
|
||||
}
|
||||
.card {
|
||||
background-color: #161b22;
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5);
|
||||
width: 100%;
|
||||
max-width: 56rem; /* Slightly wider layout for video */
|
||||
padding: 2rem;
|
||||
border-radius: 0.75rem;
|
||||
}
|
||||
|
||||
/* Input & Textarea */
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 0.75rem;
|
||||
background-color: #30363d;
|
||||
border: 1px solid #484f58;
|
||||
border-radius: 0.5rem;
|
||||
color: white;
|
||||
resize: none;
|
||||
transition: border-color 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
textarea:focus {
|
||||
outline: none;
|
||||
border-color: #58a6ff;
|
||||
box-shadow: 0 0 0 3px rgba(88, 166, 255, 0.5);
|
||||
}
|
||||
|
||||
/* Button */
|
||||
.generate-btn {
|
||||
background: linear-gradient(90deg, #58a6ff, #2f81f7);
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 0.5rem;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease-in-out;
|
||||
border: none;
|
||||
margin-top: 1rem; /* Added spacing */
|
||||
}
|
||||
.generate-btn:hover:not(:disabled) {
|
||||
background: linear-gradient(90deg, #2f81f7, #58a6ff);
|
||||
box-shadow: 0 0 15px #2f81f7;
|
||||
}
|
||||
.generate-btn:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* Video Output Area */
|
||||
.video-container {
|
||||
border: 2px solid #30363d;
|
||||
background-color: #0d1117;
|
||||
padding: 1rem;
|
||||
border-radius: 0.75rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
/* Style for the video element returned by Puter.js */
|
||||
.generated-video {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
.video-caption {
|
||||
margin-top: 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
color: #8b949e;
|
||||
word-break: break-all;
|
||||
text-align: center;
|
||||
}
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Spinner CSS */
|
||||
@keyframes spin {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="app" class="card">
|
||||
<h1 style="font-size: 1.875rem; font-weight: 800; color: white; text-align: center; margin-bottom: 0.5rem;">Puter.js Sora2 Video Generator</h1>
|
||||
|
||||
<p style="text-align: center; font-size: 0.875rem; margin-bottom: 1.5rem; border: 1px solid #10b981; color: #10b981; background-color: rgba(16, 185, 129, 0.1); padding: 0.5rem; border-radius: 0.5rem;">
|
||||
🟢 **LIVE MODE:** This will attempt to generate a video using the `'sora-2'` model and may consume user credits. Generation can take a few minutes.
|
||||
</p>
|
||||
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<label for="prompt-input" style="display: block; font-size: 0.875rem; font-weight: 500; margin-bottom: 0.5rem; color: #a9a9b2;">Video Prompt</label>
|
||||
<textarea id="prompt-input" rows="3" placeholder="A majestic lion wearing sunglasses driving a vintage convertible through the desert."></textarea>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; justify-content: space-between; gap: 1rem; margin-bottom: 1.5rem;">
|
||||
<div style="flex-grow: 1;">
|
||||
<label for="duration-select" style="display: block; font-size: 0.875rem; font-weight: 500; margin-bottom: 0.5rem; color: #a9a9b2;">Duration (seconds)</label>
|
||||
<select id="duration-select" style="width: 100%; padding: 0.75rem; background-color: #30363d; border: 1px solid #484f58; border-radius: 0.5rem; color: white;">
|
||||
<option value="4">4 Seconds</option>
|
||||
<option value="8">8 Seconds</option>
|
||||
<option value="12">12 Seconds</option>
|
||||
</select>
|
||||
</div>
|
||||
<div style="flex-grow: 1;">
|
||||
<label for="resolution-select" style="display: block; font-size: 0.875rem; font-weight: 500; margin-bottom: 0.5rem; color: #a9a9b2;">Resolution</label>
|
||||
<select id="resolution-select" style="width: 100%; padding: 0.75rem; background-color: #30363d; border: 1px solid #484f58; border-radius: 0.5rem; color: white;">
|
||||
<option value="1280x720">HD (1280x720)</option>
|
||||
<option value="720x1280">Vertical (720x1280)</option>
|
||||
<option value="1792x1024">Desktop (1792x1024)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button id="generate-btn" class="generate-btn">
|
||||
<span id="button-text">Generate Video</span>
|
||||
<!-- Spinner Icon (Inline SVG) -->
|
||||
<svg id="spinner" class="hidden" style="animation: spin 1s linear infinite; margin-left: -0.25rem; margin-right: 0.75rem; height: 1.25rem; width: 1.25rem; color: white;" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<circle style="opacity: 0.25;" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path style="opacity: 0.75;" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<div id="result-area" class="hidden">
|
||||
<h2 id="result-title" class="hidden" style="font-size: 1.25rem; font-weight: 600; margin-bottom: 1rem; text-align: center; margin-top: 2rem;">Generated Video</h2>
|
||||
<div id="video-display" class="video-container hidden">
|
||||
<!-- Video player will be inserted here by Puter.js -->
|
||||
</div>
|
||||
<p id="error-message" class="hidden" style="color: #f87171; text-align: center; margin-top: 1rem;"></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const promptInput = document.getElementById('prompt-input');
|
||||
const durationSelect = document.getElementById('duration-select');
|
||||
const resolutionSelect = document.getElementById('resolution-select');
|
||||
const generateBtn = document.getElementById('generate-btn');
|
||||
const buttonText = document.getElementById('button-text');
|
||||
const spinner = document.getElementById('spinner');
|
||||
const resultArea = document.getElementById('result-area');
|
||||
const resultTitle = document.getElementById('result-title');
|
||||
const videoDisplay = document.getElementById('video-display');
|
||||
const errorMessage = document.getElementById('error-message');
|
||||
|
||||
/**
|
||||
* Sets the loading state for the UI elements.
|
||||
* @param {boolean} isLoading - True to show loading spinner, false otherwise.
|
||||
*/
|
||||
function setLoadingState(isLoading) {
|
||||
generateBtn.disabled = isLoading;
|
||||
spinner.classList.toggle('hidden', !isLoading);
|
||||
buttonText.textContent = isLoading ? 'Generating (This can take minutes)...' : 'Generate Video';
|
||||
|
||||
// Clear previous results on new generation
|
||||
if (isLoading) {
|
||||
errorMessage.classList.add('hidden');
|
||||
videoDisplay.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the video result to the DOM.
|
||||
* @param {HTMLVideoElement} videoElement - The video element returned by puter.ai.txt2vid.
|
||||
* @param {string} prompt - The original prompt.
|
||||
*/
|
||||
function renderVideo(videoElement, prompt) {
|
||||
videoDisplay.innerHTML = '';
|
||||
|
||||
// Add custom class for styling
|
||||
videoElement.classList.add('generated-video');
|
||||
|
||||
// Append the video element
|
||||
videoDisplay.appendChild(videoElement);
|
||||
|
||||
// Add caption/source info
|
||||
const caption = document.createElement('p');
|
||||
caption.classList.add('video-caption');
|
||||
caption.textContent = `Prompt: "${prompt}"`;
|
||||
videoDisplay.appendChild(caption);
|
||||
|
||||
resultArea.classList.remove('hidden');
|
||||
resultTitle.classList.remove('hidden');
|
||||
videoDisplay.classList.remove('hidden');
|
||||
}
|
||||
|
||||
/**
|
||||
* Main event handler for the Generate button.
|
||||
*/
|
||||
generateBtn.addEventListener('click', async () => {
|
||||
const prompt = promptInput.value.trim();
|
||||
if (!prompt) {
|
||||
errorMessage.textContent = "Please enter a creative prompt to generate your video.";
|
||||
errorMessage.classList.remove('hidden');
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof puter === 'undefined' || !puter.ai || !puter.ai.txt2vid) {
|
||||
errorMessage.textContent = "Puter.js is not loaded correctly. Video generation is unavailable.";
|
||||
errorMessage.classList.remove('hidden');
|
||||
return;
|
||||
}
|
||||
|
||||
// Configuration for the live API call
|
||||
const options = {
|
||||
model: 'sora-2', // Target the sora-2 model
|
||||
seconds: parseInt(durationSelect.value, 10), // User selected duration (4, 8, or 12)
|
||||
size: resolutionSelect.value // User selected resolution
|
||||
};
|
||||
|
||||
console.log("Starting video generation with options:", options);
|
||||
|
||||
try {
|
||||
setLoadingState(true);
|
||||
|
||||
// Call the function without the 'true' flag for live generation
|
||||
const videoElement = await puter.ai.txt2vid(prompt, options);
|
||||
|
||||
renderVideo(videoElement, prompt);
|
||||
} catch (error) {
|
||||
console.error("Video Generation Process Failed:", error);
|
||||
|
||||
// Customize error message for better user guidance
|
||||
let userError = `Generation failed.`;
|
||||
if (error.message.includes('credits')) {
|
||||
userError = "Generation failed: Insufficient user credits. Please check your Puter account.";
|
||||
} else if (error.message.includes('rate limit')) {
|
||||
userError = "Generation failed: Rate limit exceeded. Please try again later.";
|
||||
} else {
|
||||
userError = `Error: ${error.message}`;
|
||||
}
|
||||
|
||||
errorMessage.textContent = userError;
|
||||
errorMessage.classList.remove('hidden');
|
||||
resultTitle.classList.add('hidden');
|
||||
videoDisplay.classList.add('hidden');
|
||||
} finally {
|
||||
setLoadingState(false);
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -20,7 +20,7 @@
|
||||
</div>
|
||||
<div class="credit-item">
|
||||
<h2>Game Testers</h2>
|
||||
<p>Khaled Abuneiab/Soren Graff</p>
|
||||
<p>all</p>
|
||||
</div>
|
||||
<div class="credit-item">
|
||||
<h2>Accounting</h2>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<html>
|
||||
<script src="/games/flach games/ruffle.js"></script>
|
||||
<script src="https://unpkg.com/@ruffle-rs/ruffle"></script>
|
||||
<body>
|
||||
<object>
|
||||
@@ -8,4 +7,4 @@
|
||||
|
||||
<script src="https://unpkg.com/@ruffle-rs/ruffle"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": " new Bad Time Simulator(1.4.7a)",
|
||||
"short_name": "new Bad Time Simulator(1.4.7a)",
|
||||
"start_url": "index.html",
|
||||
"display": "fullscreen",
|
||||
"orientation": "any",
|
||||
"icons": [{
|
||||
"src": "icon-16.png",
|
||||
"sizes": "16x16",
|
||||
"type": "image/png"
|
||||
}, {
|
||||
"src": "icon-32.png",
|
||||
"sizes": "32x32",
|
||||
"type": "image/png"
|
||||
}, {
|
||||
"src": "icon-128.png",
|
||||
"sizes": "128x128",
|
||||
"type": "image/png"
|
||||
}, {
|
||||
"src": "icon-256.png",
|
||||
"sizes": "144x144",
|
||||
"type": "image/png"
|
||||
}, {
|
||||
"src": "icon-256.png",
|
||||
"sizes": "256x256",
|
||||
"type": "image/png"
|
||||
}]
|
||||
}
|
||||
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 342 B |
|
After Width: | Height: | Size: 286 B |
|
After Width: | Height: | Size: 573 B |
|
After Width: | Height: | Size: 320 B |
|
After Width: | Height: | Size: 168 B |
|
After Width: | Height: | Size: 169 B |
|
After Width: | Height: | Size: 168 B |
|
After Width: | Height: | Size: 113 B |
|
After Width: | Height: | Size: 165 B |
|
After Width: | Height: | Size: 133 B |
|
After Width: | Height: | Size: 159 B |
|
After Width: | Height: | Size: 140 B |
|
After Width: | Height: | Size: 137 B |
|
After Width: | Height: | Size: 92 B |
|
After Width: | Height: | Size: 105 B |
|
After Width: | Height: | Size: 92 B |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 92 B |
|
After Width: | Height: | Size: 654 B |
|
After Width: | Height: | Size: 463 B |
|
After Width: | Height: | Size: 92 B |
|
After Width: | Height: | Size: 348 B |
|
After Width: | Height: | Size: 125 B |
|
After Width: | Height: | Size: 123 B |
|
After Width: | Height: | Size: 128 B |
|
After Width: | Height: | Size: 209 B |
|
After Width: | Height: | Size: 97 B |
|
After Width: | Height: | Size: 168 B |
|
After Width: | Height: | Size: 92 B |
|
After Width: | Height: | Size: 92 B |
|
After Width: | Height: | Size: 157 B |
|
After Width: | Height: | Size: 164 B |
|
After Width: | Height: | Size: 161 B |
|
After Width: | Height: | Size: 158 B |
|
After Width: | Height: | Size: 148 B |
|
After Width: | Height: | Size: 155 B |
|
After Width: | Height: | Size: 129 B |
|
After Width: | Height: | Size: 92 B |
|
After Width: | Height: | Size: 180 B |
|
After Width: | Height: | Size: 172 B |
|
After Width: | Height: | Size: 530 B |
|
After Width: | Height: | Size: 433 B |
|
After Width: | Height: | Size: 114 B |
|
After Width: | Height: | Size: 114 B |
|
After Width: | Height: | Size: 114 B |
|
After Width: | Height: | Size: 191 B |
|
After Width: | Height: | Size: 173 B |
|
After Width: | Height: | Size: 147 B |
|
After Width: | Height: | Size: 97 B |
|
After Width: | Height: | Size: 301 B |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 446 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 666 B |
|
After Width: | Height: | Size: 343 B |
|
After Width: | Height: | Size: 189 B |
|
After Width: | Height: | Size: 521 B |
|
After Width: | Height: | Size: 271 B |
|
After Width: | Height: | Size: 612 B |
|
After Width: | Height: | Size: 209 B |
|
After Width: | Height: | Size: 139 B |
|
After Width: | Height: | Size: 249 B |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 388 B |
|
After Width: | Height: | Size: 237 B |
|
After Width: | Height: | Size: 237 B |
|
After Width: | Height: | Size: 241 B |
|
After Width: | Height: | Size: 241 B |
|
After Width: | Height: | Size: 237 B |
|
After Width: | Height: | Size: 237 B |
|
After Width: | Height: | Size: 210 B |
|
After Width: | Height: | Size: 393 B |
|
After Width: | Height: | Size: 460 B |
|
After Width: | Height: | Size: 444 B |
|
After Width: | Height: | Size: 750 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 373 B |