Skip to main content
Glama
by alucardeht
frameAnalysis.js4.04 kB
import { colorToHex, extractFillInfo } from "./colors.js"; export function countElements(node) { if (!node) return 0; let count = 1; if (node.children) { for (const child of node.children) { count += countElements(child); } } return count; } export function analyzeFrame(node, depth, currentDepth = 0) { if (!node) return null; const result = { name: node.name, type: node.type, id: node.id, }; if (node.absoluteBoundingBox) { result.bounds = { x: Math.round(node.absoluteBoundingBox.x), y: Math.round(node.absoluteBoundingBox.y), width: Math.round(node.absoluteBoundingBox.width), height: Math.round(node.absoluteBoundingBox.height), }; } if (node.type === "TEXT") { result.text = node.characters; if (node.style) { result.textStyle = { fontFamily: node.style.fontFamily, fontSize: node.style.fontSize, fontWeight: node.style.fontWeight, lineHeight: node.style.lineHeightPx, letterSpacing: node.style.letterSpacing, }; } } if (node.fills?.length > 0) { result.fills = node.fills .filter((f) => f.visible !== false) .map((f) => extractFillInfo(f)); } if (node.strokes?.length > 0) { result.strokes = node.strokes.map((s) => ({ color: colorToHex(s.color), weight: node.strokeWeight, })); } if (node.effects?.length > 0) { result.effects = node.effects.map((e) => ({ type: e.type, radius: e.radius, color: e.color ? colorToHex(e.color) : null, offset: e.offset, })); } if (node.cornerRadius) { result.cornerRadius = node.cornerRadius; } if (node.paddingLeft || node.paddingTop || node.paddingRight || node.paddingBottom) { result.padding = { top: node.paddingTop || 0, right: node.paddingRight || 0, bottom: node.paddingBottom || 0, left: node.paddingLeft || 0, }; } if (node.itemSpacing) { result.gap = node.itemSpacing; } if (node.layoutMode) { result.layout = { mode: node.layoutMode, align: node.primaryAxisAlignItems, crossAlign: node.counterAxisAlignItems, }; } if (currentDepth < depth && node.children?.length > 0) { result.children = node.children.map((child) => analyzeFrame(child, depth, currentDepth + 1)); } else if (node.children?.length > 0) { result.childCount = node.children.length; } return result; } export function collectStyles(node, styles) { if (!node) return; if (node.fills) { node.fills.forEach((fill) => { if (fill.type === "SOLID" && fill.color) { styles.colors.add(colorToHex(fill.color)); } }); } if (node.strokes) { node.strokes.forEach((stroke) => { if (stroke.color) { styles.colors.add(colorToHex(stroke.color)); } }); } if (node.style) { if (node.style.fontFamily) styles.fonts.add(node.style.fontFamily); if (node.style.fontSize) styles.fontSizes.add(node.style.fontSize); } if (node.cornerRadius) styles.borderRadii.add(node.cornerRadius); if (node.paddingTop) styles.spacing.add(node.paddingTop); if (node.paddingRight) styles.spacing.add(node.paddingRight); if (node.paddingBottom) styles.spacing.add(node.paddingBottom); if (node.paddingLeft) styles.spacing.add(node.paddingLeft); if (node.itemSpacing) styles.spacing.add(node.itemSpacing); if (node.effects) { node.effects.forEach((effect) => { if (effect.type === "DROP_SHADOW" || effect.type === "INNER_SHADOW") { const shadow = { type: effect.type, color: effect.color ? colorToHex(effect.color) : null, offset: effect.offset, radius: effect.radius, spread: effect.spread, }; if (!styles.shadows.some((s) => JSON.stringify(s) === JSON.stringify(shadow))) { styles.shadows.push(shadow); } } }); } if (node.children) { node.children.forEach((child) => collectStyles(child, styles)); } }

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/alucardeht/figma-mcp'

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