@open-assets/open-assets 0.4.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/README.md +150 -25
- package/bin/open-assets.mjs +2 -3
- package/lib/init.mjs +1 -1
- package/lib/lockfile.mjs +6 -3
- package/lib/manifest.mjs +5 -17
- package/lib/render.mjs +333 -176
- package/lib/renderer.mjs +251 -88
- package/lib/server.mjs +20 -12
- package/package.json +3 -3
- package/public/img/banner/1280.png +0 -0
- package/public/img/examples/tax-days-icon.png +0 -0
- package/public/img/examples/tax-days.png +0 -0
- package/public/img/examples/thoughtful-icon.png +0 -0
- package/public/img/examples/thoughtful.png +0 -0
- package/skills/open-assets/SKILL.md +48 -36
- package/public/img/banner/1280/banner.png +0 -0
package/README.md
CHANGED
|
@@ -1,20 +1,40 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="public/img/banner/1280
|
|
2
|
+
<img src="public/img/banner/1280.png" alt="Open Assets" width="100%" />
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
# Open Assets
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
[](https://www.npmjs.com/package/@open-assets/open-assets)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
[](#2-design-with-claude-code)
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
**Screenshots, icons, and marketing assets, made a breeze in your git repo.**
|
|
10
12
|
|
|
11
|
-
Design
|
|
13
|
+
Design App Store screenshots, app icons, logos, OG images, and favicons as HTML/CSS/SVG templates. Preview them live in the browser. Render every size your stores need from a single template with one command, then export the results anywhere: your exports folder, your web app's public directory, or straight into an Xcode asset catalog.
|
|
14
|
+
|
|
15
|
+
Like Storybook, but for marketing assets. Free, local, MIT licensed, and built for AI coding agents.
|
|
16
|
+
|
|
17
|
+
## Why Open Assets
|
|
18
|
+
|
|
19
|
+
- **One template, every size.** Author a screenshot once at its source size and render it for iPhone 6.9", 6.7", iPad, Play Store, Product Hunt, and any custom dimension. No per-device rework.
|
|
20
|
+
- **Export to multiple locations.** Each export size can write to its own destination with `outFile`: drop `favicon.png` into `public/`, send the OG image to your web app, and write the app icon directly into your Xcode `.appiconset`.
|
|
21
|
+
- **Localization built in.** One template renders in every language. Mustache-style `{{placeholders}}`, locale-aware number formatting, and automatic RTL layout for Arabic, Hebrew, and friends. See [Localization](#localization).
|
|
22
|
+
- **Live preview dev server.** A Storybook-style UI with hot reload, zoom/pan, and one-click exports while you iterate on templates.
|
|
23
|
+
- **Incremental renders.** `assets.lock` checksums every source file, so you, your teammates, and CI only re-render what changed.
|
|
24
|
+
- **Versioned in git, rendered in CI.** No SaaS, no per-seat design tool. Review screenshot changes in a PR with `git diff`, re-render on every push with GitHub Actions.
|
|
25
|
+
- **Agent native.** Ships a Claude Code skill (`npx open-assets skills`), so your agent can design, localize, and render the entire asset set for you.
|
|
12
26
|
|
|
13
27
|
## Examples
|
|
14
28
|
|
|
15
|
-
<p><img src="public/img/examples/
|
|
29
|
+
<p><img src="public/img/examples/tax-days-icon.png" width="14" height="14" /> <a href="https://apps.apple.com/us/app/tax-days-residency-tracker/id6761441335"><strong>Tax Days</strong></a> (<a href="examples/tax-days">examples</a>)</p>
|
|
30
|
+
<img src="public/img/examples/tax-days.png" alt="Tax Days screenshots" width="100%" />
|
|
31
|
+
|
|
32
|
+
<p><img src="public/img/examples/only-recipes-icon.png" width="14" height="14" /> <a href="https://apps.apple.com/us/app/only-recipes-recipe-keeper/id1553858589"><strong>Only Recipes</strong></a> (<a href="examples/only-recipes">examples</a>)</p>
|
|
16
33
|
<img src="public/img/examples/only-recipes.png" alt="Only Recipes screenshots" width="100%" />
|
|
17
34
|
|
|
35
|
+
<p><img src="public/img/examples/thoughtful-icon.png" width="14" height="14" /> <a href="https://apps.apple.com/us/app/thoughtful-grow-relationships/id6762098726"><strong>Thoughtful</strong></a> (<a href="examples/thoughtful">examples</a>)</p>
|
|
36
|
+
<img src="public/img/examples/thoughtful.png" alt="Thoughtful screenshots" width="100%" />
|
|
37
|
+
|
|
18
38
|
<p><img src="public/img/examples/cat-iq-test-icon.png" width="14" height="14" /> <a href="https://apps.apple.com/us/app/cat-iq-test/id6759520249"><strong>Cat IQ Test</strong></a> (<a href="examples/cat-iq-test">examples</a>)</p>
|
|
19
39
|
<img src="public/img/examples/cat-iq-test.png" alt="Cat IQ Test screenshots" width="100%" />
|
|
20
40
|
|
|
@@ -59,7 +79,7 @@ Then use `oa` anywhere:
|
|
|
59
79
|
|
|
60
80
|
```bash
|
|
61
81
|
oa dev
|
|
62
|
-
oa render
|
|
82
|
+
oa render
|
|
63
83
|
oa init
|
|
64
84
|
```
|
|
65
85
|
|
|
@@ -75,6 +95,26 @@ open-assets uses a simple, unified data model. Every asset type follows the same
|
|
|
75
95
|
| **Source Size** | The dimensions the HTML template is authored at. Puppeteer scales from source → export size. |
|
|
76
96
|
| **Output** | An optional post-render action (e.g., write to Xcode `.appiconset`, copy SVG source). |
|
|
77
97
|
|
|
98
|
+
### One template, many sizes, many destinations
|
|
99
|
+
|
|
100
|
+
Every entry in a collection's `export` array is either a size or an output action. A single template renders to all of them in one pass:
|
|
101
|
+
|
|
102
|
+
```json
|
|
103
|
+
"export": [
|
|
104
|
+
{ "name": "iphone-6.9", "label": "iPhone 6.9\"", "size": { "width": 1320, "height": 2868 } },
|
|
105
|
+
{ "name": "iphone-6.7", "label": "iPhone 6.7\"", "size": { "width": 1290, "height": 2796 } },
|
|
106
|
+
{ "name": "favicon", "size": { "width": 32, "height": 32 }, "outFile": "public/favicon.png" },
|
|
107
|
+
{ "type": "xcode", "path": "../MyApp/Assets.xcassets/AppIcon.appiconset" }
|
|
108
|
+
]
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
- Sized entries land in `exports/{collection}/{size}/{template}.png`
|
|
112
|
+
- `outFile` sends a rendered size anywhere in your repo (`.png` or `.jpg`), like your web app's `public/` directory
|
|
113
|
+
- `xcode` fills an Xcode `.appiconset` directly
|
|
114
|
+
- `copy-source` copies SVG sources alongside the rendered PNGs
|
|
115
|
+
|
|
116
|
+
Change the template once, run `npx open-assets render`, and every destination updates. Unchanged templates are skipped automatically.
|
|
117
|
+
|
|
78
118
|
## End-to-End Screenshot Pipeline
|
|
79
119
|
|
|
80
120
|
### 1. Initialize
|
|
@@ -87,7 +127,16 @@ Creates a `assets.json`, sample HTML templates, and a `public/` directory for sh
|
|
|
87
127
|
|
|
88
128
|
### 2. Design with Claude Code
|
|
89
129
|
|
|
90
|
-
|
|
130
|
+
The easiest way to get the skill is the Claude Code plugin marketplace. Inside Claude Code, run:
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
/plugin marketplace add Parra-Inc/open-assets
|
|
134
|
+
/plugin install open-assets@open-assets
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The skill is installed once, works in every project, and updates with `/plugin marketplace update open-assets`.
|
|
138
|
+
|
|
139
|
+
Alternatively, copy the skill into a single project:
|
|
91
140
|
|
|
92
141
|
```bash
|
|
93
142
|
# Using the built-in command
|
|
@@ -123,10 +172,10 @@ Opens a live preview UI at `http://localhost:3200` with zoom/pan controls and ex
|
|
|
123
172
|
### 4. Export
|
|
124
173
|
|
|
125
174
|
```bash
|
|
126
|
-
npx open-assets render
|
|
175
|
+
npx open-assets render
|
|
127
176
|
```
|
|
128
177
|
|
|
129
|
-
Exports every template at every configured export size into `./exports/`, organized as `exports/{collection}/{size}/{template}.png`.
|
|
178
|
+
Exports every template at every configured export size into `./exports/`, skipping anything that hasn't changed, organized as `exports/{collection}/{size}/{template}.png`.
|
|
130
179
|
|
|
131
180
|
### 5. Upload to App Store Connect / Google Play
|
|
132
181
|
|
|
@@ -141,6 +190,7 @@ Capture real app screenshots via Playwright or XCTest, then use them inside your
|
|
|
141
190
|
npx playwright test --project=screenshots
|
|
142
191
|
|
|
143
192
|
# 2. Export marketing screenshots with those captures embedded
|
|
193
|
+
# (--force because captured images aren't checksummed by the cache)
|
|
144
194
|
npx open-assets render --force
|
|
145
195
|
```
|
|
146
196
|
|
|
@@ -152,10 +202,60 @@ Reference captured screenshots in your HTML templates:
|
|
|
152
202
|
The `assets.json` `command` field stores the export command so automation tools know what to run:
|
|
153
203
|
```json
|
|
154
204
|
{
|
|
155
|
-
"command": "npx open-assets render
|
|
205
|
+
"command": "npx open-assets render"
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Localization
|
|
210
|
+
|
|
211
|
+
Ship screenshots in every language you support, from the same templates. Add a localizations file (an iOS `.xcstrings`-inspired format), reference keys in templates with `{{key}}`, and every template renders once per locale:
|
|
212
|
+
|
|
213
|
+
```json
|
|
214
|
+
{
|
|
215
|
+
"sourceLanguage": "en",
|
|
216
|
+
"strings": {
|
|
217
|
+
"hero_title": {
|
|
218
|
+
"localizations": {
|
|
219
|
+
"en": { "value": "Track your tax days" },
|
|
220
|
+
"de": { "value": "Verfolge deine Steuertage" },
|
|
221
|
+
"ja": { "value": "税金の日を追跡する" },
|
|
222
|
+
"ar": { "value": "تتبع أيام الضرائب الخاصة بك" }
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Wire it to a collection in `assets.json`:
|
|
230
|
+
|
|
231
|
+
```json
|
|
232
|
+
{
|
|
233
|
+
"id": "screenshots",
|
|
234
|
+
"localizations": "localizations.json",
|
|
235
|
+
"locales": ["en", "de", "ja", "ar"]
|
|
156
236
|
}
|
|
157
237
|
```
|
|
158
238
|
|
|
239
|
+
Then use the keys in any template:
|
|
240
|
+
|
|
241
|
+
```html
|
|
242
|
+
<h1>{{hero_title}}</h1>
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
What you get:
|
|
246
|
+
|
|
247
|
+
- **Per-locale exports**: output paths become `exports/{collection}/{locale}/{size}/{template}.png`, ready for App Store Connect's per-language screenshot slots
|
|
248
|
+
- **RTL support**: right-to-left locales (Arabic, Hebrew, Persian, Urdu) automatically render with `dir="rtl"` set on the document
|
|
249
|
+
- **Locale-aware numbers**: `{{n:1234}}` renders as `1,234` in English and `1.234` in German via `Intl.NumberFormat`
|
|
250
|
+
- **Fallback chain**: exact locale (`es-419`), then base language (`es`), then the source language
|
|
251
|
+
|
|
252
|
+
Render all locales, or just one:
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
npx open-assets render --collection screenshots # every locale
|
|
256
|
+
npx open-assets render --collection screenshots --locale ja # just Japanese
|
|
257
|
+
```
|
|
258
|
+
|
|
159
259
|
## CLI Commands
|
|
160
260
|
|
|
161
261
|
### `open-assets dev [dir]`
|
|
@@ -191,8 +291,8 @@ Options:
|
|
|
191
291
|
Render assets headlessly via the command line, without opening a browser.
|
|
192
292
|
|
|
193
293
|
```bash
|
|
194
|
-
open-assets render # Render
|
|
195
|
-
open-assets render --force #
|
|
294
|
+
open-assets render # Render everything at every export size
|
|
295
|
+
open-assets render --force # Re-render everything, ignoring the cache
|
|
196
296
|
open-assets render --collection screenshots # Render a specific collection
|
|
197
297
|
open-assets render --template 01-hero # Render a single template
|
|
198
298
|
open-assets render --size iphone-6.9 # Use a named export size
|
|
@@ -206,28 +306,41 @@ Options:
|
|
|
206
306
|
| Flag | Env Var | Default | Description |
|
|
207
307
|
|------|---------|---------|-------------|
|
|
208
308
|
| `--collection <id>` | — | all | Render only the collection with this ID |
|
|
309
|
+
| `--tag <tag>` | — | all | Render only collections with this tag |
|
|
209
310
|
| `--template <name>` | — | all | Render only the template with this name |
|
|
210
311
|
| `--size <name>` | — | — | Use a named export size from config |
|
|
312
|
+
| `--locale <code>` | — | all | Render only this locale (e.g. `en`, `ar`, `ja`) |
|
|
211
313
|
| `--width <px>` | — | — | Custom output width |
|
|
212
314
|
| `--height <px>` | — | — | Custom output height |
|
|
213
|
-
| `-f, --force` | — | — |
|
|
315
|
+
| `-f, --force` | — | — | Re-render everything, ignoring the incremental cache |
|
|
214
316
|
| `-o, --output <dir>` | `OPEN_ASSETS_OUTPUT` | `./exports` | Output directory |
|
|
215
317
|
| `--config <path>` | `OPEN_ASSETS_CONFIG` | `assets.json` | Path to config file |
|
|
216
|
-
| `--parallel <count>` | `OPEN_ASSETS_PARALLEL` | `1` | Number of parallel renders |
|
|
217
318
|
| `--render-timeout <ms>` | `OPEN_ASSETS_RENDER_TIMEOUT` | `30000` | Puppeteer render timeout |
|
|
319
|
+
| — | `OPEN_ASSETS_CONCURRENCY` | auto | Templates rendered at once (see below) |
|
|
218
320
|
| `--json` | — | — | Output results as JSON |
|
|
219
321
|
| `-q, --quiet` | `OPEN_ASSETS_QUIET` | `false` | Suppress progress logs |
|
|
220
322
|
|
|
221
|
-
**
|
|
323
|
+
**Concurrency**: each template is loaded once per locale and screenshotted at
|
|
324
|
+
every export size from that single page load. A couple of templates render at a
|
|
325
|
+
time, which is where the throughput ceiling sits: Chromium serializes the
|
|
326
|
+
capture path, so extra workers queue behind each other instead of adding speed.
|
|
327
|
+
The default is `min(cores - 1, 2)`. Raise `OPEN_ASSETS_CONCURRENCY` only if your
|
|
328
|
+
templates are unusually slow to lay out relative to how long they take to
|
|
329
|
+
capture, and measure before keeping the change.
|
|
330
|
+
|
|
331
|
+
**Selective export**: flags compose naturally:
|
|
222
332
|
```bash
|
|
223
333
|
# Single template at a single device size
|
|
224
334
|
open-assets render --collection screenshots --template 01-hero --size iphone-6.9
|
|
225
335
|
|
|
226
336
|
# One template at all device sizes
|
|
227
|
-
open-assets render --collection screenshots --template 01-hero
|
|
337
|
+
open-assets render --collection screenshots --template 01-hero
|
|
228
338
|
|
|
229
339
|
# All templates at one device size
|
|
230
340
|
open-assets render --collection screenshots --size iphone-6.9
|
|
341
|
+
|
|
342
|
+
# All templates in one language
|
|
343
|
+
open-assets render --collection screenshots --locale ja
|
|
231
344
|
```
|
|
232
345
|
|
|
233
346
|
**Output structure**: `exports/{collection}/{size}/{template}.png`
|
|
@@ -272,7 +385,7 @@ open-assets validate # Check current directory
|
|
|
272
385
|
open-assets validate ./assets # Check specific directory
|
|
273
386
|
```
|
|
274
387
|
|
|
275
|
-
Returns exit code 1 if any errors are found
|
|
388
|
+
Returns exit code 1 if any errors are found, useful in CI pipelines.
|
|
276
389
|
|
|
277
390
|
### `open-assets skills [dir]`
|
|
278
391
|
|
|
@@ -286,6 +399,13 @@ open-assets skills ./my-app # Install to a specific project
|
|
|
286
399
|
npx skills add https://github.com/Parra-Inc/open-assets --skill open-assets
|
|
287
400
|
```
|
|
288
401
|
|
|
402
|
+
Prefer a global, per-user install? Use the Claude Code plugin marketplace instead: the skill then works in every project without copying files:
|
|
403
|
+
|
|
404
|
+
```
|
|
405
|
+
/plugin marketplace add Parra-Inc/open-assets
|
|
406
|
+
/plugin install open-assets@open-assets
|
|
407
|
+
```
|
|
408
|
+
|
|
289
409
|
### `open-assets init [dir]`
|
|
290
410
|
|
|
291
411
|
Scaffold a new project with a `assets.json`, sample HTML templates, and a `public/` directory.
|
|
@@ -304,7 +424,7 @@ Your project needs a `assets.json` at its root. This file defines the collection
|
|
|
304
424
|
"version": 1,
|
|
305
425
|
"name": "My App",
|
|
306
426
|
"publicDir": "public",
|
|
307
|
-
"command": "npx open-assets render
|
|
427
|
+
"command": "npx open-assets render",
|
|
308
428
|
"collections": [ ... ]
|
|
309
429
|
}
|
|
310
430
|
```
|
|
@@ -317,6 +437,7 @@ Your project needs a `assets.json` at its root. This file defines the collection
|
|
|
317
437
|
| `name` | string | yes | App display name |
|
|
318
438
|
| `publicDir` | string | no | Directory for shared assets (auto-served by dev server) |
|
|
319
439
|
| `command` | string | no | Export command for automation tools and CI |
|
|
440
|
+
| `tags` | array | no | Tag definitions (`{ id, label }`) for grouping collections |
|
|
320
441
|
| `collections` | array | yes | Asset collection definitions |
|
|
321
442
|
|
|
322
443
|
### Collection Schema (Unified)
|
|
@@ -345,8 +466,11 @@ All collections follow the same structure. No `type` field needed.
|
|
|
345
466
|
|-------|------|-------------|
|
|
346
467
|
| `id` | string | Unique collection identifier (used in CLI `--collection`) |
|
|
347
468
|
| `label` | string | Display name in the collection selector |
|
|
348
|
-
| `
|
|
469
|
+
| `tags` | array | Tag ids applied to this collection (filter renders with `--tag`) |
|
|
470
|
+
| `sourceSize` | object | `{ width, height }`: the dimensions templates are authored at |
|
|
349
471
|
| `borderRadius` | number | Border radius for preview frames (px) |
|
|
472
|
+
| `localizations` | string | Path to a localizations JSON file (see [Localization](#localization)) |
|
|
473
|
+
| `locales` | array | Optional locale filter. Omit to render every locale in the localizations file |
|
|
350
474
|
| `templates` | array | Source files to render |
|
|
351
475
|
| `templates[].src` | string | Path to HTML/SVG file (relative to project root) |
|
|
352
476
|
| `templates[].name` | string | Filename for exports (used by `--template` flag) |
|
|
@@ -354,14 +478,14 @@ All collections follow the same structure. No `type` field needed.
|
|
|
354
478
|
| `export` | array | Array of export sizes and output actions |
|
|
355
479
|
| `export[].name` | string | Size identifier (used by `--size` flag) |
|
|
356
480
|
| `export[].label` | string | Display label |
|
|
357
|
-
| `export[].size` | object | `{ width, height }
|
|
481
|
+
| `export[].size` | object | `{ width, height }`: output dimensions in pixels |
|
|
358
482
|
| `export[].outFile` | string | Optional output path for this size (supports .png, .jpg) |
|
|
359
483
|
| `export[].type` | string | Output action type (`xcode`, `copy-source`). Entries with `type` are post-render actions, not sizes |
|
|
360
484
|
| `customExport` | object | Optional `{ defaultWidth, defaultHeight }` for custom size UI |
|
|
361
485
|
|
|
362
486
|
### Output Types
|
|
363
487
|
|
|
364
|
-
Export entries with a `type` field are post-render actions
|
|
488
|
+
Export entries with a `type` field are post-render actions that run after every render:
|
|
365
489
|
|
|
366
490
|
| Type | Config | Description |
|
|
367
491
|
|------|--------|-------------|
|
|
@@ -487,7 +611,7 @@ Export entries with a `type` field are post-render actions (run with `--force`):
|
|
|
487
611
|
The `render` command maintains a `assets.lock` file that stores SHA256 checksums of each source HTML/SVG file. On subsequent renders, unchanged assets are skipped automatically:
|
|
488
612
|
|
|
489
613
|
```
|
|
490
|
-
$ open-assets render
|
|
614
|
+
$ open-assets render
|
|
491
615
|
Skipping 01-hero at 1320x2868 (unchanged)
|
|
492
616
|
Rendering 03-new-screen at 1320x2868...
|
|
493
617
|
→ exports/screenshots/iphone-6.9/03-new-screen.png
|
|
@@ -497,7 +621,7 @@ Done. 1 asset(s) rendered, 1 skipped (unchanged) in 1.2s.
|
|
|
497
621
|
|
|
498
622
|
Use `--force` to re-render everything regardless of the cache.
|
|
499
623
|
|
|
500
|
-
**Limitation**: Only source HTML/SVG files are checksummed. Changes to referenced assets (images in `publicDir`, compiled Tailwind CSS) won't trigger re-renders
|
|
624
|
+
**Limitation**: Only source HTML/SVG files are checksummed. Changes to referenced assets (images in `publicDir`, compiled Tailwind CSS) won't trigger re-renders, so use `--force` when those change.
|
|
501
625
|
|
|
502
626
|
Commit `assets.lock` to your repository so teammates and CI benefit from the cache.
|
|
503
627
|
|
|
@@ -522,7 +646,7 @@ jobs:
|
|
|
522
646
|
node-version: 20
|
|
523
647
|
- run: npm ci
|
|
524
648
|
- run: npx open-assets validate
|
|
525
|
-
- run: npx open-assets render --
|
|
649
|
+
- run: npx open-assets render --json --quiet
|
|
526
650
|
- uses: actions/upload-artifact@v4
|
|
527
651
|
with:
|
|
528
652
|
name: screenshots
|
|
@@ -550,6 +674,7 @@ jobs:
|
|
|
550
674
|
project/
|
|
551
675
|
assets.json
|
|
552
676
|
assets.lock # Auto-generated cache (commit this)
|
|
677
|
+
localizations.json # Localized strings (optional)
|
|
553
678
|
public/ # Shared assets (configured via publicDir)
|
|
554
679
|
logo-round.png
|
|
555
680
|
social/
|
|
@@ -570,7 +695,7 @@ project/
|
|
|
570
695
|
default.html
|
|
571
696
|
dist/
|
|
572
697
|
styles.css # Compiled Tailwind
|
|
573
|
-
exports/ # Rendered output (
|
|
698
|
+
exports/ # Rendered output (commit this)
|
|
574
699
|
screenshots/
|
|
575
700
|
iphone-6.9/
|
|
576
701
|
01-hero.png
|
package/bin/open-assets.mjs
CHANGED
|
@@ -92,10 +92,9 @@ program
|
|
|
92
92
|
.option("--locale <code>", "Render only this locale (e.g. en, ar, ja)")
|
|
93
93
|
.option("--width <px>", "Output width in pixels (custom size)")
|
|
94
94
|
.option("--height <px>", "Output height in pixels (custom size)")
|
|
95
|
-
.option("-f, --force", "
|
|
95
|
+
.option("-f, --force", "Re-render all assets, ignoring the incremental cache")
|
|
96
96
|
.option("-o, --output <dir>", "Output directory (env: OPEN_ASSETS_OUTPUT)", env("OPEN_ASSETS_OUTPUT", "./exports"))
|
|
97
97
|
.option("--config <path>", "Path to config file (env: OPEN_ASSETS_CONFIG)", env("OPEN_ASSETS_CONFIG", "assets.json"))
|
|
98
|
-
.option("--parallel <count>", "Number of parallel renders (env: OPEN_ASSETS_PARALLEL)", env("OPEN_ASSETS_PARALLEL", "1"))
|
|
99
98
|
.option("--render-timeout <ms>", "Puppeteer render timeout in ms", env("OPEN_ASSETS_RENDER_TIMEOUT", "30000"))
|
|
100
99
|
.option("--json", "Output results as JSON (for CI/scripting)")
|
|
101
100
|
.option("-q, --quiet", "Suppress progress logs", env("OPEN_ASSETS_QUIET") === "true")
|
|
@@ -116,7 +115,7 @@ program
|
|
|
116
115
|
|
|
117
116
|
const log = opts.quiet ? undefined : (msg) => console.log(msg);
|
|
118
117
|
const deps = {
|
|
119
|
-
|
|
118
|
+
renderVariants: renderer.renderVariants,
|
|
120
119
|
runXcodeOutput: renderer.runXcodeOutput,
|
|
121
120
|
closeBrowser: renderer.closeBrowser,
|
|
122
121
|
readLockfile: lockfile.readLockfile,
|
package/lib/init.mjs
CHANGED
package/lib/lockfile.mjs
CHANGED
|
@@ -91,14 +91,17 @@ export function computeChecksum(filePath) {
|
|
|
91
91
|
|
|
92
92
|
/**
|
|
93
93
|
* Check if an asset variant is up-to-date based on its stored checksums.
|
|
94
|
-
* Returns true if
|
|
94
|
+
* Returns true if the source and export config checksums match, the entry was
|
|
95
|
+
* recorded for the same output path, and the output file exists.
|
|
96
|
+
* @param {string} [projectDir] - Base directory for resolving relative output paths
|
|
95
97
|
*/
|
|
96
|
-
export function isUpToDate(lockData, assetKey, variantKey, currentChecksum, outputPath, exportChecksum) {
|
|
98
|
+
export function isUpToDate(lockData, assetKey, variantKey, currentChecksum, outputPath, exportChecksum, projectDir = ".") {
|
|
97
99
|
const entry = lockData.assets?.[assetKey]?.[variantKey];
|
|
98
100
|
if (!entry) return false;
|
|
99
101
|
if (entry.sourceChecksum !== currentChecksum) return false;
|
|
100
102
|
if (exportChecksum && entry.exportChecksum !== exportChecksum) return false;
|
|
101
|
-
if (
|
|
103
|
+
if (entry.outputPath !== outputPath) return false;
|
|
104
|
+
if (!existsSync(resolve(projectDir, outputPath))) return false;
|
|
102
105
|
return true;
|
|
103
106
|
}
|
|
104
107
|
|
package/lib/manifest.mjs
CHANGED
|
@@ -83,14 +83,13 @@ export function filterTemplates(templates, templateName) {
|
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
85
|
* Determine which sizes to render for a collection given CLI options.
|
|
86
|
+
* By default every configured export size is rendered; --width/--height or
|
|
87
|
+
* --size narrow the selection.
|
|
86
88
|
* @param {object} collection - The collection from the config
|
|
87
|
-
* @param {{ width?: string|number, height?: string|number, size?: string,
|
|
89
|
+
* @param {{ width?: string|number, height?: string|number, size?: string, platform?: string }} opts
|
|
88
90
|
* @returns {{ sizes: object[], warning?: string }}
|
|
89
91
|
*/
|
|
90
92
|
export function resolveRenderSizes(collection, opts = {}) {
|
|
91
|
-
const sourceW = collection.sourceSize.width;
|
|
92
|
-
const sourceH = collection.sourceSize.height;
|
|
93
|
-
|
|
94
93
|
if (opts.width && opts.height) {
|
|
95
94
|
const w = typeof opts.width === "number" ? opts.width : parseInt(opts.width);
|
|
96
95
|
const h = typeof opts.height === "number" ? opts.height : parseInt(opts.height);
|
|
@@ -116,17 +115,6 @@ export function resolveRenderSizes(collection, opts = {}) {
|
|
|
116
115
|
};
|
|
117
116
|
}
|
|
118
117
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
return { sizes };
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Default: render at source size
|
|
125
|
-
return {
|
|
126
|
-
sizes: [{
|
|
127
|
-
name: `${sourceW}x${sourceH}`,
|
|
128
|
-
label: `${sourceW}x${sourceH}`,
|
|
129
|
-
size: { width: sourceW, height: sourceH },
|
|
130
|
-
}],
|
|
131
|
-
};
|
|
118
|
+
// Default: render at every configured export size
|
|
119
|
+
return { sizes: flatSizes(collection) };
|
|
132
120
|
}
|