Objetos e criaturas
Crie objetos e criaturas, gere imagens principais e variações, anime-os e faça uma criatura falar em TypeScript com o SDK do Nodaro.
client.objects faz por código tudo o que o Estúdio de objetos/adereços faz com adereços, produtos e veículos, e client.creatures faz o mesmo com animais e criaturas. Os dois criam e editam itens, geram candidatos a imagem principal, aprovam um deles, adicionam variações e clipes de movimento e escrevem uma descrição que mantém o item consistente nos prompts seguintes. Os métodos chamam as APIs REST de Objetos e de Criaturas. Veja Objetos e adereços e Animais e criaturas para a visão do editor.
Métodos
Os dois recursos têm os mesmos métodos.
| Método | O que faz |
|---|---|
objects.list(params?), creatures.list(params?) | Lista os seus itens |
objects.listArchived(params?) | Lista os seus itens arquivados |
objects.get(id) | Lê um item, com os jobs em andamento |
objects.create(input), creatures.create(input) | Cria um item |
objects.update(id, input), creatures.update(id, input) | Altera um item |
objects.delete(id) e restore(id) | Arquiva um item ou o traz de volta |
objects.permanentDelete(id) | Destrói um item arquivado e os arquivos dele |
objects.generate(input), creatures.generate(input) | Gera candidatos a imagem principal |
objects.generateAsset(input), creatures.generateAsset(input) | Gera uma variação |
objects.generateMotion(input), creatures.generateMotion(input) | Anima a imagem principal em um clipe |
objects.approveMainImage(id, candidateJobId, expectedUpdatedAt?) | Define um candidato como a imagem principal |
objects.recaption(id) | Escreve a descrição de novo |
client.objects
Um objeto tem a imagem principal em sourceImageUrl, quatro coleções (angles, materials, variations e motionClips, cada uma uma lista de { name, url }), boards, referencePhotos, canonicalDescription e styleLock. category é furniture, vehicle, weapon, food, clothing, electronics, nature, tool, animal ou other.
Object tem o mesmo nome do objeto global do JavaScript. Quando você precisar dos dois, importe-o com outro nome: import type { Object as NodaroObject } from "@nodaro/sdk".
objects.list(params?)
Lista os seus objetos. Por padrão, retorna só os objetos ativos. A paginação é opcional: sem limit, você recebe a lista inteira; com limit, de no máximo 500, você recebe uma página e um nextCursor.
list(params?: { archived?: boolean; projectId?: string; limit?: number; cursor?: string }): Promise<{
objects: Object[]
nextCursor?: string | null
}>Prop
Type
const { objects } = await client.objects.list()
const page = await client.objects.list({ limit: 100 })objects.listArchived(params?)
Lista os seus objetos arquivados, como um atalho para list({ archived: true }). creatures.listArchived() funciona do mesmo jeito.
listArchived(params?: { projectId?: string; limit?: number; cursor?: string }): Promise<{ objects: Object[]; nextCursor?: string | null }>Prop
Type
const { objects: archived } = await client.objects.listArchived()objects.get(id)
Lê um objeto, com pendingJobs, as variações que ainda estão sendo geradas. Um objeto arquivado não é retornado: a chamada lança NotFoundError. creatures.get() funciona do mesmo jeito.
get(id: string): Promise<ObjectDetail>Prop
Type
const object = await client.objects.get(objectId)
console.log(object.sourceImageUrl, object.materials)objects.create(input)
Cria um objeto. name e nodeId são obrigatórios. Um script sem nó no canvas pode passar "mcp-managed" como nodeId.
create(input: CreateObjectInput): Promise<{ id: string }>Prop
Type
const { id: objectId } = await client.objects.create({
nodeId: "mcp-managed",
name: "Antique Lantern",
description: "Weathered brass lantern with hand-engraved filigree",
category: "tool",
style: "realistic",
})objects.update(id, input)
Altera um objeto. Só os campos que você envia são gravados. As coleções de variações não fazem parte desta chamada, porque os jobs de geração adicionam itens a elas enquanto você trabalha.
update(id: string, input: UpdateObjectInput): Promise<{ id: string; updatedAt: string }>Prop
Type
await client.objects.update(objectId, {
canonicalDescription: "A weathered brass lantern with engraved filigree and a glass chimney",
expectedUpdatedAt: object.updatedAt,
})O 409 concurrent_modification chega como um NodaroError comum. Leia o objeto de novo, mescle as alterações e tente outra vez.
objects.delete(id) e restore(id)
delete() arquiva um objeto. Repetir a chamada em um objeto arquivado não muda nada. restore() traz o objeto de volta; quando o nome agora coincide com o de um objeto ativo, sem diferenciar maiúsculas de minúsculas, o servidor acrescenta (restored) e retorna o nome que usou.
delete(id: string): Promise<{ success: true; archived: true }>
restore(id: string): Promise<{ id: string; name: string }>Prop
Type
await client.objects.delete(objectId)
const { name } = await client.objects.restore(objectId)objects.permanentDelete(id)
Destrói um objeto arquivado e todos os arquivos armazenados que ele referencia. Só funciona em objetos arquivados: um objeto ativo falha com 400 not_archived. Arquive primeiro com delete(). creatures.permanentDelete() funciona do mesmo jeito.
permanentDelete(id: string): Promise<{ success: true; permanent: true }>Prop
Type
await client.objects.delete(objectId)
await client.objects.permanentDelete(objectId)As ferramentas MCP do Nodaro não oferecem esta operação, então um assistente de IA não consegue destruir os seus objetos.
objects.generate(input)
Gera candidatos a imagem principal (POST /v1/generate-object). Com count acima de 1, todos os jobs são reservados antes de qualquer um começar, então uma falha no meio do caminho desfaz o lote inteiro.
generate(input: GenerateObjectInput): Promise<{ jobIds: string[]; jobId?: string }>Prop
Type
const { jobIds } = await client.objects.generate({ name: "Antique Lantern", count: 4 })
for (const jobId of jobIds) {
// poll each candidate with client.jobs.getStatus(jobId)
}jobIds sempre está presente, com um ID por candidato. jobId é um alias antigo para um único candidato; use jobIds. Com attachToObjectId e um único candidato, o resultado vira a imagem principal quando o job é concluído. Caso contrário, escolha um candidato com approveMainImage().
objects.generateAsset(input)
Gera uma variação (POST /v1/generate-object-asset). Com attachToObjectId, attachToColumn e attachName, o resultado é adicionado a essa coleção quando o job é concluído.
generateAsset(input: GenerateObjectAssetInput): Promise<{ jobId: string }>Prop
Type
const { jobId } = await client.objects.generateAsset({
name: "Antique Lantern",
assetType: "materials",
variant: "gold",
attachToObjectId: objectId,
attachToColumn: "materials",
attachName: "gold",
})Para angles, materials, variations e motion, a coleção é definida pelo tipo de variação. Uma variação custom precisa de attachToColumn.
objects.generateMotion(input)
Anima a imagem do objeto em um clipe (POST /v1/generate-object-motion), com o nó Gerar vídeo (Generate Video) no modo de imagem para vídeo. O clipe sempre vai para motionClips. Os padrões são pensados para fotos de produto: o modelo é kling-turbo e o quadro é 1:1.
generateMotion(input: GenerateObjectMotionInput): Promise<{ jobId: string }>Prop
Type
const { jobId } = await client.objects.generateMotion({
name: "Antique Lantern",
motionPrompt: "Slow 360-degree rotation, soft golden rim light",
sourceImageUrl: object.sourceImageUrl!,
attachToObjectId: objectId,
attachName: "rotate-360",
})objects.approveMainImage(id, candidateJobId, expectedUpdatedAt?)
Define um candidato concluído de generate() como a imagem principal do objeto. Em seguida, um modelo de visão escreve a descrição do objeto, e o método retorna as duas.
approveMainImage(id: string, candidateJobId: string, expectedUpdatedAt?: string): Promise<{
sourceImageUrl: string
canonicalDescription: string | null
}>Prop
Type
const { sourceImageUrl, canonicalDescription } = await client.objects.approveMainImage(objectId, jobIds[0])canonicalDescription é null quando não foi possível escrever a descrição. A imagem principal é definida mesmo assim; chame recaption() para tentar de novo.
objects.recaption(id)
Escreve de novo a descrição do objeto a partir da imagem principal atual. É seguro repetir a chamada, e ela não recebe token de concorrência.
recaption(id: string): Promise<{ canonicalDescription: string }>Prop
Type
const { canonicalDescription } = await client.objects.recaption(objectId)Falha com 400 main_image_required quando o objeto não tem imagem principal, e com um erro 502 quando o modelo de visão falha.
client.creatures
Uma criatura é um animal ou um ser fantástico. Ela funciona como um objeto, com quatro diferenças:
speciesé um tipo em texto livre, comodragonouwolf, e é o assunto do prompt da imagem principal.categorytambém é texto livre.posessubstituimaterials, então as coleções sãoangles,poses,variationsemotionClips. Os tipos de variação sãoangles,poses,variationsecustom.boardsguarda até 24 Painéis de criatura com nome, folhas de referência densas feitas com a predefinição Painel de criatura (Creature Board) do nó Gerar imagem (Generate Image). Você controla essa lista:create()eupdate()a substituem por inteiro.voicetransforma a criatura em uma criatura falante. Ela tem o mesmo formato da voz de um personagem:{ voiceId, voiceName, traits, voiceType?, previewUrl?, ttsProvider? }. Passevoice: nullpara removê-la.
creatures.listArchived(), get(), delete(), restore(), permanentDelete(), approveMainImage() e recaption() recebem os mesmos argumentos e se comportam como os métodos de objeto acima.
creatures.list(params?)
list(params?: { archived?: boolean; projectId?: string; limit?: number; cursor?: string }): Promise<{
creatures: Creature[]
nextCursor?: string | null
}>Prop
Type
const { creatures } = await client.creatures.list()creatures.create(input)
create(input: CreateCreatureInput): Promise<{ id: string }>Prop
Type
const { id: creatureId } = await client.creatures.create({
nodeId: "mcp-managed",
name: "Biscuit",
species: "ginger cat",
style: "realistic",
})creatures.update(id, input)
Recebe os campos de create(), exceto nodeId, além de boards, selectedAssetByVariant e expectedUpdatedAt. Só os campos que você envia são gravados.
update(id: string, input: UpdateCreatureInput): Promise<{ id: string; updatedAt: string }>Prop
Type
await client.creatures.update(creatureId, {
voice: { voiceId: chosenVoiceId, voiceName: "Aria", traits: "smug, unhurried" },
})creatures.generate(input)
Gera candidatos a imagem principal. Recebe os campos de objects.generate(), além de species, e retorna { jobIds }.
generate(input: GenerateCreatureInput): Promise<{ jobIds: string[]; jobId?: string }>Prop
Type
const { jobIds } = await client.creatures.generate({ name: "Biscuit", species: "ginger cat", count: 4 })creatures.generateAsset(input)
Gera uma variação. Funciona como objects.generateAsset(), com attachToCreatureId.
generateAsset(input: GenerateCreatureAssetInput): Promise<{ jobId: string }>Prop
Type
await client.creatures.generateAsset({
name: "Biscuit",
assetType: "poses",
variant: "sitting",
attachToCreatureId: creatureId,
attachToColumn: "poses",
attachName: "sitting",
})creatures.generateMotion(input)
Anima a imagem da criatura em um clipe. Funciona como objects.generateMotion(), com os mesmos padrões, kling-turbo e 1:1, e adiciona o clipe a motionClips.
generateMotion(input: GenerateCreatureMotionInput): Promise<{ jobId: string }>Prop
Type
await client.creatures.generateMotion({
name: "Biscuit",
motionPrompt: "The cat stretches, then yawns",
sourceImageUrl: creature.sourceImageUrl!,
attachToCreatureId: creatureId,
})Fazer uma criatura falar
A fala não precisa de um método específico de criatura. Gere a fala com a voz da criatura e depois aplique a sincronização labial na imagem da criatura:
const creature = await client.creatures.get(creatureId)
// 1. Speak the line in the creature's voice
const speech = await client.nodes.runAndWait("text-to-speech", {
text: "I knocked the vase off the shelf. I regret nothing.",
voice: creature.voice!.voiceId,
provider: creature.voice!.ttsProvider,
voiceType: creature.voice!.voiceType,
})
// 2. Lip-sync the audio onto the creature's main image
const clip = await client.nodes.runAndWait("lip-sync", {
imageUrl: creature.sourceImageUrl!,
audioUrl: speech.audioUrl,
provider: "kling-avatar",
})
console.log(clip.videoUrl)O nó Sincronização labial (Lip Sync) também dubla um vídeo existente: passe videoUrl e um modelo que aceite vídeo. volcengine-lipsync é a opção de menor preço para dublagem e a única que lida com vários falantes:
const dub = await client.nodes.runAndWait("lip-sync", {
videoUrl: "https://example.com/scene.mp4",
audioUrl: "https://example.com/new-vocal.mp3",
provider: "volcengine-lipsync",
mode: "basic", // for complex scenes
openScenedet: true, // several speakers: scene and speaker detection
audioDurationSec: 42, // sets the per-second price; without it, you pay for 5 minutes
})Para incluir uma criatura em uma tomada como referência, monte a referência com toConnectedReference({ kind: "creature", id, name, url, description }) de @nodaro/shared. O nó Gerar imagem então adiciona uma linha que mantém a anatomia, as marcas e as cores da criatura. Veja Referências.
Perguntas frequentes
Páginas relacionadas
Objetos e adereços
Animais e criaturas
Objetos
Criaturas
Personagens
Última atualização
Locais
Crie locais, gere planos de estabelecimento, aprove um deles e adicione variações de hora do dia, clima, estação, ângulo e movimento em TypeScript.
Biblioteca da comunidade
Explore a biblioteca da comunidade do Nodaro em TypeScript, clone na sua conta personagens, locais e objetos, favorite-os e denuncie uma publicação.