@rbxts/polybool
v0.1.2
Published
Boolean operations on polygons (union, intersection, difference, xor)
Downloads
3
Readme
rbxts-polybool
[!NOTE] This is a port of the https://github.com/velipso/polybool specifically for the
roblox-tsenvironment
This means it is available both as a package for those using roblox-ts or as a lua library.
Installing
If you are using roblox-ts:
npm install @rbxts/polyboolyarn install @rbxts/polyboolpnpm install @rbxts/polybool
If you are using a lua package manager:
wally install codyduong/polybool
If you want the raw files (if you are using lua you only need lua files):
- See latest release: https://github.com/codyduong/rbxts-polybool/releases/latest
- Or simply look in /out/
Example and Usage

The below examples will recreate this polygon
Using polybool in roblox-ts
More documentation is available at the original repository: https://github.com/velipso/polybool
It'll look pretty similiar and can be used the exact same as any example shown if you are using roblox-ts.
[!IMPORTANT] Please read: Vec2 vs Vector2 before proceeding
Using the Simplified Polygonal API:
import polybool from '@velipso/polybool';
console.log(polybool.intersect(
{
regions: [
[[50,50], [150,150], [190,50]],
[[130,50], [290,150], [290,50]]
],
inverted: false
},
{
regions: [
[[110,20], [110,110], [20,20]],
[[130,170], [130,20], [260,20], [260,170]]
],
inverted: false
}
));
// output:
// {
// regions: [
// [[50,50], [110,50], [110,110]],
// [[178,80], [130,50], [130,130], [150,150]],
// [[178,80], [190,50], [260,50], [260,131.25]]
// ],
// inverted: false
// }Using the Polygonal API:
import polybool from '@velipso/polybool';
const poly1 = {
regions: [
[[50,50], [150,150], [190,50]],
[[130,50], [290,150], [290,50]]
],
inverted: false
};
const poly2 = {
regions: [
[[110,20], [110,110], [20,20]],
[[130,170], [130,20], [260,20], [260,170]]
],
inverted: false
};
const segs1 = polybool.segments(poly1);
const segs2 = polybool.segments(poly2);
const combined = polybool.combine(segs1, segs2);
const segs3 = polybool.selectIntersect(combined);
const result = polybool.polygon(segs3);
console.log(result);
// output:
// {
// regions: [
// [[50,50], [110,50], [110,110]],
// [[178,80], [130,50], [130,130], [150,150]],
// [[178,80], [190,50], [260,50], [260,131.25]]
// ],
// inverted: false
// }Using the Instructional API:
import polybool from '@velipso/polybool';
const shape1 = polybool.shape()
.beginPath()
.moveTo(50, 50)
.lineTo(150, 150)
.lineTo(190, 50)
.closePath()
.moveTo(130, 50)
.lineTo(290, 150)
.lineTo(290, 50)
.closePath();
const shape2 = polybool.shape()
.beginPath()
.moveTo(110, 20)
.lineTo(110, 110)
.lineTo(20, 20)
.closePath()
.moveTo(130, 170)
.lineTo(130, 20)
.lineTo(260, 20)
.lineTo(260, 170)
.closePath();
const receiver = {
beginPath: () => { console.log('beginPath'); },
moveTo: (x: number, y: number) => { console.log('moveTo', x, y); },
lineTo: (x: number, y: number) => { console.log('lineTo', x, y); },
bezierCurveTo: (
cp1x: number,
cp1y: number,
cp2x: number,
cp2y: number,
x: number,
y: number,
) => { console.log('bezierCurveTo', cp1x, cp1y, cp2x, cp2y, x, y); },
closePath: () => { console.log('closePath'); }
}
// start with the first shape
shape1
// combine it with the second shape
.combine(shape2)
// perform the operation
.intersect()
// output results to the receiver object
.output(receiver);
// output:
// beginPath
// moveTo 110 110
// lineTo 50 50
// lineTo 110 50
// lineTo 110 110
// closePath
// moveTo 150 150
// lineTo 178 80
// lineTo 130 50
// lineTo 130 130
// lineTo 150 150
// closePath
// moveTo 260 131.25
// lineTo 178 80
// lineTo 190 50
// lineTo 260 50
// lineTo 260 131.25
// closePathUsing polybool in lua/luau
TODO
Feel free to make a pull request showcasing this code similarly as the typescript section
Vec2 vs Vector2
The primary concern is that the intermediary data format used by polybool for Vec2 is [x: number, y: number].
However, if you are familiar with Roblox you'll know that there is a
Vector2 datatype.
For sake of compatibility with the original library, we do not modify this intermediate format.
To this end we have provided a utility API to convert between the two
In typescript:
import polybool, { intoVec2, intoVector2, Vec2 } from "@rbxts/polybool";
// or if it is confusing, you can rename them
// import polybool, { intoVec2 as intoPolyboolVector2, intoRobloxVector2, Vec2 } from "@rbxts/polybool";
const vec2: Vec2 = [0.5, 0.5];
const vector2 = intoVector2(vec2); // Vector2 datatype from roblox
const vec2again = intoVec2(vector2); // back into [0.5, 0.5]
const robloxVectors: Vector2[] = [
new Vector2(0, 0),
new Vector2(0.5, 0),
new Vector2(0, 0.5),
] // right triangle
const readyForPolybool = myVectorsFromSomewhere.map(intoVec2)// ...
const result = polybool.polygon(segs3);
console.log(result);
// output:
// {
// regions: [
// [[50,50], [110,50], [110,110]],
// [[178,80], [130,50], [130,130], [150,150]],
// [[178,80], [190,50], [260,50], [260,131.25]]
// ],
// inverted: false
// }
const robloxRegions = {
regions: result.regions.map((region) => region.map(intoVector2)),
inverted: result.inverted,
}In lua/luau:
TODO
Feel free to make a pull request showcasing this code similarly as the typescript section
