Docs do Nodaro
DocumentaçãoReferência de nósModelosAgentes de IA (MCP)DesenvolvedoresSelf-hostingPesquisa
SDK para TypeScript

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étodoO 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, como dragon ou wolf, e é o assunto do prompt da imagem principal. category também é texto livre.
  • poses substitui materials, então as coleções são angles, poses, variations e motionClips. Os tipos de variação são angles, poses, variations e custom.
  • boards guarda 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() e update() a substituem por inteiro.
  • voice transforma a criatura em uma criatura falante. Ela tem o mesmo formato da voz de um personagem: { voiceId, voiceName, traits, voiceType?, previewUrl?, ttsProvider? }. Passe voice: null para 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

Última atualização

Nesta página