Last active
March 23, 2025 15:43
-
-
Save pratu16x7/f0bd5a8eba79e7df7812bc40d69e0e92 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ====================================== | |
// Show cut/score layers (Set _STR var to select "cut"/"score") and hide the rest (if want to show back the rest, set hideNode HIDENODERESET TO 1) | |
// ====================================== | |
// https://medium.com/@jebsphone/reusable-function-for-iterating-figma-objects-d2277cb65786 | |
const iterateNodes = async (hasStr:(node:any) => boolean, | |
hideNode:(node:any, nodeNum:number) => void, showNode:(node:any, nodeNum:number) => void):Promise<any[]> => { | |
const nodesFound = [] as any[]; // eventually, the return value | |
// Check if there's a selection, and if not, ask user if they want | |
// to examine all objects on the page. | |
let nodes = figma.currentPage.selection; | |
if (nodes.length === 0){ | |
// "confirm" here is a Scripter function. Change if writing a plugin. | |
nodes = figma.currentPage.children; | |
const confirmed = await confirm(`No items selected. Act upon whole page, on ${nodes.length} children?`) | |
if (confirmed){ | |
nodes = figma.currentPage.children; | |
} else { | |
return nodesFound; | |
} | |
} | |
for (const node of nodes){ | |
runFor(node, nodesFound); | |
// If current node has children, test and change its descendants | |
if ("children" in node && !node.removed){ | |
node.findAll().forEach(node => { | |
runFor(node, nodesFound); | |
}); | |
} | |
} | |
return nodesFound; | |
} | |
let _STR = "cut" | |
// _STR = "score" | |
// ~1500 items for 6 corr-like pieces, ~300-ish per piece: 20-30 sec | |
const HIDENODERESET = 0 /// 0 | |
const runFor = (node:any, nodesFound: any[]):void => { | |
if (hasStr(node)){ | |
// Change the node with hideNode and pass it the zero-based running | |
// count of nodes we've changed thus far. | |
showNode(node, nodesFound.length); | |
nodesFound.push(node); | |
} else if (toHide(node)) { | |
hideNode(node, nodesFound.length); | |
nodesFound.push(node); | |
// } else if (isFrame(node)) { | |
} else { | |
if(node.fills) { | |
const fills = clone(node.fills) | |
if (fills && fills.length) { | |
// fills[0].color.r = 0; // https://www.figma.com/plugin-docs/editing-properties/#changing-colors | |
fills[0].visible = false; | |
node.fills = fills; | |
} | |
} | |
} | |
} | |
const hasStr = (node:any):boolean => { | |
return (node.name.toLowerCase().includes(_STR)); | |
} | |
const hideNode = (node:any, nodeNum:number):void => { | |
// node.name = '*_' + node.name; | |
if ('opacity' in node) { | |
const opacityNode = node as MinimalBlendMixin; | |
opacityNode.opacity = HIDENODERESET; /// 0 | |
} | |
// node.visible = false; | |
} | |
const showNode = (node:any, nodeNum:number):void => { | |
// node.name = '==' + node.name; | |
if ('opacity' in node) { | |
const opacityNode = node as MinimalBlendMixin; | |
opacityNode.opacity = 1; | |
} | |
// node.visible = true; | |
} | |
const toHide = (node:any): boolean => { | |
return !isParent(node) || isGuide(node); | |
} | |
const isGuide = (node:any): boolean => { | |
const nameL = node.name.toLowerCase(); | |
return nameL.includes("[guide]"); | |
} | |
const isFrame = (node:any): boolean => { | |
const nameL = node.name.toLowerCase(); | |
return nameL.includes("frame"); | |
} | |
const isParent = (node:any): boolean => { | |
const nameL = node.name.toLowerCase(); | |
return "children" in node && !nameL.includes("guide") && node.opacity; | |
// return "children" in node || | |
// nameL.includes("frame") || | |
// nameL.includes("group") || | |
// nameL.includes("piece") || | |
// nameL.includes("sheet") || | |
// nameL.includes("limit") || | |
// nameL === "l" | |
} | |
function clone(val) { | |
return JSON.parse(JSON.stringify(val)); | |
} | |
const changedNodes = await iterateNodes(hasStr, hideNode, showNode); | |
// provide "toast" status to the user | |
figma.notify(`${changedNodes.length} items hidden.`) | |
// ====================================== | |
// Process Current Children Nodes | |
// ====================================== | |
// https://medium.com/@jebsphone/reusable-function-for-iterating-figma-objects-d2277cb65786 | |
const MODE = "cut" | |
// const MODE = "draw" | |
const DRAW_STR = "draw" | |
const isNodeToChange = (node:any):boolean => { | |
return (node.name.includes(DRAW_STR)); | |
} | |
const changeNode = (node:any, nodeNum:number):void => { | |
if(MODE === "cut") { | |
node.visible = false; | |
} else { | |
node.visible = true; | |
} | |
} | |
const iterateNodes = async (isNodeToChange:(node:any) => boolean, | |
changeNode:(node:any, nodeNum:number) => void):Promise<any[]> => { | |
const nodesFound = [] as any[]; // eventually, the return value | |
// Check if there's a selection, and if not, ask user if they want | |
// to examine all objects on the page. | |
let nodes = figma.currentPage.selection; | |
if (nodes.length === 0){ | |
// "confirm" here is a Scripter function. Change if writing a plugin. | |
const confirmed = await confirm("No items selected. Act upon whole page?") | |
if (confirmed){ | |
nodes = figma.currentPage.children; | |
} else { | |
return nodesFound; | |
} | |
} | |
for (const node of nodes){ | |
// Test each node using the isNodeToChange function | |
if (isNodeToChange(node)){ | |
// Change the node with changeNode and pass it the zero-based running | |
// count of nodes we've changed thus far. | |
changeNode(node, nodesFound.length); | |
nodesFound.push(node); | |
} | |
// If current node has children, test and change its descendants | |
if ("children" in node && !node.removed){ | |
node.findAll(node => isNodeToChange(node)).forEach(node => { | |
changeNode(node, nodesFound.length); | |
nodesFound.push(node); | |
}); | |
} | |
} | |
return nodesFound; | |
} | |
const changedNodes = await iterateNodes(isNodeToChange, changeNode); | |
// provide "toast" status to the user | |
figma.notify(`${changedNodes.length} items hidden.`) | |
// --- | |
// // test if the current node is a text node named #calloutLetter | |
// const isNodeToChange2 = (node:any):boolean => { | |
// return (node.type === 'TEXT' && node.name === '#calloutLetter'); | |
// } | |
// // here we will use the nodeNum parameter to calculate which letter to use | |
// const changeNode2 = (node:TextNode, nodeNum:number):void => { | |
// node.characters = String.fromCharCode('A'.charCodeAt(0) + nodeNum)); | |
// } | |
// // here we call iterateNodes and give the user a status message | |
// const changedNodes2 = await iterateNodes(isNodeToChange, changeNode); | |
// figma.notify(`${changedNodes.length} callouts updated.`); | |
// const changeNode3 = (node:TextNode, nodeNum:number):void => { | |
// const fontName = node.fontName as FontName; | |
// figma.loadFontAsync(fontName).then(() => { | |
// node.characters = String.fromCharCode('A'.charCodeAt(0) + nodeNum)); | |
// }); | |
// } | |
// let $our_element = selection()[0] | |
// selection() is of type readonly Scene node | |
// print($our_element.children) | |
// print(figma.currentPage.selection) | |
// let childs = figma.currentPage.findChildren(n => n.parent === selection()[0]) | |
// print($our_element.name, $our_element.type) | |
// print(childs) | |
// print($our_element.children) | |
// ====================================== | |
// Make a Building Roll-out for selection | |
// ====================================== | |
const STICKER_WIDTH = 30 | |
const STROKE_WIDTH = 2 | |
const OUTPUT_FRAME = "Foundation Print 1" | |
const SIDES = ["back", "left", "front", "right"]; // anticlockwise unrolling | |
const LABEL_X = 40; | |
const LABEL_Y = 40; | |
let root = figma.root.children[0]; | |
print(root.type) | |
let $our_element = selection()[0] | |
let height = 400 | |
let foundation_height = 400 | |
let facade_name = "CorridorPanel"; | |
let x_unroll = get_x_unroll($our_element, height, color_obj(1, 1, 1), false, facade_name) | |
let x_unroll_foundation = get_x_unroll($our_element, foundation_height, color_obj(0.8, 0.8, 0.8), true) | |
x_unroll_foundation.y = height; | |
add_to_paper(figma.group([x_unroll, x_unroll_foundation], root)); | |
// scripts don't need things to be components anyway. working with just groups is fine. | |
// [enhance] front and left side marker (they're opp to main L) | |
// [enhance lvl 2] tiny map on each to show which building instead of same | |
// ==== HELPERS ============================================= | |
function get_x_unroll($element, height, color, put_name=false, facade_name="", show_sides=false) { | |
let el_width = $element.width | |
let el_height = $element.height | |
let name = put_name? $element.name : ""; | |
let widths = [el_width, el_height, el_width, el_height] | |
let x_global = 0; | |
let sticker = rect(x_global, 0, STICKER_WIDTH, height, sticker_fill()) | |
x_global += STICKER_WIDTH | |
let unroll = widths.map(function(w) { | |
let face = rect(x_global, 0, w, height, color, name) | |
if(facade_name.length) { | |
print(facade_name); | |
let facade = get_facade(facade_name, w); | |
facade.x += x_global; | |
// facade.y = 0; | |
face = figma.group([face, facade], root) | |
} | |
x_global += w; | |
return face | |
}) | |
unroll.push(sticker) | |
return figma.group(unroll, root) | |
} | |
function get_facade(facade_name, total_width) { | |
let panel_compnent = figma.currentPage.findOne(n => n.type === "COMPONENT" && n.name === facade_name); | |
let instance_count = Math.floor(total_width / panel_compnent.width) | |
let panel_lain_x = (total_width - panel_compnent.width * instance_count)/ 2; | |
print(total_width, panel_lain_x); | |
let panels = range(0, instance_count).map(function(i) { | |
let panel = panel_compnent.createInstance(); | |
panel.x = panel_lain_x; | |
panel_lain_x += panel.width; | |
return panel; | |
}) | |
let facade = figma.group(panels, root); | |
return facade; | |
} | |
function add_to_paper(printable) { | |
let frames = figma.currentPage.findChildren(n => n.type === "FRAME" && n.name === OUTPUT_FRAME); | |
let paper_page_frame = frames[0]; | |
print(paper_page_frame.type); | |
print(paper_page_frame.id); | |
paper_page_frame.appendChild(printable); | |
} | |
function color_obj(r, g, b) { | |
return { | |
type:"SOLID", | |
visible:true, | |
opacity:1, | |
blendMode:"NORMAL", | |
color:{r:r, g:g, b:b} | |
} | |
} | |
function rect(x, y, w, h, color, label="fooo") { | |
let $rect = Rectangle({ | |
x: x, | |
y: y, | |
width: w, | |
height: h, | |
fills: [color], | |
strokes: [ BLACK.paint ], | |
strokeWeight: STROKE_WIDTH, | |
strokeAlign: "INSIDE" | |
}) | |
if(!label) { | |
return $rect; | |
} | |
let $label = Text({ | |
x:x + LABEL_X, | |
y:y + LABEL_Y, | |
width:279.6812744140625, | |
height:62.5, | |
rotation:0, | |
layoutAlign:"INHERIT", | |
constrainProportions:false, | |
layoutGrow:0, | |
layoutPositioning:"AUTO", | |
characters:label, | |
fontSize:32, | |
fills: [BLACK.paint], | |
textCase:"UPPER", | |
textDecoration:"NONE", | |
}) | |
if($label.width > $rect.width) { | |
return $rect; | |
} | |
let g = figma.group([$rect, $label], root); | |
return g; | |
} | |
function sticker_fill() { | |
return { | |
"type": "IMAGE", | |
"visible": true, | |
"opacity": 1, | |
"blendMode": "NORMAL", | |
"scaleMode": "TILE", | |
"imageTransform": [[1,0,0], [0,1,0]], | |
"scalingFactor": 0.03999999910593033, | |
"rotation": 0, | |
"filters": { | |
"exposure": 0, | |
"contrast": 0, | |
"saturation": 0, | |
"temperature": 0, | |
"tint": 0, | |
"highlights": 0, | |
"shadows": 0 | |
}, | |
"imageHash": "772da98746c9965bc12da9dbc51373531a4da552" | |
} | |
} | |
// viewport.scrollAndZoomIntoView(setSelection(rectangles)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment