[sdasse/gc_gen_art] Pasted FIXED Enhanced system prompt that only uses algorithms we actually implement async function ge 1750116378723 1750116378723
Claude
API Leak/Claude
29,238 characters
// FIXED: Enhanced system prompt that only uses algorithms we actually implement
async function generateAlgorithmsWithClaude(userPrompt, apiKey) {
// Enhanced validation (keeping your existing validation)
if (!userPrompt || typeof userPrompt !== 'string' || userPrompt.trim().length === 0) {
throw new Error('User prompt is required and must be a non-empty string');
}
if (!apiKey || typeof apiKey !== 'string' || apiKey.trim().length === 0) {
throw new Error('API key is required and must be a non-empty string');
}
userPrompt = userPrompt.trim();
if (userPrompt.length > 500) {
console.warn('User prompt is very long, truncating to avoid token limits');
userPrompt = userPrompt.substring(0, 500);
}
// FIXED: Enhanced system prompt with only implemented algorithms
const systemPrompt = `You are an artistic technical diagram generator. Create varied, surprising visualizations with random elements and consistent line styling.
For the concept "${userPrompt}", return ONLY this JSON structure with 3-6 algorithms chosen for maximum variety:
{
"title": "Technical diagram name",
"description": "What this represents",
"algorithms": [
// AVAILABLE ALGORITHMS (all implemented):
// STRUCTURAL: "grid", "circles", "radial_lines", "network", "spiral"
// COMPLEX: "wave", "logarithmic_spiral", "scatter"
{
"type": "circles",
"params": {
"center": [0, 0],
"count": 15,
"max_radius": 5,
"min_radius": 0.5,
"style": "clean"
}
},
{
"type": "radial_lines",
"params": {
"center": [2, -1],
"count": 24,
"length": 4,
"variation": 0.3
}
},
{
"type": "scatter",
"params": {
"count": 200,
"distribution": "clustered",
"bounds": [-6, 6]
}
}
// Add 0-3 more algorithms for 3-6 total
],
"style": {
"line_weight": 1.5,
"variation": "high",
"multiple_centers": true,
"mixed_scales": true
},
"camera": {"position": [8, 6, 10], "lookAt": [0, 0, 0]}
}
VARIATION RULES:
- Use MULTIPLE CENTERS: Place circles/radial_lines at different positions like [0,0], [3,-2], [-2,3]
- Use DIFFERENT SCALES: Same algorithm with different sizes (radius 2-8, count 10-30)
- MIX SIMPLE + COMPLEX: Combine 2-3 simple algorithms (circles, radial_lines) with 1-2 complex ones
- CREATE DEPTH: Overlap elements at different positions and scales
- ADD RANDOMNESS: Use "clustered" scatter, high "variation" in radial_lines, "noise" in grids
GOOD COMBINATIONS:
- circles (center [0,0], large) + circles (center [4,-2], small) + radial_lines + scatter
- grid (with noise) + network + circles (multiple centers) + wave
- spiral + circles (concentric) + logarithmic_spiral + scatter
- radial_lines + circles (small, scattered) + network + grid
Return ONLY the JSON - no explanations.`;
try {
console.log('Making Claude API request for algorithms:', userPrompt.substring(0, 100));
const response = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': apiKey,
'anthropic-version': '2023-06-01'
},
body: JSON.stringify({
model: 'claude-3-5-sonnet-20241022',
max_tokens: 2000,
messages: [
{
role: 'user',
content: `Generate algorithm parameters for: "${userPrompt}"`
}
],
system: systemPrompt
})
});
console.log('Claude API response status:', response.status);
if (!response.ok) {
const errorText = await response.text();
console.error('Claude API error response:', errorText);
let errorDetails = errorText;
try {
const errorJson = JSON.parse(errorText);
errorDetails = errorJson.error?.message || errorJson.message || errorText;
} catch (e) {
// Keep original error text if not JSON
}
throw new Error(`Claude API error (${response.status}): ${errorDetails}`);
}
const claudeResult = await response.json();
console.log('Claude algorithm result received');
const generatedText = claudeResult.content[0].text;
console.log('Raw algorithm response preview:', generatedText.substring(0, 200));
// Enhanced JSON extraction with multiple fallback strategies
let algorithmData;
try {
// Strategy 1: Try to parse the entire response as JSON
try {
algorithmData = JSON.parse(generatedText.trim());
} catch (e) {
// Strategy 2: Find JSON blocks in the response
const jsonRegex = /\{(?:[^{}]|{(?:[^{}]|{[^{}]*})*})*\}/g;
const matches = generatedText.match(jsonRegex);
if (matches) {
// Find the largest JSON block (most likely to be complete)
const jsonString = matches.reduce((prev, current) =>
current.length > prev.length ? current : prev
);
algorithmData = JSON.parse(jsonString);
} else {
throw new Error('No JSON found in Claude response');
}
}
} catch (parseError) {
console.error('Algorithm JSON parsing failed:', parseError);
console.error('Raw response:', generatedText);
// IMPROVED: Better fallback with variation
console.warn('Using improved fallback algorithm set');
algorithmData = {
title: "Varied Technical Art",
description: "Multi-scale algorithmic visualization",
algorithms: [
{
type: "circles",
params: { center: [0, 0], count: 12, max_radius: 5, min_radius: 0.3 }
},
{
type: "circles",
params: { center: [3, -2], count: 8, max_radius: 2.5, min_radius: 0.5 }
},
{
type: "radial_lines",
params: { center: [-2, 3], count: 20, length: 4, variation: 0.4 }
},
{
type: "scatter",
params: { count: 150, distribution: "clustered", bounds: [-6, 6] }
},
{
type: "network",
params: { nodes: 25, connection_probability: 0.3, bounds: [-4, 4] }
}
],
camera: { position: [8, 6, 10], lookAt: [0, 0, 0] }
};
}
// Validate and sanitize algorithm structure
if (!algorithmData.algorithms || !Array.isArray(algorithmData.algorithms)) {
throw new Error('Claude did not generate valid algorithms array');
}
// Limit number of algorithms
if (algorithmData.algorithms.length > 6) {
console.warn(`Claude generated ${algorithmData.algorithms.length} algorithms, limiting to 6`);
algorithmData.algorithms = algorithmData.algorithms.slice(0, 6);
}
// Validate each algorithm and filter out invalid ones
algorithmData.algorithms = algorithmData.algorithms.filter(alg => {
if (!alg || typeof alg !== 'object' || !alg.type || typeof alg.type !== 'string') {
console.warn('Filtering invalid algorithm:', alg);
return false;
}
// Check if algorithm type exists in our generators
const validTypes = [
'grid', 'circles', 'radial_lines', 'network', 'spiral', 'wave', 'scatter',
'logarithmic_spiral'
];
if (!validTypes.includes(alg.type)) {
console.warn(`Unknown algorithm type: ${alg.type}, filtering out`);
return false;
}
return true;
});
if (algorithmData.algorithms.length === 0) {
throw new Error('No valid algorithms found after filtering');
}
console.log(`Generated ${algorithmData.algorithms.length} valid algorithms`);
return algorithmData;
} catch (error) {
console.error('Claude algorithm generation error:', error);
throw error;
}
}
// FIXED: Robust algorithms with comprehensive error handling
const enhancedAlgorithmGenerators = {
// SAFE: Enhanced circles with better variation
circles: (params) => {
try {
const lines = [];
const center = Array.isArray(params.center) && params.center.length >= 2 ? params.center : [0, 0];
const count = Math.max(5, Math.min(30, Number(params.count) || 10));
const maxRadius = Math.max(1, Math.min(8, Number(params.max_radius) || 5));
const minRadius = Math.max(0.1, Math.min(maxRadius, Number(params.min_radius) || 0.5));
const style = params.style || "clean";
// Add some randomization to make each generation unique
const actualCount = count + Math.floor((Math.random() - 0.5) * 4);
for (let i = 0; i < actualCount; i++) {
const radius = minRadius + (maxRadius - minRadius) * (i / actualCount);
const points = [];
const segments = Math.max(16, Math.min(64, Math.floor(radius * 10)));
// Add organic variation for some circles
const variation = (style === "organic" || Math.random() < 0.2) ? 0.05 : 0;
for (let j = 0; j <= segments; j++) {
const angle = (j / segments) * Math.PI * 2;
const r = radius + (Math.random() - 0.5) * variation;
points.push([
center[0] + Math.cos(angle) * r,
center[1] + Math.sin(angle) * r,
0
]);
}
// Vary opacity and occasionally make lines dashed
const opacity = 0.4 + (i / actualCount) * 0.4 + Math.random() * 0.1;
const isDashed = Math.random() < 0.15; // 15% chance of dashed
lines.push({
points: points,
color: "#509EF0",
opacity: Math.min(0.9, opacity),
lineWidth: 1.5,
isDashed: isDashed
});
}
// Sometimes add radial fill lines
if (Math.random() < 0.3) {
const numRadial = 8 + Math.floor(Math.random() * 16);
for (let i = 0; i < numRadial; i++) {
const angle = (i / numRadial) * Math.PI * 2;
lines.push({
points: [
[center[0], center[1], 0],
[center[0] + Math.cos(angle) * maxRadius, center[1] + Math.sin(angle) * maxRadius, 0]
],
color: "#509EF0",
opacity: 0.3,
lineWidth: 1.5,
isDashed: Math.random() < 0.4 // Higher chance for radial lines to be dashed
});
}
}
return lines;
} catch (error) {
console.error('Error in circles algorithm:', error);
return [];
}
},
// SAFE: Enhanced radial_lines with arrows
radial_lines: (params) => {
try {
const lines = [];
const center = Array.isArray(params.center) && params.center.length >= 2 ? params.center : [0, 0];
const count = Math.max(8, Math.min(72, Number(params.count) || 24));
const length = Math.max(1, Math.min(10, Number(params.length) || 5));
const variation = Math.max(0, Math.min(2, Number(params.variation) || 0));
// Add some randomness to count
const actualCount = count + Math.floor((Math.random() - 0.5) * 8);
for (let i = 0; i < actualCount; i++) {
const angle = (i / actualCount) * Math.PI * 2;
const lineLength = length + (Math.random() - 0.5) * variation;
const isDashed = Math.random() < 0.2;
const hasArrow = Math.random() < 0.3; // 30% chance of arrow
const endX = center[0] + Math.cos(angle) * lineLength;
const endY = center[1] + Math.sin(angle) * lineLength;
// Main line
lines.push({
points: [
[center[0], center[1], 0],
[endX, endY, 0]
],
color: "#509EF0",
opacity: 0.6 + Math.random() * 0.2,
lineWidth: 1.5,
isDashed: isDashed
});
// Add arrow head if selected
if (hasArrow && lineLength > 0.5) {
const arrowSize = Math.min(0.15, lineLength * 0.1);
lines.push({
points: [
[endX, endY, 0],
[endX - Math.cos(angle - 0.3) * arrowSize, endY - Math.sin(angle - 0.3) * arrowSize, 0]
],
color: "#509EF0",
opacity: 0.8,
lineWidth: 1.5
});
lines.push({
points: [
[endX, endY, 0],
[endX - Math.cos(angle + 0.3) * arrowSize, endY - Math.sin(angle + 0.3) * arrowSize, 0]
],
color: "#509EF0",
opacity: 0.8,
lineWidth: 1.5
});
}
}
return lines;
} catch (error) {
console.error('Error in radial_lines algorithm:', error);
return [];
}
},
// SAFE: Enhanced scatter with small 3D-like markers
scatter: (params) => {
try {
const lines = [];
const count = Math.max(50, Math.min(400, Number(params.count) || 100));
const distribution = params.distribution || "random";
const bounds = Array.isArray(params.bounds) ? params.bounds : [-5, 5];
const markerStyle = params.marker_style || "mixed"; // "cross", "circle", "square", "mixed"
for (let i = 0; i < count; i++) {
let x, y, z;
// Distribution logic
if (distribution === "exponential") {
const t = (Math.random() - 0.5) * 8;
x = t;
y = t > 0 ? Math.exp(t * 0.3) - 1 : (Math.random() - 0.5) * 2;
z = (Math.random() - 0.5) * 2;
} else if (distribution === "clustered") {
const clusterCenter = [(Math.random() - 0.5) * bounds[1], (Math.random() - 0.5) * bounds[1]];
x = clusterCenter[0] + (Math.random() - 0.5) * 2;
y = clusterCenter[1] + (Math.random() - 0.5) * 2;
z = (Math.random() - 0.5) * 2;
} else {
x = (Math.random() - 0.5) * (bounds[1] - bounds[0]);
y = (Math.random() - 0.5) * (bounds[1] - bounds[0]);
z = (Math.random() - 0.5) * 4;
}
// Enhanced markers with variation
const size = 0.03 + Math.random() * 0.04;
const currentMarkerStyle = markerStyle === "mixed" ?
["cross", "circle", "square"][Math.floor(Math.random() * 3)] : markerStyle;
const isDashed = Math.random() < 0.1;
if (currentMarkerStyle === "cross") {
lines.push({
points: [[x-size, y, z], [x+size, y, z]],
color: "#509EF0",
opacity: 0.7 + Math.random() * 0.2,
lineWidth: 1.5,
isDashed: isDashed
});
lines.push({
points: [[x, y-size, z], [x, y+size, z]],
color: "#509EF0",
opacity: 0.7 + Math.random() * 0.2,
lineWidth: 1.5,
isDashed: isDashed
});
} else if (currentMarkerStyle === "circle") {
const circlePoints = [];
const segments = 8;
for (let j = 0; j <= segments; j++) {
const angle = (j / segments) * Math.PI * 2;
circlePoints.push([
x + Math.cos(angle) * size,
y + Math.sin(angle) * size,
z
]);
}
lines.push({
points: circlePoints,
color: "#509EF0",
opacity: 0.6 + Math.random() * 0.2,
lineWidth: 1.5,
isDashed: isDashed
});
} else if (currentMarkerStyle === "square") {
const squarePoints = [
[x-size, y-size, z], [x+size, y-size, z],
[x+size, y+size, z], [x-size, y+size, z],
[x-size, y-size, z]
];
lines.push({
points: squarePoints,
color: "#509EF0",
opacity: 0.6 + Math.random() * 0.2,
lineWidth: 1.5,
isDashed: isDashed
});
}
}
return lines;
} catch (error) {
console.error('Error in scatter algorithm:', error);
return [];
}
},
// SAFE: Grid algorithm with error handling
grid: (params) => {
try {
const lines = [];
const spacing = Math.max(0.1, Math.min(2, Number(params.spacing) || 0.5));
const size = Math.max(2, Math.min(12, Number(params.size) || 8));
const noise = Math.max(0, Math.min(1, Number(params.noise) || 0));
for (let x = -size; x <= size; x += spacing) {
const yOffset = noise * (Math.random() - 0.5);
lines.push({
points: [[x, -size + yOffset, 0], [x, size + yOffset, 0]],
color: "#509EF0",
opacity: 0.4,
lineWidth: 1.5,
isDashed: Math.random() < 0.1
});
}
for (let y = -size; y <= size; y += spacing) {
const xOffset = noise * (Math.random() - 0.5);
lines.push({
points: [[-size + xOffset, y, 0], [size + xOffset, y, 0]],
color: "#509EF0",
opacity: 0.4,
lineWidth: 1.5,
isDashed: Math.random() < 0.1
});
}
return lines;
} catch (error) {
console.error('Error in grid algorithm:', error);
return [];
}
},
// SAFE: Network algorithm with error handling
network: (params) => {
try {
const lines = [];
const nodes = Math.max(5, Math.min(50, Number(params.nodes) || 20));
const bounds = Array.isArray(params.bounds) ? params.bounds : [-5, 5];
const connectionProb = Math.max(0.05, Math.min(0.8, Number(params.connection_probability) || 0.2));
// Generate random nodes
const nodePositions = [];
for (let i = 0; i < nodes; i++) {
nodePositions.push([
(Math.random() - 0.5) * (bounds[1] - bounds[0]),
(Math.random() - 0.5) * (bounds[1] - bounds[0]),
(Math.random() - 0.5) * 2
]);
}
// Connect nodes based on probability
for (let i = 0; i < nodes; i++) {
for (let j = i + 1; j < nodes; j++) {
if (Math.random() < connectionProb) {
lines.push({
points: [nodePositions[i], nodePositions[j]],
color: "#509EF0",
opacity: 0.5,
lineWidth: 1.5,
isDashed: Math.random() < 0.2
});
}
}
}
return lines;
} catch (error) {
console.error('Error in network algorithm:', error);
return [];
}
},
// SAFE: Spiral algorithm with error handling
spiral: (params) => {
try {
const lines = [];
const turns = Math.max(1, Math.min(10, Number(params.turns) || 5));
const maxRadius = Math.max(1, Math.min(10, Number(params.max_radius) || 6));
const points = [];
const totalPoints = turns * 50;
for (let i = 0; i <= totalPoints; i++) {
const t = i / totalPoints;
const angle = t * turns * Math.PI * 2;
const radius = t * maxRadius;
points.push([
Math.cos(angle) * radius,
Math.sin(angle) * radius,
(Math.random() - 0.5) * 0.5
]);
}
lines.push({
points: points,
color: "#509EF0",
opacity: 0.7,
lineWidth: 1.5,
isDashed: Math.random() < 0.3
});
return lines;
} catch (error) {
console.error('Error in spiral algorithm:', error);
return [];
}
},
// SAFE: Wave algorithm with error handling
wave: (params) => {
try {
const lines = [];
const frequency = Math.max(0.5, Math.min(5, Number(params.frequency) || 2));
const amplitude = Math.max(0.5, Math.min(6, Number(params.amplitude) || 3));
const length = Math.max(4, Math.min(20, Number(params.length) || 12));
const points = [];
for (let x = -length/2; x <= length/2; x += 0.1) {
const y = amplitude * Math.sin(frequency * x);
points.push([x, y, 0]);
}
lines.push({
points: points,
color: "#509EF0",
opacity: 0.8,
lineWidth: 1.5
});
return lines;
} catch (error) {
console.error('Error in wave algorithm:', error);
return [];
}
},
// SAFE: Logarithmic spiral algorithm with error handling
logarithmic_spiral: (params) => {
try {
const lines = [];
const a = Math.max(0.1, Math.min(1, Number(params.growth_factor) || 0.3));
const turns = Math.max(1, Math.min(8, Number(params.turns) || 4));
const points = [];
for (let theta = 0; theta <= turns * Math.PI * 2; theta += 0.1) {
const r = a * Math.exp(0.2 * theta);
if (r > 20) break; // Prevent infinite growth
points.push([
r * Math.cos(theta),
r * Math.sin(theta),
0
]);
}
lines.push({
points: points,
color: "#509EF0",
opacity: 0.7,
lineWidth: 1.5
});
return lines;
} catch (error) {
console.error('Error in logarithmic_spiral algorithm:', error);
return [];
}
}
};
// Enhanced line rendering function that handles dashed lines with comprehensive error handling
function generateFromAlgorithms(algorithmData) {
const allLines = [];
const maxTotalLines = 3000; // Reduced for better performance
const maxAlgorithms = 6; // Allow more algorithms but smaller ones
console.log(`Processing ${algorithmData.algorithms.length} algorithms`);
if (!algorithmData || !algorithmData.algorithms || !Array.isArray(algorithmData.algorithms)) {
console.error('Invalid algorithm data structure');
return createFallbackVisualization();
}
const algorithmsToProcess = algorithmData.algorithms.slice(0, maxAlgorithms);
algorithmsToProcess.forEach((algorithm, index) => {
try {
console.log(`Processing algorithm ${index + 1}: ${algorithm.type}`);
if (!algorithm || typeof algorithm !== 'object' || !algorithm.type) {
console.warn(`Invalid algorithm at index ${index}:`, algorithm);
return;
}
if (allLines.length > maxTotalLines) {
console.warn(`Stopping algorithm processing - line limit reached (${allLines.length})`);
return;
}
if (!enhancedAlgorithmGenerators[algorithm.type]) {
console.warn(`Unknown algorithm type: ${algorithm.type}`);
return;
}
const params = algorithm.params || {};
const startTime = Date.now();
let lines = [];
try {
lines = enhancedAlgorithmGenerators[algorithm.type](params);
if (!Array.isArray(lines)) {
console.warn(`Algorithm ${algorithm.type} returned non-array:`, typeof lines);
return;
}
// Enhanced line validation and processing
const validLines = lines.filter(line => {
try {
if (!line || typeof line !== 'object') return false;
if (!Array.isArray(line.points)) return false;
if (line.points.length < 2) return false;
return line.points.every(point => {
if (!Array.isArray(point) || point.length !== 3) return false;
return point.every(coord => typeof coord === 'number' && isFinite(coord));
});
} catch (validationError) {
console.warn('Line validation error:', validationError);
return false;
}
}).map(line => {
try {
// Ensure consistent line weight and process dashed lines
const processedLine = {
...line,
lineWidth: 1.5, // Force consistent line weight
color: line.color || "#509EF0",
opacity: Math.max(0.1, Math.min(1.0, Number(line.opacity) || 0.6))
};
// Handle dashed lines by creating segmented geometry
if (line.isDashed && line.points.length > 1) {
processedLine.isDashed = true;
processedLine.dashArray = [0.1, 0.05]; // 10% dash, 5% gap relative to line length
}
return processedLine;
} catch (processingError) {
console.warn('Line processing error:', processingError);
return {
points: line.points,
color: "#509EF0",
opacity: 0.6,
lineWidth: 1.5
};
}
});
lines = validLines;
} catch (error) {
console.error(`Error generating ${algorithm.type}:`, error);
return;
}
const endTime = Date.now();
const duration = endTime - startTime;
if (duration > 1000) {
console.warn(`Algorithm ${algorithm.type} took ${duration}ms to generate ${lines.length} lines`);
}
// More generous per-algorithm limits since we're aiming for variety
if (lines.length > 800) {
console.warn(`Algorithm ${algorithm.type} generated too many lines (${lines.length}), truncating to 800`);
lines = lines.slice(0, 800);
}
if (allLines.length + lines.length > maxTotalLines) {
const remainingSlots = maxTotalLines - allLines.length;
console.warn(`Truncating ${algorithm.type} lines from ${lines.length} to ${remainingSlots} to stay within global limit`);
lines = lines.slice(0, remainingSlots);
}
allLines.push(...lines);
console.log(`Generated ${lines.length} lines from ${algorithm.type} (total: ${allLines.length})`);
} catch (error) {
console.error(`Fatal error processing algorithm ${algorithm.type}:`, error);
}
});
console.log(`Total lines generated: ${allLines.length}`);
const metadata = {
generated_at: new Date().toISOString(),
algorithms_used: algorithmsToProcess.map(a => a.type),
total_lines: allLines.length,
algorithms_processed: algorithmsToProcess.length,
algorithms_requested: algorithmData.algorithms.length,
visual_style: algorithmData.visual_style || {},
line_weight_standard: "1.5px",
has_dashed_lines: allLines.some(line => line.isDashed),
has_arrows: allLines.some(line => line.hasArrow),
variation_level: "high"
};
if (allLines.length > 2500) {
metadata.performance_warning = "High line count may impact rendering performance";
}
if (algorithmsToProcess.length < algorithmData.algorithms.length) {
metadata.truncation_warning = `Only processed ${algorithmsToProcess.length} of ${algorithmData.algorithms.length} algorithms`;
}
return {
title: algorithmData.title || "Generated Technical Art",
description: algorithmData.description || "Varied algorithmic visualization with consistent styling",
lines: allLines,
camera: validateCamera(algorithmData.camera),
metadata: metadata
};
}
// Fallback visualization when algorithm data is invalid
function createFallbackVisualization() {
console.warn('Creating fallback visualization');
const fallbackLines = [];
// Simple concentric circles
for (let i = 1; i <= 8; i++) {
const radius = i * 0.8;
const points = [];
const segments = 32;
for (let j = 0; j <= segments; j++) {
const angle = (j / segments) * Math.PI * 2;
points.push([
Math.cos(angle) * radius,
Math.sin(angle) * radius,
0
]);
}
fallbackLines.push({
points: points,
color: "#509EF0",
opacity: 0.6,
lineWidth: 1.5,
isDashed: i % 3 === 0 // Every third circle is dashed
});
}
// Add some radial lines
for (let i = 0; i < 12; i++) {
const angle = (i / 12) * Math.PI * 2;
fallbackLines.push({
points: [
[0, 0, 0],
[Math.cos(angle) * 6, Math.sin(angle) * 6, 0]
],
color: "#509EF0",
opacity: 0.5,
lineWidth: 1.5,
isDashed: i % 4 === 0 // Every fourth line is dashed
});
}
// Add some precision markers
for (let i = 0; i < 15; i++) {
const x = (Math.random() - 0.5) * 10;
const y = (Math.random() - 0.5) * 10;
const size = 0.05;
// Cross marker
fallbackLines.push({
points: [[x - size, y, 0], [x + size, y, 0]],
color: "#509EF0",
opacity: 0.8,
lineWidth: 1.5
});
fallbackLines.push({
points: [[x, y - size, 0], [x, y + size, 0]],
color: "#509EF0",
opacity: 0.8,
lineWidth: 1.5
});
}
return {
title: "Fallback Technical Art",
description: "Default visualization with varied line styles",
lines: fallbackLines,
camera: { position: [8, 6, 10], lookAt: [0, 0, 0] },
metadata: {
generated_at: new Date().toISOString(),
algorithms_used: ["fallback_concentric", "fallback_radial", "fallback_markers"],
total_lines: fallbackLines.length,
is_fallback: true,
line_weight_standard: "1.5px"
}
};
}
function validateCamera(camera) {
try {
if (!camera || typeof camera !== 'object') {
return { position: [8, 6, 10], lookAt: [0, 0, 0] };
}
const position = Array.isArray(camera.position) && camera.position.length === 3 &&
camera.position.every(coord => typeof coord === 'number' && isFinite(coord))
? camera.position : [8, 6, 10];
const lookAt = Array.isArray(camera.lookAt) && camera.lookAt.length === 3 &&
camera.lookAt.every(coord => typeof coord === 'number' && isFinite(coord))
? camera.lookAt : [0, 0, 0];
return { position, lookAt };
} catch (error) {
console.error('Error validating camera:', error);
return { position: [8, 6, 10], lookAt: [0, 0, 0] };
}
}