Face Hexagons Grid
Learn how to create hexagonal face patterns that respond to a control point. Hexagons closer to the control point become larger, while distant ones become smaller, creating organic wave-like effects.
Key Concepts
- Control Point: A point that influences the hexagon sizes based on distance
- Distance Scaling: Hexagons scale up/down based on how far they are from the control point
- UV Coordinates: Position the control point using 0-1 values instead of exact coordinates
- Pattern Filtering: Selectively remove some hexagons to create openings
- Rete
- Blockly
- TypeScript
Script Source (rete)
{
"id": "rete-v2-json",
"nodes": {
"ad44930c8195910f": {
"id": "ad44930c8195910f",
"name": "bitbybit.math.numberSlider",
"customName": "width",
"data": {
"options": {
"min": 5,
"max": 20,
"step": 0.1,
"width": 350,
"updateOnDrag": false
},
"number": 16.5
},
"inputs": {},
"position": [
429.0393216527848,
1082.0251674594201
]
},
"45d60b87e0a0dfe4": {
"id": "45d60b87e0a0dfe4",
"name": "bitbybit.math.numberSlider",
"customName": "heigt",
"data": {
"number": 9
},
"inputs": {},
"position": [
425.09924690643385,
1237.0805987593171
]
},
"4c96351a40ef58d6": {
"id": "4c96351a40ef58d6",
"name": "bitbybit.math.numberSlider",
"customName": "subdivisions w",
"data": {
"options": {
"min": 5,
"max": 40,
"step": 1,
"width": 350,
"updateOnDrag": false
},
"number": 29
},
"inputs": {},
"position": [
418.6444537944787,
1401.327026548878
]
},
"fc0f10f55cfd78c2": {
"id": "fc0f10f55cfd78c2",
"name": "bitbybit.math.numberSlider",
"customName": "subdivisions h",
"data": {
"options": {
"min": 0,
"max": 40,
"step": 0.1,
"width": 350,
"updateOnDrag": false
},
"number": 29
},
"inputs": {},
"position": [
420.87238961044295,
1553.8214401409848
]
},
"6d7ccba935d50289": {
"id": "6d7ccba935d50289",
"name": "bitbybit.point.hexGridScaledToFit",
"customName": "hex grid scaled to fit",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"width": 10,
"height": 10,
"nrHexagonsInWidth": 10,
"nrHexagonsInHeight": 10,
"flatTop": true,
"extendTop": false,
"extendBottom": false,
"extendLeft": false,
"extendRight": false,
"centerGrid": true,
"pointsOnGround": true
},
"inputs": {
"width": {
"connections": [
{
"node": "ad44930c8195910f",
"output": "result",
"data": {}
}
]
},
"height": {
"connections": [
{
"node": "45d60b87e0a0dfe4",
"output": "result",
"data": {}
}
]
},
"nrHexagonsInWidth": {
"connections": [
{
"node": "4c96351a40ef58d6",
"output": "result",
"data": {}
}
]
},
"nrHexagonsInHeight": {
"connections": [
{
"node": "fc0f10f55cfd78c2",
"output": "result",
"data": {}
}
]
}
},
"position": [
1228.6706775196694,
464.9599084442343
]
},
"7b0ab71fb1f37ec8": {
"id": "7b0ab71fb1f37ec8",
"name": "bitbybit.json.getValueOnProp",
"customName": "get value on prop",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"property": "centers"
},
"inputs": {
"json": {
"connections": [
{
"node": "6d7ccba935d50289",
"output": "result",
"data": {}
}
]
}
},
"position": [
1630.8940177883746,
464.77851777398433
]
},
"d040fd68bc78c1cc": {
"id": "d040fd68bc78c1cc",
"name": "bitbybit.point.distancesToPoints",
"customName": "distances to points",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"startPoint": {
"connections": [
{
"node": "e3e97d1a757cfadc",
"output": "result",
"data": {}
}
]
},
"endPoints": {
"connections": [
{
"node": "7b0ab71fb1f37ec8",
"output": "result",
"data": {}
}
]
}
},
"position": [
2466.435030881331,
224.36748166490298
]
},
"ba7f7e91dd75c55d": {
"id": "ba7f7e91dd75c55d",
"name": "bitbybit.vector.max",
"customName": "max",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"vector": {
"connections": [
{
"node": "d040fd68bc78c1cc",
"output": "result",
"data": {}
}
]
}
},
"position": [
2932.748806773879,
486.8563013473016
]
},
"c71bfe07b38e41f9": {
"id": "c71bfe07b38e41f9",
"name": "bitbybit.vector.min",
"customName": "min",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"vector": {
"connections": [
{
"node": "d040fd68bc78c1cc",
"output": "result",
"data": {}
}
]
}
},
"position": [
2936.335250319339,
225.2391480706185
]
},
"e09dbe00c352ccd0": {
"id": "e09dbe00c352ccd0",
"name": "bitbybit.math.remap",
"customName": "remap",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"number": 0.5,
"fromLow": 0,
"fromHigh": 1,
"toLow": 0.211,
"toHigh": 0.9
},
"inputs": {
"fromHigh": {
"connections": [
{
"node": "ba7f7e91dd75c55d",
"output": "result",
"data": {}
}
]
},
"fromLow": {
"connections": [
{
"node": "c71bfe07b38e41f9",
"output": "result",
"data": {}
}
]
},
"number": {
"connections": [
{
"node": "4451d9707782e77e",
"output": "result",
"data": {}
}
]
}
},
"position": [
3388.229444402424,
181.6348369460197
]
},
"4451d9707782e77e": {
"id": "4451d9707782e77e",
"name": "bitbybit.lists.flatten",
"customName": "flatten",
"data": {
"nrLevels": 1
},
"inputs": {
"list": {
"connections": [
{
"node": "d040fd68bc78c1cc",
"output": "result",
"data": {}
}
]
}
},
"position": [
2938.4179420951496,
14.356319078361025
]
},
"e1fcbf08c74d2039": {
"id": "e1fcbf08c74d2039",
"name": "bitbybit.json.parse",
"customName": "parse",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"text": "[true, true, true, true, false]"
},
"inputs": {},
"position": [
4181.572933865546,
1697.8419602693875
]
},
"16d3131b4a0a16da": {
"id": "16d3131b4a0a16da",
"name": "bitbybit.occt.shapes.face.hexagonsInGrid",
"customName": "hexagons in grid",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"width": 10,
"height": 10,
"nrHexagonsInWidth": 10,
"nrHexagonsInHeight": 10,
"flatTop": true,
"extendTop": false,
"extendBottom": false,
"extendLeft": false,
"extendRight": false
},
"inputs": {
"width": {
"connections": [
{
"node": "ad44930c8195910f",
"output": "result",
"data": {}
}
]
},
"height": {
"connections": [
{
"node": "45d60b87e0a0dfe4",
"output": "result",
"data": {}
}
]
},
"nrHexagonsInWidth": {
"connections": [
{
"node": "4c96351a40ef58d6",
"output": "result",
"data": {}
}
]
},
"nrHexagonsInHeight": {
"connections": [
{
"node": "fc0f10f55cfd78c2",
"output": "result",
"data": {}
}
]
},
"scalePatternWidth": {
"connections": [
{
"node": "188edaa55cc48f55",
"output": "list",
"data": {}
}
]
},
"scalePatternHeight": {
"connections": [
{
"node": "188edaa55cc48f55",
"output": "list",
"data": {}
}
]
},
"inclusionPattern": {
"connections": [
{
"node": "e1fcbf08c74d2039",
"output": "result",
"data": {}
}
]
}
},
"position": [
4601.643014193374,
1179.7801930070877
]
},
"6817a3e119b8001e": {
"id": "6817a3e119b8001e",
"name": "bitbybit.occt.shapes.face.createRectangleFace",
"customName": "rectangle face",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"width": 1,
"length": 2,
"center": [
0,
0,
0
],
"direction": [
0,
1,
0
]
},
"inputs": {
"width": {
"connections": [
{
"node": "ad44930c8195910f",
"output": "result",
"data": {}
}
]
},
"length": {
"connections": [
{
"node": "45d60b87e0a0dfe4",
"output": "result",
"data": {}
}
]
}
},
"position": [
1233.1555294494865,
66.5092462243021
]
},
"e3e97d1a757cfadc": {
"id": "e3e97d1a757cfadc",
"name": "bitbybit.occt.shapes.face.pointOnUV",
"customName": "point on uv",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"paramU": 0.5,
"paramV": 0.5
},
"inputs": {
"shape": {
"connections": [
{
"node": "6817a3e119b8001e",
"output": "result",
"data": {}
}
]
},
"paramU": {
"connections": [
{
"node": "70bbd4e213abbcaf",
"output": "result",
"data": {}
}
]
},
"paramV": {
"connections": [
{
"node": "75479b9084987307",
"output": "result",
"data": {}
}
]
}
},
"position": [
1804.7348160741294,
-345.33507323009553
]
},
"70bbd4e213abbcaf": {
"id": "70bbd4e213abbcaf",
"name": "bitbybit.math.numberSlider",
"customName": "u1",
"data": {
"options": {
"min": 0,
"max": 1,
"step": 0.01,
"width": 350,
"updateOnDrag": false
},
"number": 0
},
"inputs": {},
"position": [
482.238253954552,
-303.0919535070989
]
},
"75479b9084987307": {
"id": "75479b9084987307",
"name": "bitbybit.math.numberSlider",
"customName": "v1",
"data": {
"options": {
"min": 0,
"max": 1,
"step": 0.01,
"width": 350,
"updateOnDrag": false
},
"number": 0.49
},
"inputs": {},
"position": [
477.9973898770159,
-143.21421959629308
]
},
"188edaa55cc48f55": {
"id": "188edaa55cc48f55",
"name": "bitbybit.lists.createList",
"customName": "create list",
"data": {},
"inputs": {
"listElements": {
"connections": [
{
"node": "e09dbe00c352ccd0",
"output": "result",
"data": {}
}
]
}
},
"position": [
3774.1237260005505,
222.0353306345227
]
},
"7b30d93ddc67215e": {
"id": "7b30d93ddc67215e",
"name": "bitbybit.vector.add",
"customName": "add",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"first": {
"connections": [
{
"node": "e3e97d1a757cfadc",
"output": "result",
"data": {}
}
]
},
"second": {
"connections": [
{
"node": "8a9746568185ff05",
"output": "result",
"data": {}
}
]
}
},
"position": [
2808.986525228427,
-469.65148540833
]
},
"8a9746568185ff05": {
"id": "8a9746568185ff05",
"name": "bitbybit.vector.vectorXYZ",
"customName": "vector xyz",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 0,
"y": 3,
"z": 0
},
"inputs": {},
"position": [
2407.7419693212737,
-248.19410922127568
]
},
"52c7bcb502b29908": {
"id": "52c7bcb502b29908",
"name": "bitbybit.occt.dimensions.pinWithLabel",
"customName": "pin with label",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"startPoint": [
0,
0,
0
],
"endPoint": [
0,
5,
2
],
"direction": [
0,
0,
1
],
"offsetFromStart": 0.1,
"label": "Affector",
"labelOffset": 0.3,
"labelSize": 0.1
},
"inputs": {
"endPoint": {
"connections": [
{
"node": "7b30d93ddc67215e",
"output": "result",
"data": {}
}
]
},
"startPoint": {
"connections": [
{
"node": "e3e97d1a757cfadc",
"output": "result",
"data": {}
}
]
}
},
"position": [
3232.1990358973653,
-753.8800452539867
]
}
}
}
Script Source (blockly)
<xml xmlns="https://developers.google.com/blockly/xml"><variables><variable id="gridWidth">gridWidth</variable><variable id="gridHeight">gridHeight</variable><variable id="hexagonsInWidth">hexagonsInWidth</variable><variable id="hexagonsInHeight">hexagonsInHeight</variable><variable id="controlPointU">controlPointU</variable><variable id="controlPointV">controlPointV</variable><variable id="rectangleFace">rectangleFace</variable><variable id="controlPoint">controlPoint</variable><variable id="hexGrid">hexGrid</variable><variable id="hexCenters">hexCenters</variable><variable id="distances">distances</variable><variable id="minDistance">minDistance</variable><variable id="maxDistance">maxDistance</variable><variable id="scalePattern">scalePattern</variable><variable id="distance">distance</variable><variable id="scaledValue">scaledValue</variable><variable id="inclusionPattern">inclusionPattern</variable><variable id="hexagonFaces">hexagonFaces</variable><variable id="affectorPoint">affectorPoint</variable><variable id="pin">pin</variable></variables><block type="variables_set" id="setGridWidth" x="-500" y="-500"><field name="VAR" id="gridWidth">gridWidth</field><value name="VALUE"><block type="math_number" id="gridWidthValue"><field name="NUM">16.5</field></block></value><next><block type="variables_set" id="setGridHeight"><field name="VAR" id="gridHeight">gridHeight</field><value name="VALUE"><block type="math_number" id="gridHeightValue"><field name="NUM">9</field></block></value><next><block type="variables_set" id="setHexagonsInWidth"><field name="VAR" id="hexagonsInWidth">hexagonsInWidth</field><value name="VALUE"><block type="math_number" id="hexagonsInWidthValue"><field name="NUM">29</field></block></value><next><block type="variables_set" id="setHexagonsInHeight"><field name="VAR" id="hexagonsInHeight">hexagonsInHeight</field><value name="VALUE"><block type="math_number" id="hexagonsInHeightValue"><field name="NUM">29</field></block></value><next><block type="variables_set" id="setControlPointU"><field name="VAR" id="controlPointU">controlPointU</field><value name="VALUE"><block type="math_number" id="controlPointUValue"><field name="NUM">0</field></block></value><next><block type="variables_set" id="setControlPointV"><field name="VAR" id="controlPointV">controlPointV</field><value name="VALUE"><block type="math_number" id="controlPointVValue"><field name="NUM">0.49</field></block></value><next><block type="variables_set" id="setRectangleFace"><field name="VAR" id="rectangleFace">rectangleFace</field><value name="VALUE"><block type="base_time_await_return" id="awaitRectangleFace"><value name="Promise"><block type="bitbybit.occt.shapes.face.createRectangleFace" id="createRectangleFace"><value name="Width"><block type="variables_get" id="getRectangleWidth"><field name="VAR" id="gridWidth">gridWidth</field></block></value><value name="Length"><block type="variables_get" id="getRectangleLength"><field name="VAR" id="gridHeight">gridHeight</field></block></value><value name="Center"><block type="bitbybit.point.pointXYZ" id="rectangleCenter"><value name="X"><block type="math_number" id="rectangleCenterX"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="rectangleCenterY"><field name="NUM">0</field></block></value><value name="Z"><block type="math_number" id="rectangleCenterZ"><field name="NUM">0</field></block></value></block></value><value name="Direction"><block type="bitbybit.vector.vectorXYZ" id="rectangleDirection"><value name="X"><block type="math_number" id="rectangleDirectionX"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="rectangleDirectionY"><field name="NUM">1</field></block></value><value name="Z"><block type="math_number" id="rectangleDirectionZ"><field name="NUM">0</field></block></value></block></value></block></value></block></value><next><block type="variables_set" id="setControlPoint"><field name="VAR" id="controlPoint">controlPoint</field><value name="VALUE"><block type="base_time_await_return" id="awaitControlPoint"><value name="Promise"><block type="bitbybit.occt.shapes.face.pointOnUV" id="pointOnUV"><value name="Shape"><block type="variables_get" id="getShapeForUV"><field name="VAR" id="rectangleFace">rectangleFace</field></block></value><value name="ParamU"><block type="variables_get" id="getParamU"><field name="VAR" id="controlPointU">controlPointU</field></block></value><value name="ParamV"><block type="variables_get" id="getParamV"><field name="VAR" id="controlPointV">controlPointV</field></block></value></block></value></block></value><next><block type="variables_set" id="setHexGrid"><field name="VAR" id="hexGrid">hexGrid</field><value name="VALUE"><block type="bitbybit.point.hexGridScaledToFit" id="hexGridScaledToFit"><value name="Width"><block type="variables_get" id="getHexGridWidth"><field name="VAR" id="gridWidth">gridWidth</field></block></value><value name="Height"><block type="variables_get" id="getHexGridHeight"><field name="VAR" id="gridHeight">gridHeight</field></block></value><value name="NrHexagonsInWidth"><block type="variables_get" id="getHexagonsWidth"><field name="VAR" id="hexagonsInWidth">hexagonsInWidth</field></block></value><value name="NrHexagonsInHeight"><block type="variables_get" id="getHexagonsHeight"><field name="VAR" id="hexagonsInHeight">hexagonsInHeight</field></block></value><value name="FlatTop"><block type="logic_boolean" id="flatTopValue"><field name="BOOL">TRUE</field></block></value><value name="ExtendTop"><block type="logic_boolean" id="extendTopValue"><field name="BOOL">FALSE</field></block></value><value name="ExtendBottom"><block type="logic_boolean" id="extendBottomValue"><field name="BOOL">FALSE</field></block></value><value name="ExtendLeft"><block type="logic_boolean" id="extendLeftValue"><field name="BOOL">FALSE</field></block></value><value name="ExtendRight"><block type="logic_boolean" id="extendRightValue"><field name="BOOL">FALSE</field></block></value><value name="CenterGrid"><block type="logic_boolean" id="centerGridValue"><field name="BOOL">TRUE</field></block></value><value name="PointsOnGround"><block type="logic_boolean" id="pointsOnGroundValue"><field name="BOOL">TRUE</field></block></value></block></value><next><block type="variables_set" id="setHexCenters"><field name="VAR" id="hexCenters">hexCenters</field><value name="VALUE"><block type="bitbybit.json.getValueOnProp" id="getHexCenters"><value name="Json"><block type="variables_get" id="getHexGridForCenters"><field name="VAR" id="hexGrid">hexGrid</field></block></value><value name="Property"><block type="text" id="centersProperty"><field name="TEXT">centers</field></block></value></block></value><next><block type="variables_set" id="setDistances"><field name="VAR" id="distances">distances</field><value name="VALUE"><block type="bitbybit.point.distancesToPoints" id="distancesToPoints"><value name="StartPoint"><block type="variables_get" id="getControlPointForDistances"><field name="VAR" id="controlPoint">controlPoint</field></block></value><value name="EndPoints"><block type="variables_get" id="getHexCentersForDistances"><field name="VAR" id="hexCenters">hexCenters</field></block></value></block></value><next><block type="variables_set" id="setMinDistance"><field name="VAR" id="minDistance">minDistance</field><value name="VALUE"><block type="bitbybit.vector.min" id="vectorMin"><value name="Vector"><block type="variables_get" id="getDistancesForMin"><field name="VAR" id="distances">distances</field></block></value></block></value><next><block type="variables_set" id="setMaxDistance"><field name="VAR" id="maxDistance">maxDistance</field><value name="VALUE"><block type="bitbybit.vector.max" id="vectorMax"><value name="Vector"><block type="variables_get" id="getDistancesForMax"><field name="VAR" id="distances">distances</field></block></value></block></value><next><block type="variables_set" id="setScalePattern"><field name="VAR" id="scalePattern">scalePattern</field><value name="VALUE"><block type="lists_create_with" id="emptyScalePattern"><mutation items="0"></mutation></block></value><next><block type="controls_forEach" id="forEachDistance"><field name="VAR" id="distance">distance</field><value name="LIST"><block type="variables_get" id="getDistancesForLoop"><field name="VAR" id="distances">distances</field></block></value><statement name="DO"><block type="variables_set" id="setScaledValue"><field name="VAR" id="scaledValue">scaledValue</field><value name="VALUE"><block type="bitbybit.math.remap" id="remapDistance"><value name="Number"><block type="variables_get" id="getCurrentDistance"><field name="VAR" id="distance">distance</field></block></value><value name="FromLow"><block type="variables_get" id="getMinDistance"><field name="VAR" id="minDistance">minDistance</field></block></value><value name="FromHigh"><block type="variables_get" id="getMaxDistance"><field name="VAR" id="maxDistance">maxDistance</field></block></value><value name="ToLow"><block type="math_number" id="toLowValue"><field name="NUM">0.211</field></block></value><value name="ToHigh"><block type="math_number" id="toHighValue"><field name="NUM">0.9</field></block></value></block></value><next><block type="lists_setIndex" id="addScaledValue"><mutation at="false"></mutation><field name="MODE">INSERT</field><field name="WHERE">LAST</field><value name="LIST"><block type="variables_get" id="getScalePatternList"><field name="VAR" id="scalePattern">scalePattern</field></block></value><value name="TO"><block type="variables_get" id="getScaledValue"><field name="VAR" id="scaledValue">scaledValue</field></block></value></block></next></block></statement><next><block type="variables_set" id="setInclusionPattern"><field name="VAR" id="inclusionPattern">inclusionPattern</field><value name="VALUE"><block type="bitbybit.json.parse" id="parseInclusionPattern"><value name="Text"><block type="text" id="inclusionPatternText"><field name="TEXT">[true, true, true, true, false]</field></block></value></block></value><next><block type="variables_set" id="setHexagonFaces"><field name="VAR" id="hexagonFaces">hexagonFaces</field><value name="VALUE"><block type="base_time_await_return" id="awaitHexagonFaces"><value name="Promise"><block type="bitbybit.occt.shapes.face.hexagonsInGrid" id="hexagonsInGrid"><value name="Width"><block type="variables_get" id="getWidthForHexFaces"><field name="VAR" id="gridWidth">gridWidth</field></block></value><value name="Height"><block type="variables_get" id="getHeightForHexFaces"><field name="VAR" id="gridHeight">gridHeight</field></block></value><value name="NrHexagonsInWidth"><block type="variables_get" id="getHexWidthForFaces"><field name="VAR" id="hexagonsInWidth">hexagonsInWidth</field></block></value><value name="NrHexagonsInHeight"><block type="variables_get" id="getHexHeightForFaces"><field name="VAR" id="hexagonsInHeight">hexagonsInHeight</field></block></value><value name="FlatTop"><block type="logic_boolean" id="flatTopForFaces"><field name="BOOL">TRUE</field></block></value><value name="ExtendTop"><block type="logic_boolean" id="extendTopForFaces"><field name="BOOL">FALSE</field></block></value><value name="ExtendBottom"><block type="logic_boolean" id="extendBottomForFaces"><field name="BOOL">FALSE</field></block></value><value name="ExtendLeft"><block type="logic_boolean" id="extendLeftForFaces"><field name="BOOL">FALSE</field></block></value><value name="ExtendRight"><block type="logic_boolean" id="extendRightForFaces"><field name="BOOL">FALSE</field></block></value><value name="ScalePatternWidth"><block type="variables_get" id="getScalePatternForWidth"><field name="VAR" id="scalePattern">scalePattern</field></block></value><value name="ScalePatternHeight"><block type="variables_get" id="getScalePatternForHeight"><field name="VAR" id="scalePattern">scalePattern</field></block></value><value name="InclusionPattern"><block type="variables_get" id="getInclusionPattern"><field name="VAR" id="inclusionPattern">inclusionPattern</field></block></value></block></value></block></value><next><block type="variables_set" id="setAffectorPoint"><field name="VAR" id="affectorPoint">affectorPoint</field><value name="VALUE"><block type="bitbybit.vector.add" id="addAffectorOffset"><value name="First"><block type="variables_get" id="getControlPointForAffector"><field name="VAR" id="controlPoint">controlPoint</field></block></value><value name="Second"><block type="bitbybit.vector.vectorXYZ" id="affectorOffset"><value name="X"><block type="math_number" id="affectorOffsetX"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="affectorOffsetY"><field name="NUM">3</field></block></value><value name="Z"><block type="math_number" id="affectorOffsetZ"><field name="NUM">0</field></block></value></block></value></block></value><next><block type="variables_set" id="setPin"><field name="VAR" id="pin">pin</field><value name="VALUE"><block type="base_time_await_return" id="awaitPin"><value name="Promise"><block type="bitbybit.occt.dimensions.pinWithLabel" id="pinWithLabel"><value name="StartPoint"><block type="variables_get" id="getControlPointForPin"><field name="VAR" id="controlPoint">controlPoint</field></block></value><value name="EndPoint"><block type="variables_get" id="getAffectorPointForPin"><field name="VAR" id="affectorPoint">affectorPoint</field></block></value><value name="Direction"><block type="bitbybit.vector.vectorXYZ" id="pinDirection"><value name="X"><block type="math_number" id="pinDirectionX"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="pinDirectionY"><field name="NUM">0</field></block></value><value name="Z"><block type="math_number" id="pinDirectionZ"><field name="NUM">1</field></block></value></block></value><value name="OffsetFromStart"><block type="math_number" id="pinOffset"><field name="NUM">0.1</field></block></value><value name="Label"><block type="text" id="pinLabel"><field name="TEXT">Affector</field></block></value><value name="LabelOffset"><block type="math_number" id="pinLabelOffset"><field name="NUM">0.3</field></block></value><value name="LabelSize"><block type="math_number" id="pinLabelSize"><field name="NUM">0.1</field></block></value></block></value></block></value><next><block type="bitbybit.draw.drawAnyAsyncNoReturn" id="drawHexagonFaces"><value name="Entity"><block type="variables_get" id="getHexagonFacesForDraw"><field name="VAR" id="hexagonFaces">hexagonFaces</field></block></value><next><block type="bitbybit.draw.drawAnyAsyncNoReturn" id="drawPin"><value name="Entity"><block type="variables_get" id="getPinForDraw"><field name="VAR" id="pin">pin</field></block></value><next><block type="bitbybit.draw.drawAnyAsyncNoReturn" id="drawControlPoint"><value name="Entity"><block type="variables_get" id="getControlPointForDraw"><field name="VAR" id="controlPoint">controlPoint</field></block></value></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></xml>
Script Source (typescript)
// Import required DTOs and types for face hexagon grid creation
const { HexagonsInGridDto, RectangleDto, DataOnUVDto, PinWithLabelDto } = Bit.Inputs.OCCT;
const { HexGridScaledToFitDto } = Bit.Inputs.Point;
const { RemapNumberDto } = Bit.Inputs.Math;
const { HexGridData } = Bit.Models.Point;
type Point3 = Bit.Inputs.Base.Point3;
type Vector3 = Bit.Inputs.Base.Vector3;
type TopoDSFacePointer = Bit.Inputs.OCCT.TopoDSFacePointer;
// Get access to OCCT face, point, and utility functions
const { face } = bitbybit.occt.shapes;
const { point } = bitbybit;
const { math, vector, json, lists } = bitbybit;
const { dimensions } = bitbybit.occt;
// Define the main function to create advanced hexagon face pattern
const start = async () => {
// Define grid parameters
const gridWidth = 16.5;
const gridHeight = 9;
const hexagonsInWidth = 29;
const hexagonsInHeight = 29;
const controlPointU = 0; // UV parameter for control point position
const controlPointV = 0.49; // UV parameter for control point position
// Create a reference rectangle face to define the control point
const rectangleOptions = new RectangleDto();
rectangleOptions.width = gridWidth;
rectangleOptions.length = gridHeight;
rectangleOptions.center = [0, 0, 0] as Point3;
rectangleOptions.direction = [0, 1, 0] as Vector3;
const rectangleFace = await face.createRectangleFace(rectangleOptions);
// Create control point on the rectangle face using UV parameters
const pointOnUVOptions = new DataOnUVDto<TopoDSFacePointer>();
pointOnUVOptions.shape = rectangleFace;
pointOnUVOptions.paramU = controlPointU;
pointOnUVOptions.paramV = controlPointV;
const controlPoint = await face.pointOnUV(pointOnUVOptions);
// Generate hexagon grid centers for distance calculation
const hexGridOptions = new HexGridScaledToFitDto();
hexGridOptions.width = gridWidth;
hexGridOptions.height = gridHeight;
hexGridOptions.nrHexagonsInWidth = hexagonsInWidth;
hexGridOptions.nrHexagonsInHeight = hexagonsInHeight;
hexGridOptions.flatTop = true;
hexGridOptions.extendTop = false;
hexGridOptions.extendBottom = false;
hexGridOptions.extendLeft = false;
hexGridOptions.extendRight = false;
hexGridOptions.centerGrid = true;
hexGridOptions.pointsOnGround = true;
const hexGrid = point.hexGridScaledToFit(hexGridOptions);
const hexCenters = hexGrid.centers;
// Calculate distances from control point to all hexagon centers
const distances = point.distancesToPoints({
startPoint: controlPoint,
endPoints: hexCenters
});
// Flatten the distance array and find min/max values
const minDistance = vector.min({ vector: distances });
const maxDistance = vector.max({ vector: distances });
// Remap distances to scale factors (0.211 to 0.9)
const remapOptions = new RemapNumberDto();
remapOptions.fromLow = minDistance;
remapOptions.fromHigh = maxDistance;
remapOptions.toLow = 0.211;
remapOptions.toHigh = 0.9;
const scalePattern = distances.map(x => {
remapOptions.number = x;
return math.remap(remapOptions);
})
// Create inclusion pattern for selective hexagon removal
const inclusionPattern = json.parse({ text: "[true, true, true, true, false]" });
// Create the hexagon faces with advanced patterns
const hexFaceOptions = new HexagonsInGridDto();
hexFaceOptions.width = gridWidth;
hexFaceOptions.height = gridHeight;
hexFaceOptions.nrHexagonsInWidth = hexagonsInWidth;
hexFaceOptions.nrHexagonsInHeight = hexagonsInHeight;
hexFaceOptions.flatTop = true;
hexFaceOptions.extendTop = false;
hexFaceOptions.extendBottom = false;
hexFaceOptions.extendLeft = false;
hexFaceOptions.extendRight = false;
hexFaceOptions.scalePatternWidth = scalePattern;
hexFaceOptions.scalePatternHeight = scalePattern;
hexFaceOptions.inclusionPattern = inclusionPattern;
const hexagonFaces = await face.hexagonsInGrid(hexFaceOptions);
// Create affector point visualization (control point elevated)
const affectorPoint = vector.add({
first: controlPoint,
second: [0, 3, 0] as Vector3
}) as Point3;
// Create pin with label to show the affector point
const pinOptions = new PinWithLabelDto();
pinOptions.startPoint = controlPoint;
pinOptions.endPoint = affectorPoint;
pinOptions.direction = [0, 0, 1] as Vector3;
pinOptions.offsetFromStart = 0.1;
pinOptions.label = "Affector";
pinOptions.labelOffset = 0.3;
pinOptions.labelSize = 0.1;
const pin = await dimensions.pinWithLabel(pinOptions);
// Draw the hexagon faces and affector pin
bitbybit.draw.drawAnyAsync({ entity: hexagonFaces });
bitbybit.draw.drawAnyAsync({ entity: pin });
// Optional: Draw the control point for reference
bitbybit.draw.drawAnyAsync({
entity: controlPoint,
});
}
// Execute the function
start();
How It Works
This example creates hexagonal faces that vary in size based on their distance from a control point, creating natural-looking patterns.
Step-by-Step Process
- Set up the grid parameters - Define width, height, and number of hexagons
- Create a control point - Use UV coordinates (0 to 1) to position it on the grid
- Calculate distances - Measure how far each hexagon center is from the control point
- Scale the hexagons - Closer hexagons become larger, distant ones become smaller
- Apply patterns - Optionally remove some hexagons to create openings
The Math Behind It
The key is remapping distances to scale values:
- Find the shortest and longest distances
- Convert these to scale factors between 0.211 and 0.9
- Apply these scales to make hexagons bigger or smaller
Why Use UV Coordinates?
UV coordinates (from 0 to 1) are better than exact positions because:
- U=0 means left edge, U=1 means right edge
- V=0 means bottom edge, V=1 means top edge
- Works the same regardless of grid size
- Easy to understand and adjust
Pattern Control
The inclusionPattern lets you remove hexagons in a repeating pattern:
[true, true, false]= show 2, skip 1, repeat[true, true, true, true, false]= show 4, skip 1, repeat
Real-World Uses
- Architecture: Building facades that respond to sunlight or wind
- Product Design: Grip patterns, ventilation holes, decorative surfaces
- Interior Design: Ceiling panels, wall textures, lighting patterns
The beauty of this approach is that simple distance calculations create complex, organic-looking patterns that feel natural rather than mechanical.



