evolutionary-arcade 0.2.1 → 0.4.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "evolutionary-arcade",
3
- "version": "0.2.1",
3
+ "version": "0.4.0",
4
4
  "description": "The arcade CLI for Evolutionary Arcade. Publish, update, regen, fork, and blend AI-made browser games with your own coding agent.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -59,7 +59,7 @@ someone else's game, see `arcade-remix-and-blend`.
59
59
  files by relative URL is fine. `arcade dev` lets `ws:` through but the arcade doesn't, so don't
60
60
  trust dev for sockets. Don't add tracking code; the arcade measures play from outside the frame.
61
61
  4. **Start on a click or keypress.** Show a title screen with "Click to play". Create or resume the
62
- `AudioContext` inside that handler. Request pointer lock and fullscreen only from a gesture. Esc
62
+ `AudioContext` inside that handler. Request pointer lock only from a gesture. Esc
63
63
  and gamepad buttons don't count as gestures, so a controller-only player can't turn on sound.
64
64
  Show "click or press any key once."
65
65
  5. **Pointer lock comes from the sandbox token.** The arcade grants `allow-pointer-lock`, and Chrome
@@ -97,7 +97,15 @@ someone else's game, see `arcade-remix-and-blend`.
97
97
  like every game here. Anything you do bundle from others, like a vendored Three.js, keeps its
98
98
  own license: ship its LICENSE beside it (`vendor/three/LICENSE`), and only bundle what's yours
99
99
  to share.
100
- 10. **Storage is optional, and shared.** `localStorage` works (a saved high score is nice), but wrap
100
+ 10. **Don't build fullscreen. The platform owns it.** The arcade's player has the fullscreen
101
+ button, and on phones the game page's Play button opens the game straight into it. It uses
102
+ the Fullscreen API where there is one, covers the whole page on iPhone (which has none for
103
+ games), and locks the orientation on Android. So no
104
+ fullscreen button, no `requestFullscreen()` or `webkitRequestFullscreen()`, and no
105
+ `screen.orientation.lock()` of your own. Size the game to its frame (`resize` events) and it
106
+ works full-size. `arcade publish` warns when your code calls requestFullscreen: "the arcade's
107
+ player owns fullscreen; remove your fullscreen button".
108
+ 11. **Storage is optional, and shared.** `localStorage` works (a saved high score is nice), but wrap
101
109
  every access in try/catch. Every version and generation of a game shares one origin, including
102
110
  other people's regens. Prefix keys with your slug, version your save format, and handle old or
103
111
  malformed data. To keep progress across devices, use profile saves (below).
@@ -259,7 +267,7 @@ a game's history is a record of what each model could build.
259
267
  - **Touch:** without `input.touch: true`, phones get your demo video instead of the game. Set it
260
268
  only if the game has real touch controls, like an on-screen stick and buttons with large targets
261
269
  (48 px or more). Use pointer events, put `touch-action: none` on the canvas, and don't rely on
262
- hover. Test at phone width, where the 16:9 frame is tiny until the player goes fullscreen. To
270
+ hover. Test at phone width (390x844 with touch), where the player opens fullscreen. To
263
271
  try it on a real phone, run `arcade dev --host` and open the network address it prints on a
264
272
  phone on the same Wi-Fi.
265
273
  - **Tilt:** see Phone tilt, next.
@@ -282,21 +290,18 @@ that have touch on, and every tilt game needs touch controls anyway.
282
290
  little. Put "Recenter" in the pause menu.
283
291
  - **Turn the axes with the screen.** `gamma` is left-right only in portrait. In landscape it's
284
292
  `beta`, and the sign flips with the side the phone is turned to (`screen.orientation.angle`).
285
- - **Landscape lock only works in fullscreen on Android.** The arcade's Fullscreen button already
286
- locks landscape there. A game that goes fullscreen from its own tap can lock too (a portrait
287
- game can lock `"portrait"`). iPhones never lock and have no fullscreen for games, so show
288
- "Turn your phone sideways" while a landscape game is held upright.
293
+ - **Orientation is the platform's job.** Set `orientation` in arcade.json (`"landscape"`,
294
+ `"portrait"`, or `"both"`) and don't lock it yourself; the arcade's fullscreen player locks
295
+ the screen on Android. iPhones never lock, so a landscape game shows "Turn your phone sideways"
296
+ while it's held upright.
289
297
 
290
298
  ```js
291
- const LANDSCAPE = true; // a landscape-first game
292
299
  let tiltOk = false, zero = null, tilt = 0; // tilt: -1..1; steer by touch until tiltOk
293
300
  async function onStartTap() { // the "Tap to play" handler
294
301
  const DOE = globalThis.DeviceOrientationEvent;
295
302
  const asking = typeof DOE?.requestPermission === "function"
296
303
  ? DOE.requestPermission().catch(() => "denied") // iPhone: asks, so call it before any await
297
304
  : Promise.resolve(DOE ? "granted" : "denied");
298
- if (LANDSCAPE) document.documentElement.requestFullscreen?.()
299
- .then(() => screen.orientation.lock("landscape")).catch(() => {}); // Android only
300
305
  tiltOk = (await asking) === "granted";
301
306
  zero = null; // "Recenter" does this too
302
307
  startOrResume();
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: arcade-fork
3
- description: Use when someone wants to make their own version of a game on Evolutionary Arcade (evolutionaryarcade.com), usually right after they pasted the prompt from a game page's Fork or Blend button into their agent ("help me remix <game>", "help me blend <a> and <b>", `arcade guide fork`). Walks the session in Alex's order - vision (what they want to make from this game), pre-flight (CLI, skills, sign-in, tools, done while they're at the keyboard), then "let me cook": arcade fork or arcade blend, play the parent, make the changes, test, media, demo and GIF, one dry run and one go, then the link to their new game with its credit to the original creator.
3
+ description: Use when someone wants to make their own version of a game on Evolutionary Arcade (evolutionaryarcade.com), usually right after they pasted the prompt from a game page's Fork or Blend button into their agent ("help me remix <game>", "help me blend <a> and <b>", `arcade guide fork`). Walks the session in Alex's order - vision (what they want to make from this game), pre-flight (CLI, skills, sign-in, tools, done while they're at the keyboard), then "let me cook": arcade fork or arcade blend, play the parent, make the changes, test, media, demo and GIF, one dry run and one go, then the link to their new game with its credit to the original creator, and share drafts they post themselves.
4
4
  ---
5
5
 
6
6
  # Forking or blending a game on Evolutionary Arcade
@@ -23,6 +23,7 @@ Every question that needs them happens at the start, while they're excited and a
23
23
  2. **Pre-flight** (step 2): CLI, skills, sign-in, tools. All the human-in-the-loop setup, done now.
24
24
  3. **Let me cook** (steps 3-6): say "I've got it from here. I'll come back with one thing to approve," then do the work.
25
25
  4. **One go, then the link** (steps 7-8): the only question while you cook is the publish go, because it makes their game public under their name.
26
+ 5. **Share drafts** (step 9): the posts are theirs to send. You never post.
26
27
 
27
28
  ## Ground rules for the whole session
28
29
 
@@ -54,7 +55,7 @@ Play-test the idea before you touch code. Ask these together, in one message, an
54
55
  > 2. What should stay? The thing you liked most about the original. (default: its core feel)
55
56
  > 3. A name for your game? It becomes its address, evolutionaryarcade.com/g/<name>, and can't change later. (default: I'll suggest one from your idea)
56
57
  > 4. Phones: want touch controls so people watching on their phones can play it? (default: yes, if the original doesn't have them)
57
- > 5. Want me to record a short demo so your game page has a video and a GIF to share? (default: yes)"
58
+ > 5. Want me to record a short demo so your game page has a video and a GIF to share? It comes in two shapes, wide for computers and tall for phones. (default: yes)"
58
59
 
59
60
  **For a blend**, replace question 1 and 2 with: "Which game's loop is the spine? I'll assume <spine>, with <donor> giving one thing: its movement, its look, an enemy, a mechanic. Which thing do you want from <donor>?" and say in one sentence what the blend would be ("Fly a starfighter to defend a deep-space relay from drone waves"). If they can't say it without "and also", it's two games; help them pick one.
60
61
 
@@ -104,9 +105,11 @@ Play it after every meaningful change, with real inputs through Playwright again
104
105
 
105
106
  ## Step 6. Media, demo, and GIF
106
107
 
107
- Capture new media from **their** build: a fork arrives with the parent's files, and a card showing the parent's footage misrepresents the game. A 1280x720 thumbnail mid-action and 2-4 screenshots from real play (`arcade guide publishing`, "Capturing media").
108
+ Estimate (say it's an estimate): about 5 minutes for a landscape game's media and demo, the vertical set included, since `arcade media vertical` makes it; about 10 for a portrait or both game, which records upright play too.
108
109
 
109
- If they said yes to a demo (the default): record 15-30 s of real play at 1280x720 with the action in the first second, save it as `media/demo.mp4`, set `"demo_video"`, and run `arcade media preview`. That makes the hover preview and `media/preview.gif`. Look at the GIF before moving on. Keep raw recordings outside the game folder; everything in it is uploaded.
110
+ Capture new media from **their** build: a fork arrives with the parent's files, and a card showing the parent's footage misrepresents the game. A 1280x720 thumbnail mid-action and 2-4 screenshots from real play, plus the vertical (phone) set in the same pass: check `orientation` still fits their version (play it at 390x844 with touch), then capture upright play into `media/vertical/` for a portrait or both game, or run `arcade media vertical` for a landscape one, which puts the landscape media over a blurred fill (`arcade guide publishing`, "Capturing media" and "Orientation and the vertical set"). The parent's vertical files are the parent's footage too, so remake them. If the game has its own fullscreen button, remove it: the arcade's player owns fullscreen.
111
+
112
+ If they said yes to a demo (the default): record 15-30 s of real play at 1280x720 with the action in the first second, save it as `media/demo.mp4`, set `"demo_video"`, and run `arcade media preview`. That makes the hover preview and `media/preview.gif`. For a portrait or both game, also record upright play at 390x844 into `media/vertical/demo.mp4`; then run `arcade media vertical` either way. Look at both GIFs before moving on. Keep raw recordings outside the game folder; everything in it is uploaded.
110
113
 
111
114
  ## Step 7. One dry run, one go, publish
112
115
 
@@ -122,9 +125,24 @@ Failures: a taken slug (pick another with them), a game over 50 MB (compress med
122
125
 
123
126
  1. Give them the game's link: `https://evolutionaryarcade.com/g/<slug>`. Open it if you can, and check the page says "Forked from <title> by @<creator>" (or "Blended from" with both).
124
127
  2. Tell them what happens next: anyone can play it without an account, it appears in the original's family tree, and the original creator can see it was forked. To change it later, edit `~/arcade-games/<slug>/` and publish again; that makes v2.
125
- 3. Give them a ready line to share:
126
- > `I remixed <original title> by @<creator>: https://evolutionaryarcade.com/g/<slug>`
128
+
129
+ ## Step 9. Share it (you draft, they post)
130
+
131
+ `arcade publish` ended with a **Share it** block. Run `arcade share <slug> --json` for the same thing as data. Show them:
132
+
133
+ - the link and the video-description line;
134
+ - the X post draft, which credits the original's creator ("I remixed <title> by @<creator> into <their title>..."), and the X intent link that opens it ready to post;
135
+ - the GIF to attach (`media/preview.gif`);
136
+ - the badge for a README or itch page if they keep one (`arcade share <slug> --badge`).
137
+
138
+ Then:
139
+
140
+ - **You never post.** Not to X, YouTube, Discord, or anywhere else, even if they ask you to and even if you have a tool that could. You draft; they post.
141
+ - Offer once to tailor the drafts to their channel's voice (their usual tone, emoji or none, how they credit people). If they say yes, rewrite the post in that voice, keep the link and every credit, and keep it under 280 characters (X counts a link as 23).
142
+ - Remind them to put their profile link in their video descriptions: that is where viewers become players and remixers:
143
+
144
+ > `Play my games (and remix them): https://evolutionaryarcade.com/u/<handle>`
127
145
 
128
146
  ## Example
129
147
 
130
- A viewer pastes: "Help me remix "Last Signal" (evolutionaryarcade.com/g/last-signal) on Evolutionary Arcade..." You find Node but no CLI, so you install it and the skills, then `arcade info last-signal`. You ask the five vision questions. They want "the same thing but you're a stealth scout, no shooting", keep the radio station and dusk look, name it night-shift, touch yes, demo yes. Pre-flight: `arcade login` in the background, they sign in as @kai, Playwright is there, ffmpeg needs `brew install ffmpeg` and they say yes. "I've got it from here." You fork into `~/arcade-games/night-shift`, play it, replace the wave defense with a sneak-and-restore loop, add touch controls, test on desktop and phone sizes, capture media, record a demo and its GIF. The dry run says "a fork of Last Signal v1". You show one summary and ask one question. They say yes, you publish, and hand them `https://evolutionaryarcade.com/g/night-shift`, whose page reads "Forked from Last Signal by @alex".
148
+ A viewer pastes: "Help me remix "Last Signal" (evolutionaryarcade.com/g/last-signal) on Evolutionary Arcade..." You find Node but no CLI, so you install it and the skills, then `arcade info last-signal`. You ask the five vision questions. They want "the same thing but you're a stealth scout, no shooting", keep the radio station and dusk look, name it night-shift, touch yes, demo yes. Pre-flight: `arcade login` in the background, they sign in as @kai, Playwright is there, ffmpeg needs `brew install ffmpeg` and they say yes. "I've got it from here." You fork into `~/arcade-games/night-shift`, play it, replace the wave defense with a sneak-and-restore loop, add touch controls, test on desktop and phone sizes, capture media, record a demo and its GIF. The dry run says "a fork of Last Signal v1". You show one summary and ask one question. They say yes, you publish, and hand them `https://evolutionaryarcade.com/g/night-shift`, whose page reads "Forked from Last Signal by @alex". You show the Share block (the X draft credits Last Signal's creator), offer to match the voice of their TikTok captions, and remind them to put `/u/kai` in their video descriptions. They post it themselves.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: arcade-onboarding
3
- description: Use when a creator wants to put games they already made on Evolutionary Arcade (evolutionaryarcade.com), usually right after they pasted the arcade's prompt into their agent ("help me put my games on Evolutionary Arcade", `arcade guide onboarding`). Walks the first session in Alex's order - vision (what they want, asked all up front), pre-flight (sign-in, tools, the ownership and MIT check) while they're still at the keyboard, then "let me cook": find the games, a fit table with your own time estimates, as-is or optimize, demos and GIFs, one combined dry run and one go, then a ready line with their profile link. Also covers GitHub repos as a source, failures, and the 30-a-day cap.
3
+ description: Use when a creator wants to put games they already made on Evolutionary Arcade (evolutionaryarcade.com), usually right after they pasted the arcade's prompt into their agent ("help me put my games on Evolutionary Arcade", `arcade guide onboarding`). Walks the first session in Alex's order - vision (what they want, asked all up front), pre-flight (sign-in, tools, the ownership and MIT check) while they're still at the keyboard, then "let me cook": find the games, a fit table with your own time estimates, as-is or optimize, demos and GIFs, one combined dry run and one go, then a ready line with their profile link and share drafts (link, description line, X post, GIF, badge) that they post themselves. Also covers GitHub repos as a source, failures, and the 30-a-day cap.
4
4
  ---
5
5
 
6
6
  # Onboarding a creator onto Evolutionary Arcade
@@ -23,6 +23,7 @@ Every question that needs the creator happens at the start, while they're intere
23
23
  2. **Pre-flight** (step 2): sign-in, the tools you'll need, and the ownership check. All the human-in-the-loop setup, done now.
24
24
  3. **Let me cook** (steps 3-6): say "I've got it from here. I'll come back with one summary to approve," then do the work.
25
25
  4. **One go, then the link** (steps 7-8): the only question while you cook is the publish go, because it makes their games public under their name.
26
+ 5. **Share drafts** (step 9): the posts are theirs to send. You never post.
26
27
 
27
28
  ## Ground rules for the whole session
28
29
 
@@ -96,7 +97,7 @@ For each candidate, decide from facts, then build one numbered table. It goes in
96
97
 
97
98
  Verdicts: **ready** (publishes as-is once it has metadata and media), **small fixes** (absolute paths, a CDN import to vendor, a build step, a stray big file), **not a fit** (needs a server, no web build, mostly someone else's work). Give the reason in a few words.
98
99
 
99
- **Time estimates are yours.** Look at the code before you estimate, and say they're estimates. As a starting point: as-is with metadata and media takes you a few minutes per game; touch controls 10-20 min; gamepad 5-10; saves or a leaderboard 5-10 each; a demo 3-5. Adjust for what you see.
100
+ **Time estimates are yours.** Look at the code before you estimate, and say they're estimates. As a starting point: as-is with metadata and media takes you a few minutes per game, including the vertical (phone) set: about 1 more minute for a landscape game (`arcade media vertical` makes it), 3-5 for a portrait or both game (an upright capture at 390x844); touch controls 10-20 min; gamepad 5-10; saves or a leaderboard 5-10 each; a demo 3-5 (twice that for a portrait or both game, which records a vertical demo too); removing a game's own fullscreen button 2-5. Adjust for what you see.
100
101
 
101
102
  ```
102
103
  # Game Where Fit What it needs As-is / optimized
@@ -116,7 +117,9 @@ Follow their step-1 answer for the whole batch.
116
117
  - write `arcade.json` (`arcade guide publishing` has a full example): a slug you pick with them (permanent, it's the game's address), the title, a one-or-two-sentence description, exact `controls`, and honest `input` flags;
117
118
  - write `LICENSE` (MIT, "Copyright (c) <year> @<handle>") unless they already have an MIT one;
118
119
  - run it with `arcade dev`, fix anything that breaks under the arcade's CSP (outside requests, absolute paths);
119
- - capture a 1280x720 thumbnail mid-action and 2-4 screenshots from real play (`arcade guide publishing`, "Capturing media");
120
+ - decide its `orientation` by playing it at 390x844 with touch: `"landscape"` if it needs the phone sideways (fine), `"portrait"` if it plays upright, `"both"` if either works;
121
+ - capture a 1280x720 thumbnail mid-action and 2-4 screenshots from real play, and in the same pass the vertical set: for portrait or both, an upright thumbnail and 2-4 screenshots at 390x844 with touch emulation into `media/vertical/`; for landscape, run `arcade media vertical`, which puts the landscape media over a blurred fill (`arcade guide publishing`, "Capturing media" and "Orientation and the vertical set");
122
+ - remove any fullscreen button of the game's own and its `requestFullscreen` calls: the arcade's player owns fullscreen (the dry run warns about them);
120
123
  - fill the Model card with what they tell you (the model and harness they used); leave out anything unknown. Never invent numbers.
121
124
 
122
125
  **Optimize** adds, per game, only what makes sense for it, using the arcade's format (`arcade guide building-games` has each one):
@@ -130,7 +133,7 @@ Play every game after you change it. Set an input flag only when that path works
130
133
 
131
134
  ## Step 6. Demos
132
135
 
133
- If they said yes in step 1 (the default), then for each game: play it with Playwright at 1280x720 against `arcade dev` (drive real inputs, or the game's autopilot if it has one), cut 15-30 s with the action in the first second, save it as `media/demo.mp4`, set `"demo_video"`, and run `arcade media preview`. That makes `media/preview.mp4` (the hover preview) and `media/preview.gif`, and sets both fields. **A game with a demo must have its GIF**; `arcade publish` makes it when it's missing and refuses without ffmpeg. Watch the clips and look at the GIF before moving on. Bot-driven footage is fine; say so in `provenance.notes`. Keep recordings outside the game folder, since everything in it is uploaded. Recording needs Playwright and ffmpeg; if they're missing, ask before installing.
136
+ If they said yes in step 1 (the default), then for each game: play it with Playwright at 1280x720 against `arcade dev` (drive real inputs, or the game's autopilot if it has one), cut 15-30 s with the action in the first second, save it as `media/demo.mp4`, set `"demo_video"`, and run `arcade media preview`. That makes `media/preview.mp4` (the hover preview) and `media/preview.gif`, and sets both fields. Then the vertical demo: a portrait or both game records upright play at 390x844 with touch into `media/vertical/demo.mp4` (set `media_vertical.demo_video`); every game then runs `arcade media vertical` (for a landscape game it makes the whole vertical set from the landscape demo over a blurred fill). **A game with a demo must have its GIF**; `arcade publish` makes it when it's missing and refuses without ffmpeg. Watch the clips and look at the GIF before moving on. Bot-driven footage is fine; say so in `provenance.notes`. Keep recordings outside the game folder, since everything in it is uploaded. Recording needs Playwright and ffmpeg; if they're missing, ask before installing.
134
137
 
135
138
  ## Step 7. One dry run, one go, publish
136
139
 
@@ -145,13 +148,26 @@ Failures: a slug that's taken (pick another with them), a game over 50 MB (move
145
148
 
146
149
  ## Step 8. Hand back the link
147
150
 
148
- 1. Ask for their channel URL and a one-line bio, then `arcade profile set --bio "<line>" --link "YouTube <url>"` (pass every link they want; it replaces the list).
151
+ 1. Ask for their channel URL and a one-line bio, then `arcade profile set --bio "<line>" --link "YouTube <url>"` (pass every link they want; it replaces the list). If they're on X, add their X profile too: share drafts for anyone who remixes their games will then credit them by their X handle.
149
152
  2. `arcade profile show` for the profile address.
150
- 3. Give them a ready line for their video descriptions:
151
- > `Play my games (and remix them): https://evolutionaryarcade.com/u/<handle>`
152
- and each game's own link (`https://evolutionaryarcade.com/g/<slug>`).
153
+ 3. Give them their profile link and each game's own link (`https://evolutionaryarcade.com/g/<slug>`).
153
154
  4. Tell them what happens next: people can play without an account, fork and blend their games, and those remixes show up in each game's family tree. To update a game later, change it in its `~/arcade-games/<slug>/` folder and publish again; that makes the next version.
154
155
 
156
+ ## Step 9. Share it (you draft, they post)
157
+
158
+ Each publish ended with a **Share it** block. Run `arcade share --profile --json` for the whole library and `arcade share <slug> --json` for any one game. Show them:
159
+
160
+ - the description line for their videos, `Play my games (and remix them): https://evolutionaryarcade.com/u/<handle>`, and each game's own line;
161
+ - the X post draft for the library (and for a game they want to lead with), with its X intent link;
162
+ - each game's GIF to attach (`media/preview.gif`);
163
+ - the badge for READMEs, itch pages, and their website (`arcade share <slug> --badge`, or `--profile --badge` for one badge that links to everything).
164
+
165
+ Then:
166
+
167
+ - **You never post.** Not to X, YouTube, Discord, or anywhere else, even if they ask you to and even if you have a tool that could. You draft; they post.
168
+ - Offer once to tailor the drafts to their channel's voice (their usual tone, emoji or none, how they credit people). If they say yes, rewrite the post in that voice, keep the link and every credit, and keep it under 280 characters (X counts a link as 23).
169
+ - Remind them to put their profile link in their video descriptions: that is where viewers become players and remixers.
170
+
155
171
  ## Example
156
172
 
157
- Creator: "help me put my games on Evolutionary Arcade." You install, then ask the four vision questions in one message. They want a showcase for their channel, the games are in `~/Desktop/jams`, as-is, and yes to demos. Pre-flight: you start `arcade login` in the background and they approve it in the browser, ffmpeg is already there, Playwright needs one install line and they say yes, and you give the ownership warning. They mention that one game used music from a paid pack. "I've got it from here." You find five games; one needs a websocket server. You copy the four fits, write arcade.json, LICENSE and controls, vendor one CDN import, drop the paid music, capture media, and record four demos (each with its GIF). You come back with one summary (the fit table, what you changed, the combined dry run) and one question: "Publish these 4 publicly under @handle, MIT?" They say yes, four publishes, and you hand them the description line with `/u/<handle>`.
173
+ Creator: "help me put my games on Evolutionary Arcade." You install, then ask the four vision questions in one message. They want a showcase for their channel, the games are in `~/Desktop/jams`, as-is, and yes to demos. Pre-flight: you start `arcade login` in the background and they approve it in the browser, ffmpeg is already there, Playwright needs one install line and they say yes, and you give the ownership warning. They mention that one game used music from a paid pack. "I've got it from here." You find five games; one needs a websocket server. You copy the four fits, write arcade.json, LICENSE and controls, vendor one CDN import, drop the paid music, capture media, and record four demos (each with its GIF). You come back with one summary (the fit table, what you changed, the combined dry run) and one question: "Publish these 4 publicly under @handle, MIT?" They say yes, four publishes, and you hand them the description line with `/u/<handle>`, the library's X draft, and the badge for their itch page. You offer to match the voice of their video captions; they post it themselves.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: arcade-publishing
3
- description: Use when a browser game is ready, or nearly ready, to go live on Evolutionary Arcade (evolutionaryarcade.com) with the `arcade` CLI, or when you are shipping the next version of a game you already published. Covers filling in arcade.json and replacing the CLI's placeholder text, writing an honest Model card (models, harness, tokens, cost, prompts), capturing the thumbnail, screenshots, demo, and hover preview with Playwright and ffmpeg, reviewing `arcade publish --dry-run` and its Heads up list with the user before `arcade publish --yes`, fixing problems (exit code 2) including a flagged secret, finding generation ids with `arcade info` for `arcade main`, and taking a game down with `arcade unpublish`.
3
+ description: Use when a browser game is ready, or nearly ready, to go live on Evolutionary Arcade (evolutionaryarcade.com) with the `arcade` CLI, or when you are shipping the next version of a game you already published. Covers filling in arcade.json and replacing the CLI's placeholder text, writing an honest Model card (models, harness, tokens, cost, prompts), deciding the game's orientation and capturing both media sets (landscape at 1280x720, vertical at 390x844 or the CLI's blurred fill) with Playwright and ffmpeg, reviewing `arcade publish --dry-run` and its Heads up list with the user before `arcade publish --yes`, fixing problems (exit code 2) including a flagged secret, finding generation ids with `arcade info` for `arcade main`, and taking a game down with `arcade unpublish`.
4
4
  ---
5
5
 
6
6
  # Publishing a game to Evolutionary Arcade
@@ -16,6 +16,7 @@ Not playable under the arcade's rules yet? Use `arcade-building-games`. First ti
16
16
  ## What good looks like
17
17
 
18
18
  - The thumbnail is a real frame of play, mid-action, 1280x720.
19
+ - Phones get a vertical set that tells the truth about how the game plays: real upright play for a portrait game, or the landscape footage over a blurred fill for a game that only plays sideways.
19
20
  - The hover preview comes from this build's demo, and its first seconds show the game doing its best thing. No title screen, no loading.
20
21
  - A stranger understands the title and description, and the controls are exact.
21
22
  - The Model card is honest: filled in where you know, left out where you don't.
@@ -35,6 +36,8 @@ Required: `schema`, `slug`, `title`, `description`, `thumbnail`, and at least on
35
36
  - `profile_saves` (default `false`): the game saves progress to the player's profile with the `arcade-saves.js` helper. Set it only when the game uses the helper; `arcade-building-games` has the rules.
36
37
  - `leaderboards` (up to 4, default none): global leaderboards the game posts to with the `arcade-scores.js` helper. Each has an `id`, a `label`, and a `max`, and the dry run lists them with their limits. `arcade-building-games` has the rules.
37
38
  - `thumbnail` and `screenshots` (1 to 12) are .png, .jpg, or .webp. `demo_video` and `preview_video` are .mp4 or .webm. `preview_gif` is a .gif cut from the demo, required whenever there's a demo; `arcade media preview` (or `arcade publish`) makes it. Every path is relative to the folder, with no `..`.
39
+ - `orientation` (default `"landscape"`): which way up the game plays on a phone. `"landscape"`, `"portrait"`, or `"both"`. See "Orientation and the vertical set" below.
40
+ - `media_vertical` (optional): the phone (9:16) set, with the same fields as the landscape set: `thumbnail`, `screenshots` (up to 12), `demo_video`, `preview_video`, `preview_gif`. The top-level fields are the landscape set. A `portrait` or `both` game with `touch` must list a vertical thumbnail and at least one vertical screenshot, plus a vertical demo when it has a landscape demo. A landscape game's set is made by `arcade media vertical`.
38
41
  - `license` (optional): every game on the arcade is open source under MIT, so leave it out or set it to `"MIT"`. Anything else fails validation. The folder's `LICENSE` names the creator ("Copyright (c) <year> @handle"); if `arcade new` wrote it before you logged in, `arcade publish` fills in the handle. A license file at the top of the folder (`LICENSE`, `LICENSE.md`, `COPYING`, and the like) that isn't MIT stops the publish; other people's licenses go in `licenses/<name>/` or beside their code.
39
42
  - `lineage`: the CLI writes it. Don't edit it.
40
43
  - `provenance`: the Model card.
@@ -120,17 +123,52 @@ ffmpeg -ss 4 -i ../rec/<file>.webm -t 24 -an -vf scale=1280:720 \
120
123
  - **Budget:** the whole upload must stay under 50 MB and 800 files. The thumbnail and each screenshot must be at most 5 MB, and the demo, preview, and any other file at most 25 MB. A 24-second demo at CRF 23 is about 8 MB.
121
124
  - **Look at every file** before you publish. For video, a contact sheet is quick: `ffmpeg -i media/demo.mp4 -vf fps=1/3,scale=320:-1,tile=4x3 -frames:v 1 ../rec/sheet.png` (one image, covering 36 s). If headless WebGL renders black, run headed or pass GPU flags to Chromium (on macOS the seeds used `--use-angle=metal --ignore-gpu-blocklist`).
122
125
 
126
+ ## Orientation and the vertical set
127
+
128
+ Phones are a big share of players, and a 16:9 card is a sliver on a phone held upright. So every game ships two media sets: landscape (the top-level fields) and vertical (`media_vertical`). The site shows phones the vertical set. One size doesn't fit all, and the vertical set has to be honest about how the game plays.
129
+
130
+ **Decide the orientation by playing it on a phone.** Run `arcade dev`, open it in Playwright at 390x844 with touch emulation (or on a real phone), and play:
131
+ - `"portrait"`: it plays upright and was built for it (a tall playfield, thumb controls at the bottom).
132
+ - `"both"`: it lays out and plays well either way.
133
+ - `"landscape"`: it needs the phone sideways. That's fine. Don't fake an upright mode.
134
+ A game without touch controls is `"landscape"` unless you add them.
135
+
136
+ **Capture both sets in one pass.** Same build, same `arcade dev` server, two contexts:
137
+
138
+ ```js
139
+ // Landscape: as above, 1280x720.
140
+ // Vertical (portrait and both games): a phone, with touch.
141
+ const phone = await browser.newContext({
142
+ viewport: { width: 390, height: 844 },
143
+ deviceScaleFactor: 3, // screenshots come out 1170x2532
144
+ isMobile: true,
145
+ hasTouch: true,
146
+ recordVideo: { dir: "../rec/vertical", size: { width: 390, height: 844 } },
147
+ });
148
+ const p = await phone.newPage();
149
+ await p.goto("http://localhost:5173/?autopilot");
150
+ await p.tap("canvas"); // a tap, not a click
151
+ ```
152
+
153
+ Encode the vertical demo at 1080x1920: `ffmpeg -ss 4 -i ../rec/vertical/<file>.webm -t 24 -an -vf scale=1080:1920 -c:v libx264 -pix_fmt yuv420p -crf 23 -movflags +faststart media/vertical/demo.mp4`.
154
+
155
+ **Choose the vertical treatment by orientation:**
156
+ - **portrait or both:** real upright play. Save the vertical thumbnail and 2 to 4 screenshots in `media/vertical/`, the demo as `media/vertical/demo.mp4`, list them under `media_vertical`, then run `arcade media vertical`: it cuts the vertical hover preview (480x854) and GIF from your vertical demo. For `both`, still capture the landscape set at 1280x720; desktop shows it.
157
+ - **landscape:** capture only the landscape set, then run `arcade media vertical`. It centers each landscape image and the demo at full width over a blurred, darkened copy of itself at 1080x1920, writes `media/vertical/` (thumbnail, screenshots, demo, preview, GIF), and sets `media_vertical`. `arcade publish` does this for you when the set is missing. Re-run it after a new landscape demo or thumbnail; the dry run warns when the vertical set is older.
158
+
159
+ Look at the vertical files too (a contact sheet: `ffmpeg -i media/vertical/demo.mp4 -vf fps=1/3,scale=180:-1,tile=6x2 -frames:v 1 ../rec/vsheet.png`). Upright footage of a game that only plays sideways, or a blurred fill whose middle band is unreadable, is a false promise.
160
+
123
161
  ## The dry run
124
162
 
125
163
  Run `arcade publish --dry-run` and read all of it. It uploads nothing, but know what it is:
126
164
 
127
165
  - Signed out, it runs only the local checks (arcade.json, file types, license, media, secrets), prints any Heads up, and exits 1 asking you to sign in. The full dry run needs `arcade login` and a network connection, because the arcade checks the upload before anything is listed. Problems the arcade finds (a file over 25 MB, too many files, a slug that's taken, a stale base) exit before the file list prints.
128
166
  - Every problem it exits 2 on says what to produce: a missing thumbnail names the size and path to capture, a missing arcade.json lists the fields to write.
129
- - It may make `media/preview.mp4` and `media/preview.gif` and write `preview_video` and `preview_gif` into arcade.json.
167
+ - It may make `media/preview.mp4` and `media/preview.gif` and write `preview_video` and `preview_gif` into arcade.json, and, for a landscape game, the vertical set in `media/vertical/` and `media_vertical`.
130
168
  - It lists the first 40 files, then "…and N more", but files inside hidden folders (like `.claude/`) are always listed. New files are tagged `new`. Review the whole tree yourself: `find . -type f -not -path './node_modules/*' -not -path './.git/*'`.
131
169
  - It follows symlinks only when they point inside the folder. Anything else is listed as skipped, and never uploaded.
132
170
  - It says "Published games are open source under MIT" under the action line. Anything bundled from others keeps its own license and must be the user's to share.
133
- - Its **Heads up** list flags likely mistakes without stopping the publish: a leftover `parents/`, `BLEND.md` or `PROMPT.md`, media already on the arcade on a fork, blend, or regen (so probably the parent's), starter text, a placeholder slug, a home-folder path in the prompt or notes, a thumbnail over 500 KB, and no model or prompt on the Model card. Fix each one, or tell the user why it's fine.
171
+ - Its **Heads up** list flags likely mistakes without stopping the publish: a leftover `parents/`, `BLEND.md` or `PROMPT.md`, media already on the arcade on a fork, blend, or regen (so probably the parent's), starter text, a placeholder slug, a home-folder path in the prompt or notes, a thumbnail over 500 KB, no vertical thumbnail, a vertical set older than the landscape media, game code that calls `requestFullscreen` ("the arcade's player owns fullscreen; remove your fullscreen button"), and no model or prompt on the Model card. Fix each one, or tell the user why it's fine.
134
172
  - Its Model card shows the model, tokens, cost, time, process, and the prompt's length, not the prompt or notes text. Read those in arcade.json.
135
173
 
136
174
  What to check: