Build an HTML puzzle
A self-contained .html file the app can launch, drop a token into, and watch for a completion signal. That's the whole contract.
Quick start
Three steps.
- Create a self-contained
.htmlfile with your puzzle. - Upload it as an unlock condition in the clue editor.
- That's it — the app handles the rest.
The contract
Your HTML file must do two things.
1 Read the token from the URL on page load.
The app passes a secret token via the URL fragment. Read it like this:
const token = new URLSearchParams(
window.location.hash.substring(1)
).get('token');
2 Signal completion when the player solves it.
Send the token back to the app. Use both methods to support all platforms:
function completePuzzle() {
if (!token) return;
// Mobile (Android/iOS)
if (typeof PuzzleComplete !== 'undefined') {
PuzzleComplete.postMessage(token);
}
// Web
try {
if (window.parent !== window)
window.parent.postMessage(token, '*');
} catch(e) {}
try {
if (window.top !== window)
window.top.postMessage(token, '*');
} catch(e) {}
}
Call completePuzzle() when the player wins.
The rules
Four constraints.
One file — inline all CSS and JavaScript. External CDN links (e.g. Google Fonts, libraries) are OK.
No relative paths — the file is served from cloud storage, so relative paths won't resolve.
Don't hardcode the token — it's provided at runtime via the URL fragment.
Mobile-friendly — include
<meta name="viewport" content="width=device-width, initial-scale=1.0">Reference
Minimal working example.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, initial-scale=1.0">
<title>My Puzzle</title>
</head>
<body>
<h1>Type the magic word</h1>
<input type="text" id="answer"
placeholder="Enter answer...">
<script>
const token = new URLSearchParams(
window.location.hash.substring(1)
).get('token');
function completePuzzle() {
if (!token) return;
if (typeof PuzzleComplete !== 'undefined')
PuzzleComplete.postMessage(token);
try { if (window.parent !== window)
window.parent.postMessage(token, '*');
} catch(e) {}
try { if (window.top !== window)
window.top.postMessage(token, '*');
} catch(e) {}
}
document.getElementById('answer')
.addEventListener('input', (e) => {
if (e.target.value.trim()
.toLowerCase() === 'hello') {
e.target.disabled = true;
completePuzzle();
}
});
</script>
</body>
</html>
Sparks
Some directions.
You can build anything — the only limit is what HTML, CSS and JS can do:
Word puzzles
Code-breaking
Jigsaw puzzles
Quizzes
Logic grids
Cipher decoders
Hidden objects
Memory games
3D mazes
Sound-based