framejs
O framejs executa um módulo JavaScript ES6 no navegador. Um frame é o aplicativo: ele reside em uma URL estável e compartilhável framejs.app/j/<uuid> cujo conteúdo é mutável — você atualiza o aplicativo no local enviando seus parâmetros hash via POST. Seu trabalho: transformar a solicitação do usuário nesse JavaScript de navegador e entregá-lo da maneira correta para seu ambiente.
Escolha seu modo de entrega
Escolha com base no que você pode fazer — não na solicitação:
- Modo automação — você pode executar um shell /
node: gere o JavaScript, depois crie-ou-atualize o frame framejs.app da sessão, imprima sua URL/j/<uuid>e abra no navegador. Este é o padrão sempre que um shell estiver disponível. - Modo bloco de código — apenas chat / API, sem shell: responda apenas com um único bloco de código JavaScript delimitado (abra com uma string de informação
javascript) e nada mais — sem prosa ao redor, sem arquivos, sem URLs. O usuário cola no editor em framejs.io.
Em ambos os modos, o JavaScript que você escreve segue as mesmas regras — leia references/coding-guide.md.
O que a solicitação pode ser
- Criar a partir de um prompt — "uma animação de bola quicando", "plotar y = sin(x)".
- Modificar um aplicativo existente — a solicitação contém uma URL de frame. Pode ser uma URL
https://framejs.app/j/<uuid>ouhttps://framejs.io/j/<uuid>?token=...(a ação "Copiar frame para sessão de IA" copia o formulário de runtime do framejs.io), um ID hexadecimal de 32 caracteres puro, ou uma URLhttps://framejs.io/j/<sha256>/ ID de 64 caracteres legada. Sempre que você vir uma URL framejs, extraia o uuid do caminho/j/<uuid>e aponte para AQUELE frame (passe a URL diretamente para--id— o helper roteia a atualização para a camada do aplicativo mesmo para URLs framejs.io). Você DEVE buscar o código existente primeiro e modificá-lo — veja references/short-url-api.md (§ Modificar). Se a URL tiver um parâmetro de consulta?token=<key>(da ação "Copiar frame para sessão de IA" do aplicativo), passe a URL inteira para--id(ou a chave para--token): o helper a armazena e a envia como credencial bearer para que suas atualizações continuem funcionando mesmo após o proprietário do frame tê-lo reivindicado. Passar a URL inteira também aponta para o backend que a URL nomeia — então uma URL de frame de desenvolvimento ou auto-hospedado (ex:https://framejs-app.localhost:13747/j/<uuid>?token=<key>) atualiza sua própria pilha sem nenhum ambiente pré-configurado.--app-origin <url>/--io-origin <url>definem o backend explicitamente. Veja references/short-url-api.md (§ Origens locais / dev). - Visualizar arquivos locais — a solicitação referencia caminhos de arquivo (
./data.csv,/tmp/results.json). Envie-os e passe como entradas — veja references/file-inputs.md.
Modo automação — como entregar
Gere o código, depois use o helper empacotado (preferido) ou o fallback inline-node em references/short-url-api.md:
cat << 'JSCODE' | node scripts/framejs.mjs create --state "${SCRATCHPAD}/framejs-frame.json" --title "<título curto>" --description "<resumo de uma frase>" --screenshot
// seu JavaScript de navegador gerado aqui — $vars, crases, todos os caracteres especiais estão seguros dentro do heredoc
JSCODE
O helper imprime (na saída padrão) duas URLs — a URL da página primária https://framejs.app/j/<uuid> e uma URL de snapshot imutável snapshot: https://framejs.io/j/<sha256>. Ele também imprime (na saída de erro) um aviso de ciclo de vida do link compartilhável que você DEVE repassar ao usuário:
- a página
/j/<uuid>é editável e atualizada ao vivo, mas um frame anônimo (não reivindicado) é temporário e expirará — diga ao usuário para abri-lo e reivindicá-lo (conta gratuita) para mantê-lo permanentemente; - o snapshot
/j/<sha256>é uma cópia imutável do aplicativo atual que expira ~30 dias após a última abertura — um bom link estável de compartilhamento/backup, mas nunca reflete edições posteriores.
Adicione --module <url> para scripts clássicos e --input nome=valor para entradas.
Um frame por sessão, atualizado no local. Sempre passe --state "<caminho em sua área de rascunho>/framejs-frame.json" (qualquer caminho de arquivo gravável). O primeiro create cunha o frame; re-execute create com o mesmo --state para ATUALIZAR o mesmo frame — a URL /j/<uuid> permanece constante e qualquer página framejs.app aberta é atualizada ao vivo, então forneça a URL ao usuário uma vez. Somente quando o usuário quiser um aplicativo separado na mesma sessão, adicione --new para iniciar um novo frame (atualizações subsequentes então apontarão para esse novo). Para atualizar um frame específico independentemente do estado, passe --id <uuid>. Em tal atualização no local, o helper carrega automaticamente os dados Open Graph existentes do frame quando você não passa --og/--title/--description, então uma reexecução simples nunca remove o título/descrição (e o og.image retido evita uma recaptura de tela redundante). Passe --title/--description novamente apenas para alterar o texto de pré-visualização.
O navegador abre automaticamente apenas na primeira vez que um frame é cunhado (--no-open para pular até isso). Uma atualização posterior para o mesmo frame — mesmo --state, ou um --id explícito — NÃO reabre o navegador: a página já aberta o alcança ao vivo através da assinatura do mesmo frame, então abrir novamente apenas criaria uma nova aba redundante.
Se um checkout de desenvolvimento local estiver presente, o helper carrega automaticamente seu .env e aponta para as pilhas de desenvolvimento (FRAMEJS_APP_ORIGIN / FRAMEJS_IO_ORIGIN) em vez da produção — nenhuma ação necessária de sua parte.
Se o helper imprimir um aviso de atualização desatualizado (na saída de erro, no máximo a cada hora), repasse-o ao usuário textualmente uma vez — a skill instalada deles está desatualizada e o aviso informa o comando para atualizá-la.
Sempre passe --screenshot: o helper renderiza o aplicativo finalizado e armazena a captura como a pré-visualização og:image. É autoprotetor — captura APENAS quando o aplicativo ainda não tem og.image, então nunca sobrescreve uma imagem que uma execução anterior (ou o usuário) já definiu, e silenciosamente cai para a URL sem imagem se nenhum renderizador estiver disponível. A captura prefere Playwright quando pode ser importado (espera de rede ociosa verdadeira — melhor para aplicativos que buscam entradas), e caso contrário usa headless Chrome do sistema. Playwright é opcional: instale-o (npm i -g playwright && npx playwright install chromium) para o caminho mais confiável, ou aponte $FRAMEJS_PLAYWRIGHT para um diretório cujo node_modules o tenha. Ajuste com --screenshot-wait <ms> (padrão 6000 — aumente para aplicativos que carregam lentamente) e --screenshot-size <w,h> (padrão 1200,630). Substitua o binário do Chrome com $CHROME_PATH.
scripts/framejs.mjs é resolvido relativo ao diretório desta skill, não ao seu diretório de trabalho atual — execute-o da pasta da skill, ou use seu caminho absoluto (Claude Code expõe esse diretório como ${CLAUDE_SKILL_DIR}, então ${CLAUDE_SKILL_DIR}/scripts/framejs.mjs sempre funciona). Se você não conseguir localizar ou executar o helper empacotado, use o fallback inline-node em references/short-url-api.md — ele não precisa de arquivo de script.
Sempre inclua tags de pré-visualização Open Graph para que o link seja exibido corretamente ao ser compartilhado — veja as regras OG em references/short-url-api.md:
- Novo aplicativo: derive texto novo com
--title/--description, e passe--screenshotpara capturar a imagem de pré-visualização. - Modificando um aplicativo existente: o aplicativo buscado já carrega
og(o comandofetcho retorna). NÃO recalcule — passe o objeto buscado de volta diretamente com--og '<o JSON og buscado>', que preserva todos os campos (incluindoimage). Atualize o MESMO frame com--id <uuid>(ou o mesmo--state). Defina novos--title/--descriptionapenas se o usuário pediu explicitamente para alterar o texto de pré-visualização. Você ainda pode passar--screenshot: se oogbuscado já tiver umaimage, ela é deixada intacta; se não tiver nenhuma, uma nova captura é adicionada.
Regras absolutas (ambos os modos)
- JavaScript de navegador apenas — ele executa em um iframe, NÃO Node.js.
- DEVE usar sintaxe de módulo ES6:
export function onInputs(inputs) {}. - NUNCA crie arquivos HTML. NUNCA escreva arquivos
.jslocais. NUNCA use suas próprias ferramentas de visualização/renderização/widget para renderizar o resultado. - NUNCA modifique
root.style.position,root.style.heightouroot.style.width. - IMPORTANTE: a visualização DEVE ter boa aparência em dispositivos móveis e se adaptar ao tamanho da tela — use dimensionamento responsivo (leia as dimensões de
root/ escute redimensionamento), evite larguras fixas em pixels que transbordem, mantenha texto e alvos de toque legíveis em telas pequenas. - No modo automação, NUNCA produza um bloco de código para o usuário copiar e NUNCA construa manualmente uma URL hash longa como resultado — sempre POST através da API de frame (o
createdo helper). Dê ao usuário a URL da página/j/<uuid>. - No modo bloco de código, produza APENAS o bloco de código JavaScript delimitado — nada mais.
Referências
- references/coding-guide.md — globais, exportações, padrões, bibliotecas CDN, erros comuns.
- references/short-url-api.md — criar/atualizar um frame (
POST /j/<uuid>.json), estado de um frame por sessão, tags Open Graph, tokens de API (continuar atualizando após um frame ser reivindicado), fallbacks inline. - references/file-inputs.md — enviar arquivos locais e conectá-los como entradas.
scripts/framejs.mjs— helper Node:create(stdin JS → frame framejs.app),fetch <id>,upload <caminho>. Origens:FRAMEJS_APP_ORIGIN/FRAMEJS_IO_ORIGIN(carregado automaticamente de um.envpróximo em desenvolvimento local), ou por execução via--app-origin/--io-originou a origem de uma URL de frame completa passada para--id/fetch.