termi-kids 0.1.2 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -21
- package/SAFETY.md +2 -2
- package/dist/cli.js +9 -29
- package/dist/learn/runner.js +1 -1
- package/dist/projects/blankGame.js +100 -0
- package/dist/projects/gameIdeas.js +216 -0
- package/dist/setup/wizard.js +14 -88
- package/dist/surfaces/buildGame.js +335 -0
- package/dist/surfaces/buildLoop.js +114 -0
- package/dist/surfaces/commands.js +3 -3
- package/dist/surfaces/home.js +65 -25
- package/dist/ui/text.js +20 -16
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -10,17 +10,15 @@
|
|
|
10
10
|
|
|
11
11
|
# Termi
|
|
12
12
|
|
|
13
|
-
Termi is a friendly robot that helps you build
|
|
13
|
+
Termi is a friendly robot that helps you build browser games on a real computer.
|
|
14
14
|
|
|
15
|
-
You
|
|
15
|
+
You pick a game idea (or invent your own). You write a prompt, or ask Termi to help write one. Termi builds the game with you. Your game opens in the browser and updates after every prompt.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
There are 30 ready game ideas plus "Build my own idea". When you finish, Termi can run a short test pass and suggest one last improvement. Games save in your local library on this computer.
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
Not sure what to say first? Type `/quest` inside any project. Termi walks you through a real build, step by step, with a ready idea at every step. Press Enter to use it, or type your own. Finish a quest and you earn the Quest Hero badge.
|
|
19
|
+
Want to get better at prompting? Open **Learn AI**. Six short lessons teach you how to boss your AI helper. Each one earns a badge, and you can replay them any time.
|
|
22
20
|
|
|
23
|
-
|
|
21
|
+
Termi is a computer program, an AI tool. It is not a person. A grown-up sets it up first.
|
|
24
22
|
|
|
25
23
|
Ready? Ask a grown-up to read the next part.
|
|
26
24
|
|
|
@@ -37,7 +35,7 @@ Please read [SAFETY.md](SAFETY.md) before handing the keyboard to your kid. It e
|
|
|
37
35
|
- Node.js 20.19 or newer: https://nodejs.org
|
|
38
36
|
- macOS, Windows, or Linux
|
|
39
37
|
- An AI account you own (one of: a ChatGPT account, a Claude API key, an OpenAI API key, or a Grok API key)
|
|
40
|
-
- About 700 MB of free disk space for the on-device safety checker (
|
|
38
|
+
- About 700 MB of free disk space for the on-device safety checker (installed during setup)
|
|
41
39
|
|
|
42
40
|
If Node is too old, Termi prints a plain message with the download link instead of starting.
|
|
43
41
|
|
|
@@ -58,16 +56,14 @@ To update later, run `termi update` (or `npm install -g termi-kids@latest`). On
|
|
|
58
56
|
Run `termi`. The first run starts a setup wizard for a parent or guardian. It takes about five minutes:
|
|
59
57
|
|
|
60
58
|
1. **Create a grown-up PIN** (at least 4 characters). It guards the grown-up zone. Your kid should not know it.
|
|
61
|
-
2. **
|
|
59
|
+
2. **Consent.** You confirm that Termi uses an AI account you own and that you agree to watch how your kid uses it. One safety bar applies for every age (no under-13 / over-13 split). Consent is recorded in the local safety log.
|
|
62
60
|
3. **Pick an AI provider.** The default is "ChatGPT sign-in": your browser opens, you sign in to your own ChatGPT account, and no API key is needed. The other options are a Claude API key, an OpenAI API key, or a Grok API key. Grok requires an extra confirmation because the xAI API terms are adults-only (details in SAFETY.md). You can add several providers and choose which one is active.
|
|
63
|
-
4. **Safety checker
|
|
61
|
+
4. **Safety checker install.** Setup always starts the on-device safety model download (about 623 MB). It screens every message on this computer, even offline. You can wait for the progress bar or keep setting up while it finishes in the background. Basic safety is already on during the download. The download is anonymous and resumes if interrupted. Details are in [SAFETY.md](SAFETY.md).
|
|
64
62
|
5. **Hand the keyboard to your kid.** The kid picks a made-up nickname (Termi asks them not to use their real name) and sees a clear disclosure: "Termi is a computer program, an AI. It is a tool a grown-up set up for you. It is not a person."
|
|
65
63
|
6. **Desktop shortcut.** Termi offers to write a double-clickable launcher on the Desktop (`Termi.command` on macOS, `Termi.bat` on Windows, `Termi.desktop` on Linux) so your kid can come back tomorrow without typing commands.
|
|
66
|
-
7. **Optional first game.**
|
|
67
|
-
|
|
68
|
-
If you skip the provider step, Termi runs in offline mode: your kid can still create projects, play them in the preview, undo changes, and browse ideas. The chat shows a kind "ask a grown-up to set up the AI helper" screen.
|
|
64
|
+
7. **Optional first game.** The kid can jump straight into **Build a game** (pick an idea or invent one).
|
|
69
65
|
|
|
70
|
-
|
|
66
|
+
If you skip the provider step, Termi runs in offline mode: your kid can still open the library and Learn AI. Building with the AI helper needs a provider.
|
|
71
67
|
|
|
72
68
|
### What keeps your kid safe
|
|
73
69
|
|
|
@@ -87,13 +83,13 @@ Parents get a PIN-gated grown-up zone, a tamper-evident log of every block and s
|
|
|
87
83
|
|
|
88
84
|
| Command | What it does |
|
|
89
85
|
|---|---|
|
|
90
|
-
| `termi` | First run: setup wizard. After that:
|
|
91
|
-
| `termi new` |
|
|
92
|
-
| `termi go [name]` | Open a
|
|
93
|
-
| `termi preview [name]` | Open a
|
|
94
|
-
| `termi
|
|
95
|
-
| `termi learn` | Six short, replayable lessons on building with AI. Fully offline, no AI calls. |
|
|
86
|
+
| `termi` | First run: setup wizard. After that: home (Build a game, My games, Learn AI). |
|
|
87
|
+
| `termi new` | Build a game (idea list + prompt loop). |
|
|
88
|
+
| `termi go [name]` | Open a game from your library. With no name, pick from a list. |
|
|
89
|
+
| `termi preview [name]` | Open a game in the browser without the chat. |
|
|
90
|
+
| `termi learn` | Learn AI: six short offline lessons on prompting. |
|
|
96
91
|
| `termi grownups` | The grown-up zone. PIN required. |
|
|
92
|
+
| `termi update` | Update Termi to the latest npm version. |
|
|
97
93
|
| `termi help` | Show the command list. |
|
|
98
94
|
| `termi --version` | Show the version. |
|
|
99
95
|
|
|
@@ -104,7 +100,7 @@ Inside the build chat, these slash commands work:
|
|
|
104
100
|
| `/preview` | Open the project in the browser. |
|
|
105
101
|
| `/undo` | Take back the last change. |
|
|
106
102
|
| `/redo` | Bring a change back. |
|
|
107
|
-
| `/new` |
|
|
103
|
+
| `/new` | Build a new game (idea list + blank shell). |
|
|
108
104
|
| `/ideas` | Get fun ideas. |
|
|
109
105
|
| `/badges` | See earned badges. |
|
|
110
106
|
| `/learn` | Play the short AI lessons. |
|
package/SAFETY.md
CHANGED
|
@@ -50,7 +50,7 @@ Grooming, personal info, and rule-breaking tricks block at a lower threshold tha
|
|
|
50
50
|
|
|
51
51
|
Termi includes an on-device safety checker: a small AI model (Qwen3Guard 0.6B, published by the Qwen team under the Apache 2.0 license) that runs entirely on your computer. Setup offers the download (623 MB) with a yes as the default; you can decline and add it later from the grown-up zone (`termi grownups`, then **Safety checker**).
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
Setup always starts the download (it is part of install, not an easy skip). Setup says, in plain words, that basic safety (the local filter plus the online checks) is already on, then asks whether you want to wait and watch the progress bar or keep setting up while it finishes. Either way the download continues, the home menu can show its bar, and the checker attaches itself to the running safety pipeline the moment the verified file is in place; Termi announces it on screen ("Your safety helper is on."), even in the middle of a build session. If the download is interrupted (a closed laptop, a dropped connection), it resumes from where it stopped the next time Termi starts. Until the file lands, the online checks carry the load.
|
|
54
54
|
|
|
55
55
|
The download itself is anonymous. The model file comes over HTTPS from a public model repository, with no account, sign-in, or token of any kind; nothing about you or your kid is sent with the request, and the file is checked against a pinned cryptographic fingerprint before it is used.
|
|
56
56
|
|
|
@@ -117,7 +117,7 @@ Termi is built so that the developer never touches your family's data, because t
|
|
|
117
117
|
|
|
118
118
|
- **100% local.** No Termi servers exist. No telemetry, no analytics, no crash reporting, no account with Termi. Nothing phones home.
|
|
119
119
|
- **Chat goes to one place.** The kid's messages (after personal-info masking) and the project files go only to the AI provider you configured, to generate the code and run the safety checks. No other network calls are made on the kid's behalf.
|
|
120
|
-
- **You are the account holder.** Termi has no relationship with your child. You bring your own AI account, you
|
|
120
|
+
- **You are the account holder.** Termi has no relationship with your child. You bring your own AI account, you agree during setup to watch how your kid uses it, and your consent is recorded, timestamped, in the local safety log. There is one safety bar for every age (no under-13 / over-13 setup choice). The AI provider's privacy policy governs what happens to text sent to it; that is a relationship between you and the provider you chose.
|
|
121
121
|
- **Personal info is kept out of the AI.** The local filter masks names, addresses, phones, emails, and school names before sending. On "My Page" website projects, personal touches like a name are typed directly into the page in the browser preview and saved in the browser's local storage on this computer; they never pass through the chat, so they never reach the AI provider at all.
|
|
122
122
|
- **Kid projects are plain files** in `~/Termi`, readable and yours forever.
|
|
123
123
|
|
package/dist/cli.js
CHANGED
|
@@ -19,7 +19,6 @@ import { installGlobalHandlers, renderCrash } from './ui/errors.js';
|
|
|
19
19
|
import { mascot } from './ui/mascot.js';
|
|
20
20
|
import { style } from './ui/theme.js';
|
|
21
21
|
import { T } from './ui/text.js';
|
|
22
|
-
import { executeIdeas } from './surfaces/commands.js';
|
|
23
22
|
/** Pure boot branch logic: settings state in, actions out. */
|
|
24
23
|
export function decideBoot(state) {
|
|
25
24
|
return {
|
|
@@ -32,11 +31,10 @@ export function cliHelp() {
|
|
|
32
31
|
return [
|
|
33
32
|
'How to use Termi:',
|
|
34
33
|
' termi open the home menu',
|
|
35
|
-
' termi new
|
|
36
|
-
' termi go [name] open a
|
|
37
|
-
' termi preview watch a
|
|
38
|
-
' termi
|
|
39
|
-
' termi learn play six short lessons about AI',
|
|
34
|
+
' termi new build a game',
|
|
35
|
+
' termi go [name] open a game from your library',
|
|
36
|
+
' termi preview watch a game run',
|
|
37
|
+
' termi learn Learn AI (prompting lessons)',
|
|
40
38
|
' termi grownups grown-up zone (PIN needed)',
|
|
41
39
|
' termi update update Termi to the latest version',
|
|
42
40
|
' termi help show this help',
|
|
@@ -124,24 +122,6 @@ async function routePreview(nameArg, settings) {
|
|
|
124
122
|
// Held open on purpose; Ctrl+C ends it through the global handler.
|
|
125
123
|
});
|
|
126
124
|
}
|
|
127
|
-
async function routeIdeas(settings) {
|
|
128
|
-
let scaffoldId = 'games';
|
|
129
|
-
if (settings.lastProjectSlug !== null) {
|
|
130
|
-
try {
|
|
131
|
-
const store = await import('./projects/store.js');
|
|
132
|
-
const last = store.openProject(settings.lastProjectSlug);
|
|
133
|
-
if (last !== null) {
|
|
134
|
-
scaffoldId = last.meta.scaffoldId;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
catch {
|
|
138
|
-
// Fall back to game ideas.
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
await executeIdeas(scaffoldId, (text) => {
|
|
142
|
-
console.log(text);
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
125
|
async function route(command, rest, settings) {
|
|
146
126
|
const home = await import('./surfaces/home.js');
|
|
147
127
|
switch (command) {
|
|
@@ -150,10 +130,8 @@ async function route(command, rest, settings) {
|
|
|
150
130
|
return;
|
|
151
131
|
}
|
|
152
132
|
case 'new': {
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
await home.openChatLoop(project, settings);
|
|
156
|
-
}
|
|
133
|
+
const build = await import('./surfaces/buildGame.js');
|
|
134
|
+
await build.runBuildGame(settings);
|
|
157
135
|
return;
|
|
158
136
|
}
|
|
159
137
|
case 'go': {
|
|
@@ -168,7 +146,9 @@ async function route(command, rest, settings) {
|
|
|
168
146
|
return;
|
|
169
147
|
}
|
|
170
148
|
case 'ideas': {
|
|
171
|
-
|
|
149
|
+
// Ideas live inside Build a game now.
|
|
150
|
+
const build = await import('./surfaces/buildGame.js');
|
|
151
|
+
await build.runBuildGame(settings);
|
|
172
152
|
return;
|
|
173
153
|
}
|
|
174
154
|
case 'learn': {
|
package/dist/learn/runner.js
CHANGED
|
@@ -164,7 +164,7 @@ export async function runLesson(lesson, say = defaultSay) {
|
|
|
164
164
|
*/
|
|
165
165
|
export async function runLearnMenu() {
|
|
166
166
|
console.log(mascot('happy'));
|
|
167
|
-
console.log('
|
|
167
|
+
console.log('Learn AI: six tiny lessons on how to prompt. Zero homework.');
|
|
168
168
|
for (;;) {
|
|
169
169
|
const done = new Set(loadProgress().completed);
|
|
170
170
|
const options = [
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal blank game project: no stock playable game, just a local HTML
|
|
3
|
+
* shell the model fills in. Used by the Build a game flow.
|
|
4
|
+
*/
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { projectsDir } from '../config/paths.js';
|
|
8
|
+
import { slugifyName } from './create.js';
|
|
9
|
+
import { notesFileName, openProject, renderTermiMd, saveProjectMeta, } from './store.js';
|
|
10
|
+
const BLANK_HTML = `<!DOCTYPE html>
|
|
11
|
+
<html lang="en">
|
|
12
|
+
<head>
|
|
13
|
+
<meta charset="UTF-8" />
|
|
14
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
15
|
+
<title>__TITLE__</title>
|
|
16
|
+
<link rel="stylesheet" href="style.css" />
|
|
17
|
+
</head>
|
|
18
|
+
<body>
|
|
19
|
+
<main>
|
|
20
|
+
<h1 id="title">__TITLE__</h1>
|
|
21
|
+
<p id="hint">Your game will show up here after you build with Termi.</p>
|
|
22
|
+
<canvas id="game" width="480" height="320" aria-label="game"></canvas>
|
|
23
|
+
</main>
|
|
24
|
+
<script src="game.js"></script>
|
|
25
|
+
</body>
|
|
26
|
+
</html>
|
|
27
|
+
`;
|
|
28
|
+
const BLANK_CSS = `* { box-sizing: border-box; }
|
|
29
|
+
body {
|
|
30
|
+
margin: 0;
|
|
31
|
+
font-family: system-ui, sans-serif;
|
|
32
|
+
background: #0f172a;
|
|
33
|
+
color: #e2e8f0;
|
|
34
|
+
min-height: 100vh;
|
|
35
|
+
display: grid;
|
|
36
|
+
place-items: center;
|
|
37
|
+
}
|
|
38
|
+
main { text-align: center; padding: 1rem; }
|
|
39
|
+
h1 { font-size: 1.4rem; margin: 0 0 0.5rem; }
|
|
40
|
+
#hint { opacity: 0.8; margin-bottom: 1rem; }
|
|
41
|
+
canvas {
|
|
42
|
+
background: #1e293b;
|
|
43
|
+
border: 2px solid #38bdf8;
|
|
44
|
+
border-radius: 12px;
|
|
45
|
+
max-width: 100%;
|
|
46
|
+
}
|
|
47
|
+
`;
|
|
48
|
+
const BLANK_JS = `// Blank starter. Termi and the kid fill this in.
|
|
49
|
+
const canvas = document.getElementById('game');
|
|
50
|
+
const ctx = canvas.getContext('2d');
|
|
51
|
+
function frame() {
|
|
52
|
+
ctx.fillStyle = '#1e293b';
|
|
53
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
54
|
+
ctx.fillStyle = '#94a3b8';
|
|
55
|
+
ctx.font = '16px system-ui, sans-serif';
|
|
56
|
+
ctx.textAlign = 'center';
|
|
57
|
+
ctx.fillText('Ready to build!', canvas.width / 2, canvas.height / 2);
|
|
58
|
+
}
|
|
59
|
+
frame();
|
|
60
|
+
`;
|
|
61
|
+
function writeRel(dir, relPath, content) {
|
|
62
|
+
const target = path.join(dir, ...relPath.split('/'));
|
|
63
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
64
|
+
fs.writeFileSync(target, content, 'utf8');
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Creates an empty local-browser game shell under the projects library.
|
|
68
|
+
* scaffoldId stays "games" so existing badges and quests still recognize it.
|
|
69
|
+
*/
|
|
70
|
+
export function createBlankGameProject(prettyNameInput, ideaLabel = 'My game') {
|
|
71
|
+
const trimmed = prettyNameInput.trim();
|
|
72
|
+
const prettyName = trimmed.length > 0 ? trimmed : 'My Game';
|
|
73
|
+
const { slug } = slugifyName(prettyName);
|
|
74
|
+
const dir = path.join(projectsDir(), slug);
|
|
75
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
76
|
+
const html = BLANK_HTML.replaceAll('__TITLE__', prettyName);
|
|
77
|
+
writeRel(dir, 'index.html', html);
|
|
78
|
+
writeRel(dir, 'style.css', BLANK_CSS);
|
|
79
|
+
writeRel(dir, 'game.js', BLANK_JS);
|
|
80
|
+
writeRel(dir, notesFileName, renderTermiMd(prettyName, {
|
|
81
|
+
whatThisIs: `A browser game: ${ideaLabel}. Built with Termi.`,
|
|
82
|
+
files: ['index.html', 'style.css', 'game.js'],
|
|
83
|
+
builtSoFar: ['Blank game shell ready for the first prompt'],
|
|
84
|
+
recapLine: `We started ${prettyName}.`,
|
|
85
|
+
}));
|
|
86
|
+
const now = new Date().toISOString();
|
|
87
|
+
saveProjectMeta({
|
|
88
|
+
slug,
|
|
89
|
+
prettyName,
|
|
90
|
+
scaffoldId: 'games',
|
|
91
|
+
themeId: 'blank',
|
|
92
|
+
createdAt: now,
|
|
93
|
+
lastOpenedAt: now,
|
|
94
|
+
});
|
|
95
|
+
const project = openProject(slug);
|
|
96
|
+
if (project === null) {
|
|
97
|
+
throw new Error('Something went wrong while making the project. Try again.');
|
|
98
|
+
}
|
|
99
|
+
return project;
|
|
100
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kid-facing Build-a-game idea bank.
|
|
3
|
+
*
|
|
4
|
+
* Exactly 31 entries: "Build my own idea" first, then 30 browser HTML games.
|
|
5
|
+
* Every idea is local-preview only (HTML/CSS/JS), no image generation, no
|
|
6
|
+
* native installs. Pure data for tests and the Build a game menu.
|
|
7
|
+
*/
|
|
8
|
+
/** True for the custom entry that asks the kid for their own concept. */
|
|
9
|
+
export function isOwnIdea(idea) {
|
|
10
|
+
return idea.id === 'own';
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Menu order is fixed. First entry is always Build my own idea.
|
|
14
|
+
* The remaining 30 are distinct local-browser game concepts.
|
|
15
|
+
*/
|
|
16
|
+
export const GAME_IDEAS = [
|
|
17
|
+
{
|
|
18
|
+
id: 'own',
|
|
19
|
+
label: 'Build my own idea',
|
|
20
|
+
blurb: 'You invent the game. Termi helps you build it.',
|
|
21
|
+
seedPrompt: '',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
id: 'dodge-rain',
|
|
25
|
+
label: 'Dodge the rain',
|
|
26
|
+
blurb: 'Move left and right. Catch drops or dodge them.',
|
|
27
|
+
seedPrompt: 'Make a simple canvas game where I move left and right to dodge falling rain drops. Add a score and a restart key.',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
id: 'catch-stars',
|
|
31
|
+
label: 'Catch the stars',
|
|
32
|
+
blurb: 'Catch falling stars before they hit the ground.',
|
|
33
|
+
seedPrompt: 'Make a canvas catch game. Stars fall from the top. I move a basket to catch them. Show the score and lives.',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: 'memory-cards',
|
|
37
|
+
label: 'Memory cards',
|
|
38
|
+
blurb: 'Flip cards and match pairs.',
|
|
39
|
+
seedPrompt: 'Make a memory match card game with 12 cards (6 pairs) using emoji. Click to flip. Count moves. Show a win message.',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
id: 'click-targets',
|
|
43
|
+
label: 'Click the targets',
|
|
44
|
+
blurb: 'Click circles before they vanish.',
|
|
45
|
+
seedPrompt: 'Make a click target game. Circles appear for a short time. Click them for points. Add a 30 second timer and a final score.',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: 'maze-escape',
|
|
49
|
+
label: 'Maze escape',
|
|
50
|
+
blurb: 'Find the exit in a simple maze.',
|
|
51
|
+
seedPrompt: 'Make a keyboard maze game on a canvas grid. Arrow keys move a square. Reach the green exit. Keep walls solid.',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: 'snake-lite',
|
|
55
|
+
label: 'Snake lite',
|
|
56
|
+
blurb: 'Grow a snake by eating dots.',
|
|
57
|
+
seedPrompt: 'Make a simple snake game on a grid. Arrow keys move. Eat food to grow. Hitting a wall or yourself restarts.',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
id: 'pong-solo',
|
|
61
|
+
label: 'Pong solo',
|
|
62
|
+
blurb: 'Bounce a ball with one paddle.',
|
|
63
|
+
seedPrompt: 'Make a one player pong game. Move the paddle with the mouse or arrows. Ball bounces. Score points. Restart on miss.',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
id: 'whack-moles',
|
|
67
|
+
label: 'Whack a mole',
|
|
68
|
+
blurb: 'Tap moles as they pop up.',
|
|
69
|
+
seedPrompt: 'Make a whack a mole game with a 3 by 3 grid of holes. Moles pop up briefly. Click them for points. Add a timer.',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: 'color-match',
|
|
73
|
+
label: 'Color match',
|
|
74
|
+
blurb: 'Match the word color to the right button.',
|
|
75
|
+
seedPrompt: 'Make a color word game. Show a color name in a random ink color. Kid clicks the button that matches the WORD meaning. Score streaks.',
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
id: 'typing-race',
|
|
79
|
+
label: 'Typing race',
|
|
80
|
+
blurb: 'Type the word before time runs out.',
|
|
81
|
+
seedPrompt: 'Make a typing race. Show a simple word. Kid types it and presses Enter. Track speed and accuracy for 10 words.',
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
id: 'platform-jump',
|
|
85
|
+
label: 'Platform jumper',
|
|
86
|
+
blurb: 'Jump across platforms to the flag.',
|
|
87
|
+
seedPrompt: 'Make a side view platformer on canvas. Arrow keys move and jump. Reach a flag on the right. Simple gravity and platforms.',
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
id: 'balloon-pop',
|
|
91
|
+
label: 'Balloon pop',
|
|
92
|
+
blurb: 'Pop balloons before they float away.',
|
|
93
|
+
seedPrompt: 'Make a balloon pop game. Balloons float up. Click to pop them. Missed balloons cost a life. Show score.',
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
id: 'quiz-sprint',
|
|
97
|
+
label: 'Quiz sprint',
|
|
98
|
+
blurb: 'Answer fun multiple choice questions.',
|
|
99
|
+
seedPrompt: 'Make a 5 question multiple choice quiz about animals. Show score at the end. Use big clear buttons.',
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
id: 'simon-says',
|
|
103
|
+
label: 'Simon says lights',
|
|
104
|
+
blurb: 'Repeat the light pattern.',
|
|
105
|
+
seedPrompt: 'Make a Simon style memory game with 4 colored buttons. Play a growing pattern. Kid repeats it. Score the longest streak.',
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
id: 'rock-paper',
|
|
109
|
+
label: 'Rock paper scissors',
|
|
110
|
+
blurb: 'Play against the computer. Pick rock, paper, or scissors.',
|
|
111
|
+
seedPrompt: 'Make rock paper scissors with three big buttons. Computer picks at random. Track wins, losses, and ties.',
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
id: 'number-guess',
|
|
115
|
+
label: 'Number guess',
|
|
116
|
+
blurb: 'Guess the secret number.',
|
|
117
|
+
seedPrompt: 'Make a number guess game from 1 to 50. Kid types a guess. Say higher or lower. Count tries until they win.',
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
id: 'breakout-lite',
|
|
121
|
+
label: 'Breakout lite',
|
|
122
|
+
blurb: 'Bounce a ball to break bricks.',
|
|
123
|
+
seedPrompt: 'Make a simple breakout game. Paddle at the bottom, ball, and one row of bricks. Clear the bricks to win.',
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
id: 'flappy-lite',
|
|
127
|
+
label: 'Flappy lite',
|
|
128
|
+
blurb: 'Tap to flap between gaps.',
|
|
129
|
+
seedPrompt: 'Make a flappy style game. Space or click flaps up. Gravity pulls down. Fly through gaps in pipes. Score each pipe.',
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
id: 'tic-tac-toe',
|
|
133
|
+
label: 'Tic tac toe',
|
|
134
|
+
blurb: 'Play X and O on a 3 by 3 board.',
|
|
135
|
+
seedPrompt: 'Make tic tac toe for two players on one keyboard. Click cells. Detect win and draw. Add a new game button.',
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
id: 'collect-coins',
|
|
139
|
+
label: 'Collect coins',
|
|
140
|
+
blurb: 'Run around and grab all the coins.',
|
|
141
|
+
seedPrompt: 'Make a top down collect game. Arrow keys move a player. Coins sit on a small map. Collect all coins to win.',
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
id: 'avoid-cars',
|
|
145
|
+
label: 'Avoid the cars',
|
|
146
|
+
blurb: 'Cross the road safely.',
|
|
147
|
+
seedPrompt: 'Make a cross the road game. Player moves up. Cars move left and right. Reach the top without hitting a car.',
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
id: 'reaction-test',
|
|
151
|
+
label: 'Reaction test',
|
|
152
|
+
blurb: 'Click when the screen turns green.',
|
|
153
|
+
seedPrompt: 'Make a reaction time test. Screen starts red, then turns green after a random wait. Click as fast as you can. Show ms time.',
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
id: 'word-scramble',
|
|
157
|
+
label: 'Word scramble',
|
|
158
|
+
blurb: 'Unscramble the letters.',
|
|
159
|
+
seedPrompt: 'Make a word scramble game with 8 easy words. Show mixed letters. Kid types the word. Track score out of 8.',
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
id: 'tower-stack',
|
|
163
|
+
label: 'Tower stack',
|
|
164
|
+
blurb: 'Stack blocks as high as you can.',
|
|
165
|
+
seedPrompt: 'Make a stack game. A block slides left and right. Click or press space to drop it. Stack as high as you can without missing.',
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
id: 'balloon-math',
|
|
169
|
+
label: 'Balloon math',
|
|
170
|
+
blurb: 'Pop the balloon with the right answer.',
|
|
171
|
+
seedPrompt: 'Make a math balloon game. Show a simple add or subtract problem. Three balloons show answers. Click the correct one.',
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
id: 'day-night',
|
|
175
|
+
label: 'Day and night runner',
|
|
176
|
+
blurb: 'Run while the world switches day and night.',
|
|
177
|
+
seedPrompt: 'Make a runner where the player auto runs right. Jump over rocks. Every 10 seconds switch day and night colors. Track distance.',
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
id: 'fruit-slice',
|
|
181
|
+
label: 'Fruit slice',
|
|
182
|
+
blurb: 'Swipe or click fruit, avoid bombs.',
|
|
183
|
+
seedPrompt: 'Make a fruit slice style game. Fruit flies up. Click fruit for points. Clicking a bomb ends the round. Show score.',
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
id: 'hide-seek',
|
|
187
|
+
label: 'Hide and seek dots',
|
|
188
|
+
blurb: 'Find the odd color in the crowd.',
|
|
189
|
+
seedPrompt: 'Make a find the odd one out game. Show many colored dots. One is a slightly different color. Click it. Levels get harder.',
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
id: 'space-lander',
|
|
193
|
+
label: 'Soft lander',
|
|
194
|
+
blurb: 'Land the ship gently on the pad.',
|
|
195
|
+
seedPrompt: 'Make a lander game. Ship falls with gravity. Arrow keys thrust and steer. Land softly on a pad. Crash if too fast.',
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
id: 'story-choice',
|
|
199
|
+
label: 'Choice adventure',
|
|
200
|
+
blurb: 'A short story with choices you click.',
|
|
201
|
+
seedPrompt: 'Make a short click adventure with 4 scenes. Each scene has text and 2 choice buttons. End with a happy finish screen.',
|
|
202
|
+
},
|
|
203
|
+
];
|
|
204
|
+
/** Exactly one own-idea entry plus 30 game ideas. */
|
|
205
|
+
export const GAME_IDEA_COUNT = GAME_IDEAS.length;
|
|
206
|
+
/** Menu options for selects: value is idea id. */
|
|
207
|
+
export function gameIdeaMenuOptions() {
|
|
208
|
+
return GAME_IDEAS.map((idea) => ({
|
|
209
|
+
value: idea.id,
|
|
210
|
+
label: idea.label,
|
|
211
|
+
hint: idea.blurb,
|
|
212
|
+
}));
|
|
213
|
+
}
|
|
214
|
+
export function gameIdeaById(id) {
|
|
215
|
+
return GAME_IDEAS.find((idea) => idea.id === id);
|
|
216
|
+
}
|