# Save Pet

A premium, mobile-first HTML5 puzzle game. Draw protective ink lines to stop
swarming bees and keep your pet safe — 100 levels across 10 worlds, Daily
Challenge, Endless Mode, Random Challenge, coins, stars, and achievements.

Built with plain HTML5 + CSS3 + vanilla JavaScript and the Canvas API.
**No frameworks, no build step, no server-side code.** Extract the ZIP,
upload it, done.

Live target URL: **https://gamesji.com/savepet/**
Developer: **GamesJi.com**

---

## 1. What's inside

```
savepet/
├── index.html              Main app (single page)
├── offline.html             Shown only if the SW has nothing cached yet and you're offline
├── manifest.json            PWA manifest (icons, shortcuts, maskable icon)
├── sw.js                    Service worker (offline cache + update flow)
├── browserconfig.xml        Windows tile config
├── robots.txt
├── sitemap.xml
├── .htaccess                 Apache config (MIME types, cache headers, gzip) — optional
├── css/
│   ├── style.css             Human-readable source — edit this one
│   └── style.min.css         Minified build — index.html loads this
├── js/                      13 small, organized modules (see §6)
├── assets/
│   ├── icons/                All app icons, favicon, maskable icon (generated PNGs)
│   ├── images/                Social-share preview image (og-image.png)
│   └── audio/                 13 SFX + 2 music loops, procedurally composed (real files, not silence)
├── README.md                 This file
└── LICENSE
```

Everything is a real, working file — there are no placeholder images, no
missing audio, and no "TODO: add gameplay" stubs. The only things you must
fill in yourself are your own AdSense / Analytics / Search Console IDs,
because nobody but you has those.

---

## 2. Installation (shared hosting)

1. Unzip the package.
2. Upload the **contents** of the `savepet/` folder (not the folder itself)
   into `/savepet/` on your web server, e.g. via FTP/SFTP or your host's
   File Manager, so that `index.html` ends up at
   `https://gamesji.com/savepet/index.html`.
3. Visit `https://gamesji.com/savepet/` in a browser. That's it — there is
   no build step, no `npm install`, no database, no PHP.
4. Works on any Apache/Nginx/LiteSpeed shared host. `.htaccess` is optional
   (Apache only) — if your host doesn't support it, delete it; the game
   works fine without it, you'll just miss the extra cache/compression
   tuning.

### Requirements
- Any static file host (Apache, Nginx, GitHub Pages, Cloudflare Pages, etc.)
- HTTPS is required for full PWA install support (service workers require
  a secure context — `localhost` also works for local testing).

---

## 3. Google Search Console verification

1. Go to [search.google.com/search-console](https://search.google.com/search-console).
2. Add a property for `https://gamesji.com/savepet/` (URL prefix method).
3. Choose the **HTML tag** verification method. Google gives you a line like:
   ```html
   <meta name="google-site-verification" content="AbCdEf123..." />
   ```
4. Open `index.html`, find this existing line near the top of `<head>`:
   ```html
   <meta name="google-site-verification" content="REPLACE_WITH_YOUR_VERIFICATION_CODE">
   ```
   and replace the content value with the code Google gave you.
5. Re-upload `index.html` and click **Verify** in Search Console.
6. Submit `https://gamesji.com/savepet/sitemap.xml` under **Sitemaps**.

(Alternative: Search Console's "HTML file" method also works — just upload
the file it gives you to the `savepet/` root — but the meta-tag method
above needs no extra upload.)

---

## 4. AdSense integration

Ad containers already exist in the right places (top banner, bottom
banner, between-levels interstitial, game-over slot) and are positioned in
normal page flow — **they never overlay the canvas or controls.** They are
OFF by default so the game ships with zero third-party network calls.

To turn them on:

1. Open `js/config.js` and set:
   ```js
   ADSENSE_ENABLED: true,
   ADSENSE_CLIENT_ID: "ca-pub-XXXXXXXXXXXXXXXX",
   ADSENSE_SLOTS: {
     topBanner: "1111111111",
     bottomBanner: "2222222222",
     interstitial: "3333333333",
     gameOver: "4444444444"
   },
   ```
2. Open `index.html`, find the commented-out line near the bottom of
   `<head>`, and uncomment it (fill in your client id there too):
   ```html
   <script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-XXXXXXXXXXXXXXXX" crossorigin="anonymous"></script>
   ```
3. Re-upload both files. `js/ads.js` will automatically create the AdSense
   `<ins>` units inside the existing placeholder containers on load.

**Rewarded ads / Skip Level:** `js/ads.js` has `showRewarded()` and
`showInterstitial()` functions with a clearly-labeled placeholder flow (a
short in-game "Ad playing…" countdown). Replace the body of those two
functions with your real ad network's SDK call (AdMob H5 Games Ads, or any
rewarded web ad network) — just make sure you still call `onReward()`/
`onClose()` the same way so Hint/Skip keep working if an ad fails to load.

---

## 5. Analytics integration

All three are OFF by default (zero network calls until you enable them) —
edit `js/config.js`:

```js
GA_ENABLED: true,
GA_MEASUREMENT_ID: "G-XXXXXXXXXX",     // Google Analytics 4

GTM_ENABLED: true,
GTM_ID: "GTM-XXXXXXX",                  // Google Tag Manager

CLARITY_ENABLED: true,
CLARITY_PROJECT_ID: "xxxxxxxxxx",       // Microsoft Clarity
```

`js/analytics.js` already fires a few useful events out of the box:
`game_loaded`, `level_start`, `level_complete`, `level_failed`, and
`pwa_installed`. Add more calls to `SP.Analytics.track("event_name", {...})`
anywhere in the code if you want additional events.

---

## 6. Code structure (for developers)

No bundler, no npm dependency — just 13 plain `<script>` tags loaded in
dependency order (see the bottom of `index.html`). Every file attaches to
a single shared `window.SP` namespace object so nothing pollutes globals.

| File | Responsibility |
|---|---|
| `config.js` | All tunable constants + your ad/analytics IDs (edit this first) |
| `utils.js` | Math helpers, seeded RNG, save-game storage wrapper, event bus |
| `levels.js` | Deterministically generates all 100 levels + Daily/Random/Endless configs |
| `entities.js` | Pet / Bee / Hive: physics update + Canvas vector-art rendering |
| `particles.js` | Pop bursts, coin sparkle, hearts, confetti |
| `audio.js` | SFX + music playback, autoplay-policy-safe |
| `achievements.js` | Achievement definitions, derived from save data |
| `game.js` | Core engine: input, spawning, collisions, scoring, render loop |
| `ads.js` | AdSense slot injection + rewarded/interstitial placeholders |
| `analytics.js` | GA4 / GTM / Clarity loaders + event tracking |
| `ui.js` | All screens, modals, HUD, level grid — the only file that touches the DOM |
| `pwa.js` | Service worker registration, install prompt, update banner |
| `main.js` | Boots everything in the right order |

`game.js` never touches the DOM directly and `ui.js` never touches the
canvas directly — they only talk through the small set of hook functions
you'll see called on `SP.UI` from inside `game.js`. This makes it possible
to test the physics/scoring logic headlessly (which is exactly how this
project was validated before shipping — see `getState()` on `SP.Game`).

### How the "100 levels" actually work
Each level id (1–100) is fed through a seeded pseudo-random generator
(`mulberry32`), so **the same id always produces the exact same hive
layout, timer, ink budget and bee mix** — genuinely fixed, reproducible
boards, not random-every-attempt chaos. Difficulty (spawn rate, bee speed,
armored/fast bee mix, ink budget, hive count, wind) scales smoothly across
all 100 levels and is grouped into 10 themed worlds of 10 levels each, with
a harder "boss" layout on every 10th level. Daily Challenge and Random
Challenge reuse the same generator with different seeds so they stay
balanced instead of unfair.

### Audio & art
All sound effects and both music loops are **procedurally synthesized**
(see the generation notes in this repo's dev history) and shipped as real
`.wav`/`.mp3`/`.ogg` files — there is nothing to download that might 404.
All visuals (pet, bees, hives, backgrounds) are drawn live with the Canvas
2D API rather than image files, which keeps the whole game under ~1&nbsp;MB
and fully offline-capable. Swap in your own art/audio any time — see §7.

### Verifying changes (optional, for developers)
A zero-dependency headless smoke test ships in `tests/smoke-test.js`. It
mocks just enough of the browser to run the real game engine under plain
Node, so you can sanity-check an edit in seconds without opening a
browser:
```
node tests/smoke-test.js
```
It specifically guards against the class of bug where the game screen
starts hidden (`display:none`) until the player taps Play — the canvas's
parent legitimately reports 0×0 size at that moment, which is worth
re-testing any time you touch `js/game.js` rendering code.

---

## 7. Customization guide

- **Change the pet or bee look:** edit the draw functions in
  `js/entities.js` (`drawPet`, `drawBee`, `drawHive`). Everything is drawn
  with basic Canvas shapes (arcs, ellipses, gradients) proportional to a
  `radius` variable, so resizing/recoloring is just editing multipliers.
- **Retheme a world's colors:** edit the `WORLDS` array at the top of
  `js/levels.js` (`sky`, `ground`, `accent` hex colors + `name`).
- **Change difficulty curve:** edit the `lerp(...)` calls inside
  `generateLevel()` in `js/levels.js`.
- **Swap music/SFX for your own:** drop replacement files into
  `assets/audio/` using the same filenames listed in `js/audio.js`
  (`SFX_FILES` / `MUSIC_FILES`), or change the paths there to point at new
  filenames.
- **Colors/fonts/spacing:** all design tokens are CSS custom properties at
  the top of `css/style.css` (`:root { --honey: ...; }`). Edit that file,
  then regenerate `style.min.css` (any CSS minifier works, or just copy
  `style.css` over it unminified — it'll still work, just a bit larger).
- **Coin economy / hint cost / starting coins:** all in `js/config.js`.

---

## 8. PWA / installability

- **Android/Desktop Chrome/Edge:** an "Install Save Pet" banner appears
  automatically (via the native `beforeinstallprompt` flow) once the
  browser decides the site is installable; tapping it installs a
  standalone app with its own icon, splash, and 3 home-screen shortcuts
  (Daily Challenge, Endless Mode, Continue Playing).
- **iOS Safari:** iOS does not support the install-prompt API, so a banner
  with manual instructions ("tap Share → Add to Home Screen") is shown
  instead after a few seconds on the menu screen.
- **Offline play:** the service worker (`sw.js`) precaches the entire app
  shell (HTML/CSS/JS/icons/audio) on first visit. After that first visit,
  the game is fully playable with no network connection at all.
- **Shipping an update:** bump the `CACHE_VERSION` string at the top of
  `sw.js` (e.g. `savepet-v1.0.1`) whenever you change any file. Returning
  players will see a small "New version available" banner with a Refresh
  button instead of files silently changing under them mid-session.

---

## 9. Browser support

Tested against modern evergreen browsers: Chrome, Edge, Firefox, Safari
(desktop + iOS), Samsung Internet. Uses Pointer Events (mouse + touch in
one code path), the Fullscreen API (feature-detected, no-ops gracefully
where unsupported, e.g. iOS Safari), and the Vibration API (feature-
detected; iOS Safari has no vibration support on the web and simply won't
vibrate, which is expected and harmless).

---

## 10. Support / feedback

This is a static, self-contained project with no external services beyond
the ones you explicitly enable (AdSense/Analytics). If something doesn't
load, first check your browser console for the exact error — with ads and
analytics left at their default (disabled) settings there should be zero
console errors or network requests beyond the game's own files.

---

## License

See `LICENSE`. © GamesJi.com.
