Compare commits

..
23 Commits
Author SHA1 Message Date
OpenClaw Engineer d8742ec5bb Merge remote-tracking branch 'origin/main' 2026-03-14 21:22:03 -05:00
OpenClaw Engineer 1bab945dcd docs: add USB thumbdrive install/run guide for Dino Land 2026-03-14 21:12:14 -05:00
OpenClaw Engineer eb9908839d Add brief red damage flash for T-Rex on hit 2026-03-14 20:58:53 -05:00
OpenClaw Engineer 94d371d901 Make portals appear earlier with fade-in visuals and SFX 2026-03-14 20:49:27 -05:00
OpenClaw Engineer 2f07d74c78 Implement state-aware music transitions for title, biome gameplay, death, and restart 2026-03-14 20:42:00 -05:00
OpenClaw Engineer ef70c6324d Add procedural background music engine wired to music toggle 2026-03-14 20:15:23 -05:00
OpenClaw Engineer 800880ed30 dino-land: add autoplay-safe music toggle on correct CI/CD path 2026-03-14 20:08:59 -05:00
louiswhit 6a57b9dcfa Logo Updated 2026-03-10 17:45:52 -05:00
OpenClaw Engineer d57951466e Update difficulty selection visibility, enhance scores data, and modify password error message 2026-03-07 15:22:13 -06:00
OpenClaw Engineer 2377d4fa71 Reduce Easy-mode water gap widths significantly 2026-03-07 15:11:04 -06:00
OpenClaw Engineer 50671b483f Fix end-of-world portal flow to allow forward-only progression 2026-03-07 11:15:59 -06:00
OpenClaw Engineer 52717f67a9 Add difficulty portals, rebalance hearts, and tune easy water gaps 2026-03-07 10:39:21 -06:00
OpenClaw Engineer e4a1849669 Add Dino Land logo to start screen modal 2026-03-06 15:56:52 -06:00
OpenClaw Engineer 85e2bbb48b Simplify death screen restart and add biome parallax visuals 2026-03-05 06:55:38 -06:00
OpenClaw Engineer e106d8ea65 Add VIP+ mode to PIN screen and Play Again options 2026-03-05 06:39:06 -06:00
OpenClaw Engineer be519d515e balance difficulty tuning for spawn pace and damage windows 2026-03-04 07:03:53 -06:00
OpenClaw Engineer a848a6854b add password start modal, VIP hearts, difficulty, and new biome hazards 2026-03-04 06:58:36 -06:00
OpenClaw Engineer df3f1e513e Add heart color states, ant +50 popups, and action SFX 2026-03-03 23:31:09 -06:00
OpenClaw Engineer 20f4f4fbc2 docs: update LAN launch and local IP test instructions 2026-03-03 22:25:41 -06:00
OpenClaw Engineer d433141ccb Fix pterodactyl duck hitbox and prevent duplicate leaderboard submits 2026-03-03 22:23:41 -06:00
OpenClaw Engineer 4470266234 Fix pterodactyl duck lane collisions and prevent duplicate score saves 2026-03-03 21:22:54 -06:00
OpenClaw Engineer b68f71beb2 chore: polish docs and verify local PHP runtime checks 2026-03-03 20:43:23 -06:00
OpenClaw Engineer 38ec8bb1ef feat: add death screen with top-10 leaderboard and PHP score persistence 2026-03-03 20:42:59 -06:00
8 changed files with 1362 additions and 100 deletions
+69
View File
@@ -0,0 +1,69 @@
# Dino Land
No-build browser game using plain **HTML/CSS/JS/PHP**.
## Run locally
```bash
cd "/Users/lawsonawhittington/.openclaw/workspace/Dino Land"
php -S 0.0.0.0:8000
```
Open on the same machine: http://localhost:8000
LAN test URL (from another device on your network):
1. Find your LAN IP:
`python3 -c "import socket;s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM);s.connect(('8.8.8.8',80));print(s.getsockname()[0]);s.close()"`
2. Open: `http://<YOUR_LAN_IP>:8000` (example: `http://192.168.1.25:8000`)
## USB / thumbdrive distribution
Need to run Dino Land from a USB drive on unknown machines (Windows/macOS/ChromeOS)?
See: **[thumbdrive-install.md](./thumbdrive-install.md)**
## Controls
- **Up Arrow**: jump
- **Down Arrow**: duck
- **Left Arrow**: walk backward
- **Right Arrow**: walk forward
## Gameplay Rules
- TRex starts with **5 hearts** (or **10 hearts** in VIP mode).
- Easy and Medium end with a portal that advances to the next difficulty while preserving score.
- Moving forward earns score (**+1 per forward step unit**).
- Water gaps cause instant death if landed in.
- Ant collision costs 1 heart; jumping on ants crushes them.
- Pterodactyls unlock after score > 100 (duck to avoid).
- Meteors unlock after score > 250.
- On death: top-10 leaderboard is shown; top-10 runs can be saved.
## Leaderboard persistence
- Backend endpoint: `api/scores.php`
- Data file: `data/scores.json`
## Audio / music toggle behavior
- Music defaults to **OFF** when no preference exists in localStorage.
- Toggle preference key: `dinoLand.musicEnabled` (`'1'` on, `'0'` off).
- First user click on the music toggle resumes/unlocks Web Audio and starts procedural music when turned ON.
- Music state is context-aware:
- **Title/start screen** uses title music profile.
- **Gameplay** switches profile by biome (Plains, Desert, Jungle, Snow, and Lava mapped to the Volcano profile).
- **Death screen** switches to death music profile.
- **Restart/respawn to start screen** returns to title profile.
- Turning music OFF performs a short fade to mute; turning back ON fades in the current state profile.
## Quick verification checklist
1. Start server and open game.
2. Confirm score increases while moving right.
3. Confirm hearts drop on ant / pterodactyl / meteor collisions.
4. Confirm water causes immediate game over.
5. Confirm leaderboard loads and score save works.
6. With a fresh browser profile, confirm music button starts as `🔇 Music: Off`.
7. Click toggle to ON and confirm audible looping background music starts.
8. Click toggle to OFF and confirm music fades/mutes.
9. Reload page and confirm toggle state persists.
+63
View File
@@ -0,0 +1,63 @@
<?php
declare(strict_types=1);
header('Content-Type: application/json');
$storageDir = __DIR__ . '/../data';
$storageFile = $storageDir . '/scores.json';
if (!is_dir($storageDir)) {
mkdir($storageDir, 0777, true);
}
if (!file_exists($storageFile)) {
file_put_contents($storageFile, json_encode([], JSON_PRETTY_PRINT));
}
function loadScores(string $file): array {
$raw = file_get_contents($file);
if ($raw === false || trim($raw) === '') {
return [];
}
$decoded = json_decode($raw, true);
return is_array($decoded) ? $decoded : [];
}
function saveScores(string $file, array $scores): void {
usort($scores, fn($a, $b) => ($b['score'] ?? 0) <=> ($a['score'] ?? 0));
$scores = array_slice($scores, 0, 10);
file_put_contents($file, json_encode($scores, JSON_PRETTY_PRINT));
}
$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
if ($method === 'GET') {
$scores = loadScores($storageFile);
usort($scores, fn($a, $b) => ($b['score'] ?? 0) <=> ($a['score'] ?? 0));
echo json_encode(array_slice($scores, 0, 10));
exit;
}
if ($method === 'POST') {
$payload = json_decode(file_get_contents('php://input') ?: '{}', true);
$name = trim((string)($payload['name'] ?? 'Anonymous'));
$score = (int)($payload['score'] ?? 0);
if ($name === '') $name = 'Anonymous';
$name = mb_substr($name, 0, 20);
if ($score < 0) $score = 0;
$scores = loadScores($storageFile);
$scores[] = [
'name' => $name,
'score' => $score,
'date' => date('c')
];
saveScores($storageFile, $scores);
echo json_encode(['ok' => true]);
exit;
}
http_response_code(405);
echo json_encode(['error' => 'Method Not Allowed']);
Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

+1
View File
@@ -0,0 +1 @@
[]
+37 -1
View File
@@ -13,6 +13,42 @@
</div> </div>
<canvas id="game" width="960" height="540" aria-label="Dino Land game canvas"></canvas> <canvas id="game" width="960" height="540" aria-label="Dino Land game canvas"></canvas>
<button id="musicToggle" type="button" aria-pressed="false" aria-label="Toggle music">🔇 Music: Off</button>
<div id="startScreen">
<div class="panel">
<img
class="start-logo"
src="assets/images/dinoland-logo.png"
alt="Dino Land logo"
width="320"
height="180"
/>
<h1>Start Dino Land</h1>
<form id="startForm">
<label for="startPassword">Password</label>
<input id="startPassword" type="password" required placeholder="Enter password" />
<label for="accessMode">Access Mode</label>
<select id="accessMode">
<option value="standard" selected>Standard (5 hearts)</option>
<option value="vip">VIP (10 hearts)</option>
</select>
<div style="display: none; !important;">
<label for="difficulty" style="display: none; !important;">Difficulty</label>
<select id="difficulty" style="display: none; !important;">
<option value="easy" selected>Easy</option>
<option value="medium">Medium</option>
<option value="hard">Hard</option>
</select>
</div>
<p id="startError" class="error"></p>
<button type="submit">Start Game</button>
</form>
</div>
</div>
<div id="deathScreen" class="hidden"> <div id="deathScreen" class="hidden">
<div class="panel"> <div class="panel">
@@ -25,7 +61,7 @@
<input id="playerName" maxlength="20" required /> <input id="playerName" maxlength="20" required />
<button type="submit">Save Score</button> <button type="submit">Save Score</button>
</form> </form>
<button id="restartBtn">Play Again</button> <button id="restartBtn">Restart</button>
</div> </div>
</div> </div>
+936 -97
View File
File diff suppressed because it is too large Load Diff
+56 -2
View File
@@ -25,7 +25,25 @@ body {
border: 2px solid #1b3a47; border: 2px solid #1b3a47;
background: #b5ecff; background: #b5ecff;
} }
#deathScreen { #musicToggle {
position: fixed;
right: 16px;
bottom: 16px;
z-index: 9;
width: auto;
min-width: 132px;
padding: 10px 12px;
border-radius: 10px;
border: 1px solid rgba(255,255,255,0.24);
background: rgba(0,0,0,0.65);
color: #fff;
font-size: 14px;
font-weight: 700;
cursor: pointer;
}
#deathScreen,
#startScreen {
position: fixed; position: fixed;
inset: 0; inset: 0;
background: rgba(0,0,0,0.65); background: rgba(0,0,0,0.65);
@@ -39,10 +57,46 @@ body {
padding: 20px; padding: 20px;
width: min(92vw, 460px); width: min(92vw, 460px);
} }
.start-logo {
display: block;
width: min(100%, 320px);
height: auto;
margin: 0 auto 8px;
}
.hidden { display: none !important; } .hidden { display: none !important; }
button, input { button, input, select {
font-size: 16px; font-size: 16px;
padding: 8px 10px; padding: 8px 10px;
margin-top: 8px; margin-top: 8px;
width: 100%;
}
label {
display: block;
margin-top: 10px;
font-weight: 700;
}
.inline-option {
display: flex;
align-items: center;
gap: 8px;
}
.inline-option input {
width: auto;
margin: 0;
}
.error {
color: #c62828;
min-height: 20px;
} }
ol { padding-left: 22px; } ol { padding-left: 22px; }
/* removed unused play-again-row styles */
.heart {
display: inline-block;
margin-right: 2px;
}
.heart-active { color: #f2c94c; }
.heart-lost { color: #111; }
+200
View File
@@ -0,0 +1,200 @@
# Dino Land USB / Thumbdrive Install & Run Guide
For non-technical users running Dino Land from a USB drive on unknown computers (Windows, macOS, ChromeOS).
---
## 1) Quick decision tree
```text
Start
├─ Can you run a local web server (PHP or portable server) from USB?
│ ├─ Yes → Use FULL LOCAL MODE (leaderboard + API should work)
│ └─ No
│ ├─ Can you at least open files in a browser from USB?
│ │ ├─ Yes → Use OFFLINE QUICK PLAY (gameplay only, no score save)
│ │ └─ No → Host machine is locked down; ask for a machine with browser file access
└─ If security warning appears (SmartScreen/Gatekeeper), use browser-only mode or approved machine
```
---
## 2) Recommendation matrix
| Mode | Needs install/admin? | Works from USB only? | Scoreboard/API | Best when |
|---|---|---|---|---|
| **Works with no install** (open file in browser) | No | Yes | **No** (PHP API unavailable) | Locked-down machines, schools, kiosks |
| **Works with portable binaries** (USB-contained server) | Usually No (if executable allowed) | Yes | **Yes** (if local server starts) | Unknown machine, no admin, but executables allowed |
| **Requires host runtime/install** (host PHP/Python/etc.) | Often Yes (or preinstalled tools) | Not strictly | **Yes** | Managed machine with approved dev/runtime tools |
---
## 3) Packaging options to put on USB
## Option A: **Offline quick play** (no scores)
Use existing project files as-is.
Required on USB:
- `index.php` (or optional static fallback page if you create one)
- `js/`, `assets/`, `styles.css`
What works:
- Core gameplay usually works in browser file mode (`file://...`)
What does **not** work reliably:
- Leaderboard save/load via `api/scores.php`
## Option B: **Full local mode** (with local server)
Put full project folder on USB, including:
- `api/`
- `data/`
- all game assets/files
Then run a local server (portable or host runtime) and open `http://127.0.0.1:PORT`.
---
## 4) Per-OS run steps
## Windows
### A) No install (quick play)
1. Insert USB.
2. Open USB in File Explorer.
3. Right-click `index.php` -> **Open with** -> Chrome/Edge.
- If this opens raw PHP text or broken page, use Full Local Mode.
### B) Portable binaries (preferred if allowed)
If your USB has `php\php.exe` bundled:
```bat
cd /d "%~dp0"
php\php.exe -S 127.0.0.1:8000
```
Then open:
- `http://127.0.0.1:8000`
If SmartScreen appears:
- Click **More info** -> **Run anyway** only if USB is trusted.
- On locked corporate machines, this option may be blocked.
### C) Host runtime already installed
In Command Prompt (inside Dino Land folder):
```bat
php -S 127.0.0.1:8000
```
---
## macOS
### A) No install (quick play)
1. Insert USB.
2. In Finder, open Dino Land folder.
3. Drag `index.php` into Chrome/Safari (or File -> Open File).
### B) Portable binary from USB
If USB includes a PHP binary (example path `./php/bin/php`):
```bash
cd "/Volumes/<USB_NAME>/Dino Land"
./php/bin/php -S 127.0.0.1:8000
```
Open `http://127.0.0.1:8000`
If Gatekeeper blocks the binary:
- Right-click binary -> **Open** (one-time allow), or
- If policy blocks unknown binaries, use quick play mode.
If quarantine flag blocks execution, advanced users can remove it:
```bash
xattr -dr com.apple.quarantine "/Volumes/<USB_NAME>/Dino Land/php"
```
(Only do this for trusted files.)
### C) Host runtime (if preinstalled)
```bash
cd "/Volumes/<USB_NAME>/Dino Land"
php -S 127.0.0.1:8000
```
---
## ChromeOS
### A) No install (quick play)
- Open Files app -> USB -> game files.
- Open with browser.
- If browser blocks local JS/file access behavior, use another machine or Linux mode.
### B) Portable/server mode on ChromeOS
- Usually restricted unless Linux (Crostini) is enabled.
- If Linux terminal is available:
```bash
cd "/mnt/chromeos/removable/<USB_NAME>/Dino Land"
php -S 127.0.0.1:8000
```
Then open `http://127.0.0.1:8000` in Chrome.
### C) Host runtime/install required
- On managed school/work Chromebooks, installing/enabling Linux may be disabled by policy.
- In that case, only quick play (if allowed) is feasible.
---
## 5) Limitations, risks, and behavior to expect
- **`file://` origin restrictions:** browsers may block some fetch/XHR/module behaviors from local files.
- **Scoreboard/API dependency:** leaderboard save/load needs `api/scores.php` via server-side PHP. No running PHP server = no persistent scores.
- **Windows SmartScreen:** may warn/block unsigned portable executables from USB.
- **macOS Gatekeeper/quarantine:** may block downloaded/unsigned binaries on USB until manually allowed.
- **ChromeOS constraints:** managed devices often block runtime installs, local servers, or executable permissions.
- **USB write permissions:** if USB is read-only or restricted, `data/scores.json` cannot update even with server running.
---
## 6) Practical fallback order (recommended)
1. Try **Full local mode** (portable PHP on USB).
2. If blocked, try **host-installed PHP** (if already present).
3. If still blocked, use **Offline quick play** (no scores).
---
## 7) Minimal launcher scripts (optional, put on USB)
### `start-windows.bat`
```bat
@echo off
cd /d "%~dp0"
if exist php\php.exe (
php\php.exe -S 127.0.0.1:8000
) else (
php -S 127.0.0.1:8000
)
```
### `start-macos.sh`
```bash
#!/usr/bin/env bash
cd "$(dirname "$0")"
if [ -x "./php/bin/php" ]; then
./php/bin/php -S 127.0.0.1:8000
else
php -S 127.0.0.1:8000
fi
```
Make executable (once):
```bash
chmod +x start-macos.sh
```