Add Prompt Builder sets/framing and harden mobile draft look settings.

Sets and beats filter by shot size; scenes reorder/delete; portrait links Prompt Builder; landscape queue collapses; per-engine look settings and prompt Clear persist across iOS resumes.
This commit is contained in:
Towsty
2026-10-03 19:31:22 -05:00
parent 7799529788
commit a8ae61704e
9 changed files with 1441 additions and 760 deletions
+27 -7
View File
@@ -5,11 +5,13 @@ import {
normalizePromptSequence,
normalizePromptSequenceName,
normalizeCharacter,
normalizeSet,
normalizeScene,
emptyCharacter,
emptyScene,
type PromptSequence,
type PromptSequenceCharacter,
type PromptSequenceSet,
type PromptSequenceScene
} from '~/utils/promptSequences'
@@ -62,9 +64,18 @@ function normalizeCharactersInput(raw: unknown): PromptSequenceCharacter[] {
return raw.map(normalizeCharacter)
}
function normalizeScenesInput(raw: unknown, characters: PromptSequenceCharacter[]): PromptSequenceScene[] {
if (!Array.isArray(raw) || !raw.length) return [emptyScene(1, characters)]
return raw.map((scene, index) => normalizeScene(scene, index, characters))
function normalizeSetsInput(raw: unknown): PromptSequenceSet[] {
if (!Array.isArray(raw)) return []
return raw.map(normalizeSet)
}
function normalizeScenesInput(
raw: unknown,
characters: PromptSequenceCharacter[],
sets: PromptSequenceSet[]
): PromptSequenceScene[] {
if (!Array.isArray(raw) || !raw.length) return [emptyScene(1, characters, sets)]
return raw.map((scene, index) => normalizeScene(scene, index, characters, sets))
}
export function listPromptSequences(owner: string) {
@@ -81,13 +92,15 @@ export function getPromptSequence(owner: string, id: string) {
export async function savePromptSequence(owner: string, input: {
name: string
characters?: unknown
sets?: unknown
scenes?: unknown
overwrite?: boolean
}) {
const name = normalizePromptSequenceName(input.name)
if (!name) throw createError({ statusCode: 400, statusMessage: 'A sequence name is required' })
const characters = normalizeCharactersInput(input.characters)
const scenes = normalizeScenesInput(input.scenes, characters)
const sets = normalizeSetsInput(input.sets)
const scenes = normalizeScenesInput(input.scenes, characters, sets)
const now = Date.now()
return mutate(owner, (sequences) => {
const existing = sequences.find(item => item.name.toLowerCase() === name.toLowerCase())
@@ -96,6 +109,7 @@ export async function savePromptSequence(owner: string, input: {
}
if (existing) {
existing.characters = characters
existing.sets = sets
existing.scenes = scenes
existing.updatedAt = now
return existing
@@ -104,6 +118,7 @@ export async function savePromptSequence(owner: string, input: {
id: crypto.randomUUID(),
name,
characters,
sets,
scenes,
createdAt: now,
updatedAt: now
@@ -116,6 +131,7 @@ export async function savePromptSequence(owner: string, input: {
export async function updatePromptSequence(owner: string, id: string, input: {
name?: string
characters?: unknown
sets?: unknown
scenes?: unknown
}) {
const wanted = String(id || '').trim()
@@ -130,14 +146,18 @@ export async function updatePromptSequence(owner: string, id: string, input: {
if (clash) throw createError({ statusCode: 409, statusMessage: `A sequence named “${clash.name}” already exists` })
existing.name = name
}
if (input.characters !== undefined || input.scenes !== undefined) {
if (input.characters !== undefined || input.sets !== undefined || input.scenes !== undefined) {
const characters = input.characters !== undefined
? normalizeCharactersInput(input.characters)
: existing.characters
const sets = input.sets !== undefined
? normalizeSetsInput(input.sets)
: (existing.sets || [])
const scenes = input.scenes !== undefined
? normalizeScenesInput(input.scenes, characters)
: existing.scenes.map((scene, index) => normalizeScene(scene, index, characters))
? normalizeScenesInput(input.scenes, characters, sets)
: existing.scenes.map((scene, index) => normalizeScene(scene, index, characters, sets))
existing.characters = characters
existing.sets = sets
existing.scenes = scenes
}
existing.updatedAt = Date.now()