Bind permanence stills to named lock keys instead of coded categories.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+28
-15
@@ -279,18 +279,19 @@
|
||||
<div class="rounded-xl border border-white/10 bg-zinc-950/40 px-3 py-2.5">
|
||||
<PermanenceRefStrip
|
||||
:refs="familyPermanenceRefs"
|
||||
:name-options="lockBindingKeys"
|
||||
label="Permanence refs · all shots"
|
||||
hint="Shared stills"
|
||||
hint="Name + still"
|
||||
cta="Add permanence refs"
|
||||
add-title="Choose a still to label for every shot"
|
||||
add-title="Choose a still to name for every shot"
|
||||
:hidden="hideInputPreview"
|
||||
@add-ref="openPermanencePicker()"
|
||||
@remove="removeFamilyRef"
|
||||
@update-label="updateFamilyRefLabel"
|
||||
/>
|
||||
<p class="mt-2 text-[11px] leading-relaxed text-zinc-500">
|
||||
Add stills, then label each Subject / Vehicle / Interior / Object. Those names are injected into locks and
|
||||
<span class="text-zinc-300">[INHERITS]</span>, so a shot can say “same Subject, same Vehicle.”
|
||||
Name each still, or pick a GLOBAL LOCKS key. Shot prompts inherit those names.
|
||||
The generate start still stays the first frame — attach it here only if you want a named alias.
|
||||
</p>
|
||||
<p class="mt-1 text-[11px] leading-relaxed text-zinc-500">{{ permanenceComfyNote }}</p>
|
||||
<p v-if="familyRefLabelLine" class="mt-1 text-[11px] text-amber-200/80">{{ familyRefLabelLine }}</p>
|
||||
@@ -311,10 +312,11 @@
|
||||
<PermanenceRefStrip
|
||||
class="mt-2"
|
||||
:refs="shotPermanenceRefs[shot.n] || []"
|
||||
:name-options="lockBindingKeys"
|
||||
label="This shot only"
|
||||
hint="Extra stills"
|
||||
cta="Add still"
|
||||
add-title="Choose a still for this shot only"
|
||||
add-title="Choose a still to name for this shot only"
|
||||
:hidden="hideInputPreview"
|
||||
:max="4"
|
||||
@add-ref="openPermanencePicker(shot.n)"
|
||||
@@ -352,10 +354,11 @@
|
||||
<PermanenceRefStrip
|
||||
class="mt-3"
|
||||
:refs="shotPermanenceRefs[index + 2] || []"
|
||||
:name-options="lockBindingKeys"
|
||||
label="This extension only"
|
||||
hint="Extra stills"
|
||||
cta="Add still"
|
||||
add-title="Choose a still for this extension only"
|
||||
add-title="Choose a still to name for this extension only"
|
||||
:hidden="hideInputPreview"
|
||||
:max="4"
|
||||
@add-ref="openPermanencePicker(index + 2)"
|
||||
@@ -1189,6 +1192,7 @@
|
||||
v-if="entry.group.parts.length === 1 && !entry.group.head.hideThumbnail"
|
||||
class="mt-2"
|
||||
:refs="entry.group.head.permanenceRefs || []"
|
||||
:name-options="clipBindingKeys(entry.group.head)"
|
||||
cta="Add still"
|
||||
:hidden="entry.group.head.hideInput || hideInputPreview"
|
||||
@add-ref="openPermanencePicker(undefined, entry.group.head.id)"
|
||||
@@ -1263,6 +1267,7 @@
|
||||
v-if="!item.hideThumbnail"
|
||||
class="mt-2"
|
||||
:refs="item.permanenceRefs || []"
|
||||
:name-options="clipBindingKeys(item, entry.group.head)"
|
||||
cta="Add still"
|
||||
:hidden="item.hideInput || hideInputPreview"
|
||||
@add-ref="openPermanencePicker(undefined, item.id)"
|
||||
@@ -1537,7 +1542,9 @@ import {
|
||||
extractGlobalLocks,
|
||||
isBlankGlobalLocks,
|
||||
nextPermanenceLabel,
|
||||
parseLockBindingKeys,
|
||||
permanenceLabels,
|
||||
sanitizeRefLabel,
|
||||
type PermanenceRef
|
||||
} from '~/utils/globalLocks'
|
||||
import {
|
||||
@@ -1871,12 +1878,13 @@ const shotPermanenceRefs = ref<Record<number, PermanenceRef[]>>({})
|
||||
const LOCKS_STORE = 'aigen-global-locks'
|
||||
const REFS_STORE = 'aigen-permanence-refs'
|
||||
const pickerHeading = computed(() => {
|
||||
if (pickerKind.value === 'permanence') return 'Choose a permanence still'
|
||||
if (pickerKind.value === 'permanence') return 'Choose a still to name'
|
||||
if (pickerSlot.value === 'main') return studioMode.value === 'edit' ? 'Choose image 1' : 'Choose an image'
|
||||
if (pickerSlot.value === 'editRef') return 'Choose image 2'
|
||||
return `Choose Picture ${Number(pickerSlot.value) + 2}`
|
||||
})
|
||||
const permanencePicker = computed(() => pickerKind.value === 'permanence')
|
||||
const lockBindingKeys = computed(() => parseLockBindingKeys(globalLocks.value))
|
||||
const familyRefLabelLine = computed(() => {
|
||||
const labels = permanenceLabels(familyPermanenceRefs.value)
|
||||
if (!labels.length) return ''
|
||||
@@ -1884,9 +1892,9 @@ const familyRefLabelLine = computed(() => {
|
||||
})
|
||||
const permanenceComfyNote = computed(() => {
|
||||
if (studioMode.value === 'video' && videoWorkflow.value === 'v2' && useIdentityRefs.value) {
|
||||
return 'Identity-ref is on: Subject stills can map to Picture 2–5 as extra views of the same person only — never a second character or a vehicle.'
|
||||
return 'Identity-ref still only maps extra views of the start-still person, never a second character. Permanence stills name the lock text; they are not Picture 2–5.'
|
||||
}
|
||||
return 'Last-frame I2V: these refs are prompt anchors (and last-frame continuity), not extra MiniMax pictures. Turn on identity-ref only for one person.'
|
||||
return 'Last-frame I2V does not send these stills to MiniMax as extra pictures; they name what the lock text is talking about. Identity-ref still only maps extra views of the start-still person, never a second character.'
|
||||
})
|
||||
let videoTimer: ReturnType<typeof setInterval> | null = null
|
||||
let editTimer: ReturnType<typeof setInterval> | null = null
|
||||
@@ -2928,15 +2936,20 @@ function openPermanencePicker(shot?: number, clipId?: string) {
|
||||
})
|
||||
}
|
||||
|
||||
function clipBindingKeys(clip: LibraryClip, fallback?: LibraryClip) {
|
||||
return parseLockBindingKeys(clip.globalLocks || fallback?.globalLocks || '')
|
||||
}
|
||||
|
||||
function addPermanenceRef(stillId: string, shot?: number) {
|
||||
const keys = lockBindingKeys.value
|
||||
if (typeof shot === 'number') {
|
||||
const current = shotPermanenceRefs.value[shot] || []
|
||||
if (current.some(item => item.stillId === stillId) || current.length >= 4) return
|
||||
shotPermanenceRefs.value = { ...shotPermanenceRefs.value, [shot]: [...current, { stillId, label: nextPermanenceLabel(current) }] }
|
||||
shotPermanenceRefs.value = { ...shotPermanenceRefs.value, [shot]: [...current, { stillId, label: nextPermanenceLabel([...familyPermanenceRefs.value, ...current], keys) }] }
|
||||
return
|
||||
}
|
||||
if (familyPermanenceRefs.value.some(item => item.stillId === stillId) || familyPermanenceRefs.value.length >= 6) return
|
||||
familyPermanenceRefs.value = [...familyPermanenceRefs.value, { stillId, label: nextPermanenceLabel(familyPermanenceRefs.value) }]
|
||||
familyPermanenceRefs.value = [...familyPermanenceRefs.value, { stillId, label: nextPermanenceLabel(familyPermanenceRefs.value, keys) }]
|
||||
}
|
||||
|
||||
function removeFamilyRef(index: number) {
|
||||
@@ -2944,7 +2957,7 @@ function removeFamilyRef(index: number) {
|
||||
}
|
||||
|
||||
function updateFamilyRefLabel(index: number, label: string) {
|
||||
familyPermanenceRefs.value = familyPermanenceRefs.value.map((item, i) => i === index ? { ...item, label } : item)
|
||||
familyPermanenceRefs.value = familyPermanenceRefs.value.map((item, i) => i === index ? { ...item, label: sanitizeRefLabel(label) } : item)
|
||||
}
|
||||
|
||||
function removeShotRef(shot: number, index: number) {
|
||||
@@ -2956,7 +2969,7 @@ function removeShotRef(shot: number, index: number) {
|
||||
}
|
||||
|
||||
function updateShotRefLabel(shot: number, index: number, label: string) {
|
||||
const current = (shotPermanenceRefs.value[shot] || []).map((item, i) => i === index ? { ...item, label } : item)
|
||||
const current = (shotPermanenceRefs.value[shot] || []).map((item, i) => i === index ? { ...item, label: sanitizeRefLabel(label) } : item)
|
||||
shotPermanenceRefs.value = { ...shotPermanenceRefs.value, [shot]: current }
|
||||
}
|
||||
|
||||
@@ -2976,7 +2989,7 @@ function removeClipRef(clip: LibraryClip, index: number) {
|
||||
}
|
||||
|
||||
function updateClipRefLabel(clip: LibraryClip, index: number, label: string) {
|
||||
void persistClipRefs(clip, (clip.permanenceRefs || []).map((item, i) => i === index ? { ...item, label } : item))
|
||||
void persistClipRefs(clip, (clip.permanenceRefs || []).map((item, i) => i === index ? { ...item, label: sanitizeRefLabel(label) } : item))
|
||||
}
|
||||
|
||||
function onPickedPermanence(still: { id: string }) {
|
||||
@@ -2994,7 +3007,7 @@ function onPickedPermanence(still: { id: string }) {
|
||||
pickerOpen.value = false
|
||||
return
|
||||
}
|
||||
void persistClipRefs(clip, [...(clip.permanenceRefs || []), { stillId: still.id, label: nextPermanenceLabel(clip.permanenceRefs || []) }])
|
||||
void persistClipRefs(clip, [...(clip.permanenceRefs || []), { stillId: still.id, label: nextPermanenceLabel(clip.permanenceRefs || [], parseLockBindingKeys(clip.globalLocks || '')) }])
|
||||
pickerOpen.value = false
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user