wizz-method 2.17.1 → 2.18.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.
Files changed (47) hide show
  1. package/THIRD-PARTY-NOTICES.md +12 -0
  2. package/package.json +1 -1
  3. package/skills-registry.yaml +24 -6
  4. package/src/core-skills/_shared/handoff-protocol.md +3 -1
  5. package/src/modules/wizz/_shared/despacho-barato.md +1 -1
  6. package/src/modules/wizz/_shared/model-ladder.md +10 -0
  7. package/src/modules/wizz/_shared/video-pipeline.md +10 -0
  8. package/src/modules/wizz/agents/wizz-designer/customize.toml +2 -2
  9. package/src/modules/wizz/agents/wizz-maestro/SKILL.md +1 -1
  10. package/src/modules/wizz/agents/wizz-social/SKILL.md +2 -0
  11. package/src/modules/wizz/agents/wizz-social/customize.toml +10 -0
  12. package/src/modules/wizz/subagents/codex/wizz-exec-standard.toml +1 -1
  13. package/src/modules/wizz/subagents/codex/wizz-exec-strong.toml +1 -1
  14. package/src/modules/wizz/subagents/gemini/wizz-exec-standard.md +1 -1
  15. package/src/modules/wizz/subagents/gemini/wizz-exec-strong.md +1 -1
  16. package/src/modules/wizz/subagents/opencode/wizz-exec-standard.md +1 -1
  17. package/src/modules/wizz/subagents/opencode/wizz-exec-strong.md +1 -1
  18. package/src/modules/wizz/subagents/spec.yaml +6 -6
  19. package/src/modules/wizz/subagents/wizz-exec-standard.md +1 -1
  20. package/src/modules/wizz/subagents/wizz-exec-strong.md +1 -1
  21. package/src/skills-lib/wizz-hook-extractor/LICENSE +21 -0
  22. package/src/skills-lib/wizz-hook-extractor/SKILL.md +56 -0
  23. package/src/skills-lib/wizz-hook-extractor/references/examples.md +59 -0
  24. package/src/skills-lib/wizz-hook-extractor/references/formulas.md +136 -0
  25. package/src/skills-lib/wizz-hook-extractor/scripts/read-post.sh +83 -0
  26. package/src/skills-lib/wizz-ig-profile-optimizer/LICENSE +21 -0
  27. package/src/skills-lib/wizz-ig-profile-optimizer/SKILL.md +74 -0
  28. package/src/skills-lib/wizz-ig-profile-optimizer/scripts/capture-profile.sh +41 -0
  29. package/src/skills-lib/wizz-ig-profile-optimizer/scripts/limits.mjs +82 -0
  30. package/src/skills-lib/wizz-premium-landing-ui-researcher/SKILL.md +5 -0
  31. package/src/skills-lib/wizz-premium-landing-ui-researcher/references/component-sources.md +1 -1
  32. package/src/skills-lib/wizz-premium-landing-ui-researcher/references/source-first-protocol.md +1 -1
  33. package/src/skills-lib/wizz-premium-landing-ui-researcher/references/web-access-and-evidence.md +40 -0
  34. package/src/skills-lib/wizz-router/references/routing-table-flat.md +3 -1
  35. package/src/skills-lib/wizz-ui-component-curator/SKILL.md +5 -3
  36. package/src/skills-lib/wizz-video-effects/SKILL.md +1 -0
  37. package/src/skills-lib/wizz-video-styles/SKILL.md +9 -3
  38. package/src/skills-lib/wizz-video-styles/data/recipes.json +33 -1
  39. package/src/skills-lib/wizz-video-styles/data/references.json +175 -0
  40. package/src/skills-lib/wizz-video-styles/data/styles.json +55 -0
  41. package/src/skills-lib/wizz-video-styles/references/generated-prompts.md +60 -0
  42. package/src/skills-lib/wizz-video-styles/references/measured-patterns.md +2 -0
  43. package/src/skills-lib/wizz-video-styles/references/style-picker.md +5 -3
  44. package/src/skills-lib/wizz-video-styles/references/styles/tipografia-cinetica.md +68 -0
  45. package/src/skills-lib/wizz-video-styles/scripts/analyze.sh +2 -1
  46. package/src/skills-lib/wizz-video-styles/scripts/beat_grid.py +68 -0
  47. package/src/skills-lib/wizz-video-styles/scripts/references.mjs +264 -0
@@ -0,0 +1,136 @@
1
+ # Hook formulas and post shapes, mapped to the Blueprint types
2
+
3
+ The Method already numbers hooks: the **7 types** of the Viral Script Blueprint (`wizz-social` agent, `knowledge/blueprint-roteiro-viral.md`, section 1). This skill classifies the hook with **those** types, so an extracted mould drops straight into a script. What the Blueprint does not cover is the **shape of the post** around the hook (a caption cut at the "mais" fold, a carousel slide by slide, a Reel's first seconds). The 10 shapes below cover that; they are adapted from sergebulaev/instagram-skills (MIT, credited in `THIRD-PARTY-NOTICES.md`).
4
+
5
+ ## 1. Hook → Blueprint type
6
+
7
+ | Type | Name | How to spot it in the first line / slide 1 / first 3 s |
8
+ |---|---|---|
9
+ | Tipo 01 | A Façanha Pessoal | past tense + an absurd or precise result of the author ("eu fiz X em 47 minutos") |
10
+ | Tipo 02 | A Sentença de Morte | a tool, job or company declared dead ("X acabou de matar Y") |
11
+ | Tipo 03 | O Comando Provocador | an order that sounds radical ("pode demitir...", "para de postar...") |
12
+ | Tipo 04 | A Pergunta de Resultado | a question about a specific result the viewer wants |
13
+ | Tipo 05 | A Lista Urgente | a number + things/errors/prompts ("5 erros que...") |
14
+ | Tipo 06 | A Revelação de Erro | points at something the viewer does wrong, with a cost ("se você faz X, está perdendo Y") |
15
+ | Tipo 07 | O Breaking News | a fresh piece of news as a headline, with "a partir de hoje" |
16
+ | fora dos 7 | identificação / confissão | see the equivalence table: two Instagram shapes have no Blueprint type |
17
+
18
+ ## 2. Shape → Blueprint type (equivalence)
19
+
20
+ The 10 shapes do not map 1 to 1. This table is the single place where they meet; never number hooks with IG1..IG10 in a delivery, use the Tipo and the shape name.
21
+
22
+ | Shape (surface) | Closest Blueprint type | Note |
23
+ |---|---|---|
24
+ | Resultado com número (legenda) | Tipo 01 | Tipo 01 with an odd, measured number |
25
+ | Verdade contrária (legenda) | Tipo 03, or Tipo 02 when something is declared dead | |
26
+ | Identificação (legenda) | **fora dos 7** (closest: Tipo 06 without the guilt) | a shared moment, no number, no lesson |
27
+ | Confissão curta (legenda ou Reel) | **fora dos 7** (closest: Tipo 01 told from the failure) | a real cost, then the lesson |
28
+ | Lista (carrossel) | Tipo 05 | |
29
+ | Antes e depois (carrossel) | Tipo 01 | Blueprint phase 04 "resultado visual" moved to slide 1 |
30
+ | Mito e verdade (carrossel) | Tipo 06 | |
31
+ | Framework (carrossel) | Tipo 01 + the Blueprint's "Revelação de Sistema" structure | |
32
+ | Quebra de padrão (Reel) | Tipo 02, 03 or 07: the shape is how it is delivered, the type is what is said | |
33
+ | "Como eu fiz" (Reel) | Tipo 01 + the Blueprint's "Tutorial Bombástico" structure | |
34
+
35
+ Tipo 04 and Tipo 07 have no Instagram shape of their own: they live in any surface.
36
+
37
+ ## 3. The 10 shapes
38
+
39
+ Moulds use `{slots}` and Brazilian Portuguese with "você". Goal = what the shape tends to earn.
40
+
41
+ ### Legenda (single image or any post): the first ~125 characters, before "mais"
42
+
43
+ **Resultado com número** · saves
44
+ ```
45
+ {resultado com número exato} em {prazo}.
46
+
47
+ O que eu mudei está aqui embaixo.
48
+ ```
49
+ Odd numbers (47 minutos, R$ 873) read as measured. Never invent the number.
50
+
51
+ **Verdade contrária** · shares
52
+ ```
53
+ {conselho que todo mundo repete} está errado.
54
+
55
+ {o que funciona, dito sem rodeio}.
56
+ ```
57
+ Only claims the author would defend in the comments.
58
+
59
+ **Identificação** · comments
60
+ ```
61
+ {um momento específico que todo mundo do nicho conhece, sem contexto}
62
+ ```
63
+ Specific beats generic ("abrir o Canva pra fazer uma arte rápida e fechar 90 minutos depois").
64
+
65
+ **Confissão curta** · comments and follows
66
+ ```
67
+ {marcador de tempo}: {o que aconteceu, incluindo a parte feia}.
68
+
69
+ {a linha de sentido que faz valer a leitura}.
70
+ ```
71
+ It has to be true.
72
+
73
+ ### Carrossel: slide 1 promises, the last slide pays
74
+
75
+ **Lista** · saves
76
+ ```
77
+ Slide 1: {N} {coisas} que {resultado grande e específico}. (quase todo mundo erra a {k})
78
+ Slides 2..N-1: um item por slide, com exemplo concreto.
79
+ Último: resumo em uma linha + "salva pra usar depois".
80
+ ```
81
+
82
+ **Antes e depois** · saves and follows
83
+ ```
84
+ Slide 1: {o depois, com número ou imagem forte}.
85
+ Slide 2: de onde começou (o antes).
86
+ Slides 3..N-1: os passos, um por slide.
87
+ Último: "segue pra ver o sistema completo de {tema}" + pedido de salvar.
88
+ ```
89
+
90
+ **Mito e verdade** · shares
91
+ ```
92
+ Slide 1: {N} mitos de {tema} que estão te custando {perda específica}.
93
+ Slides 2..N-1: "Mito: {crença}." / "Verdade: {o que funciona}."
94
+ Último: a virada em uma linha + "manda pra quem ainda acredita no 1".
95
+ ```
96
+ Never invent the myth to knock it down.
97
+
98
+ **Framework** · saves
99
+ ```
100
+ Slide 1: o {nome} que eu uso pra {resultado}.
101
+ Slides 2..N-1: uma parte por slide, com o porquê.
102
+ Último: o framework inteiro num slide só + pedido de salvar.
103
+ ```
104
+
105
+ ### Reel: the first 1 to 3 seconds (image + text on screen + first spoken line)
106
+
107
+ **Quebra de padrão** · shares
108
+ ```
109
+ Texto do 1º quadro: {afirmação ou pergunta que faz passar reto parecer perda}.
110
+ 1ª fala: {direto ao ponto, sem "e aí, pessoal"}.
111
+ ```
112
+
113
+ **"Como eu fiz"** · saves
114
+ ```
115
+ Texto do 1º quadro: como eu {resultado com número} em {prazo}.
116
+ Corpo: passo 1, 2, 3 com rótulo na tela, cortes rápidos, sem enchimento.
117
+ Fim: "salva pra fazer junto" + resumo de uma linha na tela.
118
+ ```
119
+
120
+ ## 4. Goal of the original
121
+
122
+ | Close / structure | Goal |
123
+ |---|---|
124
+ | "salva", list, framework, how-to | saves |
125
+ | "manda pra...", contrary take, myth | shares |
126
+ | identification, question, confession | comments |
127
+ | proof of transformation, "segue pra..." | follows |
128
+
129
+ ## 5. What not to copy from a viral post
130
+
131
+ - Dashes gluing clauses together, and in text a third party reads, no em dash at all (Wizz rule).
132
+ - An AI-vocabulary cluster ("alavancar", "fundamentalmente", "eleve", "potencialize") in one paragraph.
133
+ - 20 to 30 hashtags at the top of the caption.
134
+ - Engagement bait ("comenta SIM", "marca 3 amigos"): Instagram pushes it down.
135
+ - A hook that only makes sense after the "mais" fold.
136
+ - Images and videos mixed in one carousel.
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env bash
2
+ # Reads one public Instagram post so its hook can be studied without the user pasting anything.
3
+ # Usage: read-post.sh <instagram_url> <out_dir>
4
+ # → <out_dir>/post.json (caption, author, metrics, surface), head.png (first 3 s, Reels),
5
+ # sheet.png (whole Reel), transcript.json (first 10 s of speech, local Whisper).
6
+ # Exit 0 = read; 3 = Instagram asked for a login (see the message); 2 = usage or missing tool.
7
+ # Login is never automatic: set WIZZ_IG_COOKIES_BROWSER=<browser> (chrome, opera, safari...) only
8
+ # after the user agreed to use their own logged-in browser session for this read.
9
+ set -euo pipefail
10
+ [ $# -eq 2 ] || { echo "uso: read-post.sh <url do instagram> <pasta de saída>" >&2; exit 2; }
11
+ url="$1"; out="$2"
12
+ [[ "$url" =~ ^https://(www\.)?instagram\.com/([A-Za-z0-9._]+/)?(reel|reels|p|tv)/[A-Za-z0-9_-]+/?(\?.*)?$ ]] \
13
+ || { echo "url inválida (esperado instagram.com/reel/..., /p/... ou /tv/...): $url" >&2; exit 2; }
14
+ for bin in yt-dlp ffmpeg node; do command -v "$bin" >/dev/null || { echo "falta $bin no PATH" >&2; exit 2; }; done
15
+ mkdir -p "$out"; cd "$out"
16
+ trap 'rm -f ./media.* ./head.wav ./raw.json.part' EXIT
17
+
18
+ auth=()
19
+ [ -n "${WIZZ_IG_COOKIES_BROWSER:-}" ] && auth=(--cookies-from-browser "$WIZZ_IG_COOKIES_BROWSER")
20
+ if ! yt-dlp -q --no-warnings --socket-timeout 20 ${auth[@]+"${auth[@]}"} -J "$url" > raw.json 2> err.txt; then
21
+ if grep -qiE "login|cookies|empty media|not available" err.txt; then
22
+ echo "O Instagram pediu login para este post. Opções: (1) com o OK do usuário, rodar de novo com WIZZ_IG_COOKIES_BROWSER=<navegador logado>; (2) print do post; (3) colar a legenda e o texto da tela." >&2
23
+ exit 3
24
+ fi
25
+ cat err.txt >&2; exit 1
26
+ fi
27
+
28
+ # Caption, author and metrics; a carousel comes as a playlist of entries.
29
+ node - <<'JS'
30
+ const fs = require('node:fs');
31
+ const raw = JSON.parse(fs.readFileSync('raw.json', 'utf8'));
32
+ const entries = raw._type === 'playlist' ? raw.entries ?? [] : [raw];
33
+ const videos = entries.filter((e) => e && (e.vcodec && e.vcodec !== 'none' || e.duration));
34
+ const surface = raw._type === 'playlist' ? 'carrossel' : videos.length ? 'reel' : 'imagem';
35
+ const pick = (k) => raw[k] ?? entries[0]?.[k] ?? null;
36
+ fs.writeFileSync('post.json', JSON.stringify({
37
+ url: raw.webpage_url ?? raw.original_url,
38
+ surface,
39
+ slides: raw._type === 'playlist' ? entries.length : 1,
40
+ author: pick('uploader') ?? pick('channel'),
41
+ handle: pick('channel') ?? pick('uploader_id'),
42
+ date: pick('upload_date'),
43
+ caption: pick('description') ?? '',
44
+ likes: pick('like_count'),
45
+ comments: pick('comment_count'),
46
+ views: pick('view_count'),
47
+ duration_s: pick('duration'),
48
+ }, null, 1));
49
+ JS
50
+ rm -f raw.json err.txt
51
+
52
+ surface=$(node -p "require('./post.json').surface")
53
+ if [ "$surface" = "reel" ]; then
54
+ yt-dlp -q --no-warnings --socket-timeout 20 ${auth[@]+"${auth[@]}"} -o "media.%(ext)s" "$url"
55
+ media=$(ls media.* | head -1)
56
+ ffmpeg -loglevel error -y -t 3 -i "$media" -vf "fps=2,scale=270:-1,tile=6x1" -frames:v 1 head.png
57
+ d=$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$media")
58
+ step=$(node -p "Math.max(1, $d / 8)")
59
+ ffmpeg -loglevel error -y -i "$media" -vf "fps=1/$step,scale=270:-1,tile=8x1" -frames:v 1 sheet.png
60
+ if ffmpeg -loglevel error -y -t 10 -i "$media" -vn -ac 1 -ar 16000 head.wav 2>/dev/null; then
61
+ # Local Whisper through the HyperFrames CLI: no API key. Multilingual model, Portuguese by default.
62
+ npx -y hyperframes transcribe head.wav -d . -m small -l "${WIZZ_IG_LANG:-pt}" --json >/dev/null 2>transcribe.log \
63
+ || echo "transcrição falhou (ver transcribe.log); siga pelos quadros e pela legenda" >&2
64
+ # Whisper invents words over music with no speech ("Thank you for watching", "Legendas pela
65
+ # comunidade"): stretched words or too few words per second mean there was no real speech.
66
+ [ -f transcript.json ] && node - <<'JS'
67
+ const fs = require('node:fs');
68
+ const raw = JSON.parse(fs.readFileSync('transcript.json', 'utf8'));
69
+ const words = Array.isArray(raw) ? raw : raw.words ?? [];
70
+ const span = words.length ? words.at(-1).end - words[0].start : 0;
71
+ const stretched = words.some((w) => w.end - w.start > 1.2);
72
+ const slow = span > 0 && words.length / span < 0.8;
73
+ const canned = /thank you for watching|obrigad[oa] por assistir|legendas? pela comunidade|inscreva-se/i.test(words.map((w) => w.text).join(' '));
74
+ const post = JSON.parse(fs.readFileSync('post.json', 'utf8'));
75
+ post.speech = words.length === 0 ? 'sem fala' : stretched || slow || canned ? 'suspeita' : 'ok';
76
+ fs.writeFileSync('post.json', JSON.stringify(post, null, 1));
77
+ if (post.speech !== 'ok') console.error(`transcrição ${post.speech}: provavelmente música sem fala; o gancho está nos quadros e no texto da tela`);
78
+ JS
79
+ else
80
+ echo "Reel sem áudio: o gancho está só no texto da tela (head.png)" >&2
81
+ fi
82
+ fi
83
+ echo "ok: $(pwd)/post.json ($surface)"
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sergey Bulaev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,74 @@
1
+ ---
2
+ name: wizz-ig-profile-optimizer
3
+ description: Audits and rewrites an Instagram profile so a visitor decides to follow. Captures the public profile by the @ (photo, NAME field, @, bio, link, first grid rows), scores the nine parts (photo, NAME, @, bio, link, category, highlights, first nine of the grid, pinned posts) against the profile's goal (grow, sell, land clients, authority), and delivers a scorecard, fixes ranked by impact, before and after rewrites inside Instagram's limits (bio 150, NAME 30), a highlights plan and the pins chosen by real metrics when Buffer is connected. Use when someone asks to review, fix or optimise an Instagram profile or bio. Triggers - arruma minha bio, revisa meu perfil do instagram, o que colocar nos destaques, quais posts fixar, meu perfil não converte seguidor. Does not write captions or scripts (that is wizz-social-content) and does not design the highlight covers (that is wizz-canvas-design).
4
+ ---
5
+
6
+ # wizz-ig-profile-optimizer: the header that earns the follow
7
+
8
+ The follow decision happens on the header and the first rows of the grid: photo, NAME, bio, link, then the grid at a glance. This skill reads that as a stranger would, scores it, and rewrites what fails.
9
+
10
+ All text delivered is Brazilian Portuguese with "você", and no em dash in anything public (bio, NAME, highlight names, pinned captions).
11
+
12
+ ## Inputs
13
+
14
+ - The @ (preferred), or a screenshot of the header and the first grid rows.
15
+ - The goal of the profile: **crescer**, **vender**, **conseguir cliente** or **autoridade**. It changes the link, the bio's last line and the pins. Ask once if it is not clear.
16
+
17
+ ## Steps
18
+
19
+ 1. **Read the profile.** `scripts/capture-profile.sh <@> <out_dir>` (out_dir under `_wizz-output/`) saves `profile.png` and `profile.json` (NAME, bio and link as text, follower and post counts). **Open the image.** Logged out, Instagram may hide highlights, the category label and the pin marks: ask for a screenshot of those parts instead of guessing them.
20
+ 2. **Pull what the Method already knows**, before judging:
21
+ - Positioning, audience and tone from the project's Cérebro (`/cerebro ver`).
22
+ - Highlights already made in the project (for example a `posts/highlights/` folder).
23
+ - The offer from `wizz-offer-forge`, when one exists: the link and one pin depend on it.
24
+ - Real performance: with Buffer connected, `get_aggregated_post_metrics` and the post list give the best posts by saves, shares and reach. Without it, ask which posts did best; never pick pins by guess.
25
+ 3. **Score the nine parts** (table below): passa / ajustar / reprova, one line of reason each.
26
+ 4. **Rewrite what fails**, in order of impact: NAME, bio, pins first.
27
+ - **NAME** = name + the word people type in search, up to 30 characters ("Ana Souza | Nutrição"). The NAME field is what Instagram search indexes, not the @.
28
+ - **Bio** up to 150 = who it helps + what it posts about + one proof or specific. Lead with what the follower gets, not the job title. One anchor emoji at most; line breaks are fine.
29
+ - **Link**: one, matched to the goal (offer, booking, newsletter); a link hub only when several are really needed.
30
+ - **Category** (business or creator account): one label that reinforces the bio.
31
+ - **Highlights**: 4 to 6, left to right in the order of the visitor's next question (Comece aqui, Resultados, Oferta, Dúvidas, Sobre), names short enough to show whole, covers in one style.
32
+ - **First nine**: judged as a set (consistent look, readable at a glance, range without chaos); say which tiles to move or replace.
33
+ - **Pins** (up to 3), by goal: a top performer, the offer, a "pra quem é" post.
34
+ 5. **Check every rewrite**: `node scripts/limits.mjs --bio "..." --name "..." [--handle "..."] [--highlight "..."]`. It fails on bio over 150, NAME over 30, a NAME with no search word, an @ with invalid characters, a highlight name that gets cut, an em dash, or AI words. Nothing is delivered until it passes. Then run bio and NAME through `wizz-humanizer`.
35
+ 6. **Header test.** Reading only photo + NAME + bio + link + first grid row: would a stranger know who this is for and follow? Answer yes or no, and why.
36
+
37
+ ## Scorecard
38
+
39
+ | # | Part | Passes when |
40
+ |---|---|---|
41
+ | 1 | Foto | face (or mark) fills the circle, recent, high contrast, readable small |
42
+ | 2 | NOME | name + search word, up to 30 |
43
+ | 3 | @ | short, matches the brand, no numbers or underscores when avoidable |
44
+ | 4 | Bio | value + topic + proof in up to 150, no cliché opener, no emoji storm |
45
+ | 5 | Link | one, goal-matched; the top link carries the click |
46
+ | 6 | Categoria | set, one niche label that reinforces the bio |
47
+ | 7 | Destaques | 4 to 6, ordered by the visitor's next question, one cover style, names not cut |
48
+ | 8 | 9 primeiras | consistent look, readable, shows range; weak tiles moved or replaced |
49
+ | 9 | Fixados | up to 3, each the best proof for the goal, chosen by metrics |
50
+
51
+ ## Delivery
52
+
53
+ ```
54
+ 👤 PERFIL LIDO: @ · seguidores · posts · objetivo · como foi lido (captura / print)
55
+ 📊 PLACAR: 9 linhas, passa | ajustar | reprova + motivo
56
+ 🔧 CORREÇÕES POR IMPACTO: lista curta
57
+ ✍️ ANTES → DEPOIS: NOME, bio, link, categoria (só o que reprovou), com a contagem do limits.mjs
58
+ ⭐ DESTAQUES: ordem, nomes, o que vai em cada um
59
+ 📌 FIXADOS: 3 posts + por quê (métrica)
60
+ 🧪 TESTE DO CABEÇALHO: sim/não + motivo
61
+ ```
62
+
63
+ ## Hand-off
64
+
65
+ - Highlight covers and the pinned posts' art: `wizz-canvas-design`.
66
+ - Captions of the pinned posts: `wizz-social-content`.
67
+ - The offer behind the link: `wizz-offer-forge`.
68
+
69
+ ## Hard rules
70
+
71
+ - Never ship a bio or NAME that fails `limits.mjs`, and never a truncated highlight name.
72
+ - Never invent proof for the bio (a number, a client count, a result): ask, or leave a slot.
73
+ - Never log in to Instagram on the user's behalf; a logged-out capture plus their screenshots is enough.
74
+ - Highlights and grid are judged as sets: fix order and consistency, not only single items.
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env bash
2
+ # Captures a public Instagram profile as a logged-out visitor sees it, with agent-browser.
3
+ # Usage: capture-profile.sh <@handle or handle> <out_dir>
4
+ # → <out_dir>/profile.png (phone-width, header + first rows of the grid)
5
+ # <out_dir>/profile.json (page title, meta description with counts, header text: NAME, bio, link)
6
+ # Logged out, Instagram may hide highlights, the category label and the pin marks: ask for a
7
+ # screenshot of those. Exit 2 = usage or missing tool; 1 = page did not load.
8
+ set -euo pipefail
9
+ [ $# -eq 2 ] || { echo "uso: capture-profile.sh <@perfil> <pasta de saída>" >&2; exit 2; }
10
+ handle="${1#@}"; out="$2"
11
+ [[ "$handle" =~ ^[A-Za-z0-9._]{1,30}$ ]] || { echo "@ inválido: $1" >&2; exit 2; }
12
+ command -v agent-browser >/dev/null || { echo "falta agent-browser no PATH (skill wizz-agent-browser)" >&2; exit 2; }
13
+ mkdir -p "$out"
14
+ trap 'agent-browser close >/dev/null 2>&1 || true' EXIT
15
+
16
+ agent-browser set viewport 430 1400 >/dev/null
17
+ agent-browser open "https://www.instagram.com/$handle/" >/dev/null
18
+ agent-browser wait 3000 >/dev/null
19
+ # Cookie banner (pt or en), then Escape closes the sign-up prompt that covers the grid.
20
+ agent-browser find text "Recusar cookies opcionais" click >/dev/null 2>&1 \
21
+ || agent-browser find text "Decline optional cookies" click >/dev/null 2>&1 || true
22
+ agent-browser wait 1500 >/dev/null
23
+ agent-browser press Escape >/dev/null 2>&1 || true
24
+ agent-browser wait 800 >/dev/null
25
+
26
+ agent-browser eval 'JSON.stringify({
27
+ title: document.title,
28
+ description: document.querySelector("meta[property=\"og:description\"]")?.content ?? null,
29
+ header: document.querySelector("header")?.innerText ?? null
30
+ })' > "$out/profile.raw"
31
+ node -e '
32
+ const fs = require("node:fs");
33
+ const [raw, out] = process.argv.slice(1);
34
+ let data = JSON.parse(fs.readFileSync(raw, "utf8"));
35
+ if (typeof data === "string") data = JSON.parse(data);
36
+ if (!data.header) { console.error("perfil não carregou (privado, inexistente ou bloqueado)"); process.exit(1); }
37
+ fs.writeFileSync(out, JSON.stringify(data, null, 1));
38
+ ' "$out/profile.raw" "$out/profile.json"
39
+ rm -f "$out/profile.raw"
40
+ agent-browser screenshot "$out/profile.png" >/dev/null
41
+ echo "ok: $out/profile.json + profile.png"
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env node
2
+ // Checks Instagram profile text against the platform limits and the Wizz text rules.
3
+ // node limits.mjs --bio "<text>" --name "<text>" [--handle "<text>"] [--highlight "<name>" ...] [--json]
4
+ // Exit 0 = everything fits; 1 = something fails (listed); 2 = usage.
5
+ // Counting is conservative: UTF-16 units, so an emoji counts as 2. Instagram's own counter may be
6
+ // more lenient; a text that passes here fits there.
7
+
8
+ const LIMITS = { bio: 150, name: 30, handle: 30 };
9
+ // Not a platform limit: above this a highlight name gets cut under the circle on most phones.
10
+ const HIGHLIGHT_VISIBLE = 15;
11
+ const AI_WORDS = /\b(alavanc\w*|fundamentalmente|potencializ\w*|eleve|elevar|revolucion\w*|game[- ]changer|leverage|elevate)\b/i;
12
+ const EM_DASH = /—/;
13
+ const HANDLE_CHARS = /^[A-Za-z0-9._]+$/;
14
+
15
+ function parse(argv) {
16
+ const options = { highlights: [], json: false };
17
+ for (let i = 0; i < argv.length; i++) {
18
+ const flag = argv[i];
19
+ if (flag === '--json') options.json = true;
20
+ else if (flag === '--highlight') options.highlights.push(argv[++i] ?? '');
21
+ else if (['--bio', '--name', '--handle'].includes(flag)) options[flag.slice(2)] = argv[++i] ?? '';
22
+ else usage(`unknown argument: ${flag}`);
23
+ }
24
+ if (options.bio === undefined && options.name === undefined && options.handle === undefined && options.highlights.length === 0) {
25
+ usage('nothing to check');
26
+ }
27
+ return options;
28
+ }
29
+
30
+ function usage(message) {
31
+ process.stderr.write(`limits: ${message}\nusage: node limits.mjs --bio "..." --name "..." [--handle "..."] [--highlight "..."] [--json]\n`);
32
+ process.exit(2);
33
+ }
34
+
35
+ const graphemes = (text) => [...new Intl.Segmenter('pt-BR', { granularity: 'grapheme' }).segment(text)].length;
36
+
37
+ function checkField(field, text, limit) {
38
+ const problems = [];
39
+ if (text.length > limit) problems.push(`${text.length} caracteres (limite ${limit}, emoji conta 2)`);
40
+ if (EM_DASH.test(text)) problems.push('travessão (—) em texto público');
41
+ const ai = text.match(AI_WORDS);
42
+ if (ai) problems.push(`palavra de IA: "${ai[0]}"`);
43
+ return { field, text, length: text.length, graphemes: graphemes(text), limit, ok: problems.length === 0, problems };
44
+ }
45
+
46
+ function check(options) {
47
+ const results = [];
48
+ if (options.bio !== undefined) results.push(checkField('bio', options.bio, LIMITS.bio));
49
+ if (options.name !== undefined) {
50
+ const name = checkField('nome', options.name, LIMITS.name);
51
+ if (!/[|·,\-]/.test(options.name) && options.name.trim().split(/\s+/).length < 3) {
52
+ name.problems.push('NOME sem palavra-chave de busca (ex.: "Ana Souza | Nutrição")');
53
+ name.ok = false;
54
+ }
55
+ results.push(name);
56
+ }
57
+ if (options.handle !== undefined) {
58
+ const handle = checkField('@', options.handle.replace(/^@/, ''), LIMITS.handle);
59
+ if (!HANDLE_CHARS.test(handle.text)) {
60
+ handle.problems.push('@ só aceita letras, números, ponto e sublinhado');
61
+ handle.ok = false;
62
+ }
63
+ results.push(handle);
64
+ }
65
+ for (const highlight of options.highlights) {
66
+ const result = checkField('destaque', highlight, HIGHLIGHT_VISIBLE);
67
+ result.problems = result.problems.map((p) => p.replace(/\(limite \d+, emoji conta 2\)/, `(acima de ${HIGHLIGHT_VISIBLE} corta embaixo do círculo)`));
68
+ results.push(result);
69
+ }
70
+ return results;
71
+ }
72
+
73
+ const options = parse(process.argv.slice(2));
74
+ const results = check(options);
75
+ if (options.json) process.stdout.write(`${JSON.stringify(results, null, 2)}\n`);
76
+ else {
77
+ for (const r of results) {
78
+ const mark = r.ok ? 'ok ' : 'ERRO';
79
+ process.stdout.write(`${mark} ${r.field}: ${r.length}/${r.limit}${r.problems.length ? ' · ' + r.problems.join(' · ') : ''}\n`);
80
+ }
81
+ }
82
+ process.exit(results.every((r) => r.ok) ? 0 : 1);
@@ -16,6 +16,10 @@ Check for `{output_folder}/design-state.yaml` (default `_wizz-output/`). Cheap c
16
16
  - **It does not exist, and the work is non-trivial:** invoke `skill:wizz-design-needs` first. Mining without a map is how a project ends up depending on the user to name every effect, one request at a time.
17
17
  - **It does not exist, and the work is one isolated component the user named:** proceed, and say the map was not created.
18
18
 
19
+ ## Gate 0.5: open the access (always, before the first search)
20
+
21
+ Read [web-access-and-evidence](references/web-access-and-evidence.md) and run its Step 0: load the web tools (on Claude Code, WebSearch and WebFetch are deferred and need `ToolSearch`), then fall back to `curl`, `agent-browser` and the local source cache. No web and no cache means BLOCKED, never research from memory. Before delivering, every recommended component passes that file's evidence gate; the rest are UNVERIFIED and are never recommended.
22
+
19
23
  ## Gate 1: Source-First (always, before any UI code)
20
24
 
21
25
  This skill exists because writing shaders, animations, hovers, and components from scratch is NOT the way. The way is to curate mature components, animations, and shaders from professional sources (the user's `modelos lp/`, React Bits, Cult UI, Ali Imam, Watermelon, StyleUI, Skiper UI, Componentry, and public registries) and adapt them to the brand.
@@ -64,5 +68,6 @@ Classify the project into one of 5 levels (rules, allowed/forbidden motion, and
64
68
  | Base prompts (complete landing page and 3D scroll hero) | [prompt-templates](references/prompt-templates.md) |
65
69
  | Final response format, Quality Bar, and self-check before closing the delivery | [output-format-and-quality](references/output-format-and-quality.md) |
66
70
  | Direct links to every authorized source | [source-links](references/source-links.md) |
71
+ | Opening web access before mining, BLOCKED, and the evidence gate before delivering | [web-access-and-evidence](references/web-access-and-evidence.md) |
67
72
 
68
73
  Final rule: never put real keys inside the skill (environment variables only), and never deliver a landing page that looks like a template with no positioning.
@@ -11,7 +11,7 @@ Research flow (public sources first; log evidence per [source-first-protocol](so
11
11
  3. public shadcn registries;
12
12
  4. taste/motion sources (Impeccable, Taste Skill, Design Motion Principles, MotionSites, Vibe Code Components, Refero Styles with a free DESIGN.md);
13
13
  5. open visual sources (Landing Love, Godly, Design Spells, Mobbin, Refero, ScreensDesign, DesignVault, Spline, Unicorn Studio);
14
- 6. coherent strategic hypotheses, when there is no external access.
14
+ 6. with no web and no local cache: BLOCKED, per [web-access-and-evidence](web-access-and-evidence.md). Strategic hypotheses can shape the direction, never stand in for a component source.
15
15
 
16
16
  ## Mining Evidence
17
17
 
@@ -56,7 +56,7 @@ Log in the existing design artifact (or create `design-research.md` in the proje
56
56
  |---|---|---|---|---|---|---|
57
57
  | Item actually inspected | Terms used and catalog | Real URLs or paths | SHA/tag; date if there's no version | Verified or pending | Tested / static / unavailable | Accepted/rejected and reason |
58
58
 
59
- Also include searches with no results and unavailable sources. Never fill in component names, paths, license, or test results by assumption.
59
+ Also include searches with no results and unavailable sources. Never fill in component names, paths, license, or test results by assumption. A row missing any of the five fields in [web-access-and-evidence](web-access-and-evidence.md) is UNVERIFIED and cannot be the recommendation.
60
60
 
61
61
  Show 1-3 compatible candidates per component, with a recommendation and adaptation cost. If the user has already authorized the implementation and defined the direction, choose the best option within that scope and proceed. Only ask when a material decision about direction, paid access, or scope change is missing.
62
62
 
@@ -0,0 +1,40 @@
1
+ # Web access and evidence gate
2
+
3
+ Shared by `wizz-premium-landing-ui-researcher` and `wizz-ui-component-curator`. Read it before the first search. It covers two moments: opening access before mining, and checking evidence before delivering.
4
+
5
+ Mining from memory is the failure this file exists to prevent. Component names, URLs, licenses and APIs the model "remembers" are hypotheses, and a hypothesis delivered as research is worse than no research: the user builds on it without knowing.
6
+
7
+ ## Step 0: open the access (before any query)
8
+
9
+ A tool you do not see is not a tool you do not have. In a subagent, the web tools often start unloaded.
10
+
11
+ 1. **Load the web tools.** On Claude Code, WebSearch and WebFetch are deferred: load them with `ToolSearch` (`select:WebSearch,WebFetch`) before deciding they are missing. Do the same for an Exa or scrapling MCP if the session lists one. On other platforms, use that platform's native web search and fetch.
12
+ 2. **Fallbacks, in order:** `curl -sL <url>` through the shell (raw HTML, registry JSON, `raw.githubusercontent.com` source files), then `agent-browser` (also the tool for watching hover and motion live).
13
+ 3. **Local source cache:** `~/.claude/design-sources/` holds real repositories (React Bits, Cult UI, Ali Imam, Watermelon, StyleUI). Reading a file there counts as evidence, as long as you record the path and the revision (`git -C <repo> rev-parse --short HEAD`) and say the cache may be behind the remote.
14
+ 4. **Record the outcome** in one line before mining: which access worked (`web`, `curl`, `agent-browser`, `cache only`) and which failed, with the error.
15
+
16
+ If none of the four works, stop and return:
17
+
18
+ ```text
19
+ BLOCKED: no web access and no local source cache.
20
+ Tried: <tool → error, one per line>
21
+ Unblock: <what the user can do, e.g. enable WebFetch, install agent-browser, clone the sources into ~/.claude/design-sources/>
22
+ ```
23
+
24
+ BLOCKED is a complete, correct answer. Do not deliver component recommendations instead of it, not even marked "(verify)". Direction work that needs no source (site level, motion budget, style read of the project) can still be delivered next to BLOCKED, labelled as such.
25
+
26
+ ## Evidence gate (before delivering)
27
+
28
+ Every candidate needs all five, collected in this session:
29
+
30
+ | Field | Counts | Does not count |
31
+ |---|---|---|
32
+ | URL or path | The exact demo and the exact source file or registry item you opened | A catalog homepage, a search snippet, a URL you did not open |
33
+ | Date | Today's date or the repo revision (SHA/tag) | "recent", "current" |
34
+ | License | Read in the repo or registry | Assumed from the catalog's reputation |
35
+ | Dependencies | Read from the actual imports or registry JSON | Guessed from the component's name |
36
+ | Source read | The code file was opened and its imports checked | The demo alone |
37
+
38
+ A candidate missing any field is **UNVERIFIED**. UNVERIFIED items go in a separate section of the report, with what is missing and why. They are never recommended and never placed in the top 1-3, and the implementation plan never depends on them. If every candidate for a need is UNVERIFIED, the need is reported as `unmet`, not filled.
39
+
40
+ Before closing, check the delivery against this gate once: every recommended item has its five fields in the research log (`design-research.md` or the project's design artifact), and the access line from Step 0 is in the report.
@@ -55,7 +55,7 @@ Use this table to map skills/CLIs/MCPs directly **outside a Wizz project** (no `
55
55
  | **Video with audio, narration, SFX, or synced captions** (film assembly) | `wizz-remotion-best-practices` (Remotion assembles; frame timing). Pipeline rule: HyperFrames draws the mute screens, Remotion assembles the film — don't use hyperframes to position audio/captions (~2.76s drift and CSS leaking between screens in production) | 1 |
56
56
  | Draw a video SCREEN/scene in HTML/CSS, mute visual (app mockup, animated chart, title, loop; HTML→MP4) | CLI `hyperframes` (designer registry; `npx skills add heygen-com/hyperframes`) — mute screens only; assembly with audio goes to Remotion (line above) | 2 |
57
57
  | Word-by-word timestamps for TTS narration (sync captions/cuts/animation with speech) | `ctc-align` (designer registry; single source of timing, replaces Whisper) | 2 |
58
- | Which short-video STYLE to copy, from the inventory of the material (real person, voice only, B-roll, screens, product), with the recipe measured on 99 real shorts; "edit it in the style of", "the video looks amateur" | `wizz-video-styles` (designer registry; picks the style before voice, timing, effects and assembly) | 2 |
58
+ | Which short-video STYLE to copy, from the inventory of the material (real person, voice only, B-roll, screens, product), with the recipe measured on 104 real shorts (lyric video and kinetic typography included); "edit it in the style of", "the video looks amateur" | `wizz-video-styles` (designer registry; picks the style before voice, timing, effects and assembly) | 2 |
59
59
  | Effects and sound of a short vertical video (ad or Reels): which effect goes where and when not, which SFX for each event and at what level, ducking, master loudness, safe-zone/density/excess/rhythm gates | `wizz-video-effects` (designer registry; decides the effects, Remotion assembles them) | 2 |
60
60
  | **Find B-roll / inserts / cutaways / supporting footage** for a video or Reel (real footage of the fact, person, product, news item or screen the script names; YouTube/Instagram/TikTok/Pexels/Pixabay/Commons/NASA) | CLI `get-brolls` (designer registry; **macOS**, global `skills add` + its own `install.sh`; needs ffmpeg with drawtext, Node 22+, Python 3.11+). Ends in a Storyboard the HUMAN approves — the agent never self-approves. Stock only when the user explicitly asks for stock | 1 |
61
61
  | **Edit/cut video** (cuts, selects, roughcut) | CLI `buttercut` (designer registry; **Apple Silicon only**, clone-and-run in the project, heavy deps) | 1 |
@@ -84,6 +84,8 @@ Use this table to map skills/CLIs/MCPs directly **outside a Wizz project** (no `
84
84
  | EXECUTE the SEO distribution: publish articles, build backlinks through the Distribb network, connect Search Console, autopublish news | CLI `distribb` (seo registry) — the doing half; the strategy half is the SEO row above | 2 |
85
85
  | Competitor comparison, alternatives page, war room | `wizz-competitor-alternatives` | 2 |
86
86
  | Content, social media, newsletter, threads | `wizz-content-strategy` + `wizz-social-content` + `wizz-copy-editing` | 2 |
87
+ | Tear down ONE viral Instagram post (Reel, carousel, caption) from its link: why it worked, which hook, a mould to do one like it | `wizz-hook-extractor` (social registry; reads the post itself) | 2 |
88
+ | Audit and rewrite an Instagram PROFILE: bio, search NAME, link, highlights, pinned posts | `wizz-ig-profile-optimizer` (social registry) | 2 |
87
89
  | Actually PUBLISH/schedule to social networks (Instagram, TikTok, YouTube, LinkedIn and more), not write it | CLI `buffer` (social registry; needs `BUFFER_API_KEY`; media must be a public HTTPS URL). Separates "generate" (Wizz skills above) from "publish" | 2 |
88
90
  | Cold email, B2B outbound, prospecting | `wizz-cold-email` | 2 |
89
91
  | Referral, referrals, affiliate program | `wizz-referral-program` | 2 |
@@ -21,7 +21,7 @@ If `{output_folder}/design-state.yaml` exists, the need being worked is already
21
21
 
22
22
  Not there? Look before deciding it does not exist: `find . -name design-state.yaml -not -path '*/node_modules/*'`. A map found anywhere else is still the map: use it, and tell the user it is off-place (it belongs in `{output_folder}`).
23
23
 
24
- With no state file, continue normally.
24
+ With no state file and more than one need in the request (a polish pass, "effects and animations", a dashboard), run `wizz-design-needs` first and mine against the map it writes. With no state file and one isolated component the user named, continue, and say the map was not created.
25
25
 
26
26
  ## 1. Read and infer the style DNA
27
27
 
@@ -42,7 +42,7 @@ Do not ask the user to describe the style unless the project has no inspectable
42
42
 
43
43
  Start with existing project components. Then search the public sources. The full authorized list (React Bits, Cult UI, Ali Imam, Watermelon, StyleUI, Skiper UI, Bklit UI, Componentry, shadcn/ui, plus the reference galleries) lives in one place: [component-sources](../wizz-premium-landing-ui-researcher/references/component-sources.md). Read it instead of relying on memory. Compare at least two suitable sources per need.
44
44
 
45
- Use whatever search tools the session has: web search (Exa when configured, WebSearch otherwise), WebFetch, scrapling, and `agent-browser` to watch hover and motion live. A tool that errors or hangs is not the end of the research: record the failure, move to the next tool, and never stop without reporting what was and was not checked.
45
+ Before the first query, open the access as described in [web-access-and-evidence](../wizz-premium-landing-ui-researcher/references/web-access-and-evidence.md): load the web tools (on Claude Code, WebSearch and WebFetch are deferred and need `ToolSearch`), then fall back to `curl`, `agent-browser` and the local source cache. Search with whatever that step opened: web search (Exa when configured, WebSearch otherwise), WebFetch, scrapling, and `agent-browser` to watch hover and motion live. A tool that errors or hangs is not the end of the research: record the failure, move to the next tool, and never stop without reporting what was and was not checked. With no web and no cache, return BLOCKED instead of recommending from memory.
46
46
 
47
47
  Open the exact demo and source file/registry item. Check the actual imports, license, dependencies, stack variant and revision; use current official documentation (Context7 when available) for API compatibility. Inspect animation/interaction in the available browser; label static-only inspection honestly. If a source fails, record the failure and continue elsewhere.
48
48
 
@@ -57,6 +57,8 @@ Use the inferred style DNA as the search filter. Prefer:
57
57
 
58
58
  Do not present unranked lists. Shortlist internally, then surface only the strongest matches.
59
59
 
60
+ Only candidates that pass the evidence gate in [web-access-and-evidence](../wizz-premium-landing-ui-researcher/references/web-access-and-evidence.md) can be shown here. The rest are UNVERIFIED and go to the evidence section.
61
+
60
62
  For each candidate, say briefly:
61
63
  - why it fits
62
64
  - what role it plays
@@ -131,4 +133,4 @@ Up to 2 backup options only if genuinely different and useful.
131
133
  What changes, which files, any dependency or adaptation work.
132
134
 
133
135
  ## Research evidence
134
- Exact candidate demo/source links, revision/date, license and dependencies, visual inspection status, decisions and unavailable sources. State what still needs a user decision.
136
+ The access line (what worked, what failed), then exact candidate demo/source links, revision/date, license and dependencies, visual inspection status, decisions and unavailable sources. UNVERIFIED items listed apart, with what is missing. State what still needs a user decision.
@@ -10,6 +10,7 @@ A catalogue of effects is easy. What makes a video look professional is the **re
10
10
  ## Where it sits in the video pipeline
11
11
 
12
12
  1. Script and narration exist; `ctc-align` gave word-by-word timestamps.
13
+ On a music-driven piece (lyric video over a song) the song is the narration: `scenes[]` start on the downbeats from `wizz-video-styles/scripts/beat_grid.py`, and the song's own hits count as the SFX budget already spent.
13
14
  2. Screens were drawn silent (HyperFrames) or footage was sourced.
14
15
  3. **This skill:** events → SFX and levels → effects anchored on breaths → budget → timeline JSON → (render in Remotion) → gates on the final MP4.
15
16
  4. Remotion assembles from the timeline JSON. For the `<Audio>` and `<Sequence>` API, invoke the `wizz-remotion-best-practices` skill.