juicyjuicy 0.4.2 → 0.5.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/dist/index.js CHANGED
@@ -19821,7 +19821,6 @@ var LIMITS = {
19821
19821
  * whatever draws one (the link-preview card, players' browsers) decodes every pixel.
19822
19822
  */
19823
19823
  maxThumbnailSide: 4096,
19824
- maxHowItWasMadeBytes: 20 * 1024,
19825
19824
  maxApiTokensPerUser: 20,
19826
19825
  maxTokenNameLength: 60,
19827
19826
  /** Characters in a comment (plain text, ARCHITECTURE §14). */
@@ -19983,6 +19982,15 @@ var relativePath = (what) => external_exports.string().transform(normalizePath).
19983
19982
  `${what} must be a relative path inside the project`
19984
19983
  );
19985
19984
  var tagSchema = external_exports.string().min(2).max(24).regex(/^[a-z0-9]+(-[a-z0-9]+)*$/, "tags are lowercase words, e.g. puzzle or tower-defense");
19985
+ var languageNames = new Intl.DisplayNames(["en"], { type: "language", fallback: "none" });
19986
+ function languageName(code) {
19987
+ if (!/^[a-z]{2,3}$/.test(code)) return void 0;
19988
+ return languageNames.of(code);
19989
+ }
19990
+ var languageSchema = external_exports.string().trim().toLowerCase().refine(
19991
+ (code) => languageName(code) !== void 0,
19992
+ 'use a two-letter language code, like "en" or "pl"'
19993
+ );
19986
19994
  var SOURCE_URL_PATTERN = /^https:\/\/[a-z0-9.-]+(:\d{1,5})?(\/[\w.~%/@+=:-]*)?$/i;
19987
19995
  var sourceUrlSchema = external_exports.string().max(300).regex(
19988
19996
  SOURCE_URL_PATTERN,
@@ -20002,6 +20010,8 @@ var gameFieldSchemas = {
20002
20010
  engine: external_exports.enum(ENGINES),
20003
20011
  madeWith: external_exports.array(memberText().min(1).max(40)).max(5),
20004
20012
  tags: external_exports.array(tagSchema).max(5),
20013
+ /** The languages a player can play it in, the default first. Each one counts once. */
20014
+ languages: external_exports.array(languageSchema).min(1, "list at least one language").max(5).transform((codes) => [...new Set(codes)]),
20005
20015
  input: external_exports.array(external_exports.enum(INPUTS)),
20006
20016
  orientation: external_exports.enum(ORIENTATIONS),
20007
20017
  aspectRatio: external_exports.string().regex(/^(fill|\d{1,2}:\d{1,2})$/, 'use "W:H" like "16:9", or "fill"'),
@@ -20021,6 +20031,7 @@ var manifestSchema = external_exports.strictObject({
20021
20031
  engine: gameFieldSchemas.engine.default("other"),
20022
20032
  madeWith: gameFieldSchemas.madeWith.default([]),
20023
20033
  tags: gameFieldSchemas.tags.default([]),
20034
+ languages: gameFieldSchemas.languages.default(["en"]),
20024
20035
  input: gameFieldSchemas.input.default([]),
20025
20036
  orientation: gameFieldSchemas.orientation.default("any"),
20026
20037
  aspectRatio: gameFieldSchemas.aspectRatio.default("16:9"),
@@ -20028,7 +20039,8 @@ var manifestSchema = external_exports.strictObject({
20028
20039
  (path2) => THUMBNAIL_EXTENSIONS.some((ext) => path2.toLowerCase().endsWith(`.${ext}`)),
20029
20040
  `thumbnail must be one of: ${THUMBNAIL_EXTENSIONS.join(", ")}`
20030
20041
  ).optional(),
20031
- howItWasMade: relativePath("howItWasMade").refine((path2) => path2.toLowerCase().endsWith(".md"), "howItWasMade must be a .md file").optional(),
20042
+ /** No longer used (D50); still accepted so older juicy.json files keep publishing. */
20043
+ howItWasMade: external_exports.string().optional().meta({ deprecated: true }),
20032
20044
  remixable: gameFieldSchemas.remixable.default(false),
20033
20045
  sourceUrl: gameFieldSchemas.sourceUrl.optional(),
20034
20046
  remixedFrom: slugSchema.nullable().optional()
@@ -20064,8 +20076,6 @@ var startVersionRequestSchema = external_exports.object({
20064
20076
  * when the game's current thumbnail was set on the dashboard. Older CLIs leave it out.
20065
20077
  */
20066
20078
  thumbnailAuto: external_exports.boolean().optional(),
20067
- /** Contents of the manifest's `howItWasMade` markdown file. */
20068
- howItWasMade: memberText().optional(),
20069
20079
  /** A note for the version history, e.g. what changed or a commit SHA. */
20070
20080
  message: memberText().max(200).optional(),
20071
20081
  source: external_exports.enum(PUBLISH_SOURCES).default("cli"),
@@ -20084,13 +20094,12 @@ var updateGameRequestSchema = external_exports.object({
20084
20094
  engine: gameFieldSchemas.engine.optional(),
20085
20095
  madeWith: gameFieldSchemas.madeWith.optional(),
20086
20096
  tags: gameFieldSchemas.tags.optional(),
20097
+ languages: gameFieldSchemas.languages.optional(),
20087
20098
  input: gameFieldSchemas.input.optional(),
20088
20099
  orientation: gameFieldSchemas.orientation.optional(),
20089
20100
  aspectRatio: gameFieldSchemas.aspectRatio.optional(),
20090
20101
  remixable: gameFieldSchemas.remixable.optional(),
20091
- sourceUrl: gameFieldSchemas.sourceUrl.nullable().optional(),
20092
- /** Markdown, ≤ 20 KB. */
20093
- howItWasMade: memberText().nullable().optional()
20102
+ sourceUrl: gameFieldSchemas.sourceUrl.nullable().optional()
20094
20103
  });
20095
20104
  var rollbackRequestSchema = external_exports.object({ version: external_exports.number().int().positive() });
20096
20105
  var voteRequestSchema = external_exports.object({
@@ -20785,8 +20794,16 @@ var REMIX_LICENSE_NAME = "JuicyJuicy remix license";
20785
20794
  var REMIX_LICENSE = "Members may download this game's files and publish a changed version of it on JuicyJuicy, credited to the original. It doesn't allow publishing the game or a remix of it anywhere else, or passing the files on. Turning Remixable off stops new remix downloads; remixes already published stay up.";
20786
20795
 
20787
20796
  // ../shared/src/listing.ts
20788
- var GAME_SORTS = ["newest", "upvoted", "downvoted", "played"];
20797
+ var GAME_SORTS = [
20798
+ "newest",
20799
+ "oldest",
20800
+ "trending",
20801
+ "upvoted",
20802
+ "downvoted",
20803
+ "played"
20804
+ ];
20789
20805
  var GAME_PERIODS = ["24h", "week", "month", "all"];
20806
+ var GAME_LISTS = ["featured", "favorites", "unplayed"];
20790
20807
  var DEFAULT_GAME_LIST_QUERY = {
20791
20808
  sort: "newest",
20792
20809
  period: "all",
@@ -20801,8 +20818,10 @@ var paramSchemas = {
20801
20818
  period: external_exports.preprocess(lowercase2, external_exports.enum(GAME_PERIODS)),
20802
20819
  engine: external_exports.preprocess(lowercase2, external_exports.enum(ENGINES)),
20803
20820
  tag: external_exports.preprocess(lowercase2, gameFieldSchemas.tags.element),
20821
+ lang: languageSchema,
20804
20822
  q: external_exports.string().max(MAX_GAME_SEARCH_LENGTH),
20805
20823
  remixes: external_exports.enum(["0", "1"]),
20824
+ list: external_exports.preprocess(lowercase2, external_exports.enum(GAME_LISTS)),
20806
20825
  page: external_exports.string().regex(/^\d{1,4}$/, "use a whole number").transform(Number).pipe(external_exports.number().min(1).max(MAX_GAME_LIST_PAGE))
20807
20826
  };
20808
20827
  function remixFilter(param) {
@@ -20814,8 +20833,10 @@ var gameListRequestSchema = external_exports.object({
20814
20833
  period: paramSchemas.period.default(DEFAULT_GAME_LIST_QUERY.period),
20815
20834
  engine: paramSchemas.engine.optional(),
20816
20835
  tag: paramSchemas.tag.optional(),
20836
+ lang: paramSchemas.lang.optional(),
20817
20837
  q: paramSchemas.q.optional(),
20818
20838
  remixes: paramSchemas.remixes.optional(),
20839
+ list: paramSchemas.list.optional(),
20819
20840
  page: paramSchemas.page.default(DEFAULT_GAME_LIST_QUERY.page)
20820
20841
  }).transform(({ remixes, ...rest }) => ({ ...rest, remixes: remixFilter(remixes) }));
20821
20842
 
@@ -24346,7 +24367,7 @@ var program = new Command();
24346
24367
  // package.json
24347
24368
  var package_default = {
24348
24369
  name: "juicyjuicy",
24349
- version: "0.4.2",
24370
+ version: "0.5.1",
24350
24371
  description: "Publish AI-made browser games to juicyjuicy.games",
24351
24372
  type: "module",
24352
24373
  license: "MIT",
@@ -26085,6 +26106,7 @@ async function walkFiles(root) {
26085
26106
  await visit2(root);
26086
26107
  return result;
26087
26108
  }
26109
+ var HOW_IT_WAS_MADE_WARNING = '"howItWasMade" is no longer used and its file is not sent; remove it from juicy.json (juicyjuicy init does)';
26088
26110
  var NO_THUMBNAIL_WARNING = `no thumbnail: the game's tile shows a plain gradient. Add a screenshot as thumbnail.png and set "thumbnail" in juicy.json`;
26089
26111
  function isInside(root, path2) {
26090
26112
  const rel = relative(root, path2);
@@ -26105,7 +26127,6 @@ async function checkProject(dir, options = {}) {
26105
26127
  files: [],
26106
26128
  totalBytes: 0,
26107
26129
  thumbnail: null,
26108
- howItWasMade: null,
26109
26130
  issues: [],
26110
26131
  warnings: [],
26111
26132
  findings: [],
@@ -26140,9 +26161,8 @@ async function checkProject(dir, options = {}) {
26140
26161
  }
26141
26162
  check3.files = plan.files;
26142
26163
  check3.totalBytes = plan.files.reduce((sum, file2) => sum + file2.size, 0);
26143
- const story = manifest.howItWasMade ? relative(buildDir, resolve(realDir, manifest.howItWasMade)).split(sep).join("/") : null;
26144
26164
  for (const { path: path2 } of plan.files) {
26145
- const reason = path2 === story ? null : unusualFileReason(path2);
26165
+ const reason = unusualFileReason(path2);
26146
26166
  if (reason) check3.unusualFiles.push({ path: path2, reason });
26147
26167
  }
26148
26168
  if (check3.unusualFiles.length > 0) {
@@ -26188,23 +26208,8 @@ async function checkProject(dir, options = {}) {
26188
26208
  } else {
26189
26209
  check3.warnings.push(NO_THUMBNAIL_WARNING);
26190
26210
  }
26191
- if (manifest.howItWasMade) {
26192
- const file2 = await projectFile(realDir, manifest.howItWasMade);
26193
- if (!file2) {
26194
- check3.issues.push({
26195
- code: "VALIDATION_FAILED",
26196
- message: "file not found in the project folder",
26197
- path: manifest.howItWasMade
26198
- });
26199
- } else if (file2.size > LIMITS.maxHowItWasMadeBytes) {
26200
- check3.issues.push({
26201
- code: "TOO_LARGE",
26202
- message: `${(file2.size / 1024).toFixed(1)} KB; at most ${LIMITS.maxHowItWasMadeBytes / 1024} KB`,
26203
- path: manifest.howItWasMade
26204
- });
26205
- } else {
26206
- check3.howItWasMade = { ...file2, text: await readFile2(file2.absolute, "utf8") };
26207
- }
26211
+ if (manifest.howItWasMade !== void 0) {
26212
+ check3.warnings.push(HOW_IT_WAS_MADE_WARNING);
26208
26213
  }
26209
26214
  const viteWarning = await viteBaseWarning(dir);
26210
26215
  if (viteWarning) check3.warnings.push(viteWarning);
@@ -26298,7 +26303,6 @@ async function detectProject(dir) {
26298
26303
  entry,
26299
26304
  engine: await detectEngine(dir, buildDir, deps, Boolean(pkg)),
26300
26305
  thumbnail: await firstExisting(dir, ["thumbnail.png", "thumbnail.jpg", "thumbnail.webp"]),
26301
- howItWasMade: await firstExisting(dir, ["HOW_I_MADE_IT.md"]),
26302
26306
  warnings
26303
26307
  };
26304
26308
  }
@@ -26331,11 +26335,11 @@ var KEY_ORDER = [
26331
26335
  "engine",
26332
26336
  "madeWith",
26333
26337
  "tags",
26338
+ "languages",
26334
26339
  "input",
26335
26340
  "orientation",
26336
26341
  "aspectRatio",
26337
26342
  "thumbnail",
26338
- "howItWasMade",
26339
26343
  "remixable",
26340
26344
  "sourceUrl",
26341
26345
  "remixedFrom"
@@ -26353,12 +26357,13 @@ async function buildManifest(dir, flags, ask) {
26353
26357
  orientation: pick2("orientation", "any"),
26354
26358
  aspectRatio: pick2("aspectRatio", "16:9"),
26355
26359
  tags: pick2("tags", []),
26360
+ languages: pick2("languages", ["en"]),
26356
26361
  input: pick2("input", []),
26357
26362
  remixable: pick2("remixable", false)
26358
26363
  };
26359
26364
  const thumbnail = pick2("thumbnail", detected.thumbnail);
26360
26365
  if (thumbnail) values.thumbnail = thumbnail;
26361
- if (!values.howItWasMade && detected.howItWasMade) values.howItWasMade = detected.howItWasMade;
26366
+ delete values.howItWasMade;
26362
26367
  if (flags.sourceUrl) values.sourceUrl = flags.sourceUrl;
26363
26368
  const fieldSchema = manifestSchema.shape;
26364
26369
  const check3 = (field) => (value) => fieldSchema[field].safeParse(value).error?.issues[0]?.message;
@@ -26877,7 +26882,6 @@ async function check2(out, dir, options) {
26877
26882
  unusualFiles: result.unusualFiles,
26878
26883
  thumbnail: result.thumbnail?.path ?? null,
26879
26884
  thumbnailAuto: Boolean(result.thumbnail?.auto),
26880
- howItWasMade: result.howItWasMade?.path ?? null,
26881
26885
  warnings: result.warnings,
26882
26886
  findings: result.findings,
26883
26887
  scriptHosts: result.scriptHosts
@@ -27046,7 +27050,7 @@ async function publish(out, dir, options) {
27046
27050
  const server = apiUrl();
27047
27051
  const auth = await ensureLogin(out, server);
27048
27052
  const api = new ApiClient(server, auth.token);
27049
- const { thumbnail, howItWasMade } = checked;
27053
+ const { thumbnail } = checked;
27050
27054
  const request = {
27051
27055
  manifest: checked.rawManifest,
27052
27056
  files: await hashFiles(checked.buildDir, checked.files),
@@ -27057,7 +27061,6 @@ async function publish(out, dir, options) {
27057
27061
  } : void 0,
27058
27062
  // A screenshot doesn't replace a thumbnail uploaded on the dashboard (D34).
27059
27063
  ...thumbnail?.auto ? { thumbnailAuto: true } : {},
27060
- howItWasMade: howItWasMade?.text,
27061
27064
  message: options.message,
27062
27065
  source: options.source ?? (process.env.GITHUB_ACTIONS === "true" ? "github" : "cli"),
27063
27066
  ...options.draft ? { draft: true } : {}
@@ -27740,7 +27743,11 @@ function createProgram() {
27740
27743
  "--made-with <list>",
27741
27744
  'models and tools, e.g. "Claude Opus 5.5, Claude Code"',
27742
27745
  splitList
27743
- ).option("--tags <list>", "up to 5 tags, e.g. arcade,space", splitList).addOption(new Option("--input <list>", `controls: ${INPUTS.join(", ")}`).argParser(splitList)).addOption(new Option("--orientation <orientation>").choices(ORIENTATIONS)).option("--aspect-ratio <ratio>", 'like 16:9, or "fill"').option("--thumbnail <file>", "png/jpg/webp in the game folder").option("--remixable", `let other members remix it on JuicyJuicy only (${REMIX_LICENSE_NAME})`).option("--source-url <url>", "public source code, e.g. a GitHub repo").addHelpText(
27746
+ ).option("--tags <list>", "up to 5 tags, e.g. arcade,space", splitList).option(
27747
+ "--languages <list>",
27748
+ "language codes players can pick, the default first, e.g. en,pl",
27749
+ splitList
27750
+ ).addOption(new Option("--input <list>", `controls: ${INPUTS.join(", ")}`).argParser(splitList)).addOption(new Option("--orientation <orientation>").choices(ORIENTATIONS)).option("--aspect-ratio <ratio>", 'like 16:9, or "fill"').option("--thumbnail <file>", "png/jpg/webp in the game folder").option("--remixable", `let other members remix it on JuicyJuicy only (${REMIX_LICENSE_NAME})`).option("--source-url <url>", "public source code, e.g. a GitHub repo").addHelpText(
27744
27751
  "after",
27745
27752
  `
27746
27753
  ${REMIX_LICENSE_NAME} (--remixable): ${REMIX_LICENSE}`
@@ -53,15 +53,21 @@ npx -y juicyjuicy@0 init --yes --json \
53
53
  - `init` keeps what an existing `juicy.json` already says (flags override), and detects `buildDir`, `entry` and `engine`. Check what it wrote.
54
54
  - `--made-with`: your real model and the tool you run in, e.g. `"Claude Opus 5.5, Claude Code"` or `"Gemini 3 Pro, Antigravity"`.
55
55
  - The slug (the `/g/<slug>` URL name) defaults to one made from the title. Once published it belongs to this user; reuse it to publish updates.
56
- - Offer to write `HOW_I_MADE_IT.md` (a short story of how the game was made, up to 20 KB of markdown). `init` picks it up when it exists.
56
+ - `--languages`: the languages a player can switch between, English first, e.g. `en,pl`. Leave it out for a game that's only in English (the default is `en`).
57
57
 
58
58
  All fields: [reference/manifest.md](reference/manifest.md).
59
59
 
60
+ **English first.** Every game on JuicyJuicy plays in English by default, so players anywhere can pick it up:
61
+
62
+ - If the game's text (menus, buttons, instructions, dialogue, text drawn in images) is in another language, build an English version before publishing: keep the player-facing text in one table per language, start in English, and add a visible switch (like `EN | PL`) to the language the game was made in. Tell the user in a sentence that you did. Pass both with `--languages en,pl`.
63
+ - `title` and `description` are always in English. A title that is a name (`Kasztanek`) stays as it is; one made of words in another language gets translated (`Wielka Ucieczka` → `The Great Escape`). Tell the user the English title you chose.
64
+ - Text in the thumbnail (step 4) is in English too.
65
+
60
66
  ### 4. Add a thumbnail
61
67
 
62
68
  A `thumbnail.png` (or `.jpg`/`.webp`, up to 2 MB and 4096×4096 pixels, ideally the game's shape, like 1280×720 for 16:9) in the project folder becomes the game's tile.
63
69
 
64
- - **If you can run the game in a browser and take a screenshot**, make a deliberate one: get past any title or "click to start" screen to real gameplay, then save it as `thumbnail.png` and pass `--thumbnail thumbnail.png` to `init`.
70
+ - **If you can run the game in a browser and take a screenshot**, make a deliberate one, with the game in English: get past any title or "click to start" screen to real gameplay, then save it as `thumbnail.png` and pass `--thumbnail thumbnail.png` to `init`.
65
71
  - **Otherwise the CLI takes one itself.** When `juicy.json` names no thumbnail, `check` and `publish` open the built game in Chrome, Edge, Chromium or Brave on this machine (headless, at the game's `aspectRatio`, sandboxed and offline: only the game's own files load) and use a screenshot taken a few seconds after it loads. A game that loads its engine, fonts or images from another site is captured without them. Don't block publishing on a thumbnail.
66
72
  - **Not for a remix**, unless the user agrees: the screenshot runs the other creator's code. Ask first; only if they say yes, pass `--auto-thumbnail` to `check` and `publish`. Without it you get a warning starting `no thumbnail: this is a remix`.
67
73
 
@@ -13,11 +13,11 @@ The manifest in the project folder. `juicyjuicy init` writes it; edit it by hand
13
13
  "engine": "phaser",
14
14
  "madeWith": ["Claude Opus 5.5", "Claude Code"],
15
15
  "tags": ["arcade", "space"],
16
+ "languages": ["en", "pl"],
16
17
  "input": ["keyboard", "touch"],
17
18
  "orientation": "landscape",
18
19
  "aspectRatio": "16:9",
19
20
  "thumbnail": "thumbnail.png",
20
- "howItWasMade": "HOW_I_MADE_IT.md",
21
21
  "remixable": true,
22
22
  "sourceUrl": "https://github.com/someone/space-goose"
23
23
  }
@@ -33,11 +33,12 @@ The manifest in the project folder. `juicyjuicy init` writes it; edit it by hand
33
33
  | `engine` | | `vanilla`, `phaser`, `threejs`, `pixi`, `godot`, `unity` or `other`. | `--engine` |
34
34
  | `madeWith` | | Up to 5 models/tools, e.g. `["Claude Opus 5.5", "Claude Code"]`. | `--made-with "a, b"` |
35
35
  | `tags` | | Up to 5 lowercase words or `word-word`, e.g. `puzzle`, `tower-defense`. | `--tags a,b` |
36
+ | `languages` | | Up to 5 language codes a player can switch between, English first, e.g. `["en", "pl"]`. Default `["en"]`. Shown as a language filter on JuicyJuicy. | `--languages a,b` |
36
37
  | `input` | | Any of `keyboard`, `mouse`, `touch`, `gamepad`. | `--input a,b` |
37
38
  | `orientation` | | `landscape`, `portrait` or `any` (default). | `--orientation` |
38
39
  | `aspectRatio` | | `"W:H"` like `"16:9"` or `"4:3"`, or `"fill"` to fill the player. Default `16:9`. | `--aspect-ratio` |
39
40
  | `thumbnail` | | png/jpg/webp in the project folder (not the build folder), up to 2 MB and 4096×4096 pixels. Without one, `check` and `publish` screenshot the game in a local Chrome or Edge, offline (`--no-auto-thumbnail` turns that off; a remix only with `--auto-thumbnail`). | `--thumbnail` |
40
- | `howItWasMade` | | A `.md` file in the project folder, up to 20 KB, shown on the game page. | (detected: `HOW_I_MADE_IT.md`) |
41
+ | `howItWasMade` | | No longer used; `check` warns about it and `init` removes it. | |
41
42
  | `remixable` | | `true` grants the JuicyJuicy remix license: other members may remix the game on JuicyJuicy only (see SKILL.md, "Remix a game"). Default `false`. | `--remixable` |
42
43
  | `sourceUrl` | | Plain `https://` link to the source, e.g. a GitHub repo (no `?`, `#`, spaces or quotes; at most 300 characters). | `--source-url` |
43
44
  | `remixedFrom` | | Set by `juicyjuicy remix`; don't edit. | |
@@ -17,7 +17,7 @@ With `--json`, a failed command's last line is `{"ok": false, "error": {"code",
17
17
  | `INVALID_MANIFEST` | `juicy.json` is missing, isn't JSON, or a field breaks a rule (`details` says which). | No file: run `init`. Otherwise fix the listed fields (see manifest.md). |
18
18
  | `ENTRY_MISSING` | The build folder doesn't exist, or has no entry file. | Run the build. Check `buildDir` and `entry`. |
19
19
  | `INVALID_PATH` | A file name is unsafe (backslash, control character, too long, …). | Rename the file (POSIX names, under 256 characters). |
20
- | `TOO_LARGE` | A file is over 100 MB, the whole build over 150 MB, the thumbnail over 2 MB or 4096 pixels wide or high, or `HOW_I_MADE_IT.md` over 20 KB. Or the user's games together take up more than their 2 GB of storage (the message says "your games already take up"). | Compress or remove assets; resize the thumbnail. For storage: the user deletes a game they don't need on the site; only the newest 5 versions of each game are kept, and old ones are cleaned up daily. |
20
+ | `TOO_LARGE` | A file is over 100 MB, the whole build over 150 MB, or the thumbnail over 2 MB or 4096 pixels wide or high. Or the user's games together take up more than their 2 GB of storage (the message says "your games already take up"). | Compress or remove assets; resize the thumbnail. For storage: the user deletes a game they don't need on the site; only the newest 5 versions of each game are kept, and old ones are cleaned up daily. |
21
21
  | `TOO_MANY_FILES` | More than 3,000 files. | Bundle or pack assets (sprite sheets, atlases). |
22
22
  | `VALIDATION_FAILED` | Something else is malformed, e.g. a thumbnail that isn't png/jpg/webp or a file that's missing. | Follow the message. |
23
23
  | `SLUG_TAKEN` | Another creator owns this slug. | Choose a new slug: `init --slug <new-slug>`. |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "juicyjuicy",
3
- "version": "0.4.2",
3
+ "version": "0.5.1",
4
4
  "description": "Publish AI-made browser games to juicyjuicy.games",
5
5
  "type": "module",
6
6
  "license": "MIT",