Files
aigen/components/studio2/PromptControls.vue
T

23 lines
4.3 KiB
Vue

<template>
<div class="space-y-4">
<fieldset class="space-y-3"><legend class="font-semibold">Camera beats · one continuous take</legend>
<div class="flex flex-wrap gap-2"><button v-for="(beat,i) in model.cameraBeats" :key="i" type="button" class="rounded-lg border px-3 py-2" :class="active===i?'border-amber-300 text-amber-200':'border-white/20'" @click="active=i">{{ i+1 }} · {{ beat.moves.join(' + ') }} · {{ beat.durationSec == null ? 'to end' : `${beat.durationSec}s` }}</button></div>
<div v-if="current" class="space-y-3 rounded-xl border border-white/15 p-3">
<div class="flex flex-wrap gap-2"><button v-for="move in cameraMoves" :key="move" type="button" :aria-pressed="current.moves.includes(move)" class="rounded-full border px-3 py-1 text-sm" :class="current.moves.includes(move)?'border-amber-300 bg-amber-300/10 text-amber-200':'border-white/15'" @click="model.cameraBeats[active]=toggleMove(current,move)">{{ move.replaceAll('-',' ') }}</button></div>
<div class="flex flex-wrap gap-3"><label>Amplitude<select v-model="current.amplitude" class="block rounded bg-zinc-800 p-2"><option v-for="v in ['subtle','moderate','large']" :key="v">{{ v }}</option></select></label><label>Speed<select v-model="current.speed" class="block rounded bg-zinc-800 p-2"><option v-for="v in ['slow','medium','fast']" :key="v">{{ v }}</option></select></label><label>Duration<select v-model="current.durationSec" class="block rounded bg-zinc-800 p-2"><option :value="null">To end</option><option v-for="n in 30" :key="n" :value="n/2">{{ n/2 }}s</option></select></label><button @click="model.cameraBeats.splice(active,1);active=Math.max(0,active-1)">Remove beat</button></div>
</div>
<div class="flex gap-4 text-sm text-amber-200"><button @click="addBeat">+ Camera beat</button><button @click="model.cameraBeats=[];model.camera='';active=0">Clear camera</button></div>
</fieldset>
<fieldset class="space-y-2"><legend class="font-semibold">Soundscape</legend><div class="flex flex-wrap gap-2"><button v-for="sound in soundscapeOptions" :key="sound" :aria-pressed="model.soundscapeChips.includes(sound)" class="rounded-full border px-3 py-1 text-sm" :class="model.soundscapeChips.includes(sound)?'border-amber-300 text-amber-200':'border-white/15'" @click="toggleSound(sound)">{{ sound }}</button></div><label class="block text-sm">Dynamics <select v-model="model.soundscapeLevel" class="rounded bg-zinc-800 p-2"><option>normal</option><option>crush</option></select></label></fieldset>
<fieldset class="space-y-2"><legend class="font-semibold">Dialogue</legend><div class="flex flex-wrap gap-2"><button v-for="mode in ['none','spoken to camera','spoken off-screen','whisper']" :key="mode" :aria-pressed="model.dialogue.mode===mode" class="rounded-full border px-3 py-1 text-sm" :class="model.dialogue.mode===mode?'border-amber-300 text-amber-200':'border-white/15'" @click="model.dialogue.mode=mode">{{ mode }}</button></div><template v-if="model.dialogue.mode!=='none'"><div class="flex gap-3"><label>Language<input v-model="model.dialogue.language" class="block w-full rounded bg-zinc-800 p-2"></label><label>Speaker<input v-model="model.dialogue.speaker" class="block w-20 rounded bg-zinc-800 p-2"></label></div><label class="block">Line<textarea v-model="model.dialogue.line" class="mt-1 w-full rounded-xl bg-zinc-900 p-3" /></label></template></fieldset>
<fieldset><legend class="mb-2 font-semibold">Music</legend><div class="flex gap-2"><button v-for="v in ['N/A','none','low underscore']" :key="v" :aria-pressed="model.musicChip===v" class="rounded-full border px-3 py-1 text-sm" :class="model.musicChip===v?'border-amber-300 text-amber-200':'border-white/15'" @click="model.musicChip=v;model.music=''">{{ v }}</button></div></fieldset>
</div>
</template>
<script setup lang="ts">
import {cameraMoves,soundscapeOptions,normalizeBeat,toggleMove} from '~/shared/studio2/prompt.mjs'
const model=defineModel<any>({required:true}),active=ref(0)
const current=computed(()=>model.value.cameraBeats[active.value])
function addBeat(){const last=model.value.cameraBeats.at(-1);if(last?.durationSec==null&&last)last.durationSec=2;model.value.cameraBeats.push(normalizeBeat());active.value=model.value.cameraBeats.length-1}
function toggleSound(sound:string){const chips=model.value.soundscapeChips;model.value.soundscapeChips=chips.includes(sound)?chips.filter((s:string)=>s!==sound):[...chips,sound]}
</script>