@homie-rocks/studio 0.51.4 → 0.51.5
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/CHANGELOG.md +29 -0
- package/README.md +10 -29
- package/apps/APPS.md +1 -1
- package/bin/homie-studio.mjs +28 -30
- package/guides/app/SKILL.md +1 -1
- package/guides/art/SKILL.md +68 -140
- package/guides/art/scripts/art.mjs +6 -79
- package/guides/models/SKILL.md +73 -177
- package/guides/models/references/RIGHTS.md +1 -1
- package/guides/models/scripts/models.mjs +7 -288
- package/guides/music/SKILL.md +74 -183
- package/guides/music/references/COMPOSITION.md +21 -26
- package/guides/music/references/GAME-AUDIO.md +3 -3
- package/guides/music/references/RIGHTS.md +12 -15
- package/guides/music/scripts/music.mjs +11 -202
- package/guides/parts/SKILL.md +1 -1
- package/guides/shop/SKILL.md +68 -77
- package/guides/sound/SKILL.md +70 -1
- package/guides/sound/scripts/player/sound.js +233 -0
- package/guides/studio-setup/SKILL.md +11 -27
- package/guides/studio-setup/references/OFFICIAL-MEDIA.md +66 -0
- package/guides/style/SKILL.md +66 -3
- package/guides/video/SKILL.md +83 -0
- package/guides/video/references/DELIVERY.md +73 -0
- package/guides/video/references/HONESTY.md +40 -0
- package/guides/video/references/METHOD.md +144 -0
- package/guides/video/references/RECORD.md +137 -0
- package/guides/video/references/TRAILER.md +154 -0
- package/guides/video/references/examples/site-walkthrough.json +14 -0
- package/guides/video/references/examples/studio-play-phone.json +15 -0
- package/guides/video/references/examples/studio-play.json +17 -0
- package/guides/video/scripts/capture-game.mjs +175 -0
- package/guides/video/scripts/clock.js +136 -0
- package/guides/video/scripts/drawover/film.js +58 -0
- package/guides/video/scripts/drawover/index.html +9 -0
- package/guides/video/scripts/drawover/look.js +115 -0
- package/guides/video/scripts/drawover/shots.json +12 -0
- package/guides/video/scripts/lib/browser.mjs +87 -0
- package/guides/video/scripts/lib/frames.mjs +170 -0
- package/guides/video/scripts/lib/remix.mjs +159 -0
- package/guides/video/scripts/qa.mjs +127 -0
- package/guides/video/scripts/record-fixed.mjs +403 -0
- package/guides/video/scripts/record-page.mjs +477 -0
- package/guides/video/scripts/tap.js +108 -0
- package/guides/video/scripts/video.mjs +888 -0
- package/lib/build.mjs +12 -9
- package/lib/cloudflare.mjs +6 -11
- package/lib/dev.mjs +1 -2
- package/lib/doctor.mjs +10 -54
- package/lib/mcp-tools.mjs +42 -21
- package/lib/mcp.mjs +1 -1
- package/lib/media-import.mjs +41 -0
- package/lib/media-workflows.mjs +13 -0
- package/lib/official-media.mjs +15 -0
- package/lib/rules-build.mjs +13 -5
- package/lib/scaffold.mjs +2 -2
- package/lib/shop-links.mjs +54 -18
- package/lib/shop-listen.mjs +43 -0
- package/lib/shop-local.mjs +1 -1
- package/lib/shop-mcp.mjs +58 -0
- package/lib/stripe-connect.mjs +36 -15
- package/lib/template-history.json +45 -0
- package/lib/upgrade-media.mjs +13 -0
- package/lib/upgrade.mjs +10 -0
- package/package.json +1 -1
- package/parts/PARTS.md +1 -1
- package/rules/view.ts +4 -0
- package/shop/SHOP.md +66 -34
- package/worker/build-id.mjs +1 -1
- package/worker/index.mjs +5 -1
- package/worker/purchase-reconciliation.mjs +16 -1
- package/worker/shop-subscriptions.mjs +2 -0
- package/worker/shop.mjs +7 -5
- package/worker/stripe-ownership.mjs +7 -0
- package/worker/version.mjs +1 -1
- package/guides/models/references/models.json +0 -175
- package/guides/music/scripts/lib/eleven.mjs +0 -260
- package/lib/projects-env.mjs +0 -68
- package/lib/projects.mjs +0 -311
- package/lib/provider-key.mjs +0 -21
package/shop/SHOP.md
CHANGED
|
@@ -101,26 +101,68 @@ One order stores every line and its item snapshot. `/api/shop/mine` lists the li
|
|
|
101
101
|
|
|
102
102
|
`homie-studio shop init --supporter` writes an example item and `SELLING.md`, without a policy, cap or refund
|
|
103
103
|
window. `shop check` validates settings; the build uses the same validation.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
`
|
|
123
|
-
|
|
104
|
+
## Default: Stripe's official plugin
|
|
105
|
+
|
|
106
|
+
Use Stripe's official plugin, authenticated with its browser OAuth approval, for Products,
|
|
107
|
+
Prices, Payment Links, menu links, per-slot booking links, monthly giving and the customer
|
|
108
|
+
portal. Install with `stripe agent setup` if needed; the MCP URL is
|
|
109
|
+
`https://mcp.stripe.com`. Current tools are `stripe_api_search`, `stripe_api_details`,
|
|
110
|
+
`stripe_api_read` and `stripe_api_write`. Discover the operation and its schema before
|
|
111
|
+
calling it; tool argument shapes can change. See https://docs.stripe.com/mcp.
|
|
112
|
+
|
|
113
|
+
1. Create/check `shop.json`. Read the app's published slot records and supply the complete
|
|
114
|
+
slot manifest described below. Select the owner's account and sandbox in Stripe's plugin;
|
|
115
|
+
read `/v1/account` to record its account ID. Live mode only after the owner requests it.
|
|
116
|
+
2. Call Homie's `stripe_shop_plan` with `account`, `mode: "test"`, `slots` and
|
|
117
|
+
`observations: []`. CLI equivalent: `homie-studio shop plan --have plan-input.json`.
|
|
118
|
+
That JSON file contains the same fields. A returned `next` is the exact operation:
|
|
119
|
+
method, API path, parameters, API version and (for creates) idempotency key. Updates set desired fields; read before retrying. Metadata
|
|
120
|
+
scopes objects to this studio and origin; prices and links have content revisions.
|
|
121
|
+
3. Perform each `next` through Stripe's official MCP. For GET, append
|
|
122
|
+
`{ "path": "…", "params": {…}, "body": <Stripe response> }` to `observations`
|
|
123
|
+
and plan again. Follow every pagination request. After a write, discard observations
|
|
124
|
+
and read fresh. Replanning resolves real Stripe IDs; never invent IDs or substitute
|
|
125
|
+
a different price. Reuse the supplied idempotency key where the tool supports it;
|
|
126
|
+
otherwise read before retrying and match the stable product ID/revision metadata.
|
|
127
|
+
4. When no writes remain, use fresh reads with `stripe_shop_plan` `verify: true`
|
|
128
|
+
(CLI `homie-studio shop verify --have plan-input.json`). It checks the catalog,
|
|
129
|
+
actual link fields and line items, menus, slot limits and portal settings against
|
|
130
|
+
shop.json and the slot manifest. A mismatch blocks verification. It saves only public
|
|
131
|
+
configuration to `.studio/stripe-mcp.json`; local test configuration goes to `.dev.vars`.
|
|
132
|
+
5. For a deployed HTTPS studio, run `stripe_webhook` (CLI `homie-studio shop webhook`).
|
|
133
|
+
Follow `studio_job`. This uses Stripe CLI only for private webhook installation,
|
|
134
|
+
checks the same account as the MCP, and installs the signing secret and verified
|
|
135
|
+
links through Wrangler stdin. The CLI needs one separate browser approval if its
|
|
136
|
+
studio profile is not already connected. MCP approval cannot be reused or exported.
|
|
137
|
+
Cloudflare authorization and an existing deployment are prerequisites.
|
|
138
|
+
6. After installation, perform the returned `retire` operations through Stripe MCP to
|
|
139
|
+
archive replaced catalog objects, then verify fresh reads again. Test a sandbox
|
|
140
|
+
purchase and its signed event, order grant, booking capacity or recurring invoice;
|
|
141
|
+
a browser return is never proof. Stripe CLI `trigger` can send a test event, and
|
|
142
|
+
`events resend <event> --webhook-endpoint <endpoint>` retries a delivery. Check the
|
|
143
|
+
endpoint's delivery result and the app's verified records. Do not type a card into
|
|
144
|
+
a page for an automated proof; use Stripe's documented test PaymentMethods/fixtures.
|
|
145
|
+
|
|
146
|
+
Never create a webhook through model-visible Stripe MCP: its response exposes the signing secret.
|
|
147
|
+
|
|
148
|
+
The owner never handles an API key or signing secret. No Homie backend handles payments.
|
|
149
|
+
The Worker needs only public link configuration and the signing secret; buyers pay
|
|
150
|
+
Stripe directly even when the AI and the owner's computer are offline. The old
|
|
151
|
+
`stripe_login` / `shop connect` flow remains an alternative that syncs everything
|
|
152
|
+
through Stripe CLI browser approval. `--renew` renews that approval; `--live` requires
|
|
153
|
+
the owner's go-live request. Never read CLI config or print login-completion output.
|
|
154
|
+
|
|
155
|
+
For local checkout, pass `url: "http://localhost:8787"` (or the private Wi-Fi address)
|
|
156
|
+
and `mode: "test"` to the same plan/verify flow; the official plugin makes the links.
|
|
157
|
+
Run `homie-studio shop listen --profile <sandbox-profile>` in a background terminal.
|
|
158
|
+
Stripe CLI is required for forwarding; one browser approval is enough if needed.
|
|
159
|
+
The command captures and saves the listener secret privately. Start/restart
|
|
160
|
+
`homie-studio dev --lan` once it reports ready and keep the listener running.
|
|
161
|
+
Never copy the listener's raw output into the conversation.
|
|
162
|
+
|
|
163
|
+
For a faster local iteration, `homie-studio build --quick` skips generated rules play
|
|
164
|
+
and the snapshot smoke-run, while retaining compilation, guards and type checks.
|
|
165
|
+
Run a full build before release; quick output is not evidence that play checks passed.
|
|
124
166
|
|
|
125
167
|
At purchase time, the Worker saves an opaque order reference and sends it as the link's
|
|
126
168
|
`client_reference_id`. The buyer confirms quantity or tip amount on Stripe. A signed snapshot
|
|
@@ -142,17 +184,7 @@ items; failed refunds restore the financial booking. A lost dispute revokes good
|
|
|
142
184
|
| Managed Payments | Payment Links support managed_payments.enabled; connect uses it when the studio selects Stripe as seller, subject to Stripe eligibility and terms. |
|
|
143
185
|
| Currency display | Payment Links always enable Stripe Adaptive Pricing. Bookkeeping uses integration currency; presentment details describe what the customer saw. |
|
|
144
186
|
|
|
145
|
-
|
|
146
|
-
The explicit `shop connect --manual` path remains available, including `--live`, but requires the
|
|
147
|
-
owner's existing Dashboard key step; it does not satisfy one approval. Never choose it automatically.
|
|
148
|
-
Running default connect again saves links, removes the API key, and keeps signed-event fulfillment.
|
|
149
|
-
When switching to spending restrictions, the AI must deactivate previously issued Payment Links through
|
|
150
|
-
the approved CLI and resolve in-flight checkouts before relying on those restrictions; switching credentials
|
|
151
|
-
does not cancel old Stripe sessions. The runtime OAuth finding and sources are in `docs/stripe-connect-research.md` in the source checkout.
|
|
152
|
-
|
|
153
|
-
`shop`, `shop orders`, and `/_studio/office/shop` show readiness and sales. Stripe's optional MCP
|
|
154
|
-
is useful for owner-requested refunds and analytics; honor its approval links. Do not create a
|
|
155
|
-
secret-returning webhook through a conversation tool: the private connect process owns that call.
|
|
187
|
+
`shop`, `shop orders`, and `/_studio/office/shop` show readiness and sales. Use Stripe's official MCP for owner-requested refunds and analytics; honor its approval links.
|
|
156
188
|
|
|
157
189
|
## Payment guarantees and schema
|
|
158
190
|
|
|
@@ -220,7 +252,7 @@ For referrals, use Stripe Connect to split payments or a Stripe-based affiliate
|
|
|
220
252
|
|
|
221
253
|
## Keyless menus, paid seats and monthly giving (0.51.0)
|
|
222
254
|
|
|
223
|
-
Use
|
|
255
|
+
Use the official MCP plan/verify flow by default. All objects belong to the owner's Stripe account and
|
|
224
256
|
are created through its approved CLI session. Homie has no platform key, OAuth
|
|
225
257
|
backend, payment intermediary or cut. A desktop is needed to sync, not to take money.
|
|
226
258
|
|
|
@@ -251,7 +283,7 @@ data goes in that reference. A return URL is never proof of payment.
|
|
|
251
283
|
collection with integer `capacity` and a server-managed `bookings` collection with
|
|
252
284
|
`"booking":{"slots":"slots","item":"full-tune"}`. Publish slot records, then have
|
|
253
285
|
the owner's AI write the complete manifest to `.studio/booking-slots.json` and run
|
|
254
|
-
`
|
|
286
|
+
`stripe_shop_plan` with the same `slots` array (the CLI alternative is `stripe_bookings_sync`):
|
|
255
287
|
|
|
256
288
|
```json
|
|
257
289
|
[{"app":"tune","collection":"bookings","slots":"slots","slot":"sat-0900","item":"full-tune","capacity":1}]
|
|
@@ -303,7 +335,7 @@ Signed `subscription.started`, `.renewed`, `.failed`, `.cancelled` events drive
|
|
|
303
335
|
membership and giving. Membership access ends at the paid invoice line's period end;
|
|
304
336
|
failed invoices cannot extend it and cancellation ends access. Unknown Prices grant
|
|
305
337
|
nothing. Keyless portal configuration supports cancellation, payment-method updates
|
|
306
|
-
and invoice history.
|
|
338
|
+
and invoice history. The official MCP plan enables `login_page.enabled` through Stripe’s API
|
|
307
339
|
and stores Stripe's no-code login URL; **no Dashboard toggle is required**. Givers
|
|
308
340
|
verify their email with Stripe to manage/cancel. The buyer-owned `/api/shop/portal`
|
|
309
341
|
returns this URL. Plan changes require deliberate portal configuration and fulfilment
|
package/worker/build-id.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated by lib/build-identity.mjs; identifies the bundled runtime sources.
|
|
2
|
-
export const STUDIO_BUILD = Object.freeze({"version":"0.51.
|
|
2
|
+
export const STUDIO_BUILD = Object.freeze({"version":"0.51.5","sha256":"1e11f3b33959ff475ed31b5e5e0b5b4e7a155be104d47db80901422409830b23"});
|
package/worker/index.mjs
CHANGED
|
@@ -189,7 +189,11 @@ async function availableShellShop(env, cat, game, options) {
|
|
|
189
189
|
// The shell can show a disabled catalog before payment setup is complete.
|
|
190
190
|
// Checkout readiness is enforced by the shop API, separately from visibility.
|
|
191
191
|
const preview = (cat.games ?? []).find(g => g.id === game)?.screen?.shopPreview === true;
|
|
192
|
-
|
|
192
|
+
const shop = shopOf(cat);
|
|
193
|
+
// Free services must retain their bridge in a mixed free/paid catalogue.
|
|
194
|
+
// Paid readiness, policy and atomic booking capacity remain API decisions.
|
|
195
|
+
const free = shop?.open && !shop.broken && shop.items.some(i => i.price === 0 && !i.interval && (!i.game || i.game === game));
|
|
196
|
+
return (preview && !shop?.broken || free || await sellingShop(env, cat)) ? shellShop(cat, game, options) : null;
|
|
193
197
|
}
|
|
194
198
|
|
|
195
199
|
async function postsOf(env, origin) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { stripeEventOwner } from './stripe-ownership.mjs';
|
|
1
2
|
import { hasStripeKey, shopMode, rememberMoneyEvent, rememberedMoney } from './shop-links.mjs';
|
|
2
3
|
import { paymentRefunds } from './shop-refunds.mjs';
|
|
3
4
|
import { orderFact, bindHostedSession } from './purchase-core.mjs';
|
|
@@ -303,11 +304,25 @@ export async function reconcileOrder(env, o) {
|
|
|
303
304
|
|
|
304
305
|
/** Called only AFTER the existing shop webhook signature/mode check. Return null for player orders. */
|
|
305
306
|
export async function purchasePaymentEvent(env, event) {
|
|
307
|
+
const obj = event.data?.object ?? {};
|
|
308
|
+
const owner = stripeEventOwner(obj);
|
|
309
|
+
if (owner === 'shop') return null;
|
|
310
|
+
// Stripe can omit metadata on lifecycle events; an established shop subscription
|
|
311
|
+
// still belongs to the shop. Explicit ownership takes precedence over ID lookup.
|
|
312
|
+
if (!owner && (event.type.startsWith('invoice.') || event.type.startsWith('customer.subscription.'))) {
|
|
313
|
+
const subscription = event.type.startsWith('customer.subscription.') ? obj.id : idOf(obj.parent?.subscription_details?.subscription ?? obj.subscription);
|
|
314
|
+
if (subscription) {
|
|
315
|
+
try {
|
|
316
|
+
if (await env.DB.prepare('SELECT 1 FROM shop_subscriptions WHERE id = ?1').bind(subscription).first()) return null;
|
|
317
|
+
} catch (error) {
|
|
318
|
+
if (!/no such table: (?:main\.)?shop_subscriptions\b/.test(String(error?.message))) throw error;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
306
322
|
// An existing player shop may receive webhooks before purchase migrations run.
|
|
307
323
|
try { await env.DB.prepare("SELECT 1 FROM purchase_orders LIMIT 0").first(); }
|
|
308
324
|
catch (error) { if (/no such table/.test(error.message)) return null; throw error; }
|
|
309
325
|
|
|
310
|
-
const obj = event.data?.object ?? {};
|
|
311
326
|
if (!event.type.startsWith('checkout.session.')) await rememberMoneyEvent(env,event);
|
|
312
327
|
if (obj.payment_link && obj.metadata?.homie === 'purchase-links-v1') return reconcileLinkSession(env,obj);
|
|
313
328
|
if (!hasStripeKey(env) && event.type.startsWith('customer.subscription.')) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { stripeEventOwner } from './stripe-ownership.mjs';
|
|
1
2
|
import { linkConfig, hasStripeKey } from './shop-links.mjs';
|
|
2
3
|
import { KEY_SHAPE, stripeCall } from './stripe.mjs';
|
|
3
4
|
/** Only verified shop Checkout sessions establish ownership. Provider customer IDs
|
|
@@ -48,6 +49,7 @@ export async function bindSubscription(env, order, session, shop) {
|
|
|
48
49
|
export async function subscriptionEvent(env, event, shop) {
|
|
49
50
|
if (!['invoice.paid','invoice.payment_failed','customer.subscription.updated','customer.subscription.deleted'].includes(event.type)) return null;
|
|
50
51
|
const obj=event.data.object;
|
|
52
|
+
if (stripeEventOwner(obj) === 'parts') return null;
|
|
51
53
|
const subscription=event.type.startsWith('customer.subscription.') ? obj.id : idOf(obj.parent?.subscription_details?.subscription ?? obj.subscription);
|
|
52
54
|
if (!subscription) return 'ignored';
|
|
53
55
|
let row;
|
package/worker/shop.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { stripeEventOwner } from './stripe-ownership.mjs';
|
|
1
2
|
import { localSession } from './local-test.mjs';
|
|
2
3
|
import { bindSubscription, subscriptionEvent, subscriptionPortal } from './shop-subscriptions.mjs';
|
|
3
4
|
import { bookingStatement } from './booking-store.mjs';
|
|
@@ -162,10 +163,10 @@ export const MISSING_WORDS = Object.freeze({
|
|
|
162
163
|
'shop.json-refused': 'shop.json conflicts with the studio settings or payment requirements (homie-studio shop check says which), so nothing is sold.',
|
|
163
164
|
'till-off': 'shop.json says "till": "off".',
|
|
164
165
|
items: 'shop.json has no items.',
|
|
165
|
-
'payment-links': '
|
|
166
|
-
'fuller-checkout': '
|
|
167
|
-
'stripe-key': '
|
|
168
|
-
'webhook-secret': '
|
|
166
|
+
'payment-links': 'Ask your AI to plan and verify this shop through Stripe’s official plugin, then install its private webhook (homie-studio shop plan, shop verify, shop webhook).',
|
|
167
|
+
'fuller-checkout': 'These spending allowance, expiry or recurring amount settings are not supported by Payment Links. Ask your AI to review them with you before setup.',
|
|
168
|
+
'stripe-key': 'This older checkout connection is unavailable. Ask your AI to set up Payment Links through Stripe’s official plugin.',
|
|
169
|
+
'webhook-secret': 'Ask your AI to run homie-studio shop webhook after verifying the Stripe plugin setup; it installs the signing secret privately.',
|
|
169
170
|
database: 'This Worker has no database.',
|
|
170
171
|
migration: 'The shop\'s tables are not in the studio\'s D1 yet: npm run deploy applies migrations 0008_studio_shop.sql, 0010_shop_reservations.sql and 0012_shop_lines.sql.',
|
|
171
172
|
});
|
|
@@ -832,6 +833,7 @@ async function hook(request, env, cat, shop, ready) {
|
|
|
832
833
|
if (payment) await syncRefunds(env, payment);
|
|
833
834
|
await env.DB.prepare('INSERT INTO shop_events (id, type, at) VALUES (?1, ?2, ?3) ON CONFLICT(id) DO NOTHING').bind(ev.id, ev.type, Date.now()).run(); return json({ ok: true, did: purchase }); }
|
|
834
835
|
}
|
|
836
|
+
if (stripeEventOwner(obj) === 'parts') return json({ ok: true, did: 'ignored' });
|
|
835
837
|
needed.push('payment_link.updated','invoice.paid','invoice.payment_failed','customer.subscription.updated','customer.subscription.deleted');
|
|
836
838
|
if (!needed.includes(ev.type)) return json({ ok: true, did: 'ignored' });
|
|
837
839
|
if (typeof ev.livemode === 'boolean' && (hasStripeKey(env) || linkConfig(env)) && ev.livemode !== (shopMode(env) === 'live')) return json({ ok: true, ignored: 'mode' });
|
|
@@ -1194,7 +1196,7 @@ async function disputeClosed(env, payment, status) {
|
|
|
1194
1196
|
}
|
|
1195
1197
|
|
|
1196
1198
|
/** What the owner reads when Stripe holds a refund for approval (the shop's key is an Agent key). */
|
|
1197
|
-
export const REFUND_HELD = 'Stripe is holding this refund
|
|
1199
|
+
export const REFUND_HELD = 'Stripe is holding this refund for your approval in Stripe (Settings, Approvals, Requests). Approve it there; the item leaves the player’s account after Stripe confirms the refund. You can also manage refunds through your connected Stripe AI; no credential change is needed.';
|
|
1198
1200
|
|
|
1199
1201
|
/** Refund selected lines through Stripe, revoking each only after success. */
|
|
1200
1202
|
export async function refundOrder(env, o, { reason = 'requested_by_customer', by = 'owner', line: lineId = null } = {}) {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Subscription metadata takes precedence over invoice-level metadata. */
|
|
2
|
+
export function stripeEventOwner(object) {
|
|
3
|
+
const metadata = object.parent?.subscription_details?.metadata ?? object.subscription_details?.metadata ?? object.metadata;
|
|
4
|
+
if (['shop-links-v1', 'shop-v1'].includes(metadata?.homie)) return 'shop';
|
|
5
|
+
if (['purchase-links-v1', 'purchase-v1'].includes(metadata?.homie)) return 'parts';
|
|
6
|
+
return null;
|
|
7
|
+
}
|
package/worker/version.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** The @homie-rocks/studio version this Worker code is (package.json's; a test keeps them equal). Cache-busts /_homie/site.js. */
|
|
2
|
-
export const STUDIO_VERSION_TAG = '0.51.
|
|
2
|
+
export const STUDIO_VERSION_TAG = '0.51.5';
|
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"v": 1,
|
|
3
|
-
"checked": "2026-10-03",
|
|
4
|
-
"note": "The endpoints the models skill uses, with the prices and schemas read live on the date above (fal's pricing API, its OpenAPI pages, the providers' terms). Endpoints retire and reprice monthly: `models.mjs registry` reads every price again for free and flags what moved; every receipt names the exact endpoint. Never hard-code one of these anywhere else.",
|
|
5
|
-
"concept": {
|
|
6
|
-
"withRefs": {
|
|
7
|
-
"endpoint": "fal-ai/bytedance/seedream/v5/lite/edit",
|
|
8
|
-
"price": {
|
|
9
|
-
"usd": 0.035,
|
|
10
|
-
"per": "image",
|
|
11
|
-
"read": "2026-10-02"
|
|
12
|
-
},
|
|
13
|
-
"input": {
|
|
14
|
-
"num_images": 1,
|
|
15
|
-
"image_size": {
|
|
16
|
-
"width": 2048,
|
|
17
|
-
"height": 2048
|
|
18
|
-
}
|
|
19
|
-
},
|
|
20
|
-
"refs": "image_urls",
|
|
21
|
-
"maxRefs": 10,
|
|
22
|
-
"why": "the cheapest multi-reference editor: the golden images keep every prop in one style"
|
|
23
|
-
},
|
|
24
|
-
"noRefs": {
|
|
25
|
-
"endpoint": "fal-ai/bytedance/seedream/v5/lite/text-to-image",
|
|
26
|
-
"price": {
|
|
27
|
-
"usd": 0.035,
|
|
28
|
-
"per": "image",
|
|
29
|
-
"read": "2026-10-02"
|
|
30
|
-
},
|
|
31
|
-
"input": {
|
|
32
|
-
"num_images": 1,
|
|
33
|
-
"image_size": {
|
|
34
|
-
"width": 2048,
|
|
35
|
-
"height": 2048
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
"why": "before there are golden images; the derived style prompt carries the look"
|
|
39
|
-
},
|
|
40
|
-
"minPixels": 3686400
|
|
41
|
-
},
|
|
42
|
-
"mesh": {
|
|
43
|
-
"prop": {
|
|
44
|
-
"endpoint": "tripo3d/p1/image-to-3d",
|
|
45
|
-
"price": {
|
|
46
|
-
"usd": 0.5,
|
|
47
|
-
"per": "model with textures (0.40 without)",
|
|
48
|
-
"read": "2026-10-02"
|
|
49
|
-
},
|
|
50
|
-
"credits": {
|
|
51
|
-
"base": 40,
|
|
52
|
-
"texture": 10,
|
|
53
|
-
"defaults": {
|
|
54
|
-
"texture": true
|
|
55
|
-
}
|
|
56
|
-
},
|
|
57
|
-
"input": {
|
|
58
|
-
"texture": true
|
|
59
|
-
},
|
|
60
|
-
"faceLimit": "face_limit",
|
|
61
|
-
"output": "model_mesh",
|
|
62
|
-
"why": "Tripo P1: built for low-poly game meshes, a face_limit that reaches a phone budget, $0.50 textured"
|
|
63
|
-
},
|
|
64
|
-
"fallbacks": [
|
|
65
|
-
{
|
|
66
|
-
"endpoint": "fal-ai/hyper3d/rodin/v2.5",
|
|
67
|
-
"price": {
|
|
68
|
-
"usd": 0.4,
|
|
69
|
-
"per": "generation",
|
|
70
|
-
"read": "2026-10-02"
|
|
71
|
-
},
|
|
72
|
-
"why": "quad presets and texture_delight; not wired by default"
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
"endpoint": "fal-ai/trellis",
|
|
76
|
-
"price": {
|
|
77
|
-
"usd": 0.02,
|
|
78
|
-
"per": "generation",
|
|
79
|
-
"read": "2026-10-02"
|
|
80
|
-
},
|
|
81
|
-
"why": "drafts for exploring, then local simplify; not wired by default"
|
|
82
|
-
}
|
|
83
|
-
]
|
|
84
|
-
},
|
|
85
|
-
"mood": {
|
|
86
|
-
"endpoint": "fal-ai/bytedance/seedream/v5/lite/text-to-image",
|
|
87
|
-
"price": {
|
|
88
|
-
"usd": 0.035,
|
|
89
|
-
"per": "image",
|
|
90
|
-
"read": "2026-10-02"
|
|
91
|
-
},
|
|
92
|
-
"input": {
|
|
93
|
-
"num_images": 1,
|
|
94
|
-
"image_size": {
|
|
95
|
-
"width": 2560,
|
|
96
|
-
"height": 1440
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
},
|
|
100
|
-
"terms": [
|
|
101
|
-
{
|
|
102
|
-
"who": "fal",
|
|
103
|
-
"url": "https://fal.ai/terms",
|
|
104
|
-
"read": "2026-10-02",
|
|
105
|
-
"lastUpdated": "2026-09-08",
|
|
106
|
-
"says": "Customer owns its input; no express assignment of output; output not promised original or non-infringing; no training competing models on third-party outputs."
|
|
107
|
-
},
|
|
108
|
-
{
|
|
109
|
-
"who": "Tripo (developer terms)",
|
|
110
|
-
"url": "https://developers.tripo3d.ai/en/terms",
|
|
111
|
-
"read": "2026-10-02",
|
|
112
|
-
"lastUpdated": "2025-07-11",
|
|
113
|
-
"says": "\"you may use Outputs for lawful commercial or non-commercial purposes\"."
|
|
114
|
-
},
|
|
115
|
-
{
|
|
116
|
-
"who": "Meshy (through fal)",
|
|
117
|
-
"url": "https://fal.ai/models/meshy/v7.1/image-to-3d",
|
|
118
|
-
"read": "2026-10-03",
|
|
119
|
-
"says": "fal labels the endpoint \"Commercial use\"; calls through fal are paid calls on the person's own fal account (fal's terms apply to the output). Meshy's own free plan (CC BY 4.0, Meshy owns output) does not apply: this skill never uses a Meshy free plan."
|
|
120
|
-
}
|
|
121
|
-
],
|
|
122
|
-
"character": {
|
|
123
|
-
"mesh": {
|
|
124
|
-
"endpoint": "meshy/v7.1/image-to-3d",
|
|
125
|
-
"price": {
|
|
126
|
-
"usd": 1.4,
|
|
127
|
-
"per": "textured model with auto-rigging: US$0.80 base + US$0.40 textures + US$0.20 rigging (+US$0.12 an animation preset, not used)",
|
|
128
|
-
"read": "2026-10-03",
|
|
129
|
-
"api": "the pricing API says US$0.80 a generation (the base); the page's add-ons are added on top"
|
|
130
|
-
},
|
|
131
|
-
"addons": {
|
|
132
|
-
"base": 0.8,
|
|
133
|
-
"should_texture": 0.4,
|
|
134
|
-
"enable_rigging": 0.2,
|
|
135
|
-
"enable_animation": 0.12,
|
|
136
|
-
"defaults": {
|
|
137
|
-
"should_texture": true
|
|
138
|
-
}
|
|
139
|
-
},
|
|
140
|
-
"input": {
|
|
141
|
-
"model_type": "standard",
|
|
142
|
-
"topology": "triangle",
|
|
143
|
-
"target_polycount": 7000,
|
|
144
|
-
"should_remesh": true,
|
|
145
|
-
"should_texture": true,
|
|
146
|
-
"enable_pbr": false,
|
|
147
|
-
"pose_mode": "a-pose",
|
|
148
|
-
"enable_rigging": true,
|
|
149
|
-
"enable_animation": false,
|
|
150
|
-
"symmetry_mode": "on"
|
|
151
|
-
},
|
|
152
|
-
"polycount": "target_polycount",
|
|
153
|
-
"height": "rigging_height_meters",
|
|
154
|
-
"output": "rigged_character_glb",
|
|
155
|
-
"why": "Meshy 7.1 through fal: a textured mesh, a humanoid auto-rig and basic walk and run clips in one call, on the person's own fal account; the library's clips are retargeted onto its skeleton for free"
|
|
156
|
-
},
|
|
157
|
-
"rig": {
|
|
158
|
-
"endpoint": "fal-ai/meshy/rigging",
|
|
159
|
-
"price": {
|
|
160
|
-
"usd": 0.8,
|
|
161
|
-
"per": "request (the page says US$0.20; the pricing API says US$0.80: quoted at the higher until they agree)",
|
|
162
|
-
"read": "2026-10-03"
|
|
163
|
-
},
|
|
164
|
-
"addons": {
|
|
165
|
-
"base": 0.2,
|
|
166
|
-
"enable_animation": 0.12
|
|
167
|
-
},
|
|
168
|
-
"input": {
|
|
169
|
-
"enable_animation": false
|
|
170
|
-
},
|
|
171
|
-
"why": "rig a humanoid mesh made elsewhere (a Tripo prop-style mesh, the person's own); humanoids with clear limbs only; not wired by default"
|
|
172
|
-
},
|
|
173
|
-
"concept": "uses concept.withRefs or concept.noRefs: one full-body image in an A-pose, front view, plain background"
|
|
174
|
-
}
|
|
175
|
-
}
|