Skip to main content
Glama
bbernstein
by bbernstein

generate_scene

Create custom lighting scenes for theatrical projects based on script context and design preferences, specifying scene type, color palette, mood, intensity, and focus areas using the LacyLights system.

Instructions

Generate a lighting scene based on script context and design preferences

Input Schema

NameRequiredDescriptionDefault
designPreferencesNo
fixtureFilterNo
projectIdYesProject ID to create scene in
sceneDescriptionYesDescription of the scene to light
sceneTypeNoType of scene: 'full' uses all fixtures (default), 'additive' only modifies specified fixturesfull
scriptContextNoOptional script context for the scene

Input Schema (JSON Schema)

{ "properties": { "designPreferences": { "properties": { "colorPalette": { "description": "Preferred colors for the scene", "items": { "type": "string" }, "type": "array" }, "focusAreas": { "description": "Stage areas to emphasize", "items": { "type": "string" }, "type": "array" }, "intensity": { "description": "Overall intensity level", "enum": [ "subtle", "moderate", "dramatic" ], "type": "string" }, "mood": { "description": "Mood or atmosphere for the scene", "type": "string" } }, "type": "object" }, "fixtureFilter": { "properties": { "excludeTypes": { "items": { "enum": [ "LED_PAR", "MOVING_HEAD", "STROBE", "DIMMER", "OTHER" ], "type": "string" }, "type": "array" }, "includeTags": { "items": { "type": "string" }, "type": "array" }, "includeTypes": { "items": { "enum": [ "LED_PAR", "MOVING_HEAD", "STROBE", "DIMMER", "OTHER" ], "type": "string" }, "type": "array" } }, "type": "object" }, "projectId": { "description": "Project ID to create scene in", "type": "string" }, "sceneDescription": { "description": "Description of the scene to light", "type": "string" }, "sceneType": { "default": "full", "description": "Type of scene: 'full' uses all fixtures (default), 'additive' only modifies specified fixtures", "enum": [ "full", "additive" ], "type": "string" }, "scriptContext": { "description": "Optional script context for the scene", "type": "string" } }, "required": [ "projectId", "sceneDescription" ], "type": "object" }

Implementation Reference

  • Main execution logic for the generate_scene tool. Validates input, retrieves project fixtures, generates lighting design via AI service, creates the scene in database, and optionally activates it.
    async generateScene(args: z.infer<typeof GenerateSceneSchema>) { const { projectId, sceneDescription, scriptContext, sceneType, designPreferences, fixtureFilter, activate } = GenerateSceneSchema.parse(args); try { // Get project and available fixtures const project = await this.graphqlClient.getProject(projectId); if (!project) { throw new Error(`Project with ID ${projectId} not found`); } // Get all fixtures for context, then filter based on scene type and criteria let availableFixtures = project.fixtures; const allFixtures = project.fixtures; // Keep reference to all fixtures // For additive scenes, we need fixtureFilter to specify which fixtures to modify if (sceneType === 'additive' && !fixtureFilter) { throw new Error('Additive scenes require fixtureFilter to specify which fixtures to modify'); } if (fixtureFilter) { if (fixtureFilter.includeTypes) { availableFixtures = availableFixtures.filter(f => f.type && fixtureFilter.includeTypes!.includes(f.type) ); } if (fixtureFilter.excludeTypes) { availableFixtures = availableFixtures.filter(f => f.type && !fixtureFilter.excludeTypes!.includes(f.type) ); } if (fixtureFilter.includeTags) { availableFixtures = availableFixtures.filter(f => fixtureFilter.includeTags!.some(tag => f.tags.includes(tag)) ); } } if (availableFixtures.length === 0) { throw new Error('No fixtures available matching the specified criteria'); } // Create lighting design request const lightingRequest: LightingDesignRequest = { scriptContext: scriptContext || sceneDescription, sceneDescription, availableFixtures, sceneType, allFixtures: sceneType === 'additive' ? allFixtures : undefined, designPreferences }; // Generate scene using AI const generatedScene = await this.aiLightingService.generateScene(lightingRequest); // Optimize the scene for available fixtures const optimizedScene = await this.aiLightingService.optimizeSceneForFixtures( generatedScene, availableFixtures ); // Create the scene in the database const createdScene = await this.graphqlClient.createScene({ name: optimizedScene.name, description: optimizedScene.description, projectId, fixtureValues: optimizedScene.fixtureValues }); const result: GenerateSceneResult = { sceneId: createdScene.id, scene: { name: createdScene.name, description: createdScene.description || null, fixtureValues: createdScene.fixtureValues.map(fv => ({ fixture: { id: fv.fixture.id, name: fv.fixture.name, type: fv.fixture.type || 'UNKNOWN' }, channelValues: fv.channelValues, sceneOrder: fv.sceneOrder })) }, designReasoning: optimizedScene.reasoning, fixturesUsed: availableFixtures.length, channelsSet: optimizedScene.fixtureValues.reduce((total, fv) => total + (fv.channelValues?.length || 0), 0) }; // Activate the scene if requested if (activate) { try { const success = await this.graphqlClient.setSceneLive(createdScene.id); result.activation = { success, message: success ? `Scene "${createdScene.name}" is now active` : 'Scene created but activation failed' }; } catch (activationError) { // Include activation error but don't fail the entire operation result.activation = { success: false, error: `Scene created but activation failed: ${activationError}` }; } } return result; } catch (error) { throw new Error(`Failed to generate scene: ${error}`); } }
  • Zod validation schema for the generate_scene tool input parameters, used internally for parsing and validation.
    const GenerateSceneSchema = z.object({ projectId: z.string(), sceneDescription: z.string(), scriptContext: z.string().optional(), sceneType: z.enum(['full', 'additive']).default('full'), designPreferences: z.object({ colorPalette: z.array(z.string()).optional(), mood: z.string().optional(), intensity: z.enum(['subtle', 'moderate', 'dramatic']).optional(), focusAreas: z.array(z.string()).optional() }).optional(), fixtureFilter: z.object({ includeTypes: z.array(z.enum(['LED_PAR', 'MOVING_HEAD', 'STROBE', 'DIMMER', 'OTHER'])).optional(), excludeTypes: z.array(z.enum(['LED_PAR', 'MOVING_HEAD', 'STROBE', 'DIMMER', 'OTHER'])).optional(), includeTags: z.array(z.string()).optional() }).optional(), activate: z.boolean().optional() });
  • src/index.ts:2084-2096 (registration)
    MCP server request handler dispatch for 'generate_scene' tool, calling the SceneTools.generateScene method.
    case "generate_scene": return { content: [ { type: "text", text: JSON.stringify( await this.sceneTools.generateScene(args as any), null, 2, ), }, ], };
  • MCP tool schema definition registered in list_tools response, defining input schema for generate_scene.
    description: "Generate a lighting scene based on script context and design preferences", inputSchema: { type: "object", properties: { projectId: { type: "string", description: "Project ID to create scene in", }, sceneDescription: { type: "string", description: "Description of the scene to light", }, scriptContext: { type: "string", description: "Optional script context for the scene", }, sceneType: { type: "string", enum: ["full", "additive"], default: "full", description: "Type of scene: 'full' uses all fixtures (default), 'additive' only modifies specified fixtures", }, designPreferences: { type: "object", properties: { colorPalette: { type: "array", items: { type: "string" }, description: "Preferred colors for the scene", }, mood: { type: "string", description: "Mood or atmosphere for the scene", }, intensity: { type: "string", enum: ["subtle", "moderate", "dramatic"], description: "Overall intensity level", }, focusAreas: { type: "array", items: { type: "string" }, description: "Stage areas to emphasize", }, }, }, fixtureFilter: { type: "object", properties: { includeTypes: { type: "array", items: { type: "string", enum: [ "LED_PAR", "MOVING_HEAD", "STROBE", "DIMMER", "OTHER", ], }, }, excludeTypes: { type: "array", items: { type: "string", enum: [ "LED_PAR", "MOVING_HEAD", "STROBE", "DIMMER", "OTHER", ], }, }, includeTags: { type: "array", items: { type: "string" }, }, }, }, activate: { type: "boolean", description: "Automatically activate the scene after creation", }, }, required: ["projectId", "sceneDescription"], },
  • AI-powered helper service that generates concrete fixture channel values using OpenAI GPT-4, called by the main handler.
    async generateScene(request: LightingDesignRequest): Promise<GeneratedScene> { // Get AI recommendations from RAG const recommendations = await this.ragService.generateLightingRecommendations( request.sceneDescription, request.designPreferences?.mood || "neutral", request.availableFixtures.map((f) => f.type || "OTHER"), ); // Generate fixture values using AI const fixturePrompt = this.buildFixturePrompt(request, recommendations); const response = await this.openai.chat.completions.create({ model: "gpt-4", messages: [{ role: "user", content: fixturePrompt }], temperature: 0.3, }); const content = response.choices[0].message.content || "{}"; let aiResponse: any = {}; try { aiResponse = JSON.parse(content); } catch (_error) { // If JSON parsing fails, try to extract JSON from the response const jsonMatch = content.match(/\{[\s\S]*\}/); if (jsonMatch) { try { aiResponse = JSON.parse(jsonMatch[0]); } catch (_e) { // If still fails, use fallback aiResponse = {}; } } } // Debug logging - embed in response for troubleshooting const debugInfo = { promptLength: fixturePrompt.length, responseLength: content.length, parsedResponse: !!aiResponse, hasFixtureValues: !!( aiResponse.fixtureValues && Array.isArray(aiResponse.fixtureValues) ), fixtureValuesCount: aiResponse.fixtureValues?.length || 0, availableFixturesCount: request.availableFixtures.length, firstFixtureChannelCount: request.availableFixtures[0]?.channelCount || 0, }; // Validate and clean fixture values to ensure channel IDs exist const validatedFixtureValues = this.validateFixtureValues( aiResponse.fixtureValues || [], request.availableFixtures, ); return { name: aiResponse.name || `Scene for ${request.sceneDescription}`, description: aiResponse.description || request.sceneDescription, fixtureValues: validatedFixtureValues, reasoning: aiResponse.reasoning || recommendations.reasoning + `\n\nDEBUG: ${JSON.stringify(debugInfo)}`, }; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/bbernstein/lacylights-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server