figma-metadata-extractor 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,8 +10,28 @@ npm install figma-metadata-extractor
10
10
 
11
11
  ## Quick Start
12
12
 
13
+ ### Get Metadata with Auto-Downloaded Images (LLM-Ready!)
14
+
15
+ ```typescript
16
+ import { getFigmaMetadata } from 'figma-metadata-extractor';
17
+
18
+ // Extract metadata AND automatically download image assets
19
+ const metadata = await getFigmaMetadata(
20
+ 'https://figma.com/file/ABC123/My-Design',
21
+ {
22
+ apiKey: 'your-figma-api-key',
23
+ outputFormat: 'object',
24
+ downloadImages: true, // Auto-download image assets
25
+ localPath: './assets/images' // Where to save images
26
+ }
27
+ );
28
+
29
+ ```
30
+
31
+ ### Get Metadata Only (No Downloads)
32
+
13
33
  ```typescript
14
- import { getFigmaMetadata, downloadFigmaImages } from 'figma-metadata-extractor';
34
+ import { getFigmaMetadata } from 'figma-metadata-extractor';
15
35
 
16
36
  // Extract metadata from a Figma file
17
37
  const metadata = await getFigmaMetadata(
@@ -45,6 +65,20 @@ const images = await downloadFigmaImages(
45
65
  );
46
66
 
47
67
  console.log(images); // Array of download results
68
+
69
+ // Download a single frame image from a Figma URL
70
+ const frameImage = await downloadFigmaFrameImage(
71
+ 'https://figma.com/file/ABC123/My-Design?node-id=1234-5678',
72
+ {
73
+ apiKey: 'your-figma-api-key',
74
+ localPath: './assets/frames',
75
+ fileName: 'my-frame.png',
76
+ format: 'png', // or 'svg'
77
+ pngScale: 2
78
+ }
79
+ );
80
+
81
+ console.log(frameImage.filePath); // Path to downloaded image
48
82
  ```
49
83
 
50
84
  ## API Reference
@@ -63,9 +97,24 @@ Extracts comprehensive metadata from a Figma file including layout, content, vis
63
97
  - `useOAuth?: boolean` - Whether to use OAuth instead of API key
64
98
  - `outputFormat?: 'json' | 'yaml' | 'object'` - Output format (default: 'object')
65
99
  - `depth?: number` - Maximum depth to traverse the node tree
100
+ - `downloadImages?: boolean` - Automatically download image assets and enrich metadata (default: false)
101
+ - `localPath?: string` - Local path for downloaded images (required if downloadImages is true)
102
+ - `imageFormat?: 'png' | 'svg'` - Image format for downloads (default: 'png')
103
+ - `pngScale?: number` - Export scale for PNG images (default: 2)
66
104
 
67
105
  **Returns:** Promise<FigmaMetadataResult | string>
68
106
 
107
+ When `downloadImages` is true, nodes with image assets will include a `downloadedImage` property:
108
+ ```typescript
109
+ {
110
+ filePath: string; // Absolute path
111
+ relativePath: string; // Relative path for code
112
+ dimensions: { width, height };
113
+ markdown: string; // ![name](path)
114
+ html: string; // <img src="..." />
115
+ }
116
+ ```
117
+
69
118
  ### `downloadFigmaImages(figmaUrl, nodes, options)`
70
119
 
71
120
  Downloads SVG and PNG images from a Figma file.
@@ -90,6 +139,25 @@ Downloads SVG and PNG images from a Figma file.
90
139
 
91
140
  **Returns:** Promise<FigmaImageResult[]>
92
141
 
142
+ ### `downloadFigmaFrameImage(figmaUrl, options)`
143
+
144
+ Downloads a single frame image from a Figma URL that contains a node-id parameter.
145
+
146
+ **Parameters:**
147
+ - `figmaUrl` (string): The Figma URL with node-id parameter (e.g., `https://figma.com/file/ABC123/My-Design?node-id=1234-5678`)
148
+ - `options` (FigmaFrameImageOptions): Configuration options
149
+
150
+ **Options:**
151
+ - `apiKey?: string` - Figma API key (Personal Access Token)
152
+ - `oauthToken?: string` - Figma OAuth Bearer token
153
+ - `useOAuth?: boolean` - Whether to use OAuth instead of API key
154
+ - `localPath: string` - Absolute path to save the image
155
+ - `fileName: string` - Local filename (must end with .png or .svg)
156
+ - `format?: 'png' | 'svg'` - Image format to download (default: 'png')
157
+ - `pngScale?: number` - Export scale for PNG images (default: 2)
158
+
159
+ **Returns:** Promise<FigmaImageResult>
160
+
93
161
  ## Authentication
94
162
 
95
163
  You need either a Figma API key or OAuth token:
@@ -104,6 +172,50 @@ You need either a Figma API key or OAuth token:
104
172
  2. Use the bearer token in the `oauthToken` option
105
173
  3. Set `useOAuth: true`
106
174
 
175
+ ## Usage Examples
176
+
177
+ ### Download Frame Image from Figma URL
178
+
179
+ The easiest way to download a frame image is to copy the Figma URL directly from your browser when viewing a specific frame:
180
+
181
+ ```typescript
182
+ import { downloadFigmaFrameImage } from 'figma-metadata-extractor';
183
+
184
+ // Copy this URL from Figma when viewing a frame
185
+ const figmaUrl = 'https://www.figma.com/design/ABC123/My-Design?node-id=1234-5678&t=xyz123';
186
+
187
+ const result = await downloadFigmaFrameImage(figmaUrl, {
188
+ apiKey: 'your-figma-api-key',
189
+ localPath: './downloads',
190
+ fileName: 'my-frame.png',
191
+ format: 'png',
192
+ pngScale: 2 // High resolution
193
+ });
194
+
195
+ console.log(`Downloaded to: ${result.filePath}`);
196
+ console.log(`Dimensions: ${result.finalDimensions.width}x${result.finalDimensions.height}`);
197
+ ```
198
+
199
+ ### Download Multiple Frame Images
200
+
201
+ ```typescript
202
+ import { downloadFigmaImages } from 'figma-metadata-extractor';
203
+
204
+ // For multiple frames, use the batch download function
205
+ const results = await downloadFigmaImages(
206
+ 'https://figma.com/file/ABC123/My-Design',
207
+ [
208
+ { nodeId: '1234:5678', fileName: 'frame1.png' },
209
+ { nodeId: '9876:5432', fileName: 'frame2.svg' },
210
+ { nodeId: '1111:2222', fileName: 'frame3.png' }
211
+ ],
212
+ {
213
+ apiKey: 'your-figma-api-key',
214
+ localPath: './frames'
215
+ }
216
+ );
217
+ ```
218
+
107
219
  ## Advanced Usage
108
220
 
109
221
  The library also exports the underlying extractor system for custom processing:
package/dist/index.cjs CHANGED
@@ -1365,7 +1365,17 @@ function collapseSvgContainers(node, result, children) {
1365
1365
  return children;
1366
1366
  }
1367
1367
  async function getFigmaMetadata(figmaUrl, options = {}) {
1368
- const { apiKey, oauthToken, useOAuth = false, outputFormat = "object", depth } = options;
1368
+ const {
1369
+ apiKey,
1370
+ oauthToken,
1371
+ useOAuth = false,
1372
+ outputFormat = "object",
1373
+ depth,
1374
+ downloadImages = false,
1375
+ localPath,
1376
+ imageFormat = "png",
1377
+ pngScale = 2
1378
+ } = options;
1369
1379
  if (!apiKey && !oauthToken) {
1370
1380
  throw new Error("Either apiKey or oauthToken is required");
1371
1381
  }
@@ -1399,11 +1409,33 @@ async function getFigmaMetadata(figmaUrl, options = {}) {
1399
1409
  `Successfully extracted data: ${simplifiedDesign.nodes.length} nodes, ${Object.keys(simplifiedDesign.globalVars?.styles || {}).length} styles`
1400
1410
  );
1401
1411
  const { nodes, globalVars, ...metadata } = simplifiedDesign;
1402
- const result = {
1412
+ let result = {
1403
1413
  metadata,
1404
1414
  nodes,
1405
1415
  globalVars
1406
1416
  };
1417
+ if (downloadImages) {
1418
+ if (!localPath) {
1419
+ throw new Error("localPath is required when downloadImages is true");
1420
+ }
1421
+ Logger.log("Discovering and downloading image assets...");
1422
+ const imageAssets = findImageAssets(nodes, globalVars);
1423
+ Logger.log(`Found ${imageAssets.length} image assets to download`);
1424
+ if (imageAssets.length > 0) {
1425
+ const imageNodes = imageAssets.map((asset) => ({
1426
+ nodeId: asset.id,
1427
+ fileName: sanitizeFileName(asset.name) + `.${imageFormat}`
1428
+ }));
1429
+ const downloadResults = await figmaService.downloadImages(
1430
+ fileKey,
1431
+ localPath,
1432
+ imageNodes,
1433
+ { pngScale: imageFormat === "png" ? pngScale : void 0 }
1434
+ );
1435
+ result.nodes = enrichNodesWithImages(nodes, imageAssets, downloadResults);
1436
+ Logger.log(`Successfully downloaded and enriched ${downloadResults.length} images`);
1437
+ }
1438
+ }
1407
1439
  if (outputFormat === "json") {
1408
1440
  return JSON.stringify(result, null, 2);
1409
1441
  } else if (outputFormat === "yaml") {
@@ -1446,10 +1478,116 @@ async function downloadFigmaImages(figmaUrl, nodes, options) {
1446
1478
  throw new Error(`Failed to download images: ${error instanceof Error ? error.message : String(error)}`);
1447
1479
  }
1448
1480
  }
1481
+ async function downloadFigmaFrameImage(figmaUrl, options) {
1482
+ const {
1483
+ apiKey,
1484
+ oauthToken,
1485
+ useOAuth = false,
1486
+ pngScale = 2,
1487
+ localPath,
1488
+ fileName,
1489
+ format = "png"
1490
+ } = options;
1491
+ if (!apiKey && !oauthToken) {
1492
+ throw new Error("Either apiKey or oauthToken is required");
1493
+ }
1494
+ const urlMatch = figmaUrl.match(/figma\.com\/(file|design)\/([a-zA-Z0-9]+)/);
1495
+ if (!urlMatch) {
1496
+ throw new Error("Invalid Figma URL format");
1497
+ }
1498
+ const fileKey = urlMatch[2];
1499
+ const nodeIdMatch = figmaUrl.match(/node-id=([^&]+)/);
1500
+ if (!nodeIdMatch) {
1501
+ throw new Error("No frame node-id found in URL. Please provide a Figma URL with a node-id parameter (e.g., ?node-id=123-456)");
1502
+ }
1503
+ const nodeId = nodeIdMatch[1].replace(/-/g, ":");
1504
+ const expectedExtension = `.${format}`;
1505
+ if (!fileName.toLowerCase().endsWith(expectedExtension)) {
1506
+ throw new Error(`Filename must end with ${expectedExtension} for ${format} format`);
1507
+ }
1508
+ const figmaService = new FigmaService({
1509
+ figmaApiKey: apiKey || "",
1510
+ figmaOAuthToken: oauthToken || "",
1511
+ useOAuth: useOAuth && !!oauthToken
1512
+ });
1513
+ try {
1514
+ Logger.log(`Downloading ${format.toUpperCase()} image for frame ${nodeId} from file ${fileKey}`);
1515
+ const imageNode = {
1516
+ nodeId,
1517
+ fileName
1518
+ };
1519
+ const results = await figmaService.downloadImages(fileKey, localPath, [imageNode], {
1520
+ pngScale: format === "png" ? pngScale : void 0
1521
+ });
1522
+ if (results.length === 0) {
1523
+ throw new Error(`Failed to download image for frame ${nodeId}`);
1524
+ }
1525
+ Logger.log(`Successfully downloaded frame image to: ${results[0].filePath}`);
1526
+ return results[0];
1527
+ } catch (error) {
1528
+ Logger.error(`Error downloading frame image from ${fileKey}:`, error);
1529
+ throw new Error(`Failed to download frame image: ${error instanceof Error ? error.message : String(error)}`);
1530
+ }
1531
+ }
1532
+ function sanitizeFileName(name) {
1533
+ return name.replace(/[^a-z0-9]/gi, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").toLowerCase();
1534
+ }
1535
+ function findImageAssets(nodes, globalVars) {
1536
+ const images = [];
1537
+ function traverse(node) {
1538
+ const isImageAsset = node.type === "IMAGE-SVG" || hasImageFill(node, globalVars);
1539
+ if (isImageAsset) {
1540
+ images.push(node);
1541
+ }
1542
+ if (node.children && Array.isArray(node.children)) {
1543
+ node.children.forEach(traverse);
1544
+ }
1545
+ }
1546
+ nodes.forEach(traverse);
1547
+ return images;
1548
+ }
1549
+ function hasImageFill(node, globalVars) {
1550
+ if (!node.fills || typeof node.fills !== "string") {
1551
+ return false;
1552
+ }
1553
+ const fillData = globalVars?.styles?.[node.fills];
1554
+ if (!fillData || !Array.isArray(fillData)) {
1555
+ return false;
1556
+ }
1557
+ return fillData.some((fill) => fill?.type === "IMAGE");
1558
+ }
1559
+ function enrichNodesWithImages(nodes, imageAssets, downloadResults) {
1560
+ const imageMap = /* @__PURE__ */ new Map();
1561
+ imageAssets.forEach((asset, index) => {
1562
+ const result = downloadResults[index];
1563
+ if (result) {
1564
+ imageMap.set(asset.id, {
1565
+ filePath: result.filePath,
1566
+ relativePath: result.filePath.replace(process.cwd(), "."),
1567
+ dimensions: result.finalDimensions,
1568
+ wasCropped: result.wasCropped,
1569
+ markdown: `![${asset.name}](${result.filePath.replace(process.cwd(), ".")})`,
1570
+ html: `<img src="${result.filePath.replace(process.cwd(), ".")}" alt="${asset.name}" width="${result.finalDimensions.width}" height="${result.finalDimensions.height}">`
1571
+ });
1572
+ }
1573
+ });
1574
+ function enrichNode(node) {
1575
+ const enriched = { ...node };
1576
+ if (imageMap.has(node.id)) {
1577
+ enriched.downloadedImage = imageMap.get(node.id);
1578
+ }
1579
+ if (node.children && Array.isArray(node.children)) {
1580
+ enriched.children = node.children.map(enrichNode);
1581
+ }
1582
+ return enriched;
1583
+ }
1584
+ return nodes.map(enrichNode);
1585
+ }
1449
1586
  exports.allExtractors = allExtractors;
1450
1587
  exports.collapseSvgContainers = collapseSvgContainers;
1451
1588
  exports.componentExtractor = componentExtractor;
1452
1589
  exports.contentOnly = contentOnly;
1590
+ exports.downloadFigmaFrameImage = downloadFigmaFrameImage;
1453
1591
  exports.downloadFigmaImages = downloadFigmaImages;
1454
1592
  exports.extractFromDesign = extractFromDesign;
1455
1593
  exports.getFigmaMetadata = getFigmaMetadata;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { getFigmaMetadata, downloadFigmaImages, type FigmaMetadataOptions, type FigmaImageOptions, type FigmaImageNode, type FigmaMetadataResult, type FigmaImageResult, } from "./lib.js";
1
+ export { getFigmaMetadata, downloadFigmaImages, downloadFigmaFrameImage, type FigmaMetadataOptions, type FigmaImageOptions, type FigmaFrameImageOptions, type FigmaImageNode, type FigmaMetadataResult, type FigmaImageResult, } from "./lib.js";
2
2
  export type { SimplifiedDesign } from "./extractors/types.js";
3
3
  export type { ExtractorFn, TraversalContext, TraversalOptions, GlobalVars, StyleTypes, } from "./extractors/index.js";
4
4
  export { extractFromDesign, simplifyRawFigmaObject, layoutExtractor, textExtractor, visualsExtractor, componentExtractor, allExtractors, layoutAndText, contentOnly, visualsOnly, layoutOnly, collapseSvgContainers, } from "./extractors/index.js";
package/dist/index.js CHANGED
@@ -1363,7 +1363,17 @@ function collapseSvgContainers(node, result, children) {
1363
1363
  return children;
1364
1364
  }
1365
1365
  async function getFigmaMetadata(figmaUrl, options = {}) {
1366
- const { apiKey, oauthToken, useOAuth = false, outputFormat = "object", depth } = options;
1366
+ const {
1367
+ apiKey,
1368
+ oauthToken,
1369
+ useOAuth = false,
1370
+ outputFormat = "object",
1371
+ depth,
1372
+ downloadImages = false,
1373
+ localPath,
1374
+ imageFormat = "png",
1375
+ pngScale = 2
1376
+ } = options;
1367
1377
  if (!apiKey && !oauthToken) {
1368
1378
  throw new Error("Either apiKey or oauthToken is required");
1369
1379
  }
@@ -1397,11 +1407,33 @@ async function getFigmaMetadata(figmaUrl, options = {}) {
1397
1407
  `Successfully extracted data: ${simplifiedDesign.nodes.length} nodes, ${Object.keys(simplifiedDesign.globalVars?.styles || {}).length} styles`
1398
1408
  );
1399
1409
  const { nodes, globalVars, ...metadata } = simplifiedDesign;
1400
- const result = {
1410
+ let result = {
1401
1411
  metadata,
1402
1412
  nodes,
1403
1413
  globalVars
1404
1414
  };
1415
+ if (downloadImages) {
1416
+ if (!localPath) {
1417
+ throw new Error("localPath is required when downloadImages is true");
1418
+ }
1419
+ Logger.log("Discovering and downloading image assets...");
1420
+ const imageAssets = findImageAssets(nodes, globalVars);
1421
+ Logger.log(`Found ${imageAssets.length} image assets to download`);
1422
+ if (imageAssets.length > 0) {
1423
+ const imageNodes = imageAssets.map((asset) => ({
1424
+ nodeId: asset.id,
1425
+ fileName: sanitizeFileName(asset.name) + `.${imageFormat}`
1426
+ }));
1427
+ const downloadResults = await figmaService.downloadImages(
1428
+ fileKey,
1429
+ localPath,
1430
+ imageNodes,
1431
+ { pngScale: imageFormat === "png" ? pngScale : void 0 }
1432
+ );
1433
+ result.nodes = enrichNodesWithImages(nodes, imageAssets, downloadResults);
1434
+ Logger.log(`Successfully downloaded and enriched ${downloadResults.length} images`);
1435
+ }
1436
+ }
1405
1437
  if (outputFormat === "json") {
1406
1438
  return JSON.stringify(result, null, 2);
1407
1439
  } else if (outputFormat === "yaml") {
@@ -1444,11 +1476,117 @@ async function downloadFigmaImages(figmaUrl, nodes, options) {
1444
1476
  throw new Error(`Failed to download images: ${error instanceof Error ? error.message : String(error)}`);
1445
1477
  }
1446
1478
  }
1479
+ async function downloadFigmaFrameImage(figmaUrl, options) {
1480
+ const {
1481
+ apiKey,
1482
+ oauthToken,
1483
+ useOAuth = false,
1484
+ pngScale = 2,
1485
+ localPath,
1486
+ fileName,
1487
+ format = "png"
1488
+ } = options;
1489
+ if (!apiKey && !oauthToken) {
1490
+ throw new Error("Either apiKey or oauthToken is required");
1491
+ }
1492
+ const urlMatch = figmaUrl.match(/figma\.com\/(file|design)\/([a-zA-Z0-9]+)/);
1493
+ if (!urlMatch) {
1494
+ throw new Error("Invalid Figma URL format");
1495
+ }
1496
+ const fileKey = urlMatch[2];
1497
+ const nodeIdMatch = figmaUrl.match(/node-id=([^&]+)/);
1498
+ if (!nodeIdMatch) {
1499
+ throw new Error("No frame node-id found in URL. Please provide a Figma URL with a node-id parameter (e.g., ?node-id=123-456)");
1500
+ }
1501
+ const nodeId = nodeIdMatch[1].replace(/-/g, ":");
1502
+ const expectedExtension = `.${format}`;
1503
+ if (!fileName.toLowerCase().endsWith(expectedExtension)) {
1504
+ throw new Error(`Filename must end with ${expectedExtension} for ${format} format`);
1505
+ }
1506
+ const figmaService = new FigmaService({
1507
+ figmaApiKey: apiKey || "",
1508
+ figmaOAuthToken: oauthToken || "",
1509
+ useOAuth: useOAuth && !!oauthToken
1510
+ });
1511
+ try {
1512
+ Logger.log(`Downloading ${format.toUpperCase()} image for frame ${nodeId} from file ${fileKey}`);
1513
+ const imageNode = {
1514
+ nodeId,
1515
+ fileName
1516
+ };
1517
+ const results = await figmaService.downloadImages(fileKey, localPath, [imageNode], {
1518
+ pngScale: format === "png" ? pngScale : void 0
1519
+ });
1520
+ if (results.length === 0) {
1521
+ throw new Error(`Failed to download image for frame ${nodeId}`);
1522
+ }
1523
+ Logger.log(`Successfully downloaded frame image to: ${results[0].filePath}`);
1524
+ return results[0];
1525
+ } catch (error) {
1526
+ Logger.error(`Error downloading frame image from ${fileKey}:`, error);
1527
+ throw new Error(`Failed to download frame image: ${error instanceof Error ? error.message : String(error)}`);
1528
+ }
1529
+ }
1530
+ function sanitizeFileName(name) {
1531
+ return name.replace(/[^a-z0-9]/gi, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").toLowerCase();
1532
+ }
1533
+ function findImageAssets(nodes, globalVars) {
1534
+ const images = [];
1535
+ function traverse(node) {
1536
+ const isImageAsset = node.type === "IMAGE-SVG" || hasImageFill(node, globalVars);
1537
+ if (isImageAsset) {
1538
+ images.push(node);
1539
+ }
1540
+ if (node.children && Array.isArray(node.children)) {
1541
+ node.children.forEach(traverse);
1542
+ }
1543
+ }
1544
+ nodes.forEach(traverse);
1545
+ return images;
1546
+ }
1547
+ function hasImageFill(node, globalVars) {
1548
+ if (!node.fills || typeof node.fills !== "string") {
1549
+ return false;
1550
+ }
1551
+ const fillData = globalVars?.styles?.[node.fills];
1552
+ if (!fillData || !Array.isArray(fillData)) {
1553
+ return false;
1554
+ }
1555
+ return fillData.some((fill) => fill?.type === "IMAGE");
1556
+ }
1557
+ function enrichNodesWithImages(nodes, imageAssets, downloadResults) {
1558
+ const imageMap = /* @__PURE__ */ new Map();
1559
+ imageAssets.forEach((asset, index) => {
1560
+ const result = downloadResults[index];
1561
+ if (result) {
1562
+ imageMap.set(asset.id, {
1563
+ filePath: result.filePath,
1564
+ relativePath: result.filePath.replace(process.cwd(), "."),
1565
+ dimensions: result.finalDimensions,
1566
+ wasCropped: result.wasCropped,
1567
+ markdown: `![${asset.name}](${result.filePath.replace(process.cwd(), ".")})`,
1568
+ html: `<img src="${result.filePath.replace(process.cwd(), ".")}" alt="${asset.name}" width="${result.finalDimensions.width}" height="${result.finalDimensions.height}">`
1569
+ });
1570
+ }
1571
+ });
1572
+ function enrichNode(node) {
1573
+ const enriched = { ...node };
1574
+ if (imageMap.has(node.id)) {
1575
+ enriched.downloadedImage = imageMap.get(node.id);
1576
+ }
1577
+ if (node.children && Array.isArray(node.children)) {
1578
+ enriched.children = node.children.map(enrichNode);
1579
+ }
1580
+ return enriched;
1581
+ }
1582
+ return nodes.map(enrichNode);
1583
+ }
1447
1584
  export {
1448
1585
  allExtractors,
1449
1586
  collapseSvgContainers,
1450
1587
  componentExtractor,
1451
1588
  contentOnly,
1589
+ downloadFigmaFrameImage,
1452
1590
  downloadFigmaImages,
1453
1591
  extractFromDesign,
1454
1592
  getFigmaMetadata,
package/dist/lib.d.ts CHANGED
@@ -9,6 +9,14 @@ export interface FigmaMetadataOptions {
9
9
  outputFormat?: "json" | "yaml" | "object";
10
10
  /** Maximum depth to traverse the node tree */
11
11
  depth?: number;
12
+ /** Automatically download image assets and enrich metadata with file paths */
13
+ downloadImages?: boolean;
14
+ /** Local path for downloaded images (required if downloadImages is true) */
15
+ localPath?: string;
16
+ /** Image format for downloads (defaults to 'png') */
17
+ imageFormat?: 'png' | 'svg';
18
+ /** Export scale for PNG images (defaults to 2) */
19
+ pngScale?: number;
12
20
  }
13
21
  export interface FigmaImageOptions {
14
22
  /** Export scale for PNG images (defaults to 2) */
@@ -46,6 +54,22 @@ export interface FigmaImageResult {
46
54
  wasCropped: boolean;
47
55
  cssVariables?: string;
48
56
  }
57
+ export interface FigmaFrameImageOptions {
58
+ /** The Figma API key (Personal Access Token) */
59
+ apiKey?: string;
60
+ /** The Figma OAuth Bearer token */
61
+ oauthToken?: string;
62
+ /** Whether to use OAuth instead of API key */
63
+ useOAuth?: boolean;
64
+ /** Export scale for PNG images (defaults to 2) */
65
+ pngScale?: number;
66
+ /** The absolute path to the directory where the image should be stored */
67
+ localPath: string;
68
+ /** The filename for the downloaded image (must end with .png or .svg) */
69
+ fileName: string;
70
+ /** Image format to download (defaults to 'png') */
71
+ format?: 'png' | 'svg';
72
+ }
49
73
  /**
50
74
  * Extract metadata from a Figma file or specific nodes
51
75
  *
@@ -63,6 +87,14 @@ export declare function getFigmaMetadata(figmaUrl: string, options?: FigmaMetada
63
87
  * @returns Promise resolving to array of download results
64
88
  */
65
89
  export declare function downloadFigmaImages(figmaUrl: string, nodes: FigmaImageNode[], options: FigmaMetadataOptions & FigmaImageOptions): Promise<FigmaImageResult[]>;
90
+ /**
91
+ * Download a frame image from a Figma URL
92
+ *
93
+ * @param figmaUrl - The Figma URL containing the frame (with node-id parameter)
94
+ * @param options - Configuration options including API credentials, local path, and filename
95
+ * @returns Promise resolving to the download result
96
+ */
97
+ export declare function downloadFigmaFrameImage(figmaUrl: string, options: FigmaFrameImageOptions): Promise<FigmaImageResult>;
66
98
  export type { SimplifiedDesign } from "./extractors/types.js";
67
99
  export type { ExtractorFn, TraversalContext, TraversalOptions, GlobalVars, StyleTypes, } from "./extractors/index.js";
68
100
  export { extractFromDesign, simplifyRawFigmaObject, layoutExtractor, textExtractor, visualsExtractor, componentExtractor, allExtractors, layoutAndText, contentOnly, visualsOnly, layoutOnly, collapseSvgContainers, } from "./extractors/index.js";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "figma-metadata-extractor",
3
- "version": "1.0.1",
4
- "description": "Extract metadata and download images from Figma files. A standalone library for accessing Figma design data programmatically.",
3
+ "version": "1.0.3",
4
+ "description": "Extract metadata and download images from Figma files. A standalone library for accessing Figma design data and downloading frame images programmatically.",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
7
7
  "module": "dist/index.js",