Steve Hinan presents

PLAY PORTAL TAP

Hexapuss Portal Tap: Game Design Document

Title: Hexapuss Portal Tap

Spelling: Hexapuss (two s)

Owner: Steve Hinan

Doc date: 2026-09-18

Build: HTML5 static web (no npm / no build step)

Package: COMBINED v11 (10 circles + white win + cosmic horror synth + fastest-clear LB)


1. Concept / fantasy

The player feeds a living Hexapuss portal by tapping occult magic circles. The reward video (cat eye shifting Orange → Green → Purple, then a black pupil, hexagonal tunnel, and white bloom) advances on successful taps. Lore colors: orange, green, purple for circles 1-9; circle 10 is WHITE (win). Clear all ten taps and the portal bloom completes.

Tone: dark occult / cosmic, mobile portrait, touch-first. Player-facing copy avoids em dashes.

Player-facing win subline: Ten sigils complete (not “circles”). Never show end tagline “The rift opens.”


2. Platform and aspect

ItemSpec
RuntimeHTML5 + CSS + vanilla JS
OrientationMobile-first portrait
Layout100dvh, safe-area insets, touch-action: manipulation
DesktopCentered phone column (~max 480px), same portrait rules
InputPointer events (touch + mouse)
AudiocosmicHorrorSynth.js Web Audio drone + escalate; soft reward blips

3. Title flow

  1. Full-screen dark welcome.
  2. Official Hexapuss logo (assets/hexapuss-logo-official.png) acts as the play control, with a clear PLAY affordance under it.
  3. Subtitle: PORTAL TAP. Short tagline under that.
  4. On Play (user gesture):

- Switch to game screen.

- Start cosmic horror ambient synth.

- Hold full black.

- Start video/reward.mp4 (gesture unlocks media playback).

- Fade black out so the video reveals.

Play Again starts a new run immediately (same as title Play). Title is first-load only; after a clear, stay on the Play Again end screen until Play Again.


4. Video structure and time markers

Asset: video/reward.mp4 (portrait ~404×720, H.264, ~16s).

ConstantValueMeaning
INTRO_END4.0Start hold / pure full-screen black after cat-eye zoom. Circle 1 may appear.
BLOOM_START14.0End hold for circle 10 (white bloom).
VIDEO_ENDvideo.durationNatural end (~15.97s). Win overlay after outro.

Even splits (locked)


5. Circle rules (10 total)

RuleBehavior
Count10 successful taps to clear
Colors 1-9Cycle orange → green → purple (circle n(n-1) % 3)
Circle 10WHITE (win)
Live targetsMAX_CONCURRENT = 1: short-TTL circle respawns while waiting. Never two live.
Miss / expireUntapped circle is hard-cut from the DOM (no fade / fizz / ripple)
Hit feedbackBrief hit scale/opacity; colored flash; purple stronger; white-10 win flash

HUD: Circle X / 10 + phase name (incl. White).


6. Cosmic horror synth

File: cosmicHorrorSynth.js → global CosmicHorrorSynth.

HookBehavior
startAmbient()On PLAY: louder drone + mid/high cosmic-horror layers, slow LFOs, psychedelic delay/pan
onCircle(n, {video})Escalate intensity for 1-9; distinct white-10 climax
setVideoActive(bool)Unmute while reward video playing; mute while paused
stop()Hard stop on win / game over (no leftover drone)

Game wires onCircle on every successful tap, starts ambient on PLAY, gates synth to video play/pause, and hard-stops on win. Magic SFX fire on every circle spawn and every death (TTL miss included).


7. Win / outro / end screen

After circle 10 (white):

  1. Stop spawning; clear live targets.
  2. Full-screen pure white bloom (covers letterboxing) → then full black end UI.
  3. Synth hard-stops on win / game over (no leftover drone).
  4. End / Play Again screen (title-like polish):

- Hexapuss logo (blacks match center blacks; no purple wash under the mark)

- Same purple edge glow as title/start (.edge-glow: outer screen edges only)

- Title line: PORTAL CLEARED

- Subline (player-facing): Ten sigils complete (say sigils, not circles)

- Do not show the old end tagline “The rift opens.” (removed entirely)

- Clear time (kept)

- FASTEST CLEARS leaderboard + PLAY AGAIN

- Player name is edited inline in the green is-you row (name field + OK in that cell only). No separate NAME UI above/beside the board.

  1. End-screen text color = orange family. Green ONLY for the current player’s leaderboard row highlight (is-you). Everything else on the end screen stays orange.
  2. Play Again starts a new run immediately (same as title Play). No bounce back to the title screen.
  3. Title / start screen = first load only. After a clear, stay on the Play Again end screen until Play Again.

No lose state (no timer fail).

Fastest-clear leaderboard

ItemSpec
MetricFastest clear time (lower clearTimeMs is better; ASC)
Timing startbeginGameplay after INTRO_END (~4.0s pure full-screen black pupil)
Timing endOn the 10th successful tap
DisplayClear time on win (orange); current run row green highlight (is-you) with inline name + OK
Shared boardleaderboard/scores.ashx (Meteor Attack pattern): GET / POST {name, clearTimeMs, runId}; upsert by runId keeping better (lower) time; max 15; ascending
FallbacklocalStorage keys hexapuss-portal-tap-scores / hexapuss-portal-tap-name when ashx unavailable (Desktop file://)
Ship noteDo not check in scores.json; created on first server write

8. Asset list and paths

PathRole
index.htmlShell / screens
style.cssPortrait layout, O/G/P + white phase, flash, win, LB
game.jsFlow, 10 circles, video splits, LB, synth wiring
cosmicHorrorSynth.jsAmbient drone + escalate + white climax
leaderboard/scores.ashxFastest-clear shared board (IIS/ASP.NET)
art/portal-sigil.pngMagic-circle tap target
video/reward.mp4Background reward / outro video
assets/hexapuss-logo-official.pngTitle play logo
Play Hexapuss Portal Tap.batWindows helper: opens index.html
PORTAL-TAP-GDD.mdThis document
README.mdShort play / file notes

9. Open tuning knobs

Edit constants at the top of game.js:

KnobDefaultNotes
INTRO_END4.0Start hold / pure black / gameplay begin
BLOOM_START14.0End hold for circle 10
CIRCLE_SIZE110Tap target diameter (px)
CIRCLE_TTL_MIN / MAX450 / 750 msPer-circle life; then instant DOM remove
SPAWN_GAP_MIN / MAX120 / 220 msDelay before next spawn attempt
MAX_CONCURRENT1Only one live circle
HIT_CLEAR_MS200Brief hit feedback before remove
TOTAL_CIRCLES10Win on 10th tap

10. Screen map

[Title] --Play--> [Black] --> [Video intro 0..4.0s] + ambient synth
                                    |
                                    v
                         [Circle 1..9 O/G/P + even video 2-9]
                                    |
                              (circle 10 WHITE)
                                    v
                         [Outro bloom .. VIDEO_END]
                                    |
                                    v
                              [Win + clear time + LB]
                                    |
                              Play Again --> [new run immediately]

Title appears on first load only. After a clear, the Play Again end screen stays until Play Again.


11. Success criteria (acceptance)

  1. Dark title with Hexapuss logo + PLAY.
  2. Play → ambient synth + black → video reveals.
  3. After ~4.0s, one short-TTL circle at a time (hard-cut on miss).
  4. Circles 1-9 cycle orange/green/purple; circle 10 is white.
  5. Video even-splits for taps 2-9; tap 10 seeks ~end and completes.
  6. Synth escalates 1-9; white climax on 10.
  7. Clear timer = gameplay start → 10th tap; LB ASC with name + highlight.
  8. End screen: Hexapuss logo + same purple edge glow as title; no “The rift opens.”; subline Ten sigils complete; clear time kept; orange text; green only on current LB row; Play Again starts a new run immediately.
  9. Synth louder with mid/high content; gated to video motion; hard-stop on win.
  10. INTRO_END at pure black (~4.0s); full-screen white bloom before black win UI.
  11. No CSS ring on magic circles (sigil art only); purple edge glow on title + Play Again only (not under logo).
  12. Magic SFX on spawn and death.

12. Publish / next


13. Changelog

DateChange
2026-09-18Public GDD pass: inline green-row name; live /portal-tap/; Experimental GDD link path.
2026-09-17Circle layering: #screen-game.is-gameplay (circles above blackout); white-bloom idle z-index 3.
2026-09-17Quinn polish: white bloom hold before is-out; .edge-glow CSS; synth gated off until play; soft-cap via seekVideoTo; INTRO_END 4.0 scrub-confirmed.
2026-09-17Harden video: seekVideoTo + mediaBusy for mid-run seeks; ensureVideoPlaying + stalled/canplay recovery.
2026-09-17Fix: Play / Play Again intro stuck-pause: wait for seek-to-0, introSeeking gate, cancel finishWin timer, readyState canplay.
2026-09-17End screen: remove “The rift opens.”; “Ten sigils complete”; orange text; green only for current LB row; purple edge glow like title.
2026-09-17COMBINED v11: 10 circles (O/G/P 1-9 + white 10); even video splits 2-9; cosmicHorrorSynth; LB end on 10th tap; keep Mel ashx/localStorage.
2026-09-17Fastest-clear leaderboard: ashx + localStorage; Desktop-first.
2026-09-17Playtest: MAX_CONCURRENT=1; TTL miss = instant DOM remove.
2026-09-17Locked design rebuild from score-attack prototype.