scenri 0.2.2 → 0.3.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/ASSETS-LICENSE.md +4 -4
- package/CHANGELOG.md +16 -0
- package/LICENSE +1 -1
- package/NOTICE +4 -4
- package/README.md +12 -12
- package/dist/{chunk-VE675PSG.js → chunk-GA7P7K2M.js} +2 -2
- package/dist/{cli-JVN6MY72.js → cli-GQLRYYGU.js} +4 -4
- package/dist/index.js +4 -4
- package/dist/{launcher-YT5KSSTN.js → launcher-RETYUGSR.js} +4 -4
- package/dist/serve.js +37 -12
- package/package.json +1 -1
- package/studio-dist/assets/index-BaASA7BS.js +102 -0
- package/studio-dist/favicon.svg +1 -1
- package/studio-dist/index.html +2 -2
- package/studio-dist/site.webmanifest +2 -2
- package/studio-dist/assets/index-CZX6N9rq.js +0 -102
package/ASSETS-LICENSE.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Scenri assets license
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Scenri's code is AGPL-3.0-only (see LICENSE). The imagery and curated content are
|
|
4
4
|
licensed under these terms instead.
|
|
5
5
|
|
|
6
6
|
This covers the starter content pack, everything under `templates/`, the library
|
|
7
|
-
content
|
|
7
|
+
content Scenri downloads at runtime, and the project's marketing imagery.
|
|
8
8
|
|
|
9
|
-
You may use this content freely within
|
|
9
|
+
You may use this content freely within Scenri, including for commercial work.
|
|
10
10
|
Everything you generate with it is yours.
|
|
11
11
|
|
|
12
12
|
You may not redistribute, rebundle, resell, or republish the content itself, and
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.3.0](https://github.com/tonygorb/scenri/compare/v0.2.3...v0.3.0) (2026-08-20)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* give every browser tab an intentional title ([e518396](https://github.com/tonygorb/scenri/commit/e5183961dae9f52ecd5801ae4c8cfce5fb397f3a))
|
|
9
|
+
* name the product Scenri across the interface, docs and CLI ([cce242b](https://github.com/tonygorb/scenri/commit/cce242be955520569fdffb170f14f91f752d1801))
|
|
10
|
+
|
|
11
|
+
## [0.2.3](https://github.com/tonygorb/scenri/compare/v0.2.2...v0.2.3) (2026-08-20)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
* **deps:** clear the esbuild advisory and a flaky e2e teardown ([97c6985](https://github.com/tonygorb/scenri/commit/97c6985dc7f6e92e3cac1eebd9e039201b12fc16))
|
|
17
|
+
* **deps:** clear the esbuild advisory, and stop the update fixture racing its own teardown ([5cb7bff](https://github.com/tonygorb/scenri/commit/5cb7bff083a92c929bc570b1d88b50747c3a3605))
|
|
18
|
+
|
|
3
19
|
## [0.2.2](https://github.com/tonygorb/scenri/compare/v0.2.1...v0.2.2) (2026-08-20)
|
|
4
20
|
|
|
5
21
|
|
package/LICENSE
CHANGED
|
@@ -629,7 +629,7 @@ to attach them to the start of each source file to most effectively
|
|
|
629
629
|
state the exclusion of warranty; and each file should have at least
|
|
630
630
|
the "copyright" line and a pointer to where the full notice is found.
|
|
631
631
|
|
|
632
|
-
|
|
632
|
+
Scenri - the open studio for brand-consistent AI visuals
|
|
633
633
|
Copyright (C) 2026 Tony Gorb
|
|
634
634
|
|
|
635
635
|
This program is free software: you can redistribute it and/or modify
|
package/NOTICE
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
Scenri
|
|
2
2
|
Copyright 2026 Tony Gorb
|
|
3
3
|
|
|
4
4
|
This product includes software and assets developed by third parties.
|
|
@@ -46,11 +46,11 @@ Phosphor Icons (`@phosphor-icons/react`), MIT, Copyright (c) 2023 Phosphor Icons
|
|
|
46
46
|
|
|
47
47
|
## Third-party marks
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
Scenri shows each generation provider's own mark beside its name, so that the
|
|
50
50
|
row asking for your key names the service you recognise rather than a generic
|
|
51
51
|
glyph. Every mark is reproduced unmodified, in a variant its owner publishes,
|
|
52
52
|
and is used referentially to identify which service a key or a sign-in belongs
|
|
53
|
-
to.
|
|
53
|
+
to. Scenri is not built, supported, certified, endorsed by, or affiliated with
|
|
54
54
|
any of them, and makes no such claim.
|
|
55
55
|
|
|
56
56
|
| Mark | File | Artwork source | Artwork licence |
|
|
@@ -63,7 +63,7 @@ Each mark sits on the plate its owner puts it on, in the colours its owner
|
|
|
63
63
|
publishes, sampled from that owner's own icon: OpenAI's 180px favicon (white
|
|
64
64
|
plate, black mark), OpenRouter's app icon (white plate, violet mark) and
|
|
65
65
|
Replicate's favicon (red plate, white mark). The pairs are recorded in `BRAND` in
|
|
66
|
-
`apps/studio/src/engines/providers.tsx` and are identical in both of
|
|
66
|
+
`apps/studio/src/engines/providers.tsx` and are identical in both of Scenri's
|
|
67
67
|
themes, because none of these owners publishes a dark variant and inventing one
|
|
68
68
|
would be redrawing their logo. No geometry is redrawn, distorted, recomposed,
|
|
69
69
|
recoloured or tinted, and no mark is ever separated from its own plate.
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
<picture>
|
|
4
4
|
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/tonygorb/scenri/main/docs/media/logo-on-dark.svg">
|
|
5
|
-
<img src="https://raw.githubusercontent.com/tonygorb/scenri/main/docs/media/logo-on-light.svg" alt="
|
|
5
|
+
<img src="https://raw.githubusercontent.com/tonygorb/scenri/main/docs/media/logo-on-light.svg" alt="Scenri" width="200">
|
|
6
6
|
</picture>
|
|
7
7
|
<br><br>
|
|
8
8
|
|
|
@@ -19,7 +19,7 @@ Define a client's brand once. Then generate, branch, and art-direct on-brand ima
|
|
|
19
19
|
npx scenri
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
<img src="https://raw.githubusercontent.com/tonygorb/scenri/main/docs/media/demo.gif" alt="The
|
|
22
|
+
<img src="https://raw.githubusercontent.com/tonygorb/scenri/main/docs/media/demo.gif" alt="The Scenri composer: a dollar sign opens a product picker and Selvedge Trucker is chosen, an at sign picks the presenter Maren, a slash picks the Editorial Walk scene, a line of written direction is typed after the three chips, the shot renders as a card in the wall, and it opens to show the picture beside the brief that made it" width="820">
|
|
23
23
|
|
|
24
24
|
<sub>Pick a product, pick a presenter, pick a scene, then write the direction. That is the brief.</sub>
|
|
25
25
|
|
|
@@ -29,7 +29,7 @@ npx scenri
|
|
|
29
29
|
|
|
30
30
|
## What it is
|
|
31
31
|
|
|
32
|
-
Most AI image tools give you a prompt box and a slot machine.
|
|
32
|
+
Most AI image tools give you a prompt box and a slot machine. Scenri gives you the part that actually takes the time: **art direction**.
|
|
33
33
|
|
|
34
34
|
Every shot keeps its lineage. Branch an edit from any shot, put the two side by side, and the drift heatmap shows you exactly where the model changed your product when it should not have.
|
|
35
35
|
|
|
@@ -47,7 +47,7 @@ All 97 examples on the home wall work the same way. Open one and it loads back i
|
|
|
47
47
|
|
|
48
48
|
## What you get out of the box
|
|
49
49
|
|
|
50
|
-
<img src="https://raw.githubusercontent.com/tonygorb/scenri/main/docs/media/library.gif" alt="A slow scroll down the
|
|
50
|
+
<img src="https://raw.githubusercontent.com/tonygorb/scenri/main/docs/media/library.gif" alt="A slow scroll down the Scenri home wall: rows of finished example shots across product categories, with the composer docked at the bottom of the screen" width="820">
|
|
51
51
|
|
|
52
52
|
A library of scenes, presenters and demo products, so the app is useful before you have uploaded anything of your own. Filter by category, bookmark what fits the brand, or build your own from a few reference photos.
|
|
53
53
|
|
|
@@ -61,7 +61,7 @@ npx scenri
|
|
|
61
61
|
|
|
62
62
|
That is the whole install. It opens `http://127.0.0.1:4747`.
|
|
63
63
|
|
|
64
|
-
Generation runs on **Codex CLI**, an official helper from OpenAI that draws on your own ChatGPT plan. No API key to paste, and
|
|
64
|
+
Generation runs on **Codex CLI**, an official helper from OpenAI that draws on your own ChatGPT plan. No API key to paste, and Scenri never charges you. Each image draws on your plan's Codex usage. You do not have to set it up by hand: if it is missing, Scenri offers to install it and to sign you in, both from the app. No ChatGPT plan? Add your own key from an image provider in Settings instead, see [Engines](#engines).
|
|
65
65
|
|
|
66
66
|
Requires **Node 22 or newer**. Two dependencies (`better-sqlite3` and `sharp`) ship native binaries, so on recent npm you may be asked to approve their install scripts once.
|
|
67
67
|
|
|
@@ -80,7 +80,7 @@ pnpm dev # starts the server on 127.0.0.1:4747
|
|
|
80
80
|
|
|
81
81
|
## First five minutes
|
|
82
82
|
|
|
83
|
-
1. **Paste a website URL.**
|
|
83
|
+
1. **Paste a website URL.** Scenri reads the public page and drafts the kit: name, palette, logo, tone.
|
|
84
84
|
2. **Describe a shot.** In the composer, `$` reaches for a product, `@` for a presenter, `/` for a scene, and `#` for a colour. Everything between them is your own words. The composer compiles a brief you can inspect before it runs.
|
|
85
85
|
3. **Generate on Codex CLI.** Runs on your own ChatGPT plan, so there is no key and no per-image charge from us.
|
|
86
86
|
4. **Branch an edit** from any shot, then hit compare. The heatmap shows what moved.
|
|
@@ -91,7 +91,7 @@ pnpm dev # starts the server on 127.0.0.1:4747
|
|
|
91
91
|
- **Iteration is the product.** A version tree, not a prompt box. Branch, compare, keep the winners.
|
|
92
92
|
- **Your brands are files, not hostages.** `.brand` is an open, documented format under a permissive license. Email one to a client. Any tool can adopt it.
|
|
93
93
|
- **Your AI, your cost.** Bring your own Codex CLI session or an API key. Experiments cost raw API price, or nothing at all on a local session. No credits that burn on a miss.
|
|
94
|
-
- **Local first, and it means it.** No account, no telemetry, no upload. The server binds to your machine only.
|
|
94
|
+
- **Local first, and it means it.** No account, no telemetry, no upload. The server binds to your machine only. Scenri makes exactly two requests on its own behalf: a daily version-number check against npm so updates can announce themselves, and a one-time download of the library imagery archive, cached locally forever after. Nothing about you or your work is ever sent, and both turn off: in Settings or `SCENRI_NO_UPDATE_CHECK=1` for the first, `SCENRI_NO_CONTENT_FETCH=1` for the second ([how updates work](docs/updates.md)).
|
|
95
95
|
|
|
96
96
|
## Engines
|
|
97
97
|
|
|
@@ -104,13 +104,13 @@ pnpm dev # starts the server on 127.0.0.1:4747
|
|
|
104
104
|
|
|
105
105
|
Codex CLI is the default because it needs no key and because it carries the most reference images: a shot that has to keep both a product and a person accurate needs the room.
|
|
106
106
|
|
|
107
|
-
It is not free. Every ChatGPT plan comes with some Codex usage and each image spends a little of it. OpenAI meters that, not
|
|
107
|
+
It is not free. Every ChatGPT plan comes with some Codex usage and each image spends a little of it. OpenAI meters that, not Scenri, so spend caps do not apply to this engine.
|
|
108
108
|
|
|
109
|
-
**Without a ChatGPT plan**, use your own provider key. OpenRouter is the one to pick if your shots name a Product or a Presenter. Replicate and fal take no reference images, so
|
|
109
|
+
**Without a ChatGPT plan**, use your own provider key. OpenRouter is the one to pick if your shots name a Product or a Presenter. Replicate and fal take no reference images, so Scenri refuses those briefs on them rather than generating something that only looks right.
|
|
110
110
|
|
|
111
111
|
Keys are stored in your local library folder, sent only to that provider, and never returned by the API. Set a monthly spend cap per engine in Settings.
|
|
112
112
|
|
|
113
|
-
Your Codex session is yours:
|
|
113
|
+
Your Codex session is yours: Scenri runs the official `codex` commands on your machine and never reads, copies or stores the credential. That is also why Scenri never pools user plans: a plan is licensed to the person who pays for it, not to a service reselling it to other people. Any hosted version of Scenri, if one ever exists, would run API-priced engines only.
|
|
114
114
|
|
|
115
115
|
## Configuration
|
|
116
116
|
|
|
@@ -127,7 +127,7 @@ Your Codex session is yours: scenri runs the official `codex` commands on your m
|
|
|
127
127
|
|
|
128
128
|
`OPENROUTER_API_KEY`, `REPLICATE_API_TOKEN` and `FAL_KEY` are read from the environment as an alternative to entering them in Settings.
|
|
129
129
|
|
|
130
|
-
**Before you change `SCENRI_HOST`:**
|
|
130
|
+
**Before you change `SCENRI_HOST`:** Scenri has no accounts, so anyone who can reach the port can spend your API keys and delete your library. Setting `SCENRI_HOST=0.0.0.0` opens it to your local network so you can use it from a phone. That path prints a URL carrying a one-time access token, refuses every request without it, and rejects unfamiliar `Host` headers. Treat it as convenience on a network you trust, not as a security boundary.
|
|
131
131
|
|
|
132
132
|
## Layout
|
|
133
133
|
|
|
@@ -158,7 +158,7 @@ Early. The version is `0.x` and interfaces can still move. Everything documented
|
|
|
158
158
|
|
|
159
159
|
The application is [AGPL-3.0-only](LICENSE). The `.brand` format, its schema, and its validator live in [packages/brand-spec](https://github.com/tonygorb/scenri/tree/main/packages/brand-spec) under Apache-2.0, so any tool may implement or reuse them without taking on copyleft; the npm package carries that license text as `LICENSE-APACHE-2.0-brand-spec`. Contributions require a [CLA](CLA.md).
|
|
160
160
|
|
|
161
|
-
The bundled imagery and curated content are licensed separately under [ASSETS-LICENSE.md](docs/ASSETS-LICENSE.md): free to use within
|
|
161
|
+
The bundled imagery and curated content are licensed separately under [ASSETS-LICENSE.md](docs/ASSETS-LICENSE.md): free to use within Scenri, commercial work included; no redistribution or rebundling. The npm package's `license` field describes the code; the starter imagery inside it stays under those asset terms.
|
|
162
162
|
|
|
163
163
|
The name and the mark are not part of the code license: [TRADEMARKS.md](TRADEMARKS.md) says what a fork may and may not call itself. What the app does and does not send anywhere is written down in [PRIVACY.md](PRIVACY.md).
|
|
164
164
|
|
|
@@ -202,5 +202,5 @@ async function stageVersion(deps) {
|
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
export { classify, createUpdateChecker, fetchDistTagLatest, findNpm, stageVersion };
|
|
205
|
-
//# sourceMappingURL=chunk-
|
|
206
|
-
//# sourceMappingURL=chunk-
|
|
205
|
+
//# sourceMappingURL=chunk-GA7P7K2M.js.map
|
|
206
|
+
//# sourceMappingURL=chunk-GA7P7K2M.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { stageVersion, fetchDistTagLatest, findNpm } from './chunk-
|
|
1
|
+
import { stageVersion, fetchDistTagLatest, findNpm } from './chunk-GA7P7K2M.js';
|
|
2
2
|
import { readMeta } from './chunk-Y3ZPBPLP.js';
|
|
3
3
|
import { defaultHome, newestStaged, compareSemver } from './chunk-4MAFHYAD.js';
|
|
4
4
|
|
|
@@ -34,7 +34,7 @@ async function runUpdateCommand(opts) {
|
|
|
34
34
|
const effective = staged && compareSemver(staged, meta.version) > 0 ? staged : meta.version;
|
|
35
35
|
console.log(` running ${meta.version}${staged ? ` \xB7 staged ${staged}` : ""} \xB7 latest ${latest}`);
|
|
36
36
|
if (compareSemver(latest, effective) <= 0) {
|
|
37
|
-
console.log(staged ? " the newest version is already staged. Just start
|
|
37
|
+
console.log(staged ? " the newest version is already staged. Just start Scenri." : " already the newest.");
|
|
38
38
|
return 0;
|
|
39
39
|
}
|
|
40
40
|
if (opts.check) {
|
|
@@ -62,5 +62,5 @@ async function runUpdateCommand(opts) {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
export { runUpdateCommand };
|
|
65
|
-
//# sourceMappingURL=cli-
|
|
66
|
-
//# sourceMappingURL=cli-
|
|
65
|
+
//# sourceMappingURL=cli-GQLRYYGU.js.map
|
|
66
|
+
//# sourceMappingURL=cli-GQLRYYGU.js.map
|
package/dist/index.js
CHANGED
|
@@ -23,10 +23,10 @@ function parseArgs(argv) {
|
|
|
23
23
|
return { cmd: "error", message: `unknown command '${first}' (try --help)` };
|
|
24
24
|
}
|
|
25
25
|
function helpText() {
|
|
26
|
-
return `
|
|
26
|
+
return `Scenri: local brand studio
|
|
27
27
|
|
|
28
28
|
Usage
|
|
29
|
-
scenri start
|
|
29
|
+
scenri start Scenri (auto-restarts after updates)
|
|
30
30
|
scenri serve start this exact build, no supervision
|
|
31
31
|
scenri update download and stage the newest version
|
|
32
32
|
--check only check, do not download
|
|
@@ -61,7 +61,7 @@ switch (command.cmd) {
|
|
|
61
61
|
await (await import('./serve.js')).serve();
|
|
62
62
|
break;
|
|
63
63
|
case "update": {
|
|
64
|
-
const { runUpdateCommand } = await import('./cli-
|
|
64
|
+
const { runUpdateCommand } = await import('./cli-GQLRYYGU.js');
|
|
65
65
|
process.exit(await runUpdateCommand(command));
|
|
66
66
|
break;
|
|
67
67
|
}
|
|
@@ -71,7 +71,7 @@ switch (command.cmd) {
|
|
|
71
71
|
await (await import('./serve.js')).serve();
|
|
72
72
|
break;
|
|
73
73
|
}
|
|
74
|
-
const { runLauncher } = await import('./launcher-
|
|
74
|
+
const { runLauncher } = await import('./launcher-RETYUGSR.js');
|
|
75
75
|
const { readMeta } = await import('./meta-MPQPBPBK.js');
|
|
76
76
|
const { defaultHome } = await import('./versionsDir-ILQ4CI7B.js');
|
|
77
77
|
const meta = readMeta();
|
|
@@ -31,7 +31,7 @@ async function runLauncher(deps) {
|
|
|
31
31
|
starts.push(startedAt);
|
|
32
32
|
while (starts.length > 0 && startedAt - starts[0] > LOOP_WINDOW_MS) starts.shift();
|
|
33
33
|
if (starts.length > LOOP_MAX_STARTS) {
|
|
34
|
-
log("
|
|
34
|
+
log(" Scenri is restarting in a loop and has stopped trying.");
|
|
35
35
|
log(" Recover with: rm -rf ~/.scenri/app (app versions only, your library is untouched)");
|
|
36
36
|
log(" then start fresh: npx scenri@latest");
|
|
37
37
|
return 1;
|
|
@@ -51,7 +51,7 @@ async function runLauncher(deps) {
|
|
|
51
51
|
if (signalled) return code ?? 0;
|
|
52
52
|
if (code === RESTART_EXIT_CODE) continue;
|
|
53
53
|
if (code !== 0 && useStaged && now() - startedAt < QUICK_DEATH_MS) {
|
|
54
|
-
log(`
|
|
54
|
+
log(` Scenri ${staged} failed to start. Falling back to ${deps.ownVersion}.`);
|
|
55
55
|
log(" If this keeps happening: rm -rf ~/.scenri/app");
|
|
56
56
|
distrustStaged = true;
|
|
57
57
|
continue;
|
|
@@ -61,5 +61,5 @@ async function runLauncher(deps) {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
export { LAUNCHER_PROTOCOL, RESTART_EXIT_CODE, runLauncher };
|
|
64
|
-
//# sourceMappingURL=launcher-
|
|
65
|
-
//# sourceMappingURL=launcher-
|
|
64
|
+
//# sourceMappingURL=launcher-RETYUGSR.js.map
|
|
65
|
+
//# sourceMappingURL=launcher-RETYUGSR.js.map
|
package/dist/serve.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createUpdateChecker, classify, stageVersion, findNpm } from './chunk-
|
|
1
|
+
import { createUpdateChecker, classify, stageVersion, findNpm } from './chunk-GA7P7K2M.js';
|
|
2
2
|
import { readMeta, repoSlug } from './chunk-Y3ZPBPLP.js';
|
|
3
3
|
import { newestStaged, compareSemver } from './chunk-4MAFHYAD.js';
|
|
4
4
|
import { networkInterfaces, homedir, tmpdir } from 'os';
|
|
@@ -297,7 +297,7 @@ var SCHEMA_VERSION = 1;
|
|
|
297
297
|
var SchemaTooNewError = class extends Error {
|
|
298
298
|
constructor(found, supported) {
|
|
299
299
|
super(
|
|
300
|
-
`This library was written by a newer
|
|
300
|
+
`This library was written by a newer Scenri (schema ${found}; this build understands ${supported}). Update and retry: npx scenri@latest`
|
|
301
301
|
);
|
|
302
302
|
this.name = "SchemaTooNewError";
|
|
303
303
|
}
|
|
@@ -2149,7 +2149,7 @@ function createCodexSetup(opts = {}) {
|
|
|
2149
2149
|
ok: false,
|
|
2150
2150
|
fallbackCommand: INSTALL_COMMAND,
|
|
2151
2151
|
docsUrl: INSTALL_DOCS_URL,
|
|
2152
|
-
detail: "Codex installed but is not on this app\u2019s PATH yet. Restart
|
|
2152
|
+
detail: "Codex installed but is not on this app\u2019s PATH yet. Restart Scenri, or install it yourself."
|
|
2153
2153
|
};
|
|
2154
2154
|
}
|
|
2155
2155
|
return { ok: true };
|
|
@@ -2308,7 +2308,7 @@ function createDemoEngine(saveImage) {
|
|
|
2308
2308
|
<rect width="100%" height="100%" fill="url(#g)"/>
|
|
2309
2309
|
<circle cx="${w * (0.25 + 0.5 * (seed * 37 % 100) / 100)}" cy="${h * 0.38}" r="${Math.min(w, h) * 0.18}" fill="#ffffff" opacity="0.25"/>
|
|
2310
2310
|
<text x="24" y="${h - 48}" font-family="Helvetica, Arial" font-size="${Math.max(14, Math.round(w / 42))}" fill="#ffffff" opacity="0.92">${esc(label)}</text>
|
|
2311
|
-
<text x="24" y="${h - 22}" font-family="Helvetica, Arial" font-size="12" fill="#ffffff" opacity="0.6">
|
|
2311
|
+
<text x="24" y="${h - 22}" font-family="Helvetica, Arial" font-size="12" fill="#ffffff" opacity="0.6">Scenri demo engine</text>
|
|
2312
2312
|
</svg>`;
|
|
2313
2313
|
return sharp5(Buffer.from(svg)).png().toBuffer();
|
|
2314
2314
|
}
|
|
@@ -2946,7 +2946,7 @@ function createContentFetcher(deps) {
|
|
|
2946
2946
|
const root = contentCacheRoot(env);
|
|
2947
2947
|
const staging = `${root}.staging`;
|
|
2948
2948
|
if (!deps.store.getSetting("content.disclosed")) {
|
|
2949
|
-
log(" fetching the
|
|
2949
|
+
log(" fetching the Scenri library (~95 MB, once, cached; set SCENRI_NO_CONTENT_FETCH=1 to disable)");
|
|
2950
2950
|
deps.store.setSetting("content.disclosed", "1");
|
|
2951
2951
|
}
|
|
2952
2952
|
try {
|
|
@@ -2982,7 +2982,7 @@ function createContentFetcher(deps) {
|
|
|
2982
2982
|
deps.store.setSetting("content.version", String(meta.version ?? ""));
|
|
2983
2983
|
} catch {
|
|
2984
2984
|
}
|
|
2985
|
-
log("
|
|
2985
|
+
log(" Scenri library ready");
|
|
2986
2986
|
return { ok: true, updated: true, error: null };
|
|
2987
2987
|
} catch (err) {
|
|
2988
2988
|
rmSync(staging, { recursive: true, force: true });
|
|
@@ -5900,11 +5900,11 @@ function registerAssetBuildRoutes(app, deps) {
|
|
|
5900
5900
|
engineId: engine?.capabilities().id ?? null,
|
|
5901
5901
|
engineName: engine?.capabilities().displayName ?? null,
|
|
5902
5902
|
/**
|
|
5903
|
-
* True when
|
|
5903
|
+
* True when Scenri cannot price this per image, because it is not billed
|
|
5904
5904
|
* through a key we hold. NOT the same as costing the user nothing: the
|
|
5905
5905
|
* local Codex engine spends the Codex allowance on their ChatGPT plan,
|
|
5906
5906
|
* which only OpenAI can meter. Copy built on this flag must say "nothing
|
|
5907
|
-
* billed through
|
|
5907
|
+
* billed through Scenri", never "free".
|
|
5908
5908
|
*/
|
|
5909
5909
|
free: engine ? await engine.costEstimate(COST_PROBE).catch(() => 0) <= 0 : true
|
|
5910
5910
|
};
|
|
@@ -6514,6 +6514,31 @@ function registerImageRoutes(app, deps) {
|
|
|
6514
6514
|
|
|
6515
6515
|
// src/release/notes.data.ts
|
|
6516
6516
|
var RELEASES = [
|
|
6517
|
+
{
|
|
6518
|
+
version: "0.3.0",
|
|
6519
|
+
date: "2026-08-20",
|
|
6520
|
+
title: "The name is Scenri.",
|
|
6521
|
+
sections: [
|
|
6522
|
+
{
|
|
6523
|
+
heading: "The name",
|
|
6524
|
+
body: "Written out, the product is Scenri. Every screen, every page of the documentation and every line the terminal prints now spells it that way. Lowercase stays where a machine reads it: the command you type, the folder your library lives in, and the settings that configure it are all unchanged."
|
|
6525
|
+
},
|
|
6526
|
+
{
|
|
6527
|
+
heading: "Browser tabs",
|
|
6528
|
+
body: "A tab now names what is open in it rather than the section it came from, so eight products in eight tabs read as eight product names. Settings and What's new say so, an open shot says Shot, and a tab whose page is still loading names its section instead of going blank."
|
|
6529
|
+
}
|
|
6530
|
+
]
|
|
6531
|
+
},
|
|
6532
|
+
{
|
|
6533
|
+
version: "0.2.3",
|
|
6534
|
+
date: "2026-08-20",
|
|
6535
|
+
sections: [
|
|
6536
|
+
{
|
|
6537
|
+
heading: "Security",
|
|
6538
|
+
body: "The last advisory against a build dependency is closed. Nothing about how scenri runs changes, and nothing in the published package moves."
|
|
6539
|
+
}
|
|
6540
|
+
]
|
|
6541
|
+
},
|
|
6517
6542
|
{
|
|
6518
6543
|
version: "0.2.2",
|
|
6519
6544
|
date: "2026-08-20",
|
|
@@ -6690,7 +6715,7 @@ function registerUpdateRoutes(app, deps) {
|
|
|
6690
6715
|
const apply = effectiveApply();
|
|
6691
6716
|
if (apply.phase !== "ready") return reply.status(409).send({ error: "no staged update to restart into" });
|
|
6692
6717
|
if (!runtime.supervised) {
|
|
6693
|
-
return reply.status(409).send({ error: "not supervised; restart
|
|
6718
|
+
return reply.status(409).send({ error: "not supervised; restart Scenri yourself", blockReason: "unsupervised" });
|
|
6694
6719
|
}
|
|
6695
6720
|
reply.send({ ok: true });
|
|
6696
6721
|
const exit = deps.exitImpl ?? ((code) => process.exit(code));
|
|
@@ -7495,7 +7520,7 @@ async function run() {
|
|
|
7495
7520
|
if (info.name === readMeta().name) {
|
|
7496
7521
|
const url = `http://127.0.0.1:${PORT}`;
|
|
7497
7522
|
console.log(`
|
|
7498
|
-
|
|
7523
|
+
Scenri is already running \u2192 ${url}
|
|
7499
7524
|
`);
|
|
7500
7525
|
if (process.env.SCENRI_NO_OPEN !== "1") {
|
|
7501
7526
|
try {
|
|
@@ -7517,7 +7542,7 @@ async function run() {
|
|
|
7517
7542
|
if (closing) return;
|
|
7518
7543
|
closing = true;
|
|
7519
7544
|
console.log(`
|
|
7520
|
-
${signal}: closing
|
|
7545
|
+
${signal}: closing Scenri\u2026`);
|
|
7521
7546
|
setTimeout(() => process.exit(1), 5e3).unref();
|
|
7522
7547
|
app.drain().then(() => process.exit(0)).catch(() => process.exit(1));
|
|
7523
7548
|
};
|
|
@@ -7528,7 +7553,7 @@ async function run() {
|
|
|
7528
7553
|
const query = token ? `/?t=${token}` : "";
|
|
7529
7554
|
const localUrl = `http://127.0.0.1:${PORT}${query}`;
|
|
7530
7555
|
console.log(`
|
|
7531
|
-
|
|
7556
|
+
Scenri Studio \u2192 ${localUrl}`);
|
|
7532
7557
|
for (const ip of reachableAt) console.log(` on your network \u2192 http://${ip}:${PORT}${query}`);
|
|
7533
7558
|
console.log(` data dir \u2192 ${core.home}
|
|
7534
7559
|
`);
|