Menu "Criar com IA" (Ao vivo › Gestos e Reações) com grade igual à dos favoritos. Para cada pedido escolhe-se o tipo (expressão, atividade ou figurinha) e a IA: Gemini, IA local (qualquer servidor compatível com OpenAI na rede, como o ROG Ally com LM Studio/llama-server) ou o Qwen do S10. - A IA não escreve código: responde uma receita de formato fixo (schema JSON) montada só com peças que o rosto já anima. O servidor valida, limita números e descarta peças desconhecidas antes de chegar ao celular. - Reaproveita o que existe: o prompt leva exemplos reais dos gestos e atividades atuais, e "Basear em" manda a receita de um gesto, atividade ou criação para a IA fazer uma variação. - Expressões viram sequências como as de sequencias(), com mãos e espiral. - Atividades usam uma cena genérica com o bonequinho (poses, pernas, pulo, balanço) e os objetos das cenas feitas à mão (bola, livro, xícara, notas, estrelas, coração, Zzz, chama, bolha, halter, microfone, controle, pincel, flor), com movimentos pular/girar/subir/orbitar. - Figurinhas reaproveitam o desenho e a biblioteca de reações. - A estrela põe expressões e atividades criadas nos favoritos (e nas teclas 1 a 9); a IA local é configurada na própria tela, com teste. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
120 lines
3.2 KiB
Svelte
120 lines
3.2 KiB
Svelte
<script lang="ts">
|
||
import { Star } from '@lucide/svelte';
|
||
import { favoritos, GESTOS_INFO, gestosDisponiveis, tocarFavorito } from '../comandos.svelte';
|
||
import { criacao } from '../criacao.svelte';
|
||
|
||
// compacto: só os favoritos com atalho 1–9 (dock), inclusive criações do estúdio. Completo: todos, com estrela.
|
||
let { completo = false }: { completo?: boolean } = $props();
|
||
$effect(() => {
|
||
if (!completo && !criacao.status && favoritos.lista.some((g) => g.startsWith('criado:'))) criacao.carregar();
|
||
});
|
||
function infoDe(g: string) {
|
||
if (g.startsWith('criado:')) {
|
||
const c = criacao.item(Number(g.slice(7)));
|
||
return c ? { nome: c.nome, emoji: c.emoji } : null;
|
||
}
|
||
return GESTOS_INFO[g] ?? null;
|
||
}
|
||
const lista = $derived(completo ? gestosDisponiveis() : favoritos.lista.filter((g) => infoDe(g)));
|
||
</script>
|
||
|
||
<div class="gestos" class:completo>
|
||
{#each lista as g, i (g)}
|
||
{@const info = infoDe(g)!}
|
||
<div class="item">
|
||
<button class="gesto" class:criado={g.startsWith('criado:')} onclick={() => tocarFavorito(g)} title={completo || i > 8 ? info.nome : `${info.nome} (tecla ${i + 1})`}>
|
||
<span class="emoji" aria-hidden="true">{info.emoji}</span>
|
||
<span class="nome">{info.nome}</span>
|
||
{#if !completo && i < 9}<kbd>{i + 1}</kbd>{/if}
|
||
</button>
|
||
{#if completo}
|
||
<button
|
||
class="estrela"
|
||
class:ativa={favoritos.lista.includes(g)}
|
||
aria-label={favoritos.lista.includes(g) ? `Tirar ${info.nome} dos favoritos` : `Fixar ${info.nome} nos favoritos`}
|
||
aria-pressed={favoritos.lista.includes(g)}
|
||
onclick={() => favoritos.alternar(g)}
|
||
>
|
||
<Star size={14} />
|
||
</button>
|
||
{/if}
|
||
</div>
|
||
{/each}
|
||
</div>
|
||
|
||
<style>
|
||
.gestos {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(92px, 1fr));
|
||
gap: var(--e-2);
|
||
}
|
||
.item {
|
||
position: relative;
|
||
}
|
||
.gesto {
|
||
width: 100%;
|
||
display: grid;
|
||
justify-items: center;
|
||
gap: 2px;
|
||
padding: var(--e-3) var(--e-1) var(--e-2);
|
||
border: 1px solid var(--borda);
|
||
border-radius: var(--raio);
|
||
background: var(--superficie-2);
|
||
color: var(--texto);
|
||
font: inherit;
|
||
cursor: pointer;
|
||
position: relative;
|
||
transition: background var(--transicao), border-color var(--transicao), transform var(--transicao);
|
||
}
|
||
.gesto:hover {
|
||
border-color: var(--destaque);
|
||
background: var(--destaque-suave);
|
||
}
|
||
.gesto:active {
|
||
transform: scale(0.97);
|
||
}
|
||
.emoji {
|
||
font-size: 1.6rem;
|
||
line-height: 1.2;
|
||
}
|
||
.nome {
|
||
font-size: var(--t-xs);
|
||
color: var(--texto-2);
|
||
text-align: center;
|
||
}
|
||
.gesto.criado::after {
|
||
content: '✨';
|
||
position: absolute;
|
||
left: 6px;
|
||
top: 4px;
|
||
font-size: 10px;
|
||
}
|
||
kbd {
|
||
position: absolute;
|
||
top: 4px;
|
||
right: 6px;
|
||
font: 500 10px var(--fonte-mono);
|
||
color: var(--texto-3);
|
||
}
|
||
.estrela {
|
||
position: absolute;
|
||
top: 2px;
|
||
right: 2px;
|
||
width: 26px;
|
||
height: 26px;
|
||
display: grid;
|
||
place-items: center;
|
||
border: 0;
|
||
border-radius: 50%;
|
||
background: transparent;
|
||
color: var(--texto-3);
|
||
cursor: pointer;
|
||
}
|
||
.estrela.ativa {
|
||
color: var(--aviso);
|
||
}
|
||
.estrela.ativa :global(svg) {
|
||
fill: currentColor;
|
||
}
|
||
</style>
|