@polymorphism-tech/morph-spec 8.27.0 → 8.29.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/CLAUDE.md +1 -0
- package/README.md +2 -2
- package/bin/morph-spec.js +9 -4
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +3 -2
- package/docs/QUICKSTART.md +1 -1
- package/framework/MORPH.md +8 -8
- package/framework/agents.json +14 -3
- package/framework/commands/create-umbraco-lp.md +1 -1
- package/framework/docs/CLI.md +6 -5
- package/framework/mcp/registry.json +59 -8
- package/framework/skills/core/create-umbraco-lp/SKILL.md +13 -2
- package/framework/skills/core/create-umbraco-lp/references/umbraco-lp-patterns.md +598 -0
- package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +92 -7
- package/framework/skills/core/morph-apply/SKILL.md +1 -1
- package/framework/skills/core/morph-brainstorming/SKILL.md +1 -1
- package/framework/skills/core/morph-eval/SKILL.md +1 -1
- package/framework/skills/core/morph-hotfix/SKILL.md +1 -1
- package/framework/skills/core/morph-implement/SKILL.md +1 -1
- package/framework/skills/core/morph-plan/SKILL.md +1 -1
- package/framework/skills/core/morph-proposal/SKILL.md +1 -1
- package/framework/skills/core/morph-review/SKILL.md +1 -1
- package/framework/skills/core/morph-stack-scan/SKILL.md +1 -1
- package/framework/skills/core/morph-standards/SKILL.md +1 -1
- package/framework/skills/core/morph-uiux/SKILL.md +1 -1
- package/framework/standards/PROVENANCE.json +41 -0
- package/framework/standards/STANDARDS.json +218 -7
- package/framework/standards/frontend/design-system/ai-image-generation.md +43 -0
- package/framework/standards/frontend/design-system/ai-video-generation.md +113 -0
- package/framework/standards/frontend/design-system/premium-finish.md +160 -0
- package/framework/standards/frontend/gsap/gsap-core.md +1 -1
- package/framework/standards/frontend/gsap/gsap-plugins.md +1 -1
- package/framework/standards/frontend/gsap/gsap-scrolltrigger.md +3 -1
- package/framework/standards/frontend/nextjs/motion-patterns.md +3 -1
- package/framework/standards/frontend/scroll-driven/frame-scrub.md +287 -0
- package/framework/standards/frontend/scroll-driven/scroll-components.md +256 -0
- package/framework/standards/frontend/scroll-driven/smooth-scroll.md +148 -0
- package/framework/standards/frontend/seo/meta-schema-audit.md +134 -0
- package/package.json +1 -1
- package/src/commands/project/doctor.js +9 -4
- package/src/commands/project/worktree.js +45 -3
- package/src/commands/state/advance.js +12 -0
- package/src/commands/state/approve.js +20 -0
- package/src/commands/state/create.js +4 -1
- package/src/commands/state/delete.js +63 -4
- package/src/commands/state/finish.js +20 -2
- package/src/commands/state/gate-check.js +13 -0
- package/src/commands/state/gate-decision.js +9 -0
- package/src/commands/state/handoff.js +48 -6
- package/src/commands/state/list.js +124 -10
- package/src/commands/state/score.js +9 -0
- package/src/lib/generators/handoff-generator.js +11 -4
- package/src/lib/worktree/feature-truth.js +248 -0
- package/src/lib/worktree/fleet-scanner.js +1 -65
- package/src/lib/worktree/worktree-audit.js +103 -17
|
@@ -4,7 +4,7 @@ description: Migra uma landing page existente (React/Vite, Next.js estático ou
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao receber instrução "use /migrate-lp-to-umbraco {projeto}" do usuário, ou quando o usuário descrever necessidade de migrar uma LP para Umbraco
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.29.0"
|
|
8
8
|
stacks:
|
|
9
9
|
- umbraco
|
|
10
10
|
---
|
|
@@ -35,6 +35,7 @@ O processo é reproduzível para qualquer LP (React/Vite, Next.js estático ou H
|
|
|
35
35
|
- **(a) código-fonte local** da LP (React/Vite, Next.js ou HTML) — caminho de **fidelidade máxima**, pois o CSS, o markup e os assets exatos estão disponíveis para o lift verbatim.
|
|
36
36
|
- **(b) apenas a URL** da LP em produção — fallback: scrapear o HTML renderizado, o CSS computado e baixar todos os assets. O mesmo gate de paridade (passo 6) se aplica.
|
|
37
37
|
- **Docker** disponível para boot local (`docker compose`), ou .NET 10 SDK + Node para boot sem container.
|
|
38
|
+
- **Se a origem é scroll-driven** (canvas frame-scrub, pin, parallax, smooth scroll), leia antes os standards `frontend/scroll-driven/frame-scrub.md`, `smooth-scroll.md` e `scroll-components.md`. Eles carregam o conhecimento que o lift precisa preservar; o passo 4e diz onde os assets dessa animação vivem no destino.
|
|
38
39
|
|
|
39
40
|
## Passo 0 — Obter o template (sempre)
|
|
40
41
|
|
|
@@ -192,15 +193,31 @@ O script:
|
|
|
192
193
|
|
|
193
194
|
Nunca commitar `.env`. O cache do passo 0 permanece intacto (read-only) — todo o trabalho acontece nesta cópia.
|
|
194
195
|
|
|
195
|
-
**Smoke-boot antes de qualquer customização** — boot limpo do template para confirmar que o ambiente funciona:
|
|
196
|
+
**Smoke-boot antes de qualquer customização** — boot limpo do template para confirmar que o ambiente funciona. Suba **na ordem**, backend primeiro, e só depois construa o frontend:
|
|
196
197
|
|
|
197
198
|
```bash
|
|
198
|
-
docker compose up
|
|
199
|
+
docker compose up -d backend
|
|
200
|
+
# espere a Delivery API, não o backoffice (ver abaixo)
|
|
201
|
+
until [ "$(curl -s -o /dev/null -w '%{http_code}' \
|
|
202
|
+
'http://localhost:5001/umbraco/delivery/api/v2/content?take=1')" = "200" ]; do sleep 5; done
|
|
203
|
+
docker compose up --build -d frontend
|
|
199
204
|
```
|
|
200
205
|
|
|
201
|
-
Backend sobe em `http://localhost:5001`, frontend em `http://localhost:3000`. Acessar `http://localhost:3000` e confirmar que a página carrega sem erro 500. Isso elimina problemas de ambiente antes de introduzir customizações
|
|
206
|
+
Backend sobe em `http://localhost:5001`, frontend em `http://localhost:3000`. Acessar `http://localhost:3000` e confirmar que a página carrega sem erro 500. Isso elimina problemas de ambiente antes de introduzir customizações; falha precoce economiza horas.
|
|
202
207
|
|
|
203
|
-
**Atenção (gotcha Build do Next.js):** o Dockerfile do frontend executa `next build` na imagem
|
|
208
|
+
**Atenção (gotcha Build do Next.js):** o Dockerfile do frontend executa `next build` na imagem, e nesse momento o Next busca conteúdo via Delivery API para o SSG. Se a API não responder **conteúdo**, o build falha, e a mensagem que chega é só `npm run build ... exit code 1`, sem dizer que o problema é o backend. Por isso `docker compose up --build` sozinho, do zero, não é um comando confiável: ele constrói o frontend junto com o backend.
|
|
209
|
+
|
|
210
|
+
> **O critério de prontidão é a Delivery API responder 200, nunca o backoffice.** Um healthcheck
|
|
211
|
+
> que bate em `/umbraco` fica **healthy** enquanto `/umbraco/delivery/api/v2/content` ainda devolve
|
|
212
|
+
> **500**: o backoffice sobe, o uSync importa, o seed grava, e a API só quebra quando alguém pede o
|
|
213
|
+
> conteúdo. `depends_on: condition: service_healthy` apontando para o healthcheck errado dá uma
|
|
214
|
+
> falsa sensação de ordem resolvida e o build do frontend morre mesmo assim. Aponte o healthcheck
|
|
215
|
+
> do backend para a Delivery API.
|
|
216
|
+
>
|
|
217
|
+
> **E se ela devolver 500, não é questão de esperar mais.** Um 500 persistente na Delivery API com
|
|
218
|
+
> banco recém-seedado é quase sempre **dado seedado no formato errado**, não lentidão de boot.
|
|
219
|
+
> Aumentar timeout não resolve; vá para a seção "Gotchas de campo" e diagnostique pelo log do
|
|
220
|
+
> Umbraco antes de seguir.
|
|
204
221
|
|
|
205
222
|
### 4. Lift verbatim — portar markup, mídia e tema
|
|
206
223
|
|
|
@@ -401,6 +418,33 @@ Registrar o módulo em `frontend/src/components/modules/moduleRegistry.ts`:
|
|
|
401
418
|
nomeSection: () => import('./NomeSection'),
|
|
402
419
|
```
|
|
403
420
|
|
|
421
|
+
#### 4e. Sequências de frames e assets de animação (LP scroll-driven)
|
|
422
|
+
|
|
423
|
+
Se a origem tem hero (ou seção) com **canvas frame-scrub** (o scroll avançando um vídeo quadro a quadro), a animação atravessa a migração intacta, mas só se os assets forem para o balde certo. O modelo abaixo é o que roda em produção; foi decidido uma vez e não deve ser reaberto por engano.
|
|
424
|
+
|
|
425
|
+
**Dois baldes, e a fronteira não é opinião:**
|
|
426
|
+
|
|
427
|
+
| O quê | Onde | Editável no backoffice |
|
|
428
|
+
|---|---|---|
|
|
429
|
+
| Sequência de frames (`hero-frames/`, `oficio-frames/`), fontes, monograma da marca, ícones posicionais | `frontend/public/` | não, é asset estrutural |
|
|
430
|
+
| Poster do scrub, fotos editoriais, logo, imagem de OG | `backend/seed-assets/` → Media Library → MediaPicker3 | sim |
|
|
431
|
+
|
|
432
|
+
**Por que os frames não vão para a Media Library.** Três razões, em ordem de gravidade:
|
|
433
|
+
|
|
434
|
+
1. O processamento on-the-fly do ImageSharp (`?format=webp`) exige URL assinada por HMAC, e no Umbraco 17 o HMAC não é relaxável por configuração. Uma sequência servida de `/media/` perde o webp e não tem como recuperá-lo no frontend headless.
|
|
435
|
+
2. São 145 arquivos por sequência. Como requests assinadas ao backend, é um custo por visitante que não existe servindo de `/public`.
|
|
436
|
+
3. O `SeedContentHandler` só enxerga `backend/seed-assets/` e o banco. Deixando os frames em `frontend/public/`, eles ficam fora do universo do seed: sobrevivem a re-seed, a re-import do uSync e a um `--reset-db` completo, sem nenhum tratamento especial.
|
|
437
|
+
|
|
438
|
+
**O poster é o que fica editável.** É ele que aparece no mobile e sob `prefers-reduced-motion`, então é o único da dupla que o cliente tem motivo para trocar. Frames fixos, poster no MediaPicker.
|
|
439
|
+
|
|
440
|
+
**Cache-bust é obrigatório e manual.** `frontend/public/` não recebe hash de build (o Dockerfile copia o diretório verbatim e o Next só versiona `.next/static`), então reextrair frames mantendo os mesmos nomes serve os bytes antigos de qualquer cache intermediário. O `framePath` carrega um `?v=N` que sobe a cada reextração:
|
|
441
|
+
|
|
442
|
+
```ts
|
|
443
|
+
const framePath = (i: number) => `/hero-frames/frame_${String(i).padStart(3, '0')}.jpg?v=2`
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
**No lift, não trocar a lib de animação.** O template não traz `gsap` nem `lenis`; se a origem usa, adicione ao `frontend/package.json` do destino. Portar o registry de motion e o runtime de scroll como componentes `'use client'`, com o guard de SSR no registro do ScrollTrigger (ele toca `document`) e o runtime montado uma vez na page. Detalhe completo em `frontend/scroll-driven/smooth-scroll.md` e `frontend/scroll-driven/frame-scrub.md` no acervo de standards.
|
|
447
|
+
|
|
404
448
|
### 5. Conectar o formulário ao backend de leads
|
|
405
449
|
|
|
406
450
|
O template usa uma arquitetura de **multi-sink**: o backend seleciona automaticamente a integração correta pelo valor de `leadIntegration` configurado no nó `leadsConfig` do backoffice.
|
|
@@ -446,8 +490,12 @@ Objetivo: **provar** que a LP migrada é idêntica à origem. Com o lift verbati
|
|
|
446
490
|
|
|
447
491
|
#### 6a. Boot + checklist manual (sanidade)
|
|
448
492
|
|
|
493
|
+
Mesma ordem do passo 3: backend primeiro, Delivery API respondendo 200, e só então o frontend.
|
|
494
|
+
|
|
449
495
|
```bash
|
|
450
|
-
docker compose up
|
|
496
|
+
docker compose up -d backend
|
|
497
|
+
until [ "$(curl -s -o /dev/null -w '%{http_code}' 'http://localhost:5001/umbraco/delivery/api/v2/content?take=1')" = "200" ]; do sleep 5; done
|
|
498
|
+
docker compose up --build -d frontend
|
|
451
499
|
```
|
|
452
500
|
|
|
453
501
|
Percorrer a página em `http://localhost:3000` e conferir, lado a lado com a origem: todas as seções na ordem certa, textos/mídias corretos, formulário visível, navegação e footer funcionando. Isso é só uma sanidade rápida antes dos checks automáticos.
|
|
@@ -459,7 +507,27 @@ A skill **scaffolda** o harness de paridade no projeto destino (o template **nã
|
|
|
459
507
|
1. **Estrutura DOM + nomes de classe** por seção — `compare-sections.mjs` extrai o esqueleto de tags+classes de cada `<section>`/`<nav>`/`<footer>` dos dois lados (agrupado por chave semântica/texto âncora) e aponta diferenças. Adaptar o array `KEYS` (`[nome, matchFn]`) aos textos âncora das seções do projeto.
|
|
460
508
|
2. **Estilo computado** em elementos amostrados — para cada seção, comparar `getComputedStyle` de elementos-chave (cor, `font-family`, `font-size`, `font-weight`, paddings/margins, `border-radius`) origem × destino. Divergência = falha.
|
|
461
509
|
3. **Checksum de assets** — o conjunto de `sha256` de todas as imagens/vídeos/fontes servidas pelo destino deve igualar o conjunto capturado da origem no passo 1. Asset reencode/otimizado quebra aqui (proposital).
|
|
462
|
-
4. **Comportamento por interação** — uma asserção Playwright por comportamento capturado no passo 1 (scroll-expand, carrossel, marquee, autoplay de vídeo, hover, máscara/validação de telefone, submit do formulário com `/api/leads` mockado retornando `{"ok":true}`).
|
|
510
|
+
4. **Comportamento por interação** — uma asserção Playwright por comportamento capturado no passo 1 (scroll-expand, **canvas frame-scrub**, carrossel, marquee, autoplay de vídeo, hover, máscara/validação de telefone, submit do formulário com `/api/leads` mockado retornando `{"ok":true}`).
|
|
511
|
+
|
|
512
|
+
> **Scrub e qualquer efeito dirigido por scroll se verificam COM MOVIMENTO.** Um screenshot
|
|
513
|
+
> estático não distingue um scrub vivo de um canvas quebrado: o canvas pode estar 1x1 desenhando
|
|
514
|
+
> um pixel esticado, ou ignorando o scroll por completo, e a foto continua plausível. Dirija o
|
|
515
|
+
> scroll e compare o que foi desenhado em posições diferentes:
|
|
516
|
+
>
|
|
517
|
+
> ```js
|
|
518
|
+
> const lenis = window.__lenis
|
|
519
|
+
> const h = document.querySelector('header.hero-scrub').getBoundingClientRect().height
|
|
520
|
+
> for (const p of [0, .15, .3, .45, .6, .8, 1]) {
|
|
521
|
+
> lenis.scrollTo(Math.round((h - innerHeight) * p), { immediate: true })
|
|
522
|
+
> await new Promise(r => setTimeout(r, 350)) // deixa o scrub:0.4 assentar
|
|
523
|
+
> // capture aqui: screenshot, ou uma assinatura de pixels via ctx.getImageData
|
|
524
|
+
> }
|
|
525
|
+
> ```
|
|
526
|
+
>
|
|
527
|
+
> A espera não é opcional: com `scrub: 0.4` o desenho não salta, e sem ela você fotografa o frame
|
|
528
|
+
> anterior. **Critério de aprovação:** as capturas diferem entre si. Todas iguais significa scrub
|
|
529
|
+
> morto, mesmo que a página pareça correta. Confirmar também que os frames respondem 200 com o
|
|
530
|
+
> `?v=N` em uso e que os beats de texto trocam ao longo do percurso.
|
|
463
531
|
|
|
464
532
|
```bash
|
|
465
533
|
cd frontend
|
|
@@ -487,6 +555,22 @@ A migração é "exata" quando **todos** são verdade:
|
|
|
487
555
|
- `robots.txt`/`sitemap.xml` de produção apontam pro domínio real (não o placeholder `minha-landing-page.com.br` do template) — só acontece se `NEXT_PUBLIC_SITE_URL` foi setada como Build Variable no provedor.
|
|
488
556
|
- Nenhuma chave de API ou token aparece em arquivo versionado.
|
|
489
557
|
|
|
558
|
+
## Gotchas de campo
|
|
559
|
+
|
|
560
|
+
Furos que já custaram build quebrado ou deploy revertido em migração real. Nenhum deles aparece como erro óbvio no caminho feliz.
|
|
561
|
+
|
|
562
|
+
**Property editor guarda JSON, não escalar. Seedar string crua derruba a Delivery API inteira.** `Umbraco.DropDown.Flexible` persiste **array JSON mesmo com `Multiple: false`**. Dentro do JSON de um Block List a tentação é escrever `"ctaAcao": "ancora"` como qualquer outro campo do bloco; o correto é `["ancora"]`. O erro não fica no campo: a exceção sobe pelo `BlockListPropertyValueConverter` e **derruba o documento inteiro** (500 na home), o que mata o `next build` com SSG e chega até você como `npm run build ... exit code 1`. Só aparece com banco novo, então passa despercebido até o primeiro `--reset-db` ou deploy limpo.
|
|
563
|
+
|
|
564
|
+
Regra, diagnóstico pela letra citada no `JsonException` e o procedimento de A/B estão em `references/umbraco-lp-patterns.md` (seção 6) da skill `create-umbraco-lp`, instalada em `.claude/skills/create-umbraco-lp/`. Leia essa seção antes de seedar qualquer dropdown.
|
|
565
|
+
|
|
566
|
+
**MediaPicker3 sempre volta array, mesmo em single-pick.** Na Delivery API, todo campo de mídia chega como array (`poster`, `logo`, `favicon`, `imageSeo`, `modalLogo`), embutido sem `expand`. Acessar `campo.url` direto funciona enquanto o campo está vazio e passa a estourar no instante em que um editor o preenche. Pior: em `generateMetadata` o Next trata a exceção como fatal e derruba o build inteiro, então o sintoma é um deploy que quebra sozinho depois de alguém publicar no backoffice, sem nenhuma mudança de código. Tipar como `UmbracoImage[]` e indexar em `[0]`, sempre com fallback para o asset estático de `/public`.
|
|
567
|
+
|
|
568
|
+
**Label de Block List aninhado usa UFM.** O backoffice do Umbraco 17 (Bellissima) renderiza o label do bloco com Umbraco Flavored Markdown, `{=alias}`, e não com o `{{ alias }}` do backoffice AngularJS antigo. Com a sintaxe velha o header do bloco mostra a chave literal para o editor. É só display do backoffice, não afeta o render da LP, e por isso passa despercebido em toda validação automática.
|
|
569
|
+
|
|
570
|
+
**Reverse proxy e bind do Next.** Atrás de Traefik ou Coolify, o backend precisa de `UseForwardedHeaders` (X-Forwarded-Proto/For), senão o OpenIddict do backoffice não vê HTTPS e o login em `/umbraco` falha com `ID2083: This server only accepts HTTPS requests`. E o runner do frontend precisa de `HOSTNAME=0.0.0.0`: sem isso o `server.js` do Next standalone faz bind no id do container, o healthcheck via `localhost:3000` nunca passa, o container nunca fica healthy e o deploy dá rollback sem erro de aplicação nenhum.
|
|
571
|
+
|
|
572
|
+
**Antes de escrever qualquer um destes, confira se o template já resolveu.** Correções são portadas do projeto de volta para o `MORPH_Umbraco_LP_Template`, então parte desta lista pode já estar no scaffold que o passo 0 baixou. Ensinar de novo uma correção existente cria divergência.
|
|
573
|
+
|
|
490
574
|
## Anti-padrões
|
|
491
575
|
|
|
492
576
|
- Não commitar `.env` nem nenhum arquivo com tokens ou senhas.
|
|
@@ -531,3 +615,4 @@ Repo do template (privado, branch `master`): `polymorphism-tech/MORPH_Umbraco_LP
|
|
|
531
615
|
- `MORPH_Umbraco_LP_Template/frontend/src/app/globals.css` — bloco `@theme` para portar o tema da origem
|
|
532
616
|
- `MORPH_Umbraco_LP_Template/frontend/e2e/home.spec.ts` + `playwright.config.ts` — base de e2e (estender com `parity.spec.ts`)
|
|
533
617
|
- `MORPH_Umbraco_LP_Template/docker-compose.yml` — orquestração backend + frontend com variáveis de ambiente
|
|
618
|
+
- `.claude/skills/create-umbraco-lp/references/umbraco-lp-patterns.md` — padrões e gotchas do template (controller público, multi-sink, leitura server-side, segurança da Delivery API, uSync, **dropdown como JSON array (seção 6)**, seed idempotente, build do Next.js exigindo backend). Instalado junto com a skill irmã; carregue sob demanda.
|
|
@@ -4,7 +4,7 @@ description: Orquestra a execução autônoma de tasks de uma feature morph-spec
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: após Gate 2 aprovado, ao receber instrução "use /morph-apply" ou "implementar feature"
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.29.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-apply
|
|
@@ -4,7 +4,7 @@ description: Entende o negócio, os usuários e a arquitetura antes de qualquer
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao receber um novo request de feature, antes de morph-plan
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.29.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-brainstorming
|
|
@@ -4,7 +4,7 @@ description: Avalia a qualidade de uma tarefa ou fase com rubricas graduadas 0-1
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao completar uma tarefa ou ao finalizar uma fase de implementação
|
|
6
6
|
user-invokable: false
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.29.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-eval
|
|
@@ -4,7 +4,7 @@ description: ADW cirúrgico de hotfix — resolve uma queda/bug crítico de prod
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao receber "/morph-hotfix {feature}", quando a morph-proposal classifica o pedido como workType hotfix (Passo 0), ou o usuário diz "produção caiu / hotfix / urgente"
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.29.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-hotfix
|
|
@@ -4,7 +4,7 @@ description: Guia a execução de cada tarefa de implementação com standard e
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao iniciar cada task de implementação listada em tasks.json
|
|
6
6
|
user-invokable: false
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.29.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-implement
|
|
@@ -4,7 +4,7 @@ description: Guia a produção dos artefatos de planejamento de uma feature (use
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao iniciar a fase plan de uma feature, após o Gate 1 (proposal aprovado)
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.29.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-plan
|
|
@@ -4,7 +4,7 @@ description: Orquestra a fase de proposta+plano de uma feature morph-spec. Encad
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao receber instrução "use /morph-proposal" do usuário, ou ao iniciar uma nova feature
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.29.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-proposal
|
|
@@ -4,7 +4,7 @@ description: Conduz a fase de revisão e produz o review-report.md para o Gate 3
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao iniciar a fase review, após todas as tasks de tasks.json estarem com status `done`
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.29.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-review
|
|
@@ -4,7 +4,7 @@ description: Varre o codebase existente, detecta stack atual, compara com o stac
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao iniciar uma feature em projeto brownfield (codebase já existente)
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.29.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-stack-scan
|
|
@@ -4,7 +4,7 @@ description: Localiza um standard específico via busca server-side (morph-spec
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: quando precisar consultar um standard específico durante a implementação
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.29.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-standards
|
|
@@ -4,7 +4,7 @@ description: Conduz a fase opcional de UI/UX — design system, mockups, compone
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao tomar o ramo uiux (morph-spec advance --design), depois do Gate 1 e antes do morph-plan
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "8.
|
|
7
|
+
cliVersion: "8.29.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-uiux
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.0.0",
|
|
3
|
+
"_note": "Standards distilled from an external source. The source is not a dependency at runtime: it lives in another repository and is not needed to use the framework. This file exists so drift is detectable instead of silent. Pin `sourceTree` when distilling, and re-pin deliberately after reviewing what changed. See test/framework/standards-provenance.test.js.",
|
|
4
|
+
"sources": [
|
|
5
|
+
{
|
|
6
|
+
"id": "morph-lp-cinematic",
|
|
7
|
+
"repo": "morph-HUB",
|
|
8
|
+
"path": "skills/morph-lp-cinematic",
|
|
9
|
+
"envVar": "MORPH_HUB",
|
|
10
|
+
"defaultCheckout": "R:/Polymorphism Tech/repos/morph-HUB",
|
|
11
|
+
"sourceTree": "e43114d4b28ff55680a5355cce27d31ffa74f22f",
|
|
12
|
+
"sourceCommit": "465c9b0",
|
|
13
|
+
"distilledOn": "2026-08-21",
|
|
14
|
+
"distilledFrom": [
|
|
15
|
+
"references/build-stack.md",
|
|
16
|
+
"references/component-recipes.md",
|
|
17
|
+
"references/premium-finish.md",
|
|
18
|
+
"references/seo-and-qa.md",
|
|
19
|
+
"references/gemini-image-prompt.md",
|
|
20
|
+
"references/seedance-scrub-prompt.md",
|
|
21
|
+
"references/seedance-loop-prompt.md"
|
|
22
|
+
],
|
|
23
|
+
"notDistilled": [
|
|
24
|
+
"references/gates.md",
|
|
25
|
+
"references/last-mile.md",
|
|
26
|
+
"references/copy-and-messaging.md",
|
|
27
|
+
"references/section-blueprint.md"
|
|
28
|
+
],
|
|
29
|
+
"notDistilledReason": "Deliberate split: a standard carries knowledge, a skill carries process. HITL gates, deploy and copy strategy stay with the skill.",
|
|
30
|
+
"standards": [
|
|
31
|
+
"frontend-scroll-driven-frame-scrub",
|
|
32
|
+
"frontend-scroll-driven-smooth-scroll",
|
|
33
|
+
"frontend-scroll-driven-scroll-components",
|
|
34
|
+
"frontend-design-system-premium-finish",
|
|
35
|
+
"frontend-design-system-ai-image-generation",
|
|
36
|
+
"frontend-design-system-ai-video-generation",
|
|
37
|
+
"frontend-seo-meta-schema-audit"
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
}
|
|
@@ -1226,7 +1226,7 @@
|
|
|
1226
1226
|
"react"
|
|
1227
1227
|
],
|
|
1228
1228
|
"stacks": [
|
|
1229
|
-
"
|
|
1229
|
+
"*"
|
|
1230
1230
|
],
|
|
1231
1231
|
"aliases": [
|
|
1232
1232
|
"GSAP",
|
|
@@ -1260,7 +1260,7 @@
|
|
|
1260
1260
|
"scroll-animation"
|
|
1261
1261
|
],
|
|
1262
1262
|
"stacks": [
|
|
1263
|
-
"
|
|
1263
|
+
"*"
|
|
1264
1264
|
],
|
|
1265
1265
|
"aliases": [
|
|
1266
1266
|
"ScrollTrigger",
|
|
@@ -1290,7 +1290,7 @@
|
|
|
1290
1290
|
"plugins"
|
|
1291
1291
|
],
|
|
1292
1292
|
"stacks": [
|
|
1293
|
-
"
|
|
1293
|
+
"*"
|
|
1294
1294
|
],
|
|
1295
1295
|
"aliases": [
|
|
1296
1296
|
"Flip",
|
|
@@ -1695,21 +1695,30 @@
|
|
|
1695
1695
|
"mcp"
|
|
1696
1696
|
],
|
|
1697
1697
|
"stacks": [
|
|
1698
|
-
"
|
|
1698
|
+
"*"
|
|
1699
1699
|
],
|
|
1700
1700
|
"aliases": [
|
|
1701
1701
|
"Image Generation",
|
|
1702
1702
|
"AI Assets",
|
|
1703
|
-
"Gemini Images"
|
|
1703
|
+
"Gemini Images",
|
|
1704
|
+
"brand fidelity",
|
|
1705
|
+
"reference images",
|
|
1706
|
+
"favicon",
|
|
1707
|
+
"og image",
|
|
1708
|
+
"asset generation"
|
|
1704
1709
|
],
|
|
1705
1710
|
"anchors": {
|
|
1706
1711
|
"when-to-use": "#when-to-use-ai-generated-images",
|
|
1707
1712
|
"prompt-patterns": "#prompt-engineering-patterns",
|
|
1708
1713
|
"aspect-ratios": "#aspect-ratio-guide",
|
|
1709
1714
|
"assets-md": "#assetsmd-format",
|
|
1710
|
-
"edit-workflows": "#iterative-editing-workflows"
|
|
1715
|
+
"edit-workflows": "#iterative-editing-workflows",
|
|
1716
|
+
"brand-fidelity": "#brand-fidelity-reference-dont-invent",
|
|
1717
|
+
"to-video": "#downstream-images-that-become-video",
|
|
1718
|
+
"favicon-og": "#the-two-assets-everyone-forgets",
|
|
1719
|
+
"variations": "#variations-and-cost"
|
|
1711
1720
|
},
|
|
1712
|
-
"digest": "Guidelines for generating project images with Gemini Image MCP
|
|
1721
|
+
"digest": "Guidelines for generating project images with the Gemini Image MCP: when to use AI versus stock versus SVG, prompt patterns, aspect ratios, iterative editing and assets.md format. Core principle is brand fidelity over invention: always pass the client's real assets as referenceImages via edit_image rather than generating in a vacuum, never AI-recreate a property developer's architectural render or a physical product (animate or reference the real one), and chain derivatives from an approved hero so the whole set shares light, palette and identity. Frame anything destined to become video WITHOUT a face, because video moderation is stricter (E005), and generate scrub frames at the video's exact ratio with the subject opposite the copy. Always produce the two forgotten assets: a favicon derived from the real logo (never a new one) and a 1200x630 OG share image. Offer two to three genuinely different variations per image, varying angle, light or composition rather than the seed, and never advance with a weak image because every derivative inherits it."
|
|
1713
1722
|
},
|
|
1714
1723
|
{
|
|
1715
1724
|
"id": "ai-agents-durable-workflows-hitl",
|
|
@@ -1807,6 +1816,208 @@
|
|
|
1807
1816
|
"errorbody": "#rule-2--error-path-tests-assert-the-response-body-not-just-the-status-code"
|
|
1808
1817
|
},
|
|
1809
1818
|
"digest": "Inject TimeProvider (never DateTime.UtcNow / DateOnly.FromDateTime(DateTime.UtcNow) directly in a handler or validator) and fake it with FakeTimeProvider (Microsoft.Extensions.TimeProvider.Testing) in integration tests — deterministic, no midnight-UTC flake, boundary dates (today vs. yesterday) become facts about the fake clock instead of when the suite happens to run. xUnit + WebApplicationFactory error-path tests (400/404/409) must assert the ProblemDetails response BODY (title/detail/violated field or error code), never just the HTTP status code — a status-only assertion lets the wrong validation rule or the wrong error branch pass silently as long as the status matches."
|
|
1819
|
+
},
|
|
1820
|
+
{
|
|
1821
|
+
"id": "frontend-scroll-driven-frame-scrub",
|
|
1822
|
+
"name": "frame scrub",
|
|
1823
|
+
"path": "frontend/scroll-driven/frame-scrub.md",
|
|
1824
|
+
"category": "frontend",
|
|
1825
|
+
"subcategory": "scroll-driven",
|
|
1826
|
+
"tags": [
|
|
1827
|
+
"frontend",
|
|
1828
|
+
"scroll-driven",
|
|
1829
|
+
"motion"
|
|
1830
|
+
],
|
|
1831
|
+
"stacks": [
|
|
1832
|
+
"*"
|
|
1833
|
+
],
|
|
1834
|
+
"aliases": [
|
|
1835
|
+
"frame scrub",
|
|
1836
|
+
"canvas scrub",
|
|
1837
|
+
"scroll-driven video",
|
|
1838
|
+
"scrollytelling video",
|
|
1839
|
+
"apple scroll video",
|
|
1840
|
+
"ffmpeg frames",
|
|
1841
|
+
"poster fallback"
|
|
1842
|
+
],
|
|
1843
|
+
"anchors": {
|
|
1844
|
+
"why": "#section-1-canvas-not-video-currenttime",
|
|
1845
|
+
"extraction": "#section-2-frame-extraction",
|
|
1846
|
+
"cachebust": "#section-3-cache-busting-is-mandatory",
|
|
1847
|
+
"bug": "#section-5-the-1x1-canvas-bug",
|
|
1848
|
+
"responsive": "#section-6-responsive-and-reduced-motion",
|
|
1849
|
+
"verify": "#section-8-verify-with-motion-never-with-a-still"
|
|
1850
|
+
},
|
|
1851
|
+
"digest": "Scroll-driven video is a preloaded JPG sequence drawn into a <canvas>, never a <video currentTime> driven by scroll (unreliable seek on iOS Safari, black-frame flashes) and never an autoplay loop (reads as a demo, not as user-driven). Extract with ffmpeg (fps=30, ~120-300 frames, -q:v 5), always extract a poster, hflip when the subject collides with the copy, and treat total sequence weight as a performance budget. Always cache-bust the frame URL (?v=N) when re-extracting under the same filenames. Known bug: a section starting hidden measures 0 and the canvas becomes 1x1 drawing one stretched pixel, so keep the canvas display:none and resize on the first loaded frame. Mobile and prefers-reduced-motion collapse to the static poster in both the JS guard and the CSS. Verify by driving the scroll through positions and comparing captured frames (allow ~350ms for scrub:0.4 to settle), never with a single screenshot."
|
|
1852
|
+
},
|
|
1853
|
+
{
|
|
1854
|
+
"id": "frontend-scroll-driven-smooth-scroll",
|
|
1855
|
+
"name": "smooth scroll",
|
|
1856
|
+
"path": "frontend/scroll-driven/smooth-scroll.md",
|
|
1857
|
+
"category": "frontend",
|
|
1858
|
+
"subcategory": "scroll-driven",
|
|
1859
|
+
"tags": [
|
|
1860
|
+
"frontend",
|
|
1861
|
+
"scroll-driven",
|
|
1862
|
+
"motion"
|
|
1863
|
+
],
|
|
1864
|
+
"stacks": [
|
|
1865
|
+
"*"
|
|
1866
|
+
],
|
|
1867
|
+
"aliases": [
|
|
1868
|
+
"lenis",
|
|
1869
|
+
"smooth scroll",
|
|
1870
|
+
"scroll wiring",
|
|
1871
|
+
"gsap ticker",
|
|
1872
|
+
"window.__lenis",
|
|
1873
|
+
"scrolltrigger refresh",
|
|
1874
|
+
"HMR stale triggers"
|
|
1875
|
+
],
|
|
1876
|
+
"anchors": {
|
|
1877
|
+
"registry": "#section-1-central-motion-registry",
|
|
1878
|
+
"raf": "#section-2-the-raf-handoff",
|
|
1879
|
+
"expose": "#section-3-expose-the-instance-on-window",
|
|
1880
|
+
"hmr": "#section-4-the-hmr-staleness-trap"
|
|
1881
|
+
},
|
|
1882
|
+
"digest": "Register GSAP plugins once in a shared lib/motion module that also exports prefersReducedMotion. Drive Lenis from gsap.ticker (never its own RAF loop), bind lenis.on(scroll, ScrollTrigger.update), set gsap.ticker.lagSmoothing(0), and call ScrollTrigger.refresh() on window load so triggers re-measure after fonts and images settle. Expose window.__lenis deliberately: overlays need stop()/start() to freeze the background, and automated verification needs scrollTo(y, {immediate:true}) to step through positions; consumers must use optional chaining because the instance is never created under reduced motion. After many hot reloads ScrollTrigger accumulates stale instances and pins/scrubs silently die, so full-reload before debugging, wrap every effect in gsap.context()/matchMedia() with revert on cleanup, and set invalidateOnRefresh on viewport-dependent triggers."
|
|
1883
|
+
},
|
|
1884
|
+
{
|
|
1885
|
+
"id": "frontend-scroll-driven-scroll-components",
|
|
1886
|
+
"name": "scroll components",
|
|
1887
|
+
"path": "frontend/scroll-driven/scroll-components.md",
|
|
1888
|
+
"category": "frontend",
|
|
1889
|
+
"subcategory": "scroll-driven",
|
|
1890
|
+
"tags": [
|
|
1891
|
+
"frontend",
|
|
1892
|
+
"scroll-driven",
|
|
1893
|
+
"motion"
|
|
1894
|
+
],
|
|
1895
|
+
"stacks": [
|
|
1896
|
+
"*"
|
|
1897
|
+
],
|
|
1898
|
+
"aliases": [
|
|
1899
|
+
"pinned gallery",
|
|
1900
|
+
"horizontal scroll",
|
|
1901
|
+
"scroll reveal",
|
|
1902
|
+
"parallax drift",
|
|
1903
|
+
"count-up",
|
|
1904
|
+
"lightbox",
|
|
1905
|
+
"scroll progress",
|
|
1906
|
+
"expanding modal"
|
|
1907
|
+
],
|
|
1908
|
+
"anchors": {
|
|
1909
|
+
"reveal": "#section-1-usereveal-the-base-brick",
|
|
1910
|
+
"pinned": "#section-2-pinned-horizontal-gallery",
|
|
1911
|
+
"overlays": "#section-3-expanding-modal",
|
|
1912
|
+
"parallax": "#section-5-parallax-drift",
|
|
1913
|
+
"rules": "#section-9-cross-cutting-rules"
|
|
1914
|
+
},
|
|
1915
|
+
"digest": "Toolbox of scroll-driven interaction patterns, not a mandatory list: useReveal (fade/rise with once:true) covers most content; pinned horizontal gallery needs invalidateOnRefresh:true or the travel distance stays frozen after a resize; expanding modal and lightbox mount then add an .in class on the next frame, pause the scroller via window.__lenis?.stop(), and must render OUTSIDE any pinned section because the pin transform breaks position:fixed inside it; parallax drift stays subtle at 5-8% with overflow:hidden on the figure; count-up animates a plain object and formats per locale; scroll progress uses scaleX with transform-origin 0 50% to stay on the compositor; accordions use native <details>. Cross-cutting: anything clickable that is not a button or anchor gets role=button, tabIndex 0 and Enter/Space, Escape closes overlays, every effect has a static reduced-motion fallback and reverts on cleanup."
|
|
1916
|
+
},
|
|
1917
|
+
{
|
|
1918
|
+
"id": "frontend-design-system-premium-finish",
|
|
1919
|
+
"name": "premium finish",
|
|
1920
|
+
"path": "frontend/design-system/premium-finish.md",
|
|
1921
|
+
"category": "frontend",
|
|
1922
|
+
"subcategory": "design-system",
|
|
1923
|
+
"tags": [
|
|
1924
|
+
"frontend",
|
|
1925
|
+
"design-system"
|
|
1926
|
+
],
|
|
1927
|
+
"stacks": [
|
|
1928
|
+
"*"
|
|
1929
|
+
],
|
|
1930
|
+
"aliases": [
|
|
1931
|
+
"premium finish",
|
|
1932
|
+
"polish layer",
|
|
1933
|
+
"film grain",
|
|
1934
|
+
"atmosphere",
|
|
1935
|
+
"load-in stagger",
|
|
1936
|
+
"scrim",
|
|
1937
|
+
"text over video",
|
|
1938
|
+
"metallic accent",
|
|
1939
|
+
"looks like a template"
|
|
1940
|
+
],
|
|
1941
|
+
"anchors": {
|
|
1942
|
+
"typography": "#section-1-typography-with-character",
|
|
1943
|
+
"atmosphere": "#section-2-atmosphere-never-flat-color",
|
|
1944
|
+
"loadin": "#section-3-one-orchestrated-load-in-beats-ten-micro-interactions",
|
|
1945
|
+
"legibility": "#section-4-legibility-over-video-close-to-a-hard-rule",
|
|
1946
|
+
"order": "#section-7-order-of-application"
|
|
1947
|
+
},
|
|
1948
|
+
"digest": "The finish layer that separates a working build from one a client reads as expensive, applied from the start rather than as a final polish pass. Principles, never a fixed recipe, and never converge on the same choices across projects: commit to a display font chosen from the brand (stack defaults and the AI-tell faces like Space Grotesk/Playfair announce machine-generated); use atmosphere instead of flat color (feTurbulence film grain at low opacity, radial brand glow, vignette); concentrate effort on ONE orchestrated hero load-in with staggered animation-delay rather than scattered micro-interactions; text over media always gets a DIRECTIONAL scrim (dark where the copy lives, clear over the subject) plus text-shadow as insurance against bright frames; one precious accent used in three places or fewer. Define brand tokens as CSS variables first, then atmosphere, then hero, then accent, then details."
|
|
1949
|
+
},
|
|
1950
|
+
{
|
|
1951
|
+
"id": "frontend-seo-meta-schema-audit",
|
|
1952
|
+
"name": "meta schema audit",
|
|
1953
|
+
"path": "frontend/seo/meta-schema-audit.md",
|
|
1954
|
+
"category": "frontend",
|
|
1955
|
+
"subcategory": "seo",
|
|
1956
|
+
"tags": [
|
|
1957
|
+
"frontend",
|
|
1958
|
+
"seo",
|
|
1959
|
+
"accessibility"
|
|
1960
|
+
],
|
|
1961
|
+
"stacks": [
|
|
1962
|
+
"*"
|
|
1963
|
+
],
|
|
1964
|
+
"aliases": [
|
|
1965
|
+
"seo",
|
|
1966
|
+
"meta tags",
|
|
1967
|
+
"open graph",
|
|
1968
|
+
"og:image",
|
|
1969
|
+
"schema.org",
|
|
1970
|
+
"json-ld",
|
|
1971
|
+
"rich results",
|
|
1972
|
+
"lighthouse",
|
|
1973
|
+
"go-live audit",
|
|
1974
|
+
"canonical"
|
|
1975
|
+
],
|
|
1976
|
+
"anchors": {
|
|
1977
|
+
"meta": "#section-1-essential-meta",
|
|
1978
|
+
"opengraph": "#section-2-open-graph-and-twitter-cards",
|
|
1979
|
+
"schema": "#section-3-schemaorg-json-ld-by-business-type",
|
|
1980
|
+
"a11y": "#section-4-accessibility-also-an-seo-signal",
|
|
1981
|
+
"audit": "#section-5-pre-launch-audit"
|
|
1982
|
+
},
|
|
1983
|
+
"digest": "Head-level SEO is cheap and pays for itself: title/description/canonical/theme-color/favicon, correct lang, font preconnects, and a full Open Graph set with an absolute 1200x630 og:image (without it a pasted link renders as a bare card). Pick the JSON-LD @type from the business (ClothingStore/Store for retail, LocalBusiness for services, RealEstateAgent or Residence for property, SoftwareApplication for SaaS) and include ONLY true fields: aggregateRating goes in only with a real rating and review count from a real source, otherwise omit the block, because fabricated structured data is a trust and manual-action risk. Accessibility doubles as an SEO signal (alt text, contrast checked against the brightest frames, focus order, one h1, reduced-motion honored). Before go-live run Lighthouse, a clean-console check, a share-card check and cross-device; if a heavy frame sequence costs Performance, confirm the cost sits in the scrub and state the trade rather than letting a low score pass unexamined."
|
|
1984
|
+
},
|
|
1985
|
+
{
|
|
1986
|
+
"id": "frontend-design-system-ai-video-generation",
|
|
1987
|
+
"name": "AI Video Generation",
|
|
1988
|
+
"path": "frontend/design-system/ai-video-generation.md",
|
|
1989
|
+
"category": "frontend",
|
|
1990
|
+
"subcategory": "design-system",
|
|
1991
|
+
"tags": [
|
|
1992
|
+
"video",
|
|
1993
|
+
"seedance",
|
|
1994
|
+
"asset",
|
|
1995
|
+
"ai-generation",
|
|
1996
|
+
"motion",
|
|
1997
|
+
"mcp"
|
|
1998
|
+
],
|
|
1999
|
+
"stacks": [
|
|
2000
|
+
"*"
|
|
2001
|
+
],
|
|
2002
|
+
"aliases": [
|
|
2003
|
+
"video generation",
|
|
2004
|
+
"seedance",
|
|
2005
|
+
"img2vid",
|
|
2006
|
+
"endImage",
|
|
2007
|
+
"directional footage",
|
|
2008
|
+
"loop video",
|
|
2009
|
+
"E005",
|
|
2010
|
+
"animate render",
|
|
2011
|
+
"scroll scrub footage"
|
|
2012
|
+
],
|
|
2013
|
+
"anchors": {
|
|
2014
|
+
"loop-vs-directional": "#section-1-the-distinction-that-decides-everything",
|
|
2015
|
+
"directional": "#section-2-building-directional-footage",
|
|
2016
|
+
"moderation": "#section-3-faces-trip-moderation",
|
|
2017
|
+
"cost-ladder": "#section-4-the-cost-ladder",
|
|
2018
|
+
"prompt-skeleton": "#section-5-prompt-skeleton"
|
|
2019
|
+
},
|
|
2020
|
+
"digest": "The decisive rule: a perfect loop has an end frame identical to its start, which is right for a self-playing ambient background and WRONG for scroll scrubbing, because start and end look the same and the page reads as frozen while the user scrolls. Scroll-driven footage needs directional movement via generate_video with an endImage (push-in/dolly is the most reliable, then reveal, pull-back, slow tilt); avoid orbits and any movement that returns to its origin. Client architectural renders are animated with img2vid, never AI-recreated. Human faces repeatedly trip moderation (E005), so crop the face out of frame (neck down, hands, product) and reserve faces for static image generation. Always climb the cost ladder: fast/480p/4s draft to judge framing and movement, 1080p only after approval, then re-extract frames with a bumped cache-bust. Prompts read like director notes with no hype words, and must reserve a calm dark region for the page copy with the subject on the opposite side. Generation is async: generate_video returns a request_id polled via get_video; list_videos reads local history and spends no credits."
|
|
1810
2021
|
}
|
|
1811
2022
|
],
|
|
1812
2023
|
"sharedAliases": {
|