juicyjuicy 0.5.0 → 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). */
@@ -20040,7 +20039,8 @@ var manifestSchema = external_exports.strictObject({
20040
20039
  (path2) => THUMBNAIL_EXTENSIONS.some((ext) => path2.toLowerCase().endsWith(`.${ext}`)),
20041
20040
  `thumbnail must be one of: ${THUMBNAIL_EXTENSIONS.join(", ")}`
20042
20041
  ).optional(),
20043
- 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 }),
20044
20044
  remixable: gameFieldSchemas.remixable.default(false),
20045
20045
  sourceUrl: gameFieldSchemas.sourceUrl.optional(),
20046
20046
  remixedFrom: slugSchema.nullable().optional()
@@ -20076,8 +20076,6 @@ var startVersionRequestSchema = external_exports.object({
20076
20076
  * when the game's current thumbnail was set on the dashboard. Older CLIs leave it out.
20077
20077
  */
20078
20078
  thumbnailAuto: external_exports.boolean().optional(),
20079
- /** Contents of the manifest's `howItWasMade` markdown file. */
20080
- howItWasMade: memberText().optional(),
20081
20079
  /** A note for the version history, e.g. what changed or a commit SHA. */
20082
20080
  message: memberText().max(200).optional(),
20083
20081
  source: external_exports.enum(PUBLISH_SOURCES).default("cli"),
@@ -20101,9 +20099,7 @@ var updateGameRequestSchema = external_exports.object({
20101
20099
  orientation: gameFieldSchemas.orientation.optional(),
20102
20100
  aspectRatio: gameFieldSchemas.aspectRatio.optional(),
20103
20101
  remixable: gameFieldSchemas.remixable.optional(),
20104
- sourceUrl: gameFieldSchemas.sourceUrl.nullable().optional(),
20105
- /** Markdown, ≤ 20 KB. */
20106
- howItWasMade: memberText().nullable().optional()
20102
+ sourceUrl: gameFieldSchemas.sourceUrl.nullable().optional()
20107
20103
  });
20108
20104
  var rollbackRequestSchema = external_exports.object({ version: external_exports.number().int().positive() });
20109
20105
  var voteRequestSchema = external_exports.object({
@@ -24371,7 +24367,7 @@ var program = new Command();
24371
24367
  // package.json
24372
24368
  var package_default = {
24373
24369
  name: "juicyjuicy",
24374
- version: "0.5.0",
24370
+ version: "0.5.1",
24375
24371
  description: "Publish AI-made browser games to juicyjuicy.games",
24376
24372
  type: "module",
24377
24373
  license: "MIT",
@@ -26110,6 +26106,7 @@ async function walkFiles(root) {
26110
26106
  await visit2(root);
26111
26107
  return result;
26112
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)';
26113
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`;
26114
26111
  function isInside(root, path2) {
26115
26112
  const rel = relative(root, path2);
@@ -26130,7 +26127,6 @@ async function checkProject(dir, options = {}) {
26130
26127
  files: [],
26131
26128
  totalBytes: 0,
26132
26129
  thumbnail: null,
26133
- howItWasMade: null,
26134
26130
  issues: [],
26135
26131
  warnings: [],
26136
26132
  findings: [],
@@ -26165,9 +26161,8 @@ async function checkProject(dir, options = {}) {
26165
26161
  }
26166
26162
  check3.files = plan.files;
26167
26163
  check3.totalBytes = plan.files.reduce((sum, file2) => sum + file2.size, 0);
26168
- const story = manifest.howItWasMade ? relative(buildDir, resolve(realDir, manifest.howItWasMade)).split(sep).join("/") : null;
26169
26164
  for (const { path: path2 } of plan.files) {
26170
- const reason = path2 === story ? null : unusualFileReason(path2);
26165
+ const reason = unusualFileReason(path2);
26171
26166
  if (reason) check3.unusualFiles.push({ path: path2, reason });
26172
26167
  }
26173
26168
  if (check3.unusualFiles.length > 0) {
@@ -26213,23 +26208,8 @@ async function checkProject(dir, options = {}) {
26213
26208
  } else {
26214
26209
  check3.warnings.push(NO_THUMBNAIL_WARNING);
26215
26210
  }
26216
- if (manifest.howItWasMade) {
26217
- const file2 = await projectFile(realDir, manifest.howItWasMade);
26218
- if (!file2) {
26219
- check3.issues.push({
26220
- code: "VALIDATION_FAILED",
26221
- message: "file not found in the project folder",
26222
- path: manifest.howItWasMade
26223
- });
26224
- } else if (file2.size > LIMITS.maxHowItWasMadeBytes) {
26225
- check3.issues.push({
26226
- code: "TOO_LARGE",
26227
- message: `${(file2.size / 1024).toFixed(1)} KB; at most ${LIMITS.maxHowItWasMadeBytes / 1024} KB`,
26228
- path: manifest.howItWasMade
26229
- });
26230
- } else {
26231
- check3.howItWasMade = { ...file2, text: await readFile2(file2.absolute, "utf8") };
26232
- }
26211
+ if (manifest.howItWasMade !== void 0) {
26212
+ check3.warnings.push(HOW_IT_WAS_MADE_WARNING);
26233
26213
  }
26234
26214
  const viteWarning = await viteBaseWarning(dir);
26235
26215
  if (viteWarning) check3.warnings.push(viteWarning);
@@ -26323,7 +26303,6 @@ async function detectProject(dir) {
26323
26303
  entry,
26324
26304
  engine: await detectEngine(dir, buildDir, deps, Boolean(pkg)),
26325
26305
  thumbnail: await firstExisting(dir, ["thumbnail.png", "thumbnail.jpg", "thumbnail.webp"]),
26326
- howItWasMade: await firstExisting(dir, ["HOW_I_MADE_IT.md"]),
26327
26306
  warnings
26328
26307
  };
26329
26308
  }
@@ -26361,7 +26340,6 @@ var KEY_ORDER = [
26361
26340
  "orientation",
26362
26341
  "aspectRatio",
26363
26342
  "thumbnail",
26364
- "howItWasMade",
26365
26343
  "remixable",
26366
26344
  "sourceUrl",
26367
26345
  "remixedFrom"
@@ -26385,7 +26363,7 @@ async function buildManifest(dir, flags, ask) {
26385
26363
  };
26386
26364
  const thumbnail = pick2("thumbnail", detected.thumbnail);
26387
26365
  if (thumbnail) values.thumbnail = thumbnail;
26388
- if (!values.howItWasMade && detected.howItWasMade) values.howItWasMade = detected.howItWasMade;
26366
+ delete values.howItWasMade;
26389
26367
  if (flags.sourceUrl) values.sourceUrl = flags.sourceUrl;
26390
26368
  const fieldSchema = manifestSchema.shape;
26391
26369
  const check3 = (field) => (value) => fieldSchema[field].safeParse(value).error?.issues[0]?.message;
@@ -26904,7 +26882,6 @@ async function check2(out, dir, options) {
26904
26882
  unusualFiles: result.unusualFiles,
26905
26883
  thumbnail: result.thumbnail?.path ?? null,
26906
26884
  thumbnailAuto: Boolean(result.thumbnail?.auto),
26907
- howItWasMade: result.howItWasMade?.path ?? null,
26908
26885
  warnings: result.warnings,
26909
26886
  findings: result.findings,
26910
26887
  scriptHosts: result.scriptHosts
@@ -27073,7 +27050,7 @@ async function publish(out, dir, options) {
27073
27050
  const server = apiUrl();
27074
27051
  const auth = await ensureLogin(out, server);
27075
27052
  const api = new ApiClient(server, auth.token);
27076
- const { thumbnail, howItWasMade } = checked;
27053
+ const { thumbnail } = checked;
27077
27054
  const request = {
27078
27055
  manifest: checked.rawManifest,
27079
27056
  files: await hashFiles(checked.buildDir, checked.files),
@@ -27084,7 +27061,6 @@ async function publish(out, dir, options) {
27084
27061
  } : void 0,
27085
27062
  // A screenshot doesn't replace a thumbnail uploaded on the dashboard (D34).
27086
27063
  ...thumbnail?.auto ? { thumbnailAuto: true } : {},
27087
- howItWasMade: howItWasMade?.text,
27088
27064
  message: options.message,
27089
27065
  source: options.source ?? (process.env.GITHUB_ACTIONS === "true" ? "github" : "cli"),
27090
27066
  ...options.draft ? { draft: true } : {}
@@ -54,7 +54,6 @@ npx -y juicyjuicy@0 init --yes --json \
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
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
- - 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.
58
57
 
59
58
  All fields: [reference/manifest.md](reference/manifest.md).
60
59
 
@@ -18,7 +18,6 @@ The manifest in the project folder. `juicyjuicy init` writes it; edit it by hand
18
18
  "orientation": "landscape",
19
19
  "aspectRatio": "16:9",
20
20
  "thumbnail": "thumbnail.png",
21
- "howItWasMade": "HOW_I_MADE_IT.md",
22
21
  "remixable": true,
23
22
  "sourceUrl": "https://github.com/someone/space-goose"
24
23
  }
@@ -39,7 +38,7 @@ The manifest in the project folder. `juicyjuicy init` writes it; edit it by hand
39
38
  | `orientation` | | `landscape`, `portrait` or `any` (default). | `--orientation` |
40
39
  | `aspectRatio` | | `"W:H"` like `"16:9"` or `"4:3"`, or `"fill"` to fill the player. Default `16:9`. | `--aspect-ratio` |
41
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` |
42
- | `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. | |
43
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` |
44
43
  | `sourceUrl` | | Plain `https://` link to the source, e.g. a GitHub repo (no `?`, `#`, spaces or quotes; at most 300 characters). | `--source-url` |
45
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.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "Publish AI-made browser games to juicyjuicy.games",
5
5
  "type": "module",
6
6
  "license": "MIT",