# Prepare artwork and metadata

Node.js 20+ is sufficient; this helper has no dependencies. Without a repository checkout, download [prepare.mjs](../scripts/prepare.mjs) from the published skill and run it from your download directory:

```sh
node prepare.mjs --input /absolute/path/artwork --output /absolute/path/new-prepared-folder --name "Garden Friends" --symbol "GARDEN"
```

From the repository root, the same helper is available at:

```sh
node scripts/collections/prepare.mjs --input /absolute/path/artwork --output /absolute/path/new-prepared-folder --name "Garden Friends" --symbol "GARDEN" --description "A small illustrated garden."
```

The output must be a new folder outside the input. Original files are never changed. Folders are read recursively. Supported containers are PNG, JPEG, WebP and GIF; SVG is rejected because it can contain active content. Convert SVG to a raster format in a trusted tool if needed, retaining the originals. The helper checks container structure, not full pixel decoding: inspect rendered previews before publishing. Do not bypass an invalid-image error by renaming an extension.

Files receive a stable natural sort (`1.png`, `2.png`, `10.png`) by relative path. Token IDs start at 1. Source names must be unique, including across subfolders and case differences. Rename conflicts descriptively in a working copy. Symlinks, traversal paths and unsupported files are rejected with the offending path. Finder's `.DS_Store` is ignored. Limits are 1,000 images, 32 MiB per image and 128 MiB total.

Output:

- `images/1.png` (or the normalized original raster extension): exact source bytes.
- `metadata/1.json`: a standard NFT object with name, description and relative image path.
- `manifest.json`: **local artwork preparation schema v1**, with source mapping, supply and image SHA-256 hashes. It contains no protocol commitment, CID, launch authorization or shuffled assignment.

Default names are `Garden Friends #1`, etc. No traits are fabricated. To preserve supplied metadata, add `--metadata /absolute/path/json-folder`. JSON names match image stems (`fern.json` for `fern.png`) or full filenames (`fern.png.json`). Matching is exact. Use full filenames if stems are ambiguous. Unmatched and duplicate JSON basenames fail. Existing names, descriptions, attributes and other JSON fields are retained; `image` is replaced with the normalized local path. Existing `animation_url` or `external_url` must use HTTPS, IPFS or Arweave.

For an integration, import the pure synchronous Node helper:

```js
import {prepareCollectionFiles} from './scripts/collections/prepare.mjs';
const result = prepareCollectionFiles([
  {path: 'fern.png', bytes: imageBytes, type: 'image/png'}
], {name: 'Garden Friends', symbol: 'GARDEN', description: 'A small garden.'});
```

Each file takes `path` (or `name`) and `bytes: Uint8Array` or canonical `base64`. Fields also accept `traits` as a shared attribute array, and `metadata` as an object keyed by source filename or stem. Existing per-image attributes take precedence over shared traits. `result.items` contains `tokenId`, `sourcePath`, `imagePath`, `imageType`, `imageSha256`, `imageBytes`, `metadataPath` and `metadata`. `result.manifest` is serializable and omits image bytes. Validation throws `CollectionInputError` with `errors: [{path, message}]`.

Relative image paths are for local review only. For a real launch, publish exact images, replace each metadata `image` with its final canonical IPFS reference, publish that final JSON, and retain both exact artifacts. Merely assigning an `ipfs://` string does not publish content. Hosting and protocol preparation belong to the launch workflow.
