Goo Tower Levels

This commit is contained in:
Brian Fertig 2026-07-26 15:23:18 -06:00
parent 2702bd9c91
commit 5b24cc3ad0
77 changed files with 22743 additions and 994 deletions

View File

@ -99,16 +99,6 @@
"y": 834,
"type": "common"
},
{
"x": 1160,
"y": 834,
"type": "common"
},
{
"x": 1190,
"y": 834,
"type": "common"
},
{
"x": 980,
"y": 804,
@ -140,13 +130,23 @@
"type": "common"
},
{
"x": 1160,
"y": 804,
"x": 980,
"y": 774,
"type": "common"
},
{
"x": 1190,
"y": 804,
"x": 1010,
"y": 774,
"type": "common"
},
{
"x": 1040,
"y": 774,
"type": "common"
},
{
"x": 1070,
"y": 774,
"type": "common"
}
],

View File

@ -4,10 +4,9 @@
"h": 1000
},
"level": 7,
"name": "Anchors Aweigh",
"chapter": 2,
"sandbox": true,
"tip": "Brown anchor goo sticks straight to rock and needs no friends. Start a span from a wall.",
"name": "Uphill",
"chapter": 1,
"tip": "Brace as you go. An unbraced column leans, and once it leans it keeps leaning.",
"terrain": [
{
"kind": "solid",
@ -34,20 +33,20 @@
"kind": "solid",
"poly": [
[
400,
300
-30,
0
],
[
460,
300
6,
0
],
[
460,
850
6,
1000
],
[
400,
850
-30,
1000
]
]
},
@ -55,39 +54,39 @@
"kind": "solid",
"poly": [
[
1120,
300
1594,
0
],
[
1180,
300
1630,
0
],
[
1180,
850
1630,
1000
],
[
1120,
850
1594,
1000
]
]
}
],
"balls": [
{
"x": 749,
"x": 566,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 811,
"x": 628,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 780,
"x": 597,
"y": 782,
"type": "common"
}
@ -106,143 +105,133 @@
1
]
],
"pipe": {
"x": 780,
"y": 400,
"r": 46
},
"pile": [
{
"x": 860,
"x": 857,
"y": 834,
"type": "anchor"
"type": "common"
},
{
"x": 890,
"x": 887,
"y": 834,
"type": "anchor"
"type": "common"
},
{
"x": 920,
"x": 917,
"y": 834,
"type": "anchor"
"type": "common"
},
{
"x": 950,
"x": 947,
"y": 834,
"type": "anchor"
"type": "common"
},
{
"x": 980,
"x": 977,
"y": 834,
"type": "anchor"
"type": "common"
},
{
"x": 1010,
"x": 1007,
"y": 834,
"type": "anchor"
"type": "common"
},
{
"x": 860,
"x": 1037,
"y": 834,
"type": "common"
},
{
"x": 1067,
"y": 834,
"type": "common"
},
{
"x": 857,
"y": 804,
"type": "common"
},
{
"x": 890,
"x": 887,
"y": 804,
"type": "common"
},
{
"x": 920,
"x": 917,
"y": 804,
"type": "common"
},
{
"x": 950,
"x": 947,
"y": 804,
"type": "common"
},
{
"x": 980,
"x": 977,
"y": 804,
"type": "common"
},
{
"x": 1010,
"x": 1007,
"y": 804,
"type": "common"
},
{
"x": 860,
"x": 1037,
"y": 804,
"type": "common"
},
{
"x": 1067,
"y": 804,
"type": "common"
},
{
"x": 857,
"y": 774,
"type": "common"
},
{
"x": 890,
"x": 887,
"y": 774,
"type": "common"
},
{
"x": 920,
"x": 917,
"y": 774,
"type": "common"
},
{
"x": 950,
"x": 947,
"y": 774,
"type": "common"
},
{
"x": 980,
"x": 977,
"y": 774,
"type": "common"
},
{
"x": 1010,
"x": 1007,
"y": 774,
"type": "common"
},
{
"x": 860,
"y": 744,
"x": 1037,
"y": 774,
"type": "common"
},
{
"x": 890,
"y": 744,
"type": "common"
},
{
"x": 920,
"y": 744,
"type": "common"
},
{
"x": 950,
"y": 744,
"type": "common"
},
{
"x": 980,
"y": 744,
"type": "common"
},
{
"x": 1010,
"y": 744,
"type": "common"
},
{
"x": 860,
"y": 714,
"type": "common"
},
{
"x": 890,
"y": 714,
"x": 1067,
"y": 774,
"type": "common"
}
],
"required": 5,
"ocdTarget": 12
"pipe": {
"x": 597,
"y": 553,
"r": 46
},
"required": 4,
"ocdTarget": 9
}

View File

@ -4,10 +4,9 @@
"h": 1000
},
"level": 8,
"name": "Sticking Point",
"chapter": 2,
"sandbox": true,
"tip": "Pokey goo grips rock. There is no ground here worth building from.",
"name": "Higher Ground",
"chapter": 1,
"tip": "Brace as you go. An unbraced column leans, and once it leans it keeps leaning.",
"terrain": [
{
"kind": "solid",
@ -34,20 +33,20 @@
"kind": "solid",
"poly": [
[
240,
200
-30,
0
],
[
320,
200
6,
0
],
[
320,
760
6,
1000
],
[
240,
760
-30,
1000
]
]
},
@ -55,40 +54,40 @@
"kind": "solid",
"poly": [
[
1120,
200
1594,
0
],
[
1200,
200
1630,
0
],
[
1200,
760
1630,
1000
],
[
1120,
760
1594,
1000
]
]
}
],
"balls": [
{
"x": 340,
"y": 560,
"type": "pokey",
"x": 808,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 340,
"y": 498,
"type": "pokey",
"x": 870,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 398,
"y": 530,
"x": 839,
"y": 782,
"type": "common"
}
],
@ -106,153 +105,133 @@
1
]
],
"pipe": {
"x": 1080,
"y": 430,
"r": 46
},
"pile": [
{
"x": 620,
"x": 1099,
"y": 834,
"type": "pokey"
"type": "common"
},
{
"x": 650,
"x": 1129,
"y": 834,
"type": "pokey"
"type": "common"
},
{
"x": 680,
"x": 1159,
"y": 834,
"type": "pokey"
"type": "common"
},
{
"x": 710,
"x": 1189,
"y": 834,
"type": "pokey"
"type": "common"
},
{
"x": 740,
"x": 1219,
"y": 834,
"type": "pokey"
"type": "common"
},
{
"x": 770,
"x": 1249,
"y": 834,
"type": "pokey"
"type": "common"
},
{
"x": 620,
"x": 1279,
"y": 834,
"type": "common"
},
{
"x": 1309,
"y": 834,
"type": "common"
},
{
"x": 1099,
"y": 804,
"type": "common"
},
{
"x": 650,
"x": 1129,
"y": 804,
"type": "common"
},
{
"x": 680,
"x": 1159,
"y": 804,
"type": "common"
},
{
"x": 710,
"x": 1189,
"y": 804,
"type": "common"
},
{
"x": 740,
"x": 1219,
"y": 804,
"type": "common"
},
{
"x": 770,
"x": 1249,
"y": 804,
"type": "common"
},
{
"x": 800,
"x": 1279,
"y": 804,
"type": "common"
},
{
"x": 830,
"x": 1309,
"y": 804,
"type": "common"
},
{
"x": 620,
"x": 1099,
"y": 774,
"type": "common"
},
{
"x": 650,
"x": 1129,
"y": 774,
"type": "common"
},
{
"x": 680,
"x": 1159,
"y": 774,
"type": "common"
},
{
"x": 710,
"x": 1189,
"y": 774,
"type": "common"
},
{
"x": 740,
"x": 1219,
"y": 774,
"type": "common"
},
{
"x": 770,
"x": 1249,
"y": 774,
"type": "common"
},
{
"x": 800,
"x": 1279,
"y": 774,
"type": "common"
},
{
"x": 830,
"x": 1309,
"y": 774,
"type": "common"
},
{
"x": 620,
"y": 744,
"type": "common"
},
{
"x": 650,
"y": 744,
"type": "common"
},
{
"x": 680,
"y": 744,
"type": "common"
},
{
"x": 710,
"y": 744,
"type": "common"
},
{
"x": 740,
"y": 744,
"type": "common"
},
{
"x": 770,
"y": 744,
"type": "common"
}
],
"pipe": {
"x": 839,
"y": 505,
"r": 46
},
"required": 5,
"ocdTarget": 12
"ocdTarget": 10
}

View File

@ -4,10 +4,9 @@
"h": 1000
},
"level": 9,
"name": "Demolition",
"chapter": 2,
"sandbox": true,
"tip": "Drop a bomb by the fire and the soft rock goes with it. Or take the long way over.",
"name": "The Long Climb",
"chapter": 1,
"tip": "Brace as you go. An unbraced column leans, and once it leans it keeps leaning.",
"terrain": [
{
"kind": "solid",
@ -34,61 +33,60 @@
"kind": "solid",
"poly": [
[
700,
660
-30,
0
],
[
780,
660
6,
0
],
[
780,
850
6,
1000
],
[
700,
850
-30,
1000
]
],
"destructible": true
]
},
{
"kind": "fire",
"kind": "solid",
"poly": [
[
600,
806
1594,
0
],
[
680,
806
1630,
0
],
[
680,
850
1630,
1000
],
[
600,
850
1594,
1000
]
]
}
],
"balls": [
{
"x": 369,
"x": 722,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 431,
"x": 784,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 400,
"x": 753,
"y": 782,
"type": "common"
}
@ -107,159 +105,133 @@
1
]
],
"pipe": {
"x": 980,
"y": 700,
"r": 46
},
"waypoints": [
{
"x": 740,
"y": 590
}
],
"pile": [
{
"x": 160,
"x": 1013,
"y": 834,
"type": "bomb"
"type": "common"
},
{
"x": 190,
"x": 1043,
"y": 834,
"type": "bomb"
"type": "common"
},
{
"x": 220,
"x": 1073,
"y": 834,
"type": "bomb"
"type": "common"
},
{
"x": 250,
"x": 1103,
"y": 834,
"type": "bomb"
"type": "common"
},
{
"x": 160,
"x": 1133,
"y": 834,
"type": "common"
},
{
"x": 1163,
"y": 834,
"type": "common"
},
{
"x": 1193,
"y": 834,
"type": "common"
},
{
"x": 1223,
"y": 834,
"type": "common"
},
{
"x": 1013,
"y": 804,
"type": "common"
},
{
"x": 190,
"x": 1043,
"y": 804,
"type": "common"
},
{
"x": 220,
"x": 1073,
"y": 804,
"type": "common"
},
{
"x": 250,
"x": 1103,
"y": 804,
"type": "common"
},
{
"x": 280,
"x": 1133,
"y": 804,
"type": "common"
},
{
"x": 310,
"x": 1163,
"y": 804,
"type": "common"
},
{
"x": 340,
"x": 1193,
"y": 804,
"type": "common"
},
{
"x": 160,
"x": 1223,
"y": 804,
"type": "common"
},
{
"x": 1013,
"y": 774,
"type": "common"
},
{
"x": 190,
"x": 1043,
"y": 774,
"type": "common"
},
{
"x": 220,
"x": 1073,
"y": 774,
"type": "common"
},
{
"x": 250,
"x": 1103,
"y": 774,
"type": "common"
},
{
"x": 280,
"x": 1133,
"y": 774,
"type": "common"
},
{
"x": 310,
"x": 1163,
"y": 774,
"type": "common"
},
{
"x": 340,
"x": 1193,
"y": 774,
"type": "common"
},
{
"x": 160,
"y": 744,
"type": "common"
},
{
"x": 190,
"y": 744,
"type": "common"
},
{
"x": 220,
"y": 744,
"type": "common"
},
{
"x": 250,
"y": 744,
"type": "common"
},
{
"x": 280,
"y": 744,
"type": "common"
},
{
"x": 310,
"y": 744,
"type": "common"
},
{
"x": 340,
"y": 744,
"type": "common"
},
{
"x": 160,
"y": 714,
"type": "common"
},
{
"x": 190,
"y": 714,
"type": "common"
},
{
"x": 220,
"y": 714,
"x": 1223,
"y": 774,
"type": "common"
}
],
"required": 5,
"pipe": {
"x": 753,
"y": 455,
"r": 46
},
"required": 6,
"ocdTarget": 12
}

View File

@ -4,11 +4,52 @@
"h": 1000
},
"level": 10,
"name": "Updraft",
"chapter": 2,
"sandbox": true,
"tip": "The updraft takes weight off everything inside it. Spans reach further in the wind.",
"name": "Across",
"chapter": 1,
"tip": "Triangles carry weight across a gap. Long chains just sag into the spikes.",
"terrain": [
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
@ -17,11 +58,11 @@
700
],
[
600,
628,
700
],
[
600,
628,
1000
],
[
@ -34,7 +75,7 @@
"kind": "solid",
"poly": [
[
940,
828,
700
],
[
@ -46,7 +87,7 @@
1000
],
[
940,
828,
1000
]
]
@ -55,19 +96,19 @@
"kind": "spike",
"poly": [
[
600,
628,
930
],
[
940,
828,
930
],
[
940,
828,
1000
],
[
600,
628,
1000
]
]
@ -77,14 +118,14 @@
"poly": [
[
0,
620
610
],
[
40,
620
44,
610
],
[
40,
44,
700
],
[
@ -92,34 +133,44 @@
700
]
]
}
],
"fans": [
},
{
"x": 600,
"y": 300,
"w": 340,
"h": 630,
"dx": 0,
"dy": -1,
"force": 1150
"kind": "solid",
"poly": [
[
584,
610
],
[
628,
610
],
[
628,
700
],
[
584,
700
]
]
}
],
"balls": [
{
"x": 329,
"x": 407,
"y": 686,
"type": "common",
"pinned": true
},
{
"x": 391,
"x": 469,
"y": 686,
"type": "common",
"pinned": true
},
{
"x": 360,
"x": 438,
"y": 632,
"type": "common"
}
@ -138,17 +189,17 @@
1
]
],
"pipe": {
"x": 1060,
"y": 630,
"r": 46
},
"pile": [
{
"x": 120,
"x": 90,
"y": 684,
"type": "common"
},
{
"x": 120,
"y": 684,
"type": "ivy"
},
{
"x": 150,
"y": 684,
@ -157,7 +208,7 @@
{
"x": 180,
"y": 684,
"type": "common"
"type": "ivy"
},
{
"x": 210,
@ -167,17 +218,17 @@
{
"x": 240,
"y": 684,
"type": "common"
"type": "ivy"
},
{
"x": 270,
"y": 684,
"x": 90,
"y": 654,
"type": "common"
},
{
"x": 120,
"y": 654,
"type": "common"
"type": "ivy"
},
{
"x": 150,
@ -187,7 +238,7 @@
{
"x": 180,
"y": 654,
"type": "common"
"type": "ivy"
},
{
"x": 210,
@ -197,17 +248,17 @@
{
"x": 240,
"y": 654,
"type": "common"
"type": "ivy"
},
{
"x": 270,
"y": 654,
"x": 90,
"y": 624,
"type": "common"
},
{
"x": 120,
"y": 624,
"type": "common"
"type": "ivy"
},
{
"x": 150,
@ -217,7 +268,7 @@
{
"x": 180,
"y": 624,
"type": "common"
"type": "ivy"
},
{
"x": 210,
@ -227,17 +278,17 @@
{
"x": 240,
"y": 624,
"type": "common"
"type": "ivy"
},
{
"x": 270,
"y": 624,
"x": 90,
"y": 594,
"type": "common"
},
{
"x": 120,
"y": 594,
"type": "common"
"type": "ivy"
},
{
"x": 150,
@ -260,8 +311,8 @@
"type": "common"
},
{
"x": 270,
"y": 594,
"x": 90,
"y": 564,
"type": "common"
},
{
@ -273,8 +324,24 @@
"x": 150,
"y": 564,
"type": "common"
},
{
"x": 180,
"y": 564,
"type": "common"
}
],
"pipe": {
"x": 938,
"y": 640,
"r": 46
},
"waypoints": [
{
"x": 728,
"y": 605
}
],
"required": 4,
"ocdTarget": 12
"ocdTarget": 8
}

View File

@ -4,24 +4,65 @@
"h": 1000
},
"level": 11,
"name": "Cogs",
"chapter": 2,
"sandbox": true,
"tip": "The cog is solid and it is turning. Anything it touches gets dragged along.",
"name": "Wider Still",
"chapter": 1,
"tip": "Triangles carry weight across a gap. Long chains just sag into the spikes.",
"terrain": [
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
0,
850
700
],
[
1600,
850
638,
700
],
[
1600,
638,
1000
],
[
@ -29,33 +70,108 @@
1000
]
]
}
],
"gears": [
},
{
"x": 800,
"y": 470,
"r": 110,
"teeth": 9,
"omega": 1.4
"kind": "solid",
"poly": [
[
869,
700
],
[
1600,
700
],
[
1600,
1000
],
[
869,
1000
]
]
},
{
"kind": "spike",
"poly": [
[
638,
930
],
[
869,
930
],
[
869,
1000
],
[
638,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
0,
610
],
[
44,
610
],
[
44,
700
],
[
0,
700
]
]
},
{
"kind": "solid",
"poly": [
[
594,
610
],
[
638,
610
],
[
638,
700
],
[
594,
700
]
]
}
],
"balls": [
{
"x": 269,
"y": 836,
"x": 417,
"y": 686,
"type": "common",
"pinned": true
},
{
"x": 331,
"y": 836,
"x": 479,
"y": 686,
"type": "common",
"pinned": true
},
{
"x": 300,
"y": 782,
"x": 448,
"y": 632,
"type": "common"
}
],
@ -73,153 +189,159 @@
1
]
],
"pipe": {
"x": 1240,
"y": 560,
"r": 46
},
"pile": [
{
"x": 1000,
"y": 834,
"x": 90,
"y": 684,
"type": "common"
},
{
"x": 1030,
"y": 834,
"x": 120,
"y": 684,
"type": "ivy"
},
{
"x": 150,
"y": 684,
"type": "common"
},
{
"x": 1060,
"y": 834,
"x": 180,
"y": 684,
"type": "ivy"
},
{
"x": 210,
"y": 684,
"type": "common"
},
{
"x": 1090,
"y": 834,
"x": 240,
"y": 684,
"type": "ivy"
},
{
"x": 90,
"y": 654,
"type": "common"
},
{
"x": 1120,
"y": 834,
"x": 120,
"y": 654,
"type": "ivy"
},
{
"x": 150,
"y": 654,
"type": "common"
},
{
"x": 1150,
"y": 834,
"x": 180,
"y": 654,
"type": "ivy"
},
{
"x": 210,
"y": 654,
"type": "common"
},
{
"x": 1180,
"y": 834,
"x": 240,
"y": 654,
"type": "ivy"
},
{
"x": 90,
"y": 624,
"type": "common"
},
{
"x": 1210,
"y": 834,
"x": 120,
"y": 624,
"type": "ivy"
},
{
"x": 150,
"y": 624,
"type": "common"
},
{
"x": 1240,
"y": 834,
"x": 180,
"y": 624,
"type": "ivy"
},
{
"x": 210,
"y": 624,
"type": "common"
},
{
"x": 1000,
"y": 804,
"x": 240,
"y": 624,
"type": "ivy"
},
{
"x": 90,
"y": 594,
"type": "common"
},
{
"x": 1030,
"y": 804,
"x": 120,
"y": 594,
"type": "ivy"
},
{
"x": 150,
"y": 594,
"type": "common"
},
{
"x": 1060,
"y": 804,
"x": 180,
"y": 594,
"type": "common"
},
{
"x": 1090,
"y": 804,
"x": 210,
"y": 594,
"type": "common"
},
{
"x": 1120,
"y": 804,
"x": 240,
"y": 594,
"type": "common"
},
{
"x": 1150,
"y": 804,
"x": 90,
"y": 564,
"type": "common"
},
{
"x": 1180,
"y": 804,
"x": 120,
"y": 564,
"type": "common"
},
{
"x": 1210,
"y": 804,
"x": 150,
"y": 564,
"type": "common"
},
{
"x": 1240,
"y": 804,
"type": "common"
},
{
"x": 1000,
"y": 774,
"type": "common"
},
{
"x": 1030,
"y": 774,
"type": "common"
},
{
"x": 1060,
"y": 774,
"type": "common"
},
{
"x": 1090,
"y": 774,
"type": "common"
},
{
"x": 1120,
"y": 774,
"type": "common"
},
{
"x": 1150,
"y": 774,
"type": "common"
},
{
"x": 1180,
"y": 774,
"type": "common"
},
{
"x": 1210,
"y": 774,
"type": "common"
},
{
"x": 1240,
"y": 774,
"type": "common"
},
{
"x": 1000,
"y": 744,
"x": 180,
"y": 564,
"type": "common"
}
],
"pipe": {
"x": 979,
"y": 640,
"r": 46
},
"waypoints": [
{
"x": 753.5,
"y": 605
}
],
"required": 5,
"ocdTarget": 13
"ocdTarget": 10
}

View File

@ -4,24 +4,65 @@
"h": 1000
},
"level": 12,
"name": "Lighter Than Air",
"chapter": 2,
"sandbox": true,
"tip": "Balloons pull up, blocks hold rigid, bits are cheap and weak. Mix them.",
"name": "The Drop",
"chapter": 1,
"tip": "Triangles carry weight across a gap. Long chains just sag into the spikes.",
"terrain": [
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
0,
850
700
],
[
1600,
850
582,
700
],
[
1600,
582,
1000
],
[
@ -29,24 +70,108 @@
1000
]
]
},
{
"kind": "solid",
"poly": [
[
828,
700
],
[
1600,
700
],
[
1600,
1000
],
[
828,
1000
]
]
},
{
"kind": "spike",
"poly": [
[
582,
930
],
[
828,
930
],
[
828,
1000
],
[
582,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
0,
610
],
[
44,
610
],
[
44,
700
],
[
0,
700
]
]
},
{
"kind": "solid",
"poly": [
[
538,
610
],
[
582,
610
],
[
582,
700
],
[
538,
700
]
]
}
],
"balls": [
{
"x": 369,
"y": 836,
"x": 361,
"y": 686,
"type": "common",
"pinned": true
},
{
"x": 431,
"y": 836,
"x": 423,
"y": 686,
"type": "common",
"pinned": true
},
{
"x": 400,
"y": 782,
"x": 392,
"y": 632,
"type": "common"
}
],
@ -64,203 +189,159 @@
1
]
],
"pipe": {
"x": 400,
"y": 300,
"r": 46
},
"pile": [
{
"x": 700,
"y": 834,
"type": "balloon"
},
{
"x": 730,
"y": 834,
"type": "balloon"
},
{
"x": 760,
"y": 834,
"type": "balloon"
},
{
"x": 790,
"y": 834,
"type": "balloon"
},
{
"x": 820,
"y": 834,
"type": "balloon"
},
{
"x": 850,
"y": 834,
"type": "balloon"
},
{
"x": 700,
"y": 800,
"type": "block"
},
{
"x": 730,
"y": 800,
"type": "block"
},
{
"x": 760,
"y": 800,
"type": "block"
},
{
"x": 790,
"y": 800,
"type": "block"
},
{
"x": 820,
"y": 800,
"type": "block"
},
{
"x": 850,
"y": 800,
"type": "block"
},
{
"x": 880,
"y": 800,
"type": "block"
},
{
"x": 910,
"y": 800,
"type": "block"
},
{
"x": 700,
"y": 766,
"type": "bit"
},
{
"x": 730,
"y": 766,
"type": "bit"
},
{
"x": 760,
"y": 766,
"type": "bit"
},
{
"x": 790,
"y": 766,
"type": "bit"
},
{
"x": 820,
"y": 766,
"type": "bit"
},
{
"x": 850,
"y": 766,
"type": "bit"
},
{
"x": 700,
"y": 734,
"x": 90,
"y": 684,
"type": "common"
},
{
"x": 730,
"y": 734,
"x": 120,
"y": 684,
"type": "ivy"
},
{
"x": 150,
"y": 684,
"type": "common"
},
{
"x": 760,
"y": 734,
"x": 180,
"y": 684,
"type": "ivy"
},
{
"x": 210,
"y": 684,
"type": "common"
},
{
"x": 790,
"y": 734,
"x": 240,
"y": 684,
"type": "ivy"
},
{
"x": 90,
"y": 654,
"type": "common"
},
{
"x": 820,
"y": 734,
"x": 120,
"y": 654,
"type": "ivy"
},
{
"x": 150,
"y": 654,
"type": "common"
},
{
"x": 850,
"y": 734,
"x": 180,
"y": 654,
"type": "ivy"
},
{
"x": 210,
"y": 654,
"type": "common"
},
{
"x": 880,
"y": 734,
"x": 240,
"y": 654,
"type": "ivy"
},
{
"x": 90,
"y": 624,
"type": "common"
},
{
"x": 910,
"y": 734,
"x": 120,
"y": 624,
"type": "ivy"
},
{
"x": 150,
"y": 624,
"type": "common"
},
{
"x": 940,
"y": 734,
"x": 180,
"y": 624,
"type": "ivy"
},
{
"x": 210,
"y": 624,
"type": "common"
},
{
"x": 700,
"y": 704,
"x": 240,
"y": 624,
"type": "ivy"
},
{
"x": 90,
"y": 594,
"type": "common"
},
{
"x": 730,
"y": 704,
"x": 120,
"y": 594,
"type": "ivy"
},
{
"x": 150,
"y": 594,
"type": "common"
},
{
"x": 760,
"y": 704,
"x": 180,
"y": 594,
"type": "common"
},
{
"x": 790,
"y": 704,
"x": 210,
"y": 594,
"type": "common"
},
{
"x": 820,
"y": 704,
"x": 240,
"y": 594,
"type": "common"
},
{
"x": 850,
"y": 704,
"x": 90,
"y": 564,
"type": "common"
},
{
"x": 880,
"y": 704,
"x": 120,
"y": 564,
"type": "common"
},
{
"x": 910,
"y": 704,
"x": 150,
"y": 564,
"type": "common"
},
{
"x": 940,
"y": 704,
"x": 180,
"y": 564,
"type": "common"
}
],
"required": 5,
"pipe": {
"x": 938,
"y": 640,
"r": 46
},
"waypoints": [
{
"x": 705,
"y": 605
}
],
"required": 6,
"ocdTarget": 12
}

View File

@ -0,0 +1,284 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 13,
"name": "Under It",
"chapter": 1,
"tip": "You cannot build through rock. Come out from under it first.",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
260,
607
],
[
759,
607
],
[
759,
677
],
[
260,
677
]
]
}
],
"balls": [
{
"x": 547,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 609,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 578,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 879,
"y": 834,
"type": "common"
},
{
"x": 909,
"y": 834,
"type": "ivy"
},
{
"x": 939,
"y": 834,
"type": "common"
},
{
"x": 969,
"y": 834,
"type": "ivy"
},
{
"x": 999,
"y": 834,
"type": "common"
},
{
"x": 1029,
"y": 834,
"type": "ivy"
},
{
"x": 1059,
"y": 834,
"type": "common"
},
{
"x": 1089,
"y": 834,
"type": "ivy"
},
{
"x": 1119,
"y": 834,
"type": "common"
},
{
"x": 879,
"y": 804,
"type": "ivy"
},
{
"x": 909,
"y": 804,
"type": "common"
},
{
"x": 939,
"y": 804,
"type": "ivy"
},
{
"x": 969,
"y": 804,
"type": "common"
},
{
"x": 999,
"y": 804,
"type": "ivy"
},
{
"x": 1029,
"y": 804,
"type": "common"
},
{
"x": 1059,
"y": 804,
"type": "ivy"
},
{
"x": 1089,
"y": 804,
"type": "common"
},
{
"x": 1119,
"y": 804,
"type": "ivy"
},
{
"x": 879,
"y": 774,
"type": "common"
},
{
"x": 909,
"y": 774,
"type": "ivy"
},
{
"x": 939,
"y": 774,
"type": "common"
},
{
"x": 969,
"y": 774,
"type": "common"
},
{
"x": 999,
"y": 774,
"type": "common"
},
{
"x": 1029,
"y": 774,
"type": "common"
},
{
"x": 1059,
"y": 774,
"type": "common"
},
{
"x": 1089,
"y": 774,
"type": "common"
},
{
"x": 1119,
"y": 774,
"type": "common"
},
{
"x": 879,
"y": 744,
"type": "common"
}
],
"pipe": {
"x": 909,
"y": 547,
"r": 46
},
"waypoints": [
{
"x": 799,
"y": 627
}
],
"required": 5,
"ocdTarget": 10
}

View File

@ -0,0 +1,284 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 14,
"name": "Round the Back",
"chapter": 1,
"tip": "You cannot build through rock. Come out from under it first.",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
260,
602
],
[
767,
602
],
[
767,
672
],
[
260,
672
]
]
}
],
"balls": [
{
"x": 520,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 582,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 551,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 887,
"y": 834,
"type": "common"
},
{
"x": 917,
"y": 834,
"type": "ivy"
},
{
"x": 947,
"y": 834,
"type": "common"
},
{
"x": 977,
"y": 834,
"type": "ivy"
},
{
"x": 1007,
"y": 834,
"type": "common"
},
{
"x": 1037,
"y": 834,
"type": "ivy"
},
{
"x": 1067,
"y": 834,
"type": "common"
},
{
"x": 1097,
"y": 834,
"type": "ivy"
},
{
"x": 1127,
"y": 834,
"type": "common"
},
{
"x": 887,
"y": 804,
"type": "ivy"
},
{
"x": 917,
"y": 804,
"type": "common"
},
{
"x": 947,
"y": 804,
"type": "ivy"
},
{
"x": 977,
"y": 804,
"type": "common"
},
{
"x": 1007,
"y": 804,
"type": "ivy"
},
{
"x": 1037,
"y": 804,
"type": "common"
},
{
"x": 1067,
"y": 804,
"type": "ivy"
},
{
"x": 1097,
"y": 804,
"type": "common"
},
{
"x": 1127,
"y": 804,
"type": "ivy"
},
{
"x": 887,
"y": 774,
"type": "common"
},
{
"x": 917,
"y": 774,
"type": "ivy"
},
{
"x": 947,
"y": 774,
"type": "common"
},
{
"x": 977,
"y": 774,
"type": "common"
},
{
"x": 1007,
"y": 774,
"type": "common"
},
{
"x": 1037,
"y": 774,
"type": "common"
},
{
"x": 1067,
"y": 774,
"type": "common"
},
{
"x": 1097,
"y": 774,
"type": "common"
},
{
"x": 1127,
"y": 774,
"type": "common"
},
{
"x": 887,
"y": 744,
"type": "common"
}
],
"pipe": {
"x": 917,
"y": 542,
"r": 46
},
"waypoints": [
{
"x": 807,
"y": 622
}
],
"required": 5,
"ocdTarget": 10
}

View File

@ -0,0 +1,284 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 15,
"name": "Out and Up",
"chapter": 1,
"tip": "You cannot build through rock. Come out from under it first.",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
260,
580
],
[
800,
580
],
[
800,
650
],
[
260,
650
]
]
}
],
"balls": [
{
"x": 561,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 623,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 592,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 920,
"y": 834,
"type": "common"
},
{
"x": 950,
"y": 834,
"type": "ivy"
},
{
"x": 980,
"y": 834,
"type": "common"
},
{
"x": 1010,
"y": 834,
"type": "ivy"
},
{
"x": 1040,
"y": 834,
"type": "common"
},
{
"x": 1070,
"y": 834,
"type": "ivy"
},
{
"x": 1100,
"y": 834,
"type": "common"
},
{
"x": 1130,
"y": 834,
"type": "ivy"
},
{
"x": 1160,
"y": 834,
"type": "common"
},
{
"x": 920,
"y": 804,
"type": "ivy"
},
{
"x": 950,
"y": 804,
"type": "common"
},
{
"x": 980,
"y": 804,
"type": "ivy"
},
{
"x": 1010,
"y": 804,
"type": "common"
},
{
"x": 1040,
"y": 804,
"type": "ivy"
},
{
"x": 1070,
"y": 804,
"type": "common"
},
{
"x": 1100,
"y": 804,
"type": "ivy"
},
{
"x": 1130,
"y": 804,
"type": "common"
},
{
"x": 1160,
"y": 804,
"type": "ivy"
},
{
"x": 920,
"y": 774,
"type": "common"
},
{
"x": 950,
"y": 774,
"type": "ivy"
},
{
"x": 980,
"y": 774,
"type": "common"
},
{
"x": 1010,
"y": 774,
"type": "common"
},
{
"x": 1040,
"y": 774,
"type": "common"
},
{
"x": 1070,
"y": 774,
"type": "common"
},
{
"x": 1100,
"y": 774,
"type": "common"
},
{
"x": 1130,
"y": 774,
"type": "common"
},
{
"x": 1160,
"y": 774,
"type": "common"
},
{
"x": 920,
"y": 744,
"type": "common"
}
],
"pipe": {
"x": 950,
"y": 520,
"r": 46
},
"waypoints": [
{
"x": 840,
"y": 600
}
],
"required": 6,
"ocdTarget": 13
}

View File

@ -0,0 +1,247 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 16,
"name": "Light Head",
"chapter": 2,
"tip": "Brace as you go. An unbraced column leans, and once it leans it keeps leaning.",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
}
],
"balls": [
{
"x": 796,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 858,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 827,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 1087,
"y": 834,
"type": "common"
},
{
"x": 1117,
"y": 834,
"type": "balloon"
},
{
"x": 1147,
"y": 834,
"type": "common"
},
{
"x": 1177,
"y": 834,
"type": "balloon"
},
{
"x": 1207,
"y": 834,
"type": "common"
},
{
"x": 1237,
"y": 834,
"type": "balloon"
},
{
"x": 1267,
"y": 834,
"type": "common"
},
{
"x": 1297,
"y": 834,
"type": "balloon"
},
{
"x": 1327,
"y": 834,
"type": "common"
},
{
"x": 1087,
"y": 804,
"type": "balloon"
},
{
"x": 1117,
"y": 804,
"type": "common"
},
{
"x": 1147,
"y": 804,
"type": "balloon"
},
{
"x": 1177,
"y": 804,
"type": "common"
},
{
"x": 1207,
"y": 804,
"type": "common"
},
{
"x": 1237,
"y": 804,
"type": "common"
},
{
"x": 1267,
"y": 804,
"type": "common"
},
{
"x": 1297,
"y": 804,
"type": "common"
},
{
"x": 1327,
"y": 804,
"type": "common"
},
{
"x": 1087,
"y": 774,
"type": "common"
},
{
"x": 1117,
"y": 774,
"type": "common"
},
{
"x": 1147,
"y": 774,
"type": "common"
},
{
"x": 1177,
"y": 774,
"type": "common"
},
{
"x": 1207,
"y": 774,
"type": "common"
},
{
"x": 1237,
"y": 774,
"type": "common"
},
{
"x": 1267,
"y": 774,
"type": "common"
},
{
"x": 1297,
"y": 774,
"type": "common"
}
],
"pipe": {
"x": 827,
"y": 472,
"r": 46
},
"required": 6,
"ocdTarget": 12
}

View File

@ -0,0 +1,247 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 17,
"name": "Buoyant",
"chapter": 2,
"tip": "Brace as you go. An unbraced column leans, and once it leans it keeps leaning.",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
}
],
"balls": [
{
"x": 669,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 731,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 700,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 960,
"y": 834,
"type": "common"
},
{
"x": 990,
"y": 834,
"type": "balloon"
},
{
"x": 1020,
"y": 834,
"type": "common"
},
{
"x": 1050,
"y": 834,
"type": "balloon"
},
{
"x": 1080,
"y": 834,
"type": "common"
},
{
"x": 1110,
"y": 834,
"type": "balloon"
},
{
"x": 1140,
"y": 834,
"type": "common"
},
{
"x": 1170,
"y": 834,
"type": "balloon"
},
{
"x": 1200,
"y": 834,
"type": "common"
},
{
"x": 960,
"y": 804,
"type": "balloon"
},
{
"x": 990,
"y": 804,
"type": "common"
},
{
"x": 1020,
"y": 804,
"type": "balloon"
},
{
"x": 1050,
"y": 804,
"type": "common"
},
{
"x": 1080,
"y": 804,
"type": "common"
},
{
"x": 1110,
"y": 804,
"type": "common"
},
{
"x": 1140,
"y": 804,
"type": "common"
},
{
"x": 1170,
"y": 804,
"type": "common"
},
{
"x": 1200,
"y": 804,
"type": "common"
},
{
"x": 960,
"y": 774,
"type": "common"
},
{
"x": 990,
"y": 774,
"type": "common"
},
{
"x": 1020,
"y": 774,
"type": "common"
},
{
"x": 1050,
"y": 774,
"type": "common"
},
{
"x": 1080,
"y": 774,
"type": "common"
},
{
"x": 1110,
"y": 774,
"type": "common"
},
{
"x": 1140,
"y": 774,
"type": "common"
},
{
"x": 1170,
"y": 774,
"type": "common"
}
],
"pipe": {
"x": 700,
"y": 448,
"r": 46
},
"required": 6,
"ocdTarget": 12
}

View File

@ -0,0 +1,268 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 18,
"name": "Low Ceiling",
"chapter": 2,
"tip": "The ceiling bites. Stop short of it.",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "spike",
"poly": [
[
112,
323
],
[
952,
323
],
[
952,
383
],
[
112,
383
]
]
}
],
"balls": [
{
"x": 501,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 563,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 532,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 812,
"y": 834,
"type": "common"
},
{
"x": 842,
"y": 834,
"type": "balloon"
},
{
"x": 872,
"y": 834,
"type": "common"
},
{
"x": 902,
"y": 834,
"type": "balloon"
},
{
"x": 932,
"y": 834,
"type": "common"
},
{
"x": 962,
"y": 834,
"type": "balloon"
},
{
"x": 992,
"y": 834,
"type": "common"
},
{
"x": 1022,
"y": 834,
"type": "balloon"
},
{
"x": 1052,
"y": 834,
"type": "common"
},
{
"x": 812,
"y": 804,
"type": "balloon"
},
{
"x": 842,
"y": 804,
"type": "common"
},
{
"x": 872,
"y": 804,
"type": "balloon"
},
{
"x": 902,
"y": 804,
"type": "common"
},
{
"x": 932,
"y": 804,
"type": "common"
},
{
"x": 962,
"y": 804,
"type": "common"
},
{
"x": 992,
"y": 804,
"type": "common"
},
{
"x": 1022,
"y": 804,
"type": "common"
},
{
"x": 1052,
"y": 804,
"type": "common"
},
{
"x": 812,
"y": 774,
"type": "common"
},
{
"x": 842,
"y": 774,
"type": "common"
},
{
"x": 872,
"y": 774,
"type": "common"
},
{
"x": 902,
"y": 774,
"type": "common"
},
{
"x": 932,
"y": 774,
"type": "common"
},
{
"x": 962,
"y": 774,
"type": "common"
},
{
"x": 992,
"y": 774,
"type": "common"
},
{
"x": 1022,
"y": 774,
"type": "common"
}
],
"pipe": {
"x": 532,
"y": 488,
"r": 46
},
"required": 5,
"ocdTarget": 10
}

View File

@ -0,0 +1,268 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 19,
"name": "Mind Your Head",
"chapter": 2,
"tip": "The ceiling bites. Stop short of it.",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "spike",
"poly": [
[
186,
298
],
[
1026,
298
],
[
1026,
358
],
[
186,
358
]
]
}
],
"balls": [
{
"x": 575,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 637,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 606,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 886,
"y": 834,
"type": "common"
},
{
"x": 916,
"y": 834,
"type": "balloon"
},
{
"x": 946,
"y": 834,
"type": "common"
},
{
"x": 976,
"y": 834,
"type": "balloon"
},
{
"x": 1006,
"y": 834,
"type": "common"
},
{
"x": 1036,
"y": 834,
"type": "balloon"
},
{
"x": 1066,
"y": 834,
"type": "common"
},
{
"x": 1096,
"y": 834,
"type": "balloon"
},
{
"x": 1126,
"y": 834,
"type": "common"
},
{
"x": 886,
"y": 804,
"type": "balloon"
},
{
"x": 916,
"y": 804,
"type": "common"
},
{
"x": 946,
"y": 804,
"type": "balloon"
},
{
"x": 976,
"y": 804,
"type": "common"
},
{
"x": 1006,
"y": 804,
"type": "common"
},
{
"x": 1036,
"y": 804,
"type": "common"
},
{
"x": 1066,
"y": 804,
"type": "common"
},
{
"x": 1096,
"y": 804,
"type": "common"
},
{
"x": 1126,
"y": 804,
"type": "common"
},
{
"x": 886,
"y": 774,
"type": "common"
},
{
"x": 916,
"y": 774,
"type": "common"
},
{
"x": 946,
"y": 774,
"type": "common"
},
{
"x": 976,
"y": 774,
"type": "common"
},
{
"x": 1006,
"y": 774,
"type": "common"
},
{
"x": 1036,
"y": 774,
"type": "common"
},
{
"x": 1066,
"y": 774,
"type": "common"
},
{
"x": 1096,
"y": 774,
"type": "common"
}
],
"pipe": {
"x": 606,
"y": 463,
"r": 46
},
"required": 6,
"ocdTarget": 12
}

View File

@ -0,0 +1,268 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 20,
"name": "Overhead",
"chapter": 2,
"tip": "The ceiling bites. Stop short of it.",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "spike",
"poly": [
[
306,
282
],
[
1146,
282
],
[
1146,
342
],
[
306,
342
]
]
}
],
"balls": [
{
"x": 695,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 757,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 726,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 1006,
"y": 834,
"type": "common"
},
{
"x": 1036,
"y": 834,
"type": "balloon"
},
{
"x": 1066,
"y": 834,
"type": "common"
},
{
"x": 1096,
"y": 834,
"type": "balloon"
},
{
"x": 1126,
"y": 834,
"type": "common"
},
{
"x": 1156,
"y": 834,
"type": "balloon"
},
{
"x": 1186,
"y": 834,
"type": "common"
},
{
"x": 1216,
"y": 834,
"type": "balloon"
},
{
"x": 1246,
"y": 834,
"type": "common"
},
{
"x": 1006,
"y": 804,
"type": "balloon"
},
{
"x": 1036,
"y": 804,
"type": "common"
},
{
"x": 1066,
"y": 804,
"type": "balloon"
},
{
"x": 1096,
"y": 804,
"type": "common"
},
{
"x": 1126,
"y": 804,
"type": "common"
},
{
"x": 1156,
"y": 804,
"type": "common"
},
{
"x": 1186,
"y": 804,
"type": "common"
},
{
"x": 1216,
"y": 804,
"type": "common"
},
{
"x": 1246,
"y": 804,
"type": "common"
},
{
"x": 1006,
"y": 774,
"type": "common"
},
{
"x": 1036,
"y": 774,
"type": "common"
},
{
"x": 1066,
"y": 774,
"type": "common"
},
{
"x": 1096,
"y": 774,
"type": "common"
},
{
"x": 1126,
"y": 774,
"type": "common"
},
{
"x": 1156,
"y": 774,
"type": "common"
},
{
"x": 1186,
"y": 774,
"type": "common"
},
{
"x": 1216,
"y": 774,
"type": "common"
}
],
"pipe": {
"x": 726,
"y": 447,
"r": 46
},
"required": 6,
"ocdTarget": 13
}

View File

@ -0,0 +1,272 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 21,
"name": "First Gust",
"chapter": 2,
"tip": "Brace as you go. An unbraced column leans, and once it leans it keeps leaning.",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
}
],
"balls": [
{
"x": 455,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 517,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 486,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 746,
"y": 834,
"type": "common"
},
{
"x": 776,
"y": 834,
"type": "balloon"
},
{
"x": 806,
"y": 834,
"type": "ivy"
},
{
"x": 836,
"y": 834,
"type": "common"
},
{
"x": 866,
"y": 834,
"type": "balloon"
},
{
"x": 896,
"y": 834,
"type": "ivy"
},
{
"x": 926,
"y": 834,
"type": "common"
},
{
"x": 956,
"y": 834,
"type": "balloon"
},
{
"x": 986,
"y": 834,
"type": "ivy"
},
{
"x": 1016,
"y": 834,
"type": "common"
},
{
"x": 746,
"y": 804,
"type": "balloon"
},
{
"x": 776,
"y": 804,
"type": "ivy"
},
{
"x": 806,
"y": 804,
"type": "common"
},
{
"x": 836,
"y": 804,
"type": "balloon"
},
{
"x": 866,
"y": 804,
"type": "common"
},
{
"x": 896,
"y": 804,
"type": "common"
},
{
"x": 926,
"y": 804,
"type": "common"
},
{
"x": 956,
"y": 804,
"type": "common"
},
{
"x": 986,
"y": 804,
"type": "common"
},
{
"x": 1016,
"y": 804,
"type": "common"
},
{
"x": 746,
"y": 774,
"type": "common"
},
{
"x": 776,
"y": 774,
"type": "common"
},
{
"x": 806,
"y": 774,
"type": "common"
},
{
"x": 836,
"y": 774,
"type": "common"
},
{
"x": 866,
"y": 774,
"type": "common"
},
{
"x": 896,
"y": 774,
"type": "common"
},
{
"x": 926,
"y": 774,
"type": "common"
},
{
"x": 956,
"y": 774,
"type": "common"
},
{
"x": 986,
"y": 774,
"type": "common"
},
{
"x": 1016,
"y": 774,
"type": "common"
},
{
"x": 746,
"y": 744,
"type": "common"
}
],
"pipe": {
"x": 486,
"y": 552,
"r": 46
},
"required": 4,
"ocdTarget": 9
}

View File

@ -0,0 +1,272 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 22,
"name": "Updraft",
"chapter": 2,
"tip": "Brace as you go. An unbraced column leans, and once it leans it keeps leaning.",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
}
],
"balls": [
{
"x": 546,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 608,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 577,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 837,
"y": 834,
"type": "common"
},
{
"x": 867,
"y": 834,
"type": "balloon"
},
{
"x": 897,
"y": 834,
"type": "ivy"
},
{
"x": 927,
"y": 834,
"type": "common"
},
{
"x": 957,
"y": 834,
"type": "balloon"
},
{
"x": 987,
"y": 834,
"type": "ivy"
},
{
"x": 1017,
"y": 834,
"type": "common"
},
{
"x": 1047,
"y": 834,
"type": "balloon"
},
{
"x": 1077,
"y": 834,
"type": "ivy"
},
{
"x": 1107,
"y": 834,
"type": "common"
},
{
"x": 837,
"y": 804,
"type": "balloon"
},
{
"x": 867,
"y": 804,
"type": "ivy"
},
{
"x": 897,
"y": 804,
"type": "common"
},
{
"x": 927,
"y": 804,
"type": "balloon"
},
{
"x": 957,
"y": 804,
"type": "common"
},
{
"x": 987,
"y": 804,
"type": "common"
},
{
"x": 1017,
"y": 804,
"type": "common"
},
{
"x": 1047,
"y": 804,
"type": "common"
},
{
"x": 1077,
"y": 804,
"type": "common"
},
{
"x": 1107,
"y": 804,
"type": "common"
},
{
"x": 837,
"y": 774,
"type": "common"
},
{
"x": 867,
"y": 774,
"type": "common"
},
{
"x": 897,
"y": 774,
"type": "common"
},
{
"x": 927,
"y": 774,
"type": "common"
},
{
"x": 957,
"y": 774,
"type": "common"
},
{
"x": 987,
"y": 774,
"type": "common"
},
{
"x": 1017,
"y": 774,
"type": "common"
},
{
"x": 1047,
"y": 774,
"type": "common"
},
{
"x": 1077,
"y": 774,
"type": "common"
},
{
"x": 1107,
"y": 774,
"type": "common"
},
{
"x": 837,
"y": 744,
"type": "common"
}
],
"pipe": {
"x": 577,
"y": 523,
"r": 46
},
"required": 5,
"ocdTarget": 10
}

View File

@ -0,0 +1,374 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 23,
"name": "Riding the Wind",
"chapter": 2,
"tip": "The updraft takes weight off everything inside it. Spans reach further in the wind.",
"element": "fan",
"terrain": [
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
0,
700
],
[
560,
700
],
[
560,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
967,
700
],
[
1600,
700
],
[
1600,
1000
],
[
967,
1000
]
]
},
{
"kind": "spike",
"poly": [
[
560,
930
],
[
967,
930
],
[
967,
1000
],
[
560,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
0,
610
],
[
44,
610
],
[
44,
700
],
[
0,
700
]
]
},
{
"kind": "solid",
"poly": [
[
516,
610
],
[
560,
610
],
[
560,
700
],
[
516,
700
]
]
}
],
"balls": [
{
"x": 339,
"y": 686,
"type": "common",
"pinned": true
},
{
"x": 401,
"y": 686,
"type": "common",
"pinned": true
},
{
"x": 370,
"y": 632,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 90,
"y": 684,
"type": "common"
},
{
"x": 120,
"y": 684,
"type": "balloon"
},
{
"x": 150,
"y": 684,
"type": "ivy"
},
{
"x": 180,
"y": 684,
"type": "common"
},
{
"x": 210,
"y": 684,
"type": "balloon"
},
{
"x": 240,
"y": 684,
"type": "ivy"
},
{
"x": 90,
"y": 654,
"type": "common"
},
{
"x": 120,
"y": 654,
"type": "balloon"
},
{
"x": 150,
"y": 654,
"type": "ivy"
},
{
"x": 180,
"y": 654,
"type": "common"
},
{
"x": 210,
"y": 654,
"type": "balloon"
},
{
"x": 240,
"y": 654,
"type": "ivy"
},
{
"x": 90,
"y": 624,
"type": "common"
},
{
"x": 120,
"y": 624,
"type": "balloon"
},
{
"x": 150,
"y": 624,
"type": "common"
},
{
"x": 180,
"y": 624,
"type": "common"
},
{
"x": 210,
"y": 624,
"type": "common"
},
{
"x": 240,
"y": 624,
"type": "common"
},
{
"x": 90,
"y": 594,
"type": "common"
},
{
"x": 120,
"y": 594,
"type": "common"
},
{
"x": 150,
"y": 594,
"type": "common"
},
{
"x": 180,
"y": 594,
"type": "common"
},
{
"x": 210,
"y": 594,
"type": "common"
},
{
"x": 240,
"y": 594,
"type": "common"
},
{
"x": 90,
"y": 564,
"type": "common"
},
{
"x": 120,
"y": 564,
"type": "common"
},
{
"x": 150,
"y": 564,
"type": "common"
},
{
"x": 180,
"y": 564,
"type": "common"
},
{
"x": 210,
"y": 564,
"type": "common"
},
{
"x": 240,
"y": 564,
"type": "common"
},
{
"x": 90,
"y": 534,
"type": "common"
}
],
"pipe": {
"x": 1077,
"y": 640,
"r": 46
},
"fans": [
{
"x": 560,
"y": 260,
"w": 407,
"h": 660,
"dx": 0,
"dy": -1,
"force": 1342
}
],
"waypoints": [
{
"x": 763.5,
"y": 580
}
],
"required": 6,
"ocdTarget": 12
}

View File

@ -0,0 +1,374 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 24,
"name": "Thermals",
"chapter": 2,
"tip": "The updraft takes weight off everything inside it. Spans reach further in the wind.",
"element": "fan",
"terrain": [
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
0,
700
],
[
560,
700
],
[
560,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
979,
700
],
[
1600,
700
],
[
1600,
1000
],
[
979,
1000
]
]
},
{
"kind": "spike",
"poly": [
[
560,
930
],
[
979,
930
],
[
979,
1000
],
[
560,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
0,
610
],
[
44,
610
],
[
44,
700
],
[
0,
700
]
]
},
{
"kind": "solid",
"poly": [
[
516,
610
],
[
560,
610
],
[
560,
700
],
[
516,
700
]
]
}
],
"balls": [
{
"x": 339,
"y": 686,
"type": "common",
"pinned": true
},
{
"x": 401,
"y": 686,
"type": "common",
"pinned": true
},
{
"x": 370,
"y": 632,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 90,
"y": 684,
"type": "common"
},
{
"x": 120,
"y": 684,
"type": "balloon"
},
{
"x": 150,
"y": 684,
"type": "ivy"
},
{
"x": 180,
"y": 684,
"type": "common"
},
{
"x": 210,
"y": 684,
"type": "balloon"
},
{
"x": 240,
"y": 684,
"type": "ivy"
},
{
"x": 90,
"y": 654,
"type": "common"
},
{
"x": 120,
"y": 654,
"type": "balloon"
},
{
"x": 150,
"y": 654,
"type": "ivy"
},
{
"x": 180,
"y": 654,
"type": "common"
},
{
"x": 210,
"y": 654,
"type": "balloon"
},
{
"x": 240,
"y": 654,
"type": "ivy"
},
{
"x": 90,
"y": 624,
"type": "common"
},
{
"x": 120,
"y": 624,
"type": "balloon"
},
{
"x": 150,
"y": 624,
"type": "common"
},
{
"x": 180,
"y": 624,
"type": "common"
},
{
"x": 210,
"y": 624,
"type": "common"
},
{
"x": 240,
"y": 624,
"type": "common"
},
{
"x": 90,
"y": 594,
"type": "common"
},
{
"x": 120,
"y": 594,
"type": "common"
},
{
"x": 150,
"y": 594,
"type": "common"
},
{
"x": 180,
"y": 594,
"type": "common"
},
{
"x": 210,
"y": 594,
"type": "common"
},
{
"x": 240,
"y": 594,
"type": "common"
},
{
"x": 90,
"y": 564,
"type": "common"
},
{
"x": 120,
"y": 564,
"type": "common"
},
{
"x": 150,
"y": 564,
"type": "common"
},
{
"x": 180,
"y": 564,
"type": "common"
},
{
"x": 210,
"y": 564,
"type": "common"
},
{
"x": 240,
"y": 564,
"type": "common"
},
{
"x": 90,
"y": 534,
"type": "common"
}
],
"pipe": {
"x": 1089,
"y": 640,
"r": 46
},
"fans": [
{
"x": 560,
"y": 260,
"w": 419,
"h": 660,
"dx": 0,
"dy": -1,
"force": 1332
}
],
"waypoints": [
{
"x": 769.5,
"y": 580
}
],
"required": 6,
"ocdTarget": 13
}

View File

@ -0,0 +1,362 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 25,
"name": "Long Reach",
"chapter": 2,
"tip": "Triangles carry weight across a gap. Long chains just sag into the spikes.",
"terrain": [
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
0,
700
],
[
562,
700
],
[
562,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
819,
700
],
[
1600,
700
],
[
1600,
1000
],
[
819,
1000
]
]
},
{
"kind": "spike",
"poly": [
[
562,
930
],
[
819,
930
],
[
819,
1000
],
[
562,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
0,
610
],
[
44,
610
],
[
44,
700
],
[
0,
700
]
]
},
{
"kind": "solid",
"poly": [
[
518,
610
],
[
562,
610
],
[
562,
700
],
[
518,
700
]
]
}
],
"balls": [
{
"x": 341,
"y": 686,
"type": "common",
"pinned": true
},
{
"x": 403,
"y": 686,
"type": "common",
"pinned": true
},
{
"x": 372,
"y": 632,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 90,
"y": 684,
"type": "common"
},
{
"x": 120,
"y": 684,
"type": "balloon"
},
{
"x": 150,
"y": 684,
"type": "ivy"
},
{
"x": 180,
"y": 684,
"type": "common"
},
{
"x": 210,
"y": 684,
"type": "balloon"
},
{
"x": 240,
"y": 684,
"type": "ivy"
},
{
"x": 90,
"y": 654,
"type": "common"
},
{
"x": 120,
"y": 654,
"type": "balloon"
},
{
"x": 150,
"y": 654,
"type": "ivy"
},
{
"x": 180,
"y": 654,
"type": "common"
},
{
"x": 210,
"y": 654,
"type": "balloon"
},
{
"x": 240,
"y": 654,
"type": "ivy"
},
{
"x": 90,
"y": 624,
"type": "common"
},
{
"x": 120,
"y": 624,
"type": "balloon"
},
{
"x": 150,
"y": 624,
"type": "common"
},
{
"x": 180,
"y": 624,
"type": "common"
},
{
"x": 210,
"y": 624,
"type": "common"
},
{
"x": 240,
"y": 624,
"type": "common"
},
{
"x": 90,
"y": 594,
"type": "common"
},
{
"x": 120,
"y": 594,
"type": "common"
},
{
"x": 150,
"y": 594,
"type": "common"
},
{
"x": 180,
"y": 594,
"type": "common"
},
{
"x": 210,
"y": 594,
"type": "common"
},
{
"x": 240,
"y": 594,
"type": "common"
},
{
"x": 90,
"y": 564,
"type": "common"
},
{
"x": 120,
"y": 564,
"type": "common"
},
{
"x": 150,
"y": 564,
"type": "common"
},
{
"x": 180,
"y": 564,
"type": "common"
},
{
"x": 210,
"y": 564,
"type": "common"
},
{
"x": 240,
"y": 564,
"type": "common"
},
{
"x": 90,
"y": 534,
"type": "common"
}
],
"pipe": {
"x": 929,
"y": 640,
"r": 46
},
"waypoints": [
{
"x": 690.5,
"y": 605
}
],
"required": 6,
"ocdTarget": 12
}

View File

@ -0,0 +1,362 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 26,
"name": "The Wide Crossing",
"chapter": 2,
"tip": "Triangles carry weight across a gap. Long chains just sag into the spikes.",
"terrain": [
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
0,
700
],
[
575,
700
],
[
575,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
852,
700
],
[
1600,
700
],
[
1600,
1000
],
[
852,
1000
]
]
},
{
"kind": "spike",
"poly": [
[
575,
930
],
[
852,
930
],
[
852,
1000
],
[
575,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
0,
610
],
[
44,
610
],
[
44,
700
],
[
0,
700
]
]
},
{
"kind": "solid",
"poly": [
[
531,
610
],
[
575,
610
],
[
575,
700
],
[
531,
700
]
]
}
],
"balls": [
{
"x": 354,
"y": 686,
"type": "common",
"pinned": true
},
{
"x": 416,
"y": 686,
"type": "common",
"pinned": true
},
{
"x": 385,
"y": 632,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 90,
"y": 684,
"type": "common"
},
{
"x": 120,
"y": 684,
"type": "balloon"
},
{
"x": 150,
"y": 684,
"type": "ivy"
},
{
"x": 180,
"y": 684,
"type": "common"
},
{
"x": 210,
"y": 684,
"type": "balloon"
},
{
"x": 240,
"y": 684,
"type": "ivy"
},
{
"x": 90,
"y": 654,
"type": "common"
},
{
"x": 120,
"y": 654,
"type": "balloon"
},
{
"x": 150,
"y": 654,
"type": "ivy"
},
{
"x": 180,
"y": 654,
"type": "common"
},
{
"x": 210,
"y": 654,
"type": "balloon"
},
{
"x": 240,
"y": 654,
"type": "ivy"
},
{
"x": 90,
"y": 624,
"type": "common"
},
{
"x": 120,
"y": 624,
"type": "balloon"
},
{
"x": 150,
"y": 624,
"type": "common"
},
{
"x": 180,
"y": 624,
"type": "common"
},
{
"x": 210,
"y": 624,
"type": "common"
},
{
"x": 240,
"y": 624,
"type": "common"
},
{
"x": 90,
"y": 594,
"type": "common"
},
{
"x": 120,
"y": 594,
"type": "common"
},
{
"x": 150,
"y": 594,
"type": "common"
},
{
"x": 180,
"y": 594,
"type": "common"
},
{
"x": 210,
"y": 594,
"type": "common"
},
{
"x": 240,
"y": 594,
"type": "common"
},
{
"x": 90,
"y": 564,
"type": "common"
},
{
"x": 120,
"y": 564,
"type": "common"
},
{
"x": 150,
"y": 564,
"type": "common"
},
{
"x": 180,
"y": 564,
"type": "common"
},
{
"x": 210,
"y": 564,
"type": "common"
},
{
"x": 240,
"y": 564,
"type": "common"
},
{
"x": 90,
"y": 534,
"type": "common"
}
],
"pipe": {
"x": 962,
"y": 640,
"r": 46
},
"waypoints": [
{
"x": 713.5,
"y": 605
}
],
"required": 6,
"ocdTarget": 13
}

View File

@ -0,0 +1,362 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 27,
"name": "Windswept",
"chapter": 2,
"tip": "Triangles carry weight across a gap. Long chains just sag into the spikes.",
"terrain": [
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
0,
700
],
[
575,
700
],
[
575,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
871,
700
],
[
1600,
700
],
[
1600,
1000
],
[
871,
1000
]
]
},
{
"kind": "spike",
"poly": [
[
575,
930
],
[
871,
930
],
[
871,
1000
],
[
575,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
0,
610
],
[
44,
610
],
[
44,
700
],
[
0,
700
]
]
},
{
"kind": "solid",
"poly": [
[
531,
610
],
[
575,
610
],
[
575,
700
],
[
531,
700
]
]
}
],
"balls": [
{
"x": 354,
"y": 686,
"type": "common",
"pinned": true
},
{
"x": 416,
"y": 686,
"type": "common",
"pinned": true
},
{
"x": 385,
"y": 632,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 90,
"y": 684,
"type": "common"
},
{
"x": 120,
"y": 684,
"type": "balloon"
},
{
"x": 150,
"y": 684,
"type": "ivy"
},
{
"x": 180,
"y": 684,
"type": "common"
},
{
"x": 210,
"y": 684,
"type": "balloon"
},
{
"x": 240,
"y": 684,
"type": "ivy"
},
{
"x": 90,
"y": 654,
"type": "common"
},
{
"x": 120,
"y": 654,
"type": "balloon"
},
{
"x": 150,
"y": 654,
"type": "ivy"
},
{
"x": 180,
"y": 654,
"type": "common"
},
{
"x": 210,
"y": 654,
"type": "balloon"
},
{
"x": 240,
"y": 654,
"type": "ivy"
},
{
"x": 90,
"y": 624,
"type": "common"
},
{
"x": 120,
"y": 624,
"type": "balloon"
},
{
"x": 150,
"y": 624,
"type": "common"
},
{
"x": 180,
"y": 624,
"type": "common"
},
{
"x": 210,
"y": 624,
"type": "common"
},
{
"x": 240,
"y": 624,
"type": "common"
},
{
"x": 90,
"y": 594,
"type": "common"
},
{
"x": 120,
"y": 594,
"type": "common"
},
{
"x": 150,
"y": 594,
"type": "common"
},
{
"x": 180,
"y": 594,
"type": "common"
},
{
"x": 210,
"y": 594,
"type": "common"
},
{
"x": 240,
"y": 594,
"type": "common"
},
{
"x": 90,
"y": 564,
"type": "common"
},
{
"x": 120,
"y": 564,
"type": "common"
},
{
"x": 150,
"y": 564,
"type": "common"
},
{
"x": 180,
"y": 564,
"type": "common"
},
{
"x": 210,
"y": 564,
"type": "common"
},
{
"x": 240,
"y": 564,
"type": "common"
},
{
"x": 90,
"y": 534,
"type": "common"
}
],
"pipe": {
"x": 981,
"y": 640,
"r": 46
},
"waypoints": [
{
"x": 723,
"y": 605
}
],
"required": 7,
"ocdTarget": 15
}

View File

@ -0,0 +1,374 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 28,
"name": "Gale",
"chapter": 2,
"tip": "The updraft takes weight off everything inside it. Spans reach further in the wind.",
"element": "fan",
"terrain": [
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
0,
700
],
[
560,
700
],
[
560,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
981,
700
],
[
1600,
700
],
[
1600,
1000
],
[
981,
1000
]
]
},
{
"kind": "spike",
"poly": [
[
560,
930
],
[
981,
930
],
[
981,
1000
],
[
560,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
0,
610
],
[
44,
610
],
[
44,
700
],
[
0,
700
]
]
},
{
"kind": "solid",
"poly": [
[
516,
610
],
[
560,
610
],
[
560,
700
],
[
516,
700
]
]
}
],
"balls": [
{
"x": 339,
"y": 686,
"type": "common",
"pinned": true
},
{
"x": 401,
"y": 686,
"type": "common",
"pinned": true
},
{
"x": 370,
"y": 632,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 90,
"y": 684,
"type": "common"
},
{
"x": 120,
"y": 684,
"type": "balloon"
},
{
"x": 150,
"y": 684,
"type": "ivy"
},
{
"x": 180,
"y": 684,
"type": "common"
},
{
"x": 210,
"y": 684,
"type": "balloon"
},
{
"x": 240,
"y": 684,
"type": "ivy"
},
{
"x": 90,
"y": 654,
"type": "common"
},
{
"x": 120,
"y": 654,
"type": "balloon"
},
{
"x": 150,
"y": 654,
"type": "ivy"
},
{
"x": 180,
"y": 654,
"type": "common"
},
{
"x": 210,
"y": 654,
"type": "balloon"
},
{
"x": 240,
"y": 654,
"type": "ivy"
},
{
"x": 90,
"y": 624,
"type": "common"
},
{
"x": 120,
"y": 624,
"type": "balloon"
},
{
"x": 150,
"y": 624,
"type": "common"
},
{
"x": 180,
"y": 624,
"type": "common"
},
{
"x": 210,
"y": 624,
"type": "common"
},
{
"x": 240,
"y": 624,
"type": "common"
},
{
"x": 90,
"y": 594,
"type": "common"
},
{
"x": 120,
"y": 594,
"type": "common"
},
{
"x": 150,
"y": 594,
"type": "common"
},
{
"x": 180,
"y": 594,
"type": "common"
},
{
"x": 210,
"y": 594,
"type": "common"
},
{
"x": 240,
"y": 594,
"type": "common"
},
{
"x": 90,
"y": 564,
"type": "common"
},
{
"x": 120,
"y": 564,
"type": "common"
},
{
"x": 150,
"y": 564,
"type": "common"
},
{
"x": 180,
"y": 564,
"type": "common"
},
{
"x": 210,
"y": 564,
"type": "common"
},
{
"x": 240,
"y": 564,
"type": "common"
},
{
"x": 90,
"y": 534,
"type": "common"
}
],
"pipe": {
"x": 1091,
"y": 640,
"r": 46
},
"fans": [
{
"x": 560,
"y": 260,
"w": 421,
"h": 660,
"dx": 0,
"dy": -1,
"force": 1330
}
],
"waypoints": [
{
"x": 770.5,
"y": 580
}
],
"required": 6,
"ocdTarget": 13
}

View File

@ -0,0 +1,272 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 29,
"name": "Squall",
"chapter": 2,
"tip": "Brace as you go. An unbraced column leans, and once it leans it keeps leaning.",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
}
],
"balls": [
{
"x": 512,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 574,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 543,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 803,
"y": 834,
"type": "common"
},
{
"x": 833,
"y": 834,
"type": "balloon"
},
{
"x": 863,
"y": 834,
"type": "ivy"
},
{
"x": 893,
"y": 834,
"type": "common"
},
{
"x": 923,
"y": 834,
"type": "balloon"
},
{
"x": 953,
"y": 834,
"type": "ivy"
},
{
"x": 983,
"y": 834,
"type": "common"
},
{
"x": 1013,
"y": 834,
"type": "balloon"
},
{
"x": 1043,
"y": 834,
"type": "ivy"
},
{
"x": 1073,
"y": 834,
"type": "common"
},
{
"x": 803,
"y": 804,
"type": "balloon"
},
{
"x": 833,
"y": 804,
"type": "ivy"
},
{
"x": 863,
"y": 804,
"type": "common"
},
{
"x": 893,
"y": 804,
"type": "balloon"
},
{
"x": 923,
"y": 804,
"type": "common"
},
{
"x": 953,
"y": 804,
"type": "common"
},
{
"x": 983,
"y": 804,
"type": "common"
},
{
"x": 1013,
"y": 804,
"type": "common"
},
{
"x": 1043,
"y": 804,
"type": "common"
},
{
"x": 1073,
"y": 804,
"type": "common"
},
{
"x": 803,
"y": 774,
"type": "common"
},
{
"x": 833,
"y": 774,
"type": "common"
},
{
"x": 863,
"y": 774,
"type": "common"
},
{
"x": 893,
"y": 774,
"type": "common"
},
{
"x": 923,
"y": 774,
"type": "common"
},
{
"x": 953,
"y": 774,
"type": "common"
},
{
"x": 983,
"y": 774,
"type": "common"
},
{
"x": 1013,
"y": 774,
"type": "common"
},
{
"x": 1043,
"y": 774,
"type": "common"
},
{
"x": 1073,
"y": 774,
"type": "common"
},
{
"x": 803,
"y": 744,
"type": "common"
}
],
"pipe": {
"x": 543,
"y": 432,
"r": 46
},
"required": 6,
"ocdTarget": 13
}

View File

@ -0,0 +1,247 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 30,
"name": "Headwind",
"chapter": 2,
"tip": "Brace as you go. An unbraced column leans, and once it leans it keeps leaning.",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
}
],
"balls": [
{
"x": 764,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 826,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 795,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 1055,
"y": 834,
"type": "common"
},
{
"x": 1085,
"y": 834,
"type": "balloon"
},
{
"x": 1115,
"y": 834,
"type": "common"
},
{
"x": 1145,
"y": 834,
"type": "balloon"
},
{
"x": 1175,
"y": 834,
"type": "common"
},
{
"x": 1205,
"y": 834,
"type": "balloon"
},
{
"x": 1235,
"y": 834,
"type": "common"
},
{
"x": 1265,
"y": 834,
"type": "balloon"
},
{
"x": 1295,
"y": 834,
"type": "common"
},
{
"x": 1055,
"y": 804,
"type": "balloon"
},
{
"x": 1085,
"y": 804,
"type": "common"
},
{
"x": 1115,
"y": 804,
"type": "balloon"
},
{
"x": 1145,
"y": 804,
"type": "common"
},
{
"x": 1175,
"y": 804,
"type": "common"
},
{
"x": 1205,
"y": 804,
"type": "common"
},
{
"x": 1235,
"y": 804,
"type": "common"
},
{
"x": 1265,
"y": 804,
"type": "common"
},
{
"x": 1295,
"y": 804,
"type": "common"
},
{
"x": 1055,
"y": 774,
"type": "common"
},
{
"x": 1085,
"y": 774,
"type": "common"
},
{
"x": 1115,
"y": 774,
"type": "common"
},
{
"x": 1145,
"y": 774,
"type": "common"
},
{
"x": 1175,
"y": 774,
"type": "common"
},
{
"x": 1205,
"y": 774,
"type": "common"
},
{
"x": 1235,
"y": 774,
"type": "common"
},
{
"x": 1265,
"y": 774,
"type": "common"
}
],
"pipe": {
"x": 795,
"y": 491,
"r": 46
},
"required": 5,
"ocdTarget": 11
}

View File

@ -0,0 +1,287 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 31,
"name": "First Cog",
"chapter": 3,
"tip": "The cog is solid and it is turning. Whatever it touches gets dragged along.",
"element": "gear",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
}
],
"balls": [
{
"x": 339,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 401,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 370,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 1000,
"y": 834,
"type": "common"
},
{
"x": 1030,
"y": 834,
"type": "block"
},
{
"x": 1060,
"y": 834,
"type": "common"
},
{
"x": 1090,
"y": 834,
"type": "block"
},
{
"x": 1120,
"y": 834,
"type": "common"
},
{
"x": 1150,
"y": 834,
"type": "block"
},
{
"x": 1180,
"y": 834,
"type": "common"
},
{
"x": 1210,
"y": 834,
"type": "block"
},
{
"x": 1240,
"y": 834,
"type": "common"
},
{
"x": 1000,
"y": 804,
"type": "block"
},
{
"x": 1030,
"y": 804,
"type": "common"
},
{
"x": 1060,
"y": 804,
"type": "block"
},
{
"x": 1090,
"y": 804,
"type": "common"
},
{
"x": 1120,
"y": 804,
"type": "block"
},
{
"x": 1150,
"y": 804,
"type": "common"
},
{
"x": 1180,
"y": 804,
"type": "block"
},
{
"x": 1210,
"y": 804,
"type": "common"
},
{
"x": 1240,
"y": 804,
"type": "common"
},
{
"x": 1000,
"y": 774,
"type": "common"
},
{
"x": 1030,
"y": 774,
"type": "common"
},
{
"x": 1060,
"y": 774,
"type": "common"
},
{
"x": 1090,
"y": 774,
"type": "common"
},
{
"x": 1120,
"y": 774,
"type": "common"
},
{
"x": 1150,
"y": 774,
"type": "common"
},
{
"x": 1180,
"y": 774,
"type": "common"
},
{
"x": 1210,
"y": 774,
"type": "common"
},
{
"x": 1240,
"y": 774,
"type": "common"
},
{
"x": 1000,
"y": 744,
"type": "common"
},
{
"x": 1030,
"y": 744,
"type": "common"
},
{
"x": 1060,
"y": 744,
"type": "common"
},
{
"x": 1090,
"y": 744,
"type": "common"
},
{
"x": 1120,
"y": 744,
"type": "common"
}
],
"pipe": {
"x": 1170,
"y": 615,
"r": 46
},
"gears": [
{
"x": 793,
"y": 515,
"r": 97,
"teeth": 9,
"omega": -1.1696241107210519
}
],
"required": 4,
"ocdTarget": 8
}

View File

@ -0,0 +1,287 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 32,
"name": "Gearworks",
"chapter": 3,
"tip": "The cog is solid and it is turning. Whatever it touches gets dragged along.",
"element": "gear",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
}
],
"balls": [
{
"x": 255,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 317,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 286,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 1000,
"y": 834,
"type": "common"
},
{
"x": 1030,
"y": 834,
"type": "block"
},
{
"x": 1060,
"y": 834,
"type": "common"
},
{
"x": 1090,
"y": 834,
"type": "block"
},
{
"x": 1120,
"y": 834,
"type": "common"
},
{
"x": 1150,
"y": 834,
"type": "block"
},
{
"x": 1180,
"y": 834,
"type": "common"
},
{
"x": 1210,
"y": 834,
"type": "block"
},
{
"x": 1240,
"y": 834,
"type": "common"
},
{
"x": 1000,
"y": 804,
"type": "block"
},
{
"x": 1030,
"y": 804,
"type": "common"
},
{
"x": 1060,
"y": 804,
"type": "block"
},
{
"x": 1090,
"y": 804,
"type": "common"
},
{
"x": 1120,
"y": 804,
"type": "block"
},
{
"x": 1150,
"y": 804,
"type": "common"
},
{
"x": 1180,
"y": 804,
"type": "block"
},
{
"x": 1210,
"y": 804,
"type": "common"
},
{
"x": 1240,
"y": 804,
"type": "common"
},
{
"x": 1000,
"y": 774,
"type": "common"
},
{
"x": 1030,
"y": 774,
"type": "common"
},
{
"x": 1060,
"y": 774,
"type": "common"
},
{
"x": 1090,
"y": 774,
"type": "common"
},
{
"x": 1120,
"y": 774,
"type": "common"
},
{
"x": 1150,
"y": 774,
"type": "common"
},
{
"x": 1180,
"y": 774,
"type": "common"
},
{
"x": 1210,
"y": 774,
"type": "common"
},
{
"x": 1240,
"y": 774,
"type": "common"
},
{
"x": 1000,
"y": 744,
"type": "common"
},
{
"x": 1030,
"y": 744,
"type": "common"
},
{
"x": 1060,
"y": 744,
"type": "common"
},
{
"x": 1090,
"y": 744,
"type": "common"
},
{
"x": 1120,
"y": 744,
"type": "common"
}
],
"pipe": {
"x": 1194,
"y": 602,
"r": 46
},
"gears": [
{
"x": 781,
"y": 502,
"r": 103,
"teeth": 9,
"omega": -1.3370113929565997
}
],
"required": 5,
"ocdTarget": 10
}

View File

@ -0,0 +1,287 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 33,
"name": "Clockwise",
"chapter": 3,
"tip": "The cog is solid and it is turning. Whatever it touches gets dragged along.",
"element": "gear",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
}
],
"balls": [
{
"x": 292,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 354,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 323,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 1000,
"y": 834,
"type": "common"
},
{
"x": 1030,
"y": 834,
"type": "block"
},
{
"x": 1060,
"y": 834,
"type": "common"
},
{
"x": 1090,
"y": 834,
"type": "block"
},
{
"x": 1120,
"y": 834,
"type": "common"
},
{
"x": 1150,
"y": 834,
"type": "block"
},
{
"x": 1180,
"y": 834,
"type": "common"
},
{
"x": 1210,
"y": 834,
"type": "block"
},
{
"x": 1240,
"y": 834,
"type": "common"
},
{
"x": 1000,
"y": 804,
"type": "block"
},
{
"x": 1030,
"y": 804,
"type": "common"
},
{
"x": 1060,
"y": 804,
"type": "block"
},
{
"x": 1090,
"y": 804,
"type": "common"
},
{
"x": 1120,
"y": 804,
"type": "block"
},
{
"x": 1150,
"y": 804,
"type": "common"
},
{
"x": 1180,
"y": 804,
"type": "block"
},
{
"x": 1210,
"y": 804,
"type": "common"
},
{
"x": 1240,
"y": 804,
"type": "common"
},
{
"x": 1000,
"y": 774,
"type": "common"
},
{
"x": 1030,
"y": 774,
"type": "common"
},
{
"x": 1060,
"y": 774,
"type": "common"
},
{
"x": 1090,
"y": 774,
"type": "common"
},
{
"x": 1120,
"y": 774,
"type": "common"
},
{
"x": 1150,
"y": 774,
"type": "common"
},
{
"x": 1180,
"y": 774,
"type": "common"
},
{
"x": 1210,
"y": 774,
"type": "common"
},
{
"x": 1240,
"y": 774,
"type": "common"
},
{
"x": 1000,
"y": 744,
"type": "common"
},
{
"x": 1030,
"y": 744,
"type": "common"
},
{
"x": 1060,
"y": 744,
"type": "common"
},
{
"x": 1090,
"y": 744,
"type": "common"
},
{
"x": 1120,
"y": 744,
"type": "common"
}
],
"pipe": {
"x": 1209,
"y": 594,
"r": 46
},
"gears": [
{
"x": 767,
"y": 494,
"r": 106,
"teeth": 9,
"omega": 1.4362818361772225
}
],
"required": 5,
"ocdTarget": 11
}

View File

@ -0,0 +1,287 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 34,
"name": "Widdershins",
"chapter": 3,
"tip": "The cog is solid and it is turning. Whatever it touches gets dragged along.",
"element": "gear",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
}
],
"balls": [
{
"x": 344,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 406,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 375,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 1000,
"y": 834,
"type": "common"
},
{
"x": 1030,
"y": 834,
"type": "block"
},
{
"x": 1060,
"y": 834,
"type": "common"
},
{
"x": 1090,
"y": 834,
"type": "block"
},
{
"x": 1120,
"y": 834,
"type": "common"
},
{
"x": 1150,
"y": 834,
"type": "block"
},
{
"x": 1180,
"y": 834,
"type": "common"
},
{
"x": 1210,
"y": 834,
"type": "block"
},
{
"x": 1240,
"y": 834,
"type": "common"
},
{
"x": 1000,
"y": 804,
"type": "block"
},
{
"x": 1030,
"y": 804,
"type": "common"
},
{
"x": 1060,
"y": 804,
"type": "block"
},
{
"x": 1090,
"y": 804,
"type": "common"
},
{
"x": 1120,
"y": 804,
"type": "block"
},
{
"x": 1150,
"y": 804,
"type": "common"
},
{
"x": 1180,
"y": 804,
"type": "block"
},
{
"x": 1210,
"y": 804,
"type": "common"
},
{
"x": 1240,
"y": 804,
"type": "common"
},
{
"x": 1000,
"y": 774,
"type": "common"
},
{
"x": 1030,
"y": 774,
"type": "common"
},
{
"x": 1060,
"y": 774,
"type": "common"
},
{
"x": 1090,
"y": 774,
"type": "common"
},
{
"x": 1120,
"y": 774,
"type": "common"
},
{
"x": 1150,
"y": 774,
"type": "common"
},
{
"x": 1180,
"y": 774,
"type": "common"
},
{
"x": 1210,
"y": 774,
"type": "common"
},
{
"x": 1240,
"y": 774,
"type": "common"
},
{
"x": 1000,
"y": 744,
"type": "common"
},
{
"x": 1030,
"y": 744,
"type": "common"
},
{
"x": 1060,
"y": 744,
"type": "common"
},
{
"x": 1090,
"y": 744,
"type": "common"
},
{
"x": 1120,
"y": 744,
"type": "common"
}
],
"pipe": {
"x": 1225,
"y": 585,
"r": 46
},
"gears": [
{
"x": 776,
"y": 485,
"r": 110,
"teeth": 9,
"omega": 1.548741678437218
}
],
"required": 6,
"ocdTarget": 12
}

View File

@ -0,0 +1,277 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 35,
"name": "Rigid Thinking",
"chapter": 3,
"tip": "Brace as you go. An unbraced column leans, and once it leans it keeps leaning.",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
}
],
"balls": [
{
"x": 712,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 774,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 743,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 1003,
"y": 834,
"type": "common"
},
{
"x": 1033,
"y": 834,
"type": "block"
},
{
"x": 1063,
"y": 834,
"type": "common"
},
{
"x": 1093,
"y": 834,
"type": "block"
},
{
"x": 1123,
"y": 834,
"type": "common"
},
{
"x": 1153,
"y": 834,
"type": "block"
},
{
"x": 1183,
"y": 834,
"type": "common"
},
{
"x": 1213,
"y": 834,
"type": "block"
},
{
"x": 1243,
"y": 834,
"type": "common"
},
{
"x": 1273,
"y": 834,
"type": "block"
},
{
"x": 1303,
"y": 834,
"type": "common"
},
{
"x": 1003,
"y": 804,
"type": "block"
},
{
"x": 1033,
"y": 804,
"type": "common"
},
{
"x": 1063,
"y": 804,
"type": "block"
},
{
"x": 1093,
"y": 804,
"type": "common"
},
{
"x": 1123,
"y": 804,
"type": "block"
},
{
"x": 1153,
"y": 804,
"type": "common"
},
{
"x": 1183,
"y": 804,
"type": "common"
},
{
"x": 1213,
"y": 804,
"type": "common"
},
{
"x": 1243,
"y": 804,
"type": "common"
},
{
"x": 1273,
"y": 804,
"type": "common"
},
{
"x": 1303,
"y": 804,
"type": "common"
},
{
"x": 1003,
"y": 774,
"type": "common"
},
{
"x": 1033,
"y": 774,
"type": "common"
},
{
"x": 1063,
"y": 774,
"type": "common"
},
{
"x": 1093,
"y": 774,
"type": "common"
},
{
"x": 1123,
"y": 774,
"type": "common"
},
{
"x": 1153,
"y": 774,
"type": "common"
},
{
"x": 1183,
"y": 774,
"type": "common"
},
{
"x": 1213,
"y": 774,
"type": "common"
},
{
"x": 1243,
"y": 774,
"type": "common"
},
{
"x": 1273,
"y": 774,
"type": "common"
}
],
"pipe": {
"x": 743,
"y": 428,
"r": 46
},
"required": 6,
"ocdTarget": 13
}

View File

@ -0,0 +1,277 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 36,
"name": "Girders",
"chapter": 3,
"tip": "Brace as you go. An unbraced column leans, and once it leans it keeps leaning.",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
}
],
"balls": [
{
"x": 481,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 543,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 512,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 772,
"y": 834,
"type": "common"
},
{
"x": 802,
"y": 834,
"type": "block"
},
{
"x": 832,
"y": 834,
"type": "common"
},
{
"x": 862,
"y": 834,
"type": "block"
},
{
"x": 892,
"y": 834,
"type": "common"
},
{
"x": 922,
"y": 834,
"type": "block"
},
{
"x": 952,
"y": 834,
"type": "common"
},
{
"x": 982,
"y": 834,
"type": "block"
},
{
"x": 1012,
"y": 834,
"type": "common"
},
{
"x": 1042,
"y": 834,
"type": "block"
},
{
"x": 1072,
"y": 834,
"type": "common"
},
{
"x": 772,
"y": 804,
"type": "block"
},
{
"x": 802,
"y": 804,
"type": "common"
},
{
"x": 832,
"y": 804,
"type": "block"
},
{
"x": 862,
"y": 804,
"type": "common"
},
{
"x": 892,
"y": 804,
"type": "block"
},
{
"x": 922,
"y": 804,
"type": "common"
},
{
"x": 952,
"y": 804,
"type": "common"
},
{
"x": 982,
"y": 804,
"type": "common"
},
{
"x": 1012,
"y": 804,
"type": "common"
},
{
"x": 1042,
"y": 804,
"type": "common"
},
{
"x": 1072,
"y": 804,
"type": "common"
},
{
"x": 772,
"y": 774,
"type": "common"
},
{
"x": 802,
"y": 774,
"type": "common"
},
{
"x": 832,
"y": 774,
"type": "common"
},
{
"x": 862,
"y": 774,
"type": "common"
},
{
"x": 892,
"y": 774,
"type": "common"
},
{
"x": 922,
"y": 774,
"type": "common"
},
{
"x": 952,
"y": 774,
"type": "common"
},
{
"x": 982,
"y": 774,
"type": "common"
},
{
"x": 1012,
"y": 774,
"type": "common"
},
{
"x": 1042,
"y": 774,
"type": "common"
}
],
"pipe": {
"x": 512,
"y": 393,
"r": 46
},
"required": 7,
"ocdTarget": 15
}

View File

@ -0,0 +1,337 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 37,
"name": "Soft Rock",
"chapter": 3,
"tip": "Drop a bomb by the fire and the soft rock goes with it. Or take the long way over.",
"element": "bomb",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
731,
695
],
[
811,
695
],
[
811,
850
],
[
731,
850
]
],
"destructible": true
},
{
"kind": "fire",
"poly": [
[
621,
806
],
[
701,
806
],
[
701,
850
],
[
621,
850
]
]
}
],
"balls": [
{
"x": 376,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 438,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 407,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 117,
"y": 834,
"type": "common"
},
{
"x": 147,
"y": 834,
"type": "block"
},
{
"x": 177,
"y": 834,
"type": "bomb"
},
{
"x": 207,
"y": 834,
"type": "common"
},
{
"x": 237,
"y": 834,
"type": "block"
},
{
"x": 267,
"y": 834,
"type": "bomb"
},
{
"x": 297,
"y": 834,
"type": "common"
},
{
"x": 117,
"y": 804,
"type": "block"
},
{
"x": 147,
"y": 804,
"type": "bomb"
},
{
"x": 177,
"y": 804,
"type": "common"
},
{
"x": 207,
"y": 804,
"type": "block"
},
{
"x": 237,
"y": 804,
"type": "bomb"
},
{
"x": 267,
"y": 804,
"type": "common"
},
{
"x": 297,
"y": 804,
"type": "block"
},
{
"x": 117,
"y": 774,
"type": "common"
},
{
"x": 147,
"y": 774,
"type": "block"
},
{
"x": 177,
"y": 774,
"type": "common"
},
{
"x": 207,
"y": 774,
"type": "block"
},
{
"x": 237,
"y": 774,
"type": "common"
},
{
"x": 267,
"y": 774,
"type": "block"
},
{
"x": 297,
"y": 774,
"type": "common"
},
{
"x": 117,
"y": 744,
"type": "common"
},
{
"x": 147,
"y": 744,
"type": "common"
},
{
"x": 177,
"y": 744,
"type": "common"
},
{
"x": 207,
"y": 744,
"type": "common"
},
{
"x": 237,
"y": 744,
"type": "common"
},
{
"x": 267,
"y": 744,
"type": "common"
},
{
"x": 297,
"y": 744,
"type": "common"
},
{
"x": 117,
"y": 714,
"type": "common"
},
{
"x": 147,
"y": 714,
"type": "common"
},
{
"x": 177,
"y": 714,
"type": "common"
},
{
"x": 207,
"y": 714,
"type": "common"
},
{
"x": 237,
"y": 714,
"type": "common"
},
{
"x": 267,
"y": 714,
"type": "common"
}
],
"pipe": {
"x": 992,
"y": 700,
"r": 46
},
"waypoints": [
{
"x": 771,
"y": 620
}
],
"required": 4,
"ocdTarget": 8
}

View File

@ -0,0 +1,337 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 38,
"name": "Demolition",
"chapter": 3,
"tip": "Drop a bomb by the fire and the soft rock goes with it. Or take the long way over.",
"element": "bomb",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
748,
684
],
[
828,
684
],
[
828,
850
],
[
748,
850
]
],
"destructible": true
},
{
"kind": "fire",
"poly": [
[
638,
806
],
[
718,
806
],
[
718,
850
],
[
638,
850
]
]
}
],
"balls": [
{
"x": 338,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 400,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 369,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 79,
"y": 834,
"type": "common"
},
{
"x": 109,
"y": 834,
"type": "block"
},
{
"x": 139,
"y": 834,
"type": "bomb"
},
{
"x": 169,
"y": 834,
"type": "common"
},
{
"x": 199,
"y": 834,
"type": "block"
},
{
"x": 229,
"y": 834,
"type": "bomb"
},
{
"x": 259,
"y": 834,
"type": "common"
},
{
"x": 79,
"y": 804,
"type": "block"
},
{
"x": 109,
"y": 804,
"type": "bomb"
},
{
"x": 139,
"y": 804,
"type": "common"
},
{
"x": 169,
"y": 804,
"type": "block"
},
{
"x": 199,
"y": 804,
"type": "bomb"
},
{
"x": 229,
"y": 804,
"type": "common"
},
{
"x": 259,
"y": 804,
"type": "block"
},
{
"x": 79,
"y": 774,
"type": "common"
},
{
"x": 109,
"y": 774,
"type": "block"
},
{
"x": 139,
"y": 774,
"type": "common"
},
{
"x": 169,
"y": 774,
"type": "block"
},
{
"x": 199,
"y": 774,
"type": "common"
},
{
"x": 229,
"y": 774,
"type": "block"
},
{
"x": 259,
"y": 774,
"type": "common"
},
{
"x": 79,
"y": 744,
"type": "common"
},
{
"x": 109,
"y": 744,
"type": "common"
},
{
"x": 139,
"y": 744,
"type": "common"
},
{
"x": 169,
"y": 744,
"type": "common"
},
{
"x": 199,
"y": 744,
"type": "common"
},
{
"x": 229,
"y": 744,
"type": "common"
},
{
"x": 259,
"y": 744,
"type": "common"
},
{
"x": 79,
"y": 714,
"type": "common"
},
{
"x": 109,
"y": 714,
"type": "common"
},
{
"x": 139,
"y": 714,
"type": "common"
},
{
"x": 169,
"y": 714,
"type": "common"
},
{
"x": 199,
"y": 714,
"type": "common"
},
{
"x": 229,
"y": 714,
"type": "common"
}
],
"pipe": {
"x": 1017,
"y": 700,
"r": 46
},
"waypoints": [
{
"x": 788,
"y": 609
}
],
"required": 5,
"ocdTarget": 10
}

View File

@ -0,0 +1,337 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 39,
"name": "Blast Radius",
"chapter": 3,
"tip": "Drop a bomb by the fire and the soft rock goes with it. Or take the long way over.",
"element": "bomb",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
737,
675
],
[
817,
675
],
[
817,
850
],
[
737,
850
]
],
"destructible": true
},
{
"kind": "fire",
"poly": [
[
627,
806
],
[
707,
806
],
[
707,
850
],
[
627,
850
]
]
}
],
"balls": [
{
"x": 368,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 430,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 399,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 109,
"y": 834,
"type": "common"
},
{
"x": 139,
"y": 834,
"type": "block"
},
{
"x": 169,
"y": 834,
"type": "bomb"
},
{
"x": 199,
"y": 834,
"type": "common"
},
{
"x": 229,
"y": 834,
"type": "block"
},
{
"x": 259,
"y": 834,
"type": "bomb"
},
{
"x": 289,
"y": 834,
"type": "common"
},
{
"x": 109,
"y": 804,
"type": "block"
},
{
"x": 139,
"y": 804,
"type": "bomb"
},
{
"x": 169,
"y": 804,
"type": "common"
},
{
"x": 199,
"y": 804,
"type": "block"
},
{
"x": 229,
"y": 804,
"type": "bomb"
},
{
"x": 259,
"y": 804,
"type": "common"
},
{
"x": 289,
"y": 804,
"type": "block"
},
{
"x": 109,
"y": 774,
"type": "common"
},
{
"x": 139,
"y": 774,
"type": "block"
},
{
"x": 169,
"y": 774,
"type": "common"
},
{
"x": 199,
"y": 774,
"type": "block"
},
{
"x": 229,
"y": 774,
"type": "common"
},
{
"x": 259,
"y": 774,
"type": "block"
},
{
"x": 289,
"y": 774,
"type": "common"
},
{
"x": 109,
"y": 744,
"type": "common"
},
{
"x": 139,
"y": 744,
"type": "common"
},
{
"x": 169,
"y": 744,
"type": "common"
},
{
"x": 199,
"y": 744,
"type": "common"
},
{
"x": 229,
"y": 744,
"type": "common"
},
{
"x": 259,
"y": 744,
"type": "common"
},
{
"x": 289,
"y": 744,
"type": "common"
},
{
"x": 109,
"y": 714,
"type": "common"
},
{
"x": 139,
"y": 714,
"type": "common"
},
{
"x": 169,
"y": 714,
"type": "common"
},
{
"x": 199,
"y": 714,
"type": "common"
},
{
"x": 229,
"y": 714,
"type": "common"
},
{
"x": 259,
"y": 714,
"type": "common"
}
],
"pipe": {
"x": 1038,
"y": 700,
"r": 46
},
"waypoints": [
{
"x": 777,
"y": 600
}
],
"required": 6,
"ocdTarget": 12
}

View File

@ -0,0 +1,337 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 40,
"name": "Controlled Burn",
"chapter": 3,
"tip": "Drop a bomb by the fire and the soft rock goes with it. Or take the long way over.",
"element": "bomb",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
718,
664
],
[
798,
664
],
[
798,
850
],
[
718,
850
]
],
"destructible": true
},
{
"kind": "fire",
"poly": [
[
608,
806
],
[
688,
806
],
[
688,
850
],
[
608,
850
]
]
}
],
"balls": [
{
"x": 360,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 422,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 391,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 101,
"y": 834,
"type": "common"
},
{
"x": 131,
"y": 834,
"type": "block"
},
{
"x": 161,
"y": 834,
"type": "bomb"
},
{
"x": 191,
"y": 834,
"type": "common"
},
{
"x": 221,
"y": 834,
"type": "block"
},
{
"x": 251,
"y": 834,
"type": "bomb"
},
{
"x": 281,
"y": 834,
"type": "common"
},
{
"x": 101,
"y": 804,
"type": "block"
},
{
"x": 131,
"y": 804,
"type": "bomb"
},
{
"x": 161,
"y": 804,
"type": "common"
},
{
"x": 191,
"y": 804,
"type": "block"
},
{
"x": 221,
"y": 804,
"type": "bomb"
},
{
"x": 251,
"y": 804,
"type": "common"
},
{
"x": 281,
"y": 804,
"type": "block"
},
{
"x": 101,
"y": 774,
"type": "common"
},
{
"x": 131,
"y": 774,
"type": "block"
},
{
"x": 161,
"y": 774,
"type": "common"
},
{
"x": 191,
"y": 774,
"type": "block"
},
{
"x": 221,
"y": 774,
"type": "common"
},
{
"x": 251,
"y": 774,
"type": "block"
},
{
"x": 281,
"y": 774,
"type": "common"
},
{
"x": 101,
"y": 744,
"type": "common"
},
{
"x": 131,
"y": 744,
"type": "common"
},
{
"x": 161,
"y": 744,
"type": "common"
},
{
"x": 191,
"y": 744,
"type": "common"
},
{
"x": 221,
"y": 744,
"type": "common"
},
{
"x": 251,
"y": 744,
"type": "common"
},
{
"x": 281,
"y": 744,
"type": "common"
},
{
"x": 101,
"y": 714,
"type": "common"
},
{
"x": 131,
"y": 714,
"type": "common"
},
{
"x": 161,
"y": 714,
"type": "common"
},
{
"x": 191,
"y": 714,
"type": "common"
},
{
"x": 221,
"y": 714,
"type": "common"
},
{
"x": 251,
"y": 714,
"type": "common"
}
],
"pipe": {
"x": 1065,
"y": 700,
"r": 46
},
"waypoints": [
{
"x": 758,
"y": 589
}
],
"required": 6,
"ocdTarget": 13
}

View File

@ -0,0 +1,297 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 41,
"name": "The Machine",
"chapter": 3,
"tip": "The cog is solid and it is turning. Whatever it touches gets dragged along.",
"element": "gear",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
}
],
"balls": [
{
"x": 260,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 322,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 291,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 1000,
"y": 834,
"type": "common"
},
{
"x": 1030,
"y": 834,
"type": "block"
},
{
"x": 1060,
"y": 834,
"type": "bomb"
},
{
"x": 1090,
"y": 834,
"type": "common"
},
{
"x": 1120,
"y": 834,
"type": "block"
},
{
"x": 1150,
"y": 834,
"type": "bomb"
},
{
"x": 1180,
"y": 834,
"type": "common"
},
{
"x": 1210,
"y": 834,
"type": "block"
},
{
"x": 1240,
"y": 834,
"type": "bomb"
},
{
"x": 1000,
"y": 804,
"type": "common"
},
{
"x": 1030,
"y": 804,
"type": "block"
},
{
"x": 1060,
"y": 804,
"type": "bomb"
},
{
"x": 1090,
"y": 804,
"type": "common"
},
{
"x": 1120,
"y": 804,
"type": "block"
},
{
"x": 1150,
"y": 804,
"type": "common"
},
{
"x": 1180,
"y": 804,
"type": "block"
},
{
"x": 1210,
"y": 804,
"type": "common"
},
{
"x": 1240,
"y": 804,
"type": "block"
},
{
"x": 1000,
"y": 774,
"type": "common"
},
{
"x": 1030,
"y": 774,
"type": "block"
},
{
"x": 1060,
"y": 774,
"type": "common"
},
{
"x": 1090,
"y": 774,
"type": "common"
},
{
"x": 1120,
"y": 774,
"type": "common"
},
{
"x": 1150,
"y": 774,
"type": "common"
},
{
"x": 1180,
"y": 774,
"type": "common"
},
{
"x": 1210,
"y": 774,
"type": "common"
},
{
"x": 1240,
"y": 774,
"type": "common"
},
{
"x": 1000,
"y": 744,
"type": "common"
},
{
"x": 1030,
"y": 744,
"type": "common"
},
{
"x": 1060,
"y": 744,
"type": "common"
},
{
"x": 1090,
"y": 744,
"type": "common"
},
{
"x": 1120,
"y": 744,
"type": "common"
},
{
"x": 1150,
"y": 744,
"type": "common"
},
{
"x": 1180,
"y": 744,
"type": "common"
}
],
"pipe": {
"x": 1232,
"y": 581,
"r": 46
},
"gears": [
{
"x": 756,
"y": 481,
"r": 112,
"teeth": 9,
"omega": -1.5957301009483635
}
],
"required": 6,
"ocdTarget": 13
}

View File

@ -0,0 +1,297 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 42,
"name": "Grinding Gears",
"chapter": 3,
"tip": "The cog is solid and it is turning. Whatever it touches gets dragged along.",
"element": "gear",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
}
],
"balls": [
{
"x": 258,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 320,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 289,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 1000,
"y": 834,
"type": "common"
},
{
"x": 1030,
"y": 834,
"type": "block"
},
{
"x": 1060,
"y": 834,
"type": "bomb"
},
{
"x": 1090,
"y": 834,
"type": "common"
},
{
"x": 1120,
"y": 834,
"type": "block"
},
{
"x": 1150,
"y": 834,
"type": "bomb"
},
{
"x": 1180,
"y": 834,
"type": "common"
},
{
"x": 1210,
"y": 834,
"type": "block"
},
{
"x": 1240,
"y": 834,
"type": "bomb"
},
{
"x": 1000,
"y": 804,
"type": "common"
},
{
"x": 1030,
"y": 804,
"type": "block"
},
{
"x": 1060,
"y": 804,
"type": "bomb"
},
{
"x": 1090,
"y": 804,
"type": "common"
},
{
"x": 1120,
"y": 804,
"type": "block"
},
{
"x": 1150,
"y": 804,
"type": "common"
},
{
"x": 1180,
"y": 804,
"type": "block"
},
{
"x": 1210,
"y": 804,
"type": "common"
},
{
"x": 1240,
"y": 804,
"type": "block"
},
{
"x": 1000,
"y": 774,
"type": "common"
},
{
"x": 1030,
"y": 774,
"type": "block"
},
{
"x": 1060,
"y": 774,
"type": "common"
},
{
"x": 1090,
"y": 774,
"type": "common"
},
{
"x": 1120,
"y": 774,
"type": "common"
},
{
"x": 1150,
"y": 774,
"type": "common"
},
{
"x": 1180,
"y": 774,
"type": "common"
},
{
"x": 1210,
"y": 774,
"type": "common"
},
{
"x": 1240,
"y": 774,
"type": "common"
},
{
"x": 1000,
"y": 744,
"type": "common"
},
{
"x": 1030,
"y": 744,
"type": "common"
},
{
"x": 1060,
"y": 744,
"type": "common"
},
{
"x": 1090,
"y": 744,
"type": "common"
},
{
"x": 1120,
"y": 744,
"type": "common"
},
{
"x": 1150,
"y": 744,
"type": "common"
},
{
"x": 1180,
"y": 744,
"type": "common"
}
],
"pipe": {
"x": 1254,
"y": 569,
"r": 46
},
"gears": [
{
"x": 775,
"y": 469,
"r": 117,
"teeth": 9,
"omega": -1.7502086996054276
}
],
"required": 7,
"ocdTarget": 15
}

View File

@ -0,0 +1,297 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 43,
"name": "Flywheel",
"chapter": 3,
"tip": "The cog is solid and it is turning. Whatever it touches gets dragged along.",
"element": "gear",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
}
],
"balls": [
{
"x": 286,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 348,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 317,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 1000,
"y": 834,
"type": "common"
},
{
"x": 1030,
"y": 834,
"type": "block"
},
{
"x": 1060,
"y": 834,
"type": "bomb"
},
{
"x": 1090,
"y": 834,
"type": "common"
},
{
"x": 1120,
"y": 834,
"type": "block"
},
{
"x": 1150,
"y": 834,
"type": "bomb"
},
{
"x": 1180,
"y": 834,
"type": "common"
},
{
"x": 1210,
"y": 834,
"type": "block"
},
{
"x": 1240,
"y": 834,
"type": "bomb"
},
{
"x": 1000,
"y": 804,
"type": "common"
},
{
"x": 1030,
"y": 804,
"type": "block"
},
{
"x": 1060,
"y": 804,
"type": "bomb"
},
{
"x": 1090,
"y": 804,
"type": "common"
},
{
"x": 1120,
"y": 804,
"type": "block"
},
{
"x": 1150,
"y": 804,
"type": "common"
},
{
"x": 1180,
"y": 804,
"type": "block"
},
{
"x": 1210,
"y": 804,
"type": "common"
},
{
"x": 1240,
"y": 804,
"type": "block"
},
{
"x": 1000,
"y": 774,
"type": "common"
},
{
"x": 1030,
"y": 774,
"type": "block"
},
{
"x": 1060,
"y": 774,
"type": "common"
},
{
"x": 1090,
"y": 774,
"type": "common"
},
{
"x": 1120,
"y": 774,
"type": "common"
},
{
"x": 1150,
"y": 774,
"type": "common"
},
{
"x": 1180,
"y": 774,
"type": "common"
},
{
"x": 1210,
"y": 774,
"type": "common"
},
{
"x": 1240,
"y": 774,
"type": "common"
},
{
"x": 1000,
"y": 744,
"type": "common"
},
{
"x": 1030,
"y": 744,
"type": "common"
},
{
"x": 1060,
"y": 744,
"type": "common"
},
{
"x": 1090,
"y": 744,
"type": "common"
},
{
"x": 1120,
"y": 744,
"type": "common"
},
{
"x": 1150,
"y": 744,
"type": "common"
},
{
"x": 1180,
"y": 744,
"type": "common"
}
],
"pipe": {
"x": 1278,
"y": 556,
"r": 46
},
"gears": [
{
"x": 816,
"y": 456,
"r": 122,
"teeth": 9,
"omega": 1.9166405162680893
}
],
"required": 8,
"ocdTarget": 17
}

View File

@ -0,0 +1,314 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 44,
"name": "Under the Works",
"chapter": 3,
"tip": "You cannot build through rock. Come out from under it first.",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
260,
573
],
[
810,
573
],
[
810,
643
],
[
260,
643
]
]
}
],
"balls": [
{
"x": 495,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 557,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 526,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 930,
"y": 834,
"type": "common"
},
{
"x": 960,
"y": 834,
"type": "block"
},
{
"x": 990,
"y": 834,
"type": "bomb"
},
{
"x": 1020,
"y": 834,
"type": "common"
},
{
"x": 1050,
"y": 834,
"type": "block"
},
{
"x": 1080,
"y": 834,
"type": "bomb"
},
{
"x": 1110,
"y": 834,
"type": "common"
},
{
"x": 1140,
"y": 834,
"type": "block"
},
{
"x": 1170,
"y": 834,
"type": "bomb"
},
{
"x": 1200,
"y": 834,
"type": "common"
},
{
"x": 1230,
"y": 834,
"type": "block"
},
{
"x": 930,
"y": 804,
"type": "bomb"
},
{
"x": 960,
"y": 804,
"type": "common"
},
{
"x": 990,
"y": 804,
"type": "block"
},
{
"x": 1020,
"y": 804,
"type": "common"
},
{
"x": 1050,
"y": 804,
"type": "block"
},
{
"x": 1080,
"y": 804,
"type": "common"
},
{
"x": 1110,
"y": 804,
"type": "block"
},
{
"x": 1140,
"y": 804,
"type": "common"
},
{
"x": 1170,
"y": 804,
"type": "block"
},
{
"x": 1200,
"y": 804,
"type": "common"
},
{
"x": 1230,
"y": 804,
"type": "common"
},
{
"x": 930,
"y": 774,
"type": "common"
},
{
"x": 960,
"y": 774,
"type": "common"
},
{
"x": 990,
"y": 774,
"type": "common"
},
{
"x": 1020,
"y": 774,
"type": "common"
},
{
"x": 1050,
"y": 774,
"type": "common"
},
{
"x": 1080,
"y": 774,
"type": "common"
},
{
"x": 1110,
"y": 774,
"type": "common"
},
{
"x": 1140,
"y": 774,
"type": "common"
},
{
"x": 1170,
"y": 774,
"type": "common"
},
{
"x": 1200,
"y": 774,
"type": "common"
},
{
"x": 1230,
"y": 774,
"type": "common"
},
{
"x": 930,
"y": 744,
"type": "common"
}
],
"pipe": {
"x": 960,
"y": 513,
"r": 46
},
"waypoints": [
{
"x": 850,
"y": 593
}
],
"required": 6,
"ocdTarget": 13
}

View File

@ -0,0 +1,314 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 45,
"name": "Assembly",
"chapter": 3,
"tip": "You cannot build through rock. Come out from under it first.",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
260,
560
],
[
831,
560
],
[
831,
630
],
[
260,
630
]
]
}
],
"balls": [
{
"x": 546,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 608,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 577,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 951,
"y": 834,
"type": "common"
},
{
"x": 981,
"y": 834,
"type": "block"
},
{
"x": 1011,
"y": 834,
"type": "bomb"
},
{
"x": 1041,
"y": 834,
"type": "common"
},
{
"x": 1071,
"y": 834,
"type": "block"
},
{
"x": 1101,
"y": 834,
"type": "bomb"
},
{
"x": 1131,
"y": 834,
"type": "common"
},
{
"x": 1161,
"y": 834,
"type": "block"
},
{
"x": 1191,
"y": 834,
"type": "bomb"
},
{
"x": 1221,
"y": 834,
"type": "common"
},
{
"x": 1251,
"y": 834,
"type": "block"
},
{
"x": 951,
"y": 804,
"type": "bomb"
},
{
"x": 981,
"y": 804,
"type": "common"
},
{
"x": 1011,
"y": 804,
"type": "block"
},
{
"x": 1041,
"y": 804,
"type": "common"
},
{
"x": 1071,
"y": 804,
"type": "block"
},
{
"x": 1101,
"y": 804,
"type": "common"
},
{
"x": 1131,
"y": 804,
"type": "block"
},
{
"x": 1161,
"y": 804,
"type": "common"
},
{
"x": 1191,
"y": 804,
"type": "block"
},
{
"x": 1221,
"y": 804,
"type": "common"
},
{
"x": 1251,
"y": 804,
"type": "common"
},
{
"x": 951,
"y": 774,
"type": "common"
},
{
"x": 981,
"y": 774,
"type": "common"
},
{
"x": 1011,
"y": 774,
"type": "common"
},
{
"x": 1041,
"y": 774,
"type": "common"
},
{
"x": 1071,
"y": 774,
"type": "common"
},
{
"x": 1101,
"y": 774,
"type": "common"
},
{
"x": 1131,
"y": 774,
"type": "common"
},
{
"x": 1161,
"y": 774,
"type": "common"
},
{
"x": 1191,
"y": 774,
"type": "common"
},
{
"x": 1221,
"y": 774,
"type": "common"
},
{
"x": 1251,
"y": 774,
"type": "common"
},
{
"x": 951,
"y": 744,
"type": "common"
}
],
"pipe": {
"x": 981,
"y": 500,
"r": 46
},
"waypoints": [
{
"x": 871,
"y": 580
}
],
"required": 7,
"ocdTarget": 15
}

View File

@ -0,0 +1,335 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 46,
"name": "Handhold",
"chapter": 4,
"tip": "Anchor goo sticks straight to rock. The pillars are fair game.",
"element": "anchor",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
420,
349
],
[
480,
349
],
[
480,
850
],
[
420,
850
]
]
},
{
"kind": "solid",
"poly": [
[
1040,
349
],
[
1100,
349
],
[
1100,
850
],
[
1040,
850
]
]
}
],
"balls": [
{
"x": 729,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 791,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 760,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 870,
"y": 834,
"type": "pokey"
},
{
"x": 900,
"y": 834,
"type": "anchor"
},
{
"x": 930,
"y": 834,
"type": "common"
},
{
"x": 960,
"y": 834,
"type": "pokey"
},
{
"x": 990,
"y": 834,
"type": "anchor"
},
{
"x": 1020,
"y": 834,
"type": "common"
},
{
"x": 870,
"y": 804,
"type": "pokey"
},
{
"x": 900,
"y": 804,
"type": "anchor"
},
{
"x": 930,
"y": 804,
"type": "common"
},
{
"x": 960,
"y": 804,
"type": "pokey"
},
{
"x": 990,
"y": 804,
"type": "anchor"
},
{
"x": 1020,
"y": 804,
"type": "common"
},
{
"x": 870,
"y": 774,
"type": "pokey"
},
{
"x": 900,
"y": 774,
"type": "anchor"
},
{
"x": 930,
"y": 774,
"type": "common"
},
{
"x": 960,
"y": 774,
"type": "pokey"
},
{
"x": 990,
"y": 774,
"type": "common"
},
{
"x": 1020,
"y": 774,
"type": "pokey"
},
{
"x": 870,
"y": 744,
"type": "common"
},
{
"x": 900,
"y": 744,
"type": "pokey"
},
{
"x": 930,
"y": 744,
"type": "common"
},
{
"x": 960,
"y": 744,
"type": "common"
},
{
"x": 990,
"y": 744,
"type": "common"
},
{
"x": 1020,
"y": 744,
"type": "common"
},
{
"x": 870,
"y": 714,
"type": "common"
},
{
"x": 900,
"y": 714,
"type": "common"
},
{
"x": 930,
"y": 714,
"type": "common"
},
{
"x": 960,
"y": 714,
"type": "common"
},
{
"x": 990,
"y": 714,
"type": "common"
},
{
"x": 1020,
"y": 714,
"type": "common"
},
{
"x": 870,
"y": 684,
"type": "common"
},
{
"x": 900,
"y": 684,
"type": "common"
},
{
"x": 930,
"y": 684,
"type": "common"
},
{
"x": 960,
"y": 684,
"type": "common"
},
{
"x": 990,
"y": 684,
"type": "common"
}
],
"pipe": {
"x": 760,
"y": 409,
"r": 46
},
"required": 5,
"ocdTarget": 10
}

View File

@ -0,0 +1,335 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 47,
"name": "Two Pillars",
"chapter": 4,
"tip": "Anchor goo sticks straight to rock. The pillars are fair game.",
"element": "anchor",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
420,
342
],
[
480,
342
],
[
480,
850
],
[
420,
850
]
]
},
{
"kind": "solid",
"poly": [
[
1040,
342
],
[
1100,
342
],
[
1100,
850
],
[
1040,
850
]
]
}
],
"balls": [
{
"x": 729,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 791,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 760,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 870,
"y": 834,
"type": "pokey"
},
{
"x": 900,
"y": 834,
"type": "anchor"
},
{
"x": 930,
"y": 834,
"type": "common"
},
{
"x": 960,
"y": 834,
"type": "pokey"
},
{
"x": 990,
"y": 834,
"type": "anchor"
},
{
"x": 1020,
"y": 834,
"type": "common"
},
{
"x": 870,
"y": 804,
"type": "pokey"
},
{
"x": 900,
"y": 804,
"type": "anchor"
},
{
"x": 930,
"y": 804,
"type": "common"
},
{
"x": 960,
"y": 804,
"type": "pokey"
},
{
"x": 990,
"y": 804,
"type": "anchor"
},
{
"x": 1020,
"y": 804,
"type": "common"
},
{
"x": 870,
"y": 774,
"type": "pokey"
},
{
"x": 900,
"y": 774,
"type": "anchor"
},
{
"x": 930,
"y": 774,
"type": "common"
},
{
"x": 960,
"y": 774,
"type": "pokey"
},
{
"x": 990,
"y": 774,
"type": "common"
},
{
"x": 1020,
"y": 774,
"type": "pokey"
},
{
"x": 870,
"y": 744,
"type": "common"
},
{
"x": 900,
"y": 744,
"type": "pokey"
},
{
"x": 930,
"y": 744,
"type": "common"
},
{
"x": 960,
"y": 744,
"type": "common"
},
{
"x": 990,
"y": 744,
"type": "common"
},
{
"x": 1020,
"y": 744,
"type": "common"
},
{
"x": 870,
"y": 714,
"type": "common"
},
{
"x": 900,
"y": 714,
"type": "common"
},
{
"x": 930,
"y": 714,
"type": "common"
},
{
"x": 960,
"y": 714,
"type": "common"
},
{
"x": 990,
"y": 714,
"type": "common"
},
{
"x": 1020,
"y": 714,
"type": "common"
},
{
"x": 870,
"y": 684,
"type": "common"
},
{
"x": 900,
"y": 684,
"type": "common"
},
{
"x": 930,
"y": 684,
"type": "common"
},
{
"x": 960,
"y": 684,
"type": "common"
},
{
"x": 990,
"y": 684,
"type": "common"
}
],
"pipe": {
"x": 760,
"y": 402,
"r": 46
},
"required": 5,
"ocdTarget": 10
}

View File

@ -0,0 +1,335 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 48,
"name": "Stepping Up",
"chapter": 4,
"tip": "Anchor goo sticks straight to rock. The pillars are fair game.",
"element": "anchor",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
420,
328
],
[
480,
328
],
[
480,
850
],
[
420,
850
]
]
},
{
"kind": "solid",
"poly": [
[
1040,
328
],
[
1100,
328
],
[
1100,
850
],
[
1040,
850
]
]
}
],
"balls": [
{
"x": 729,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 791,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 760,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 870,
"y": 834,
"type": "pokey"
},
{
"x": 900,
"y": 834,
"type": "anchor"
},
{
"x": 930,
"y": 834,
"type": "common"
},
{
"x": 960,
"y": 834,
"type": "pokey"
},
{
"x": 990,
"y": 834,
"type": "anchor"
},
{
"x": 1020,
"y": 834,
"type": "common"
},
{
"x": 870,
"y": 804,
"type": "pokey"
},
{
"x": 900,
"y": 804,
"type": "anchor"
},
{
"x": 930,
"y": 804,
"type": "common"
},
{
"x": 960,
"y": 804,
"type": "pokey"
},
{
"x": 990,
"y": 804,
"type": "anchor"
},
{
"x": 1020,
"y": 804,
"type": "common"
},
{
"x": 870,
"y": 774,
"type": "pokey"
},
{
"x": 900,
"y": 774,
"type": "anchor"
},
{
"x": 930,
"y": 774,
"type": "common"
},
{
"x": 960,
"y": 774,
"type": "pokey"
},
{
"x": 990,
"y": 774,
"type": "common"
},
{
"x": 1020,
"y": 774,
"type": "pokey"
},
{
"x": 870,
"y": 744,
"type": "common"
},
{
"x": 900,
"y": 744,
"type": "pokey"
},
{
"x": 930,
"y": 744,
"type": "common"
},
{
"x": 960,
"y": 744,
"type": "common"
},
{
"x": 990,
"y": 744,
"type": "common"
},
{
"x": 1020,
"y": 744,
"type": "common"
},
{
"x": 870,
"y": 714,
"type": "common"
},
{
"x": 900,
"y": 714,
"type": "common"
},
{
"x": 930,
"y": 714,
"type": "common"
},
{
"x": 960,
"y": 714,
"type": "common"
},
{
"x": 990,
"y": 714,
"type": "common"
},
{
"x": 1020,
"y": 714,
"type": "common"
},
{
"x": 870,
"y": 684,
"type": "common"
},
{
"x": 900,
"y": 684,
"type": "common"
},
{
"x": 930,
"y": 684,
"type": "common"
},
{
"x": 960,
"y": 684,
"type": "common"
},
{
"x": 990,
"y": 684,
"type": "common"
}
],
"pipe": {
"x": 760,
"y": 388,
"r": 46
},
"required": 6,
"ocdTarget": 12
}

View File

@ -0,0 +1,383 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 49,
"name": "The Face",
"chapter": 4,
"tip": "Pokey goo grips bare rock and needs no friends. Start from the wall.",
"element": "anchor",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
210,
180
],
[
300,
180
],
[
300,
800
],
[
210,
800
]
]
},
{
"kind": "solid",
"poly": [
[
1200,
180
],
[
1290,
180
],
[
1290,
800
],
[
1200,
800
]
]
},
{
"kind": "spike",
"poly": [
[
300,
930
],
[
1200,
930
],
[
1200,
1000
],
[
300,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
300,
631
],
[
600,
631
],
[
600,
707
],
[
300,
707
]
]
}
],
"balls": [
{
"x": 340,
"y": 587,
"type": "pokey",
"pinned": true
},
{
"x": 340,
"y": 525,
"type": "pokey",
"pinned": true
},
{
"x": 398,
"y": 556,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 430,
"y": 615,
"type": "pokey"
},
{
"x": 460,
"y": 615,
"type": "anchor"
},
{
"x": 490,
"y": 615,
"type": "common"
},
{
"x": 520,
"y": 615,
"type": "pokey"
},
{
"x": 550,
"y": 615,
"type": "anchor"
},
{
"x": 580,
"y": 615,
"type": "common"
},
{
"x": 430,
"y": 585,
"type": "pokey"
},
{
"x": 460,
"y": 585,
"type": "anchor"
},
{
"x": 490,
"y": 585,
"type": "common"
},
{
"x": 520,
"y": 585,
"type": "pokey"
},
{
"x": 550,
"y": 585,
"type": "anchor"
},
{
"x": 580,
"y": 585,
"type": "common"
},
{
"x": 430,
"y": 555,
"type": "pokey"
},
{
"x": 460,
"y": 555,
"type": "anchor"
},
{
"x": 490,
"y": 555,
"type": "common"
},
{
"x": 520,
"y": 555,
"type": "pokey"
},
{
"x": 550,
"y": 555,
"type": "common"
},
{
"x": 580,
"y": 555,
"type": "pokey"
},
{
"x": 430,
"y": 525,
"type": "common"
},
{
"x": 460,
"y": 525,
"type": "pokey"
},
{
"x": 490,
"y": 525,
"type": "common"
},
{
"x": 520,
"y": 525,
"type": "common"
},
{
"x": 550,
"y": 525,
"type": "common"
},
{
"x": 580,
"y": 525,
"type": "common"
},
{
"x": 430,
"y": 495,
"type": "common"
},
{
"x": 460,
"y": 495,
"type": "common"
},
{
"x": 490,
"y": 495,
"type": "common"
},
{
"x": 520,
"y": 495,
"type": "common"
},
{
"x": 550,
"y": 495,
"type": "common"
},
{
"x": 580,
"y": 495,
"type": "common"
},
{
"x": 430,
"y": 465,
"type": "common"
},
{
"x": 460,
"y": 465,
"type": "common"
},
{
"x": 490,
"y": 465,
"type": "common"
},
{
"x": 520,
"y": 465,
"type": "common"
},
{
"x": 550,
"y": 465,
"type": "common"
}
],
"pipe": {
"x": 1150,
"y": 450,
"r": 46
},
"waypoints": [
{
"x": 740,
"y": 444
}
],
"required": 5,
"ocdTarget": 10
}

View File

@ -0,0 +1,383 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 50,
"name": "Sheer",
"chapter": 4,
"tip": "Pokey goo grips bare rock and needs no friends. Start from the wall.",
"element": "anchor",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
210,
180
],
[
300,
180
],
[
300,
800
],
[
210,
800
]
]
},
{
"kind": "solid",
"poly": [
[
1200,
180
],
[
1290,
180
],
[
1290,
800
],
[
1200,
800
]
]
},
{
"kind": "spike",
"poly": [
[
300,
930
],
[
1200,
930
],
[
1200,
1000
],
[
300,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
300,
621
],
[
600,
621
],
[
600,
697
],
[
300,
697
]
]
}
],
"balls": [
{
"x": 340,
"y": 577,
"type": "pokey",
"pinned": true
},
{
"x": 340,
"y": 515,
"type": "pokey",
"pinned": true
},
{
"x": 398,
"y": 546,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 430,
"y": 605,
"type": "pokey"
},
{
"x": 460,
"y": 605,
"type": "anchor"
},
{
"x": 490,
"y": 605,
"type": "common"
},
{
"x": 520,
"y": 605,
"type": "pokey"
},
{
"x": 550,
"y": 605,
"type": "anchor"
},
{
"x": 580,
"y": 605,
"type": "common"
},
{
"x": 430,
"y": 575,
"type": "pokey"
},
{
"x": 460,
"y": 575,
"type": "anchor"
},
{
"x": 490,
"y": 575,
"type": "common"
},
{
"x": 520,
"y": 575,
"type": "pokey"
},
{
"x": 550,
"y": 575,
"type": "anchor"
},
{
"x": 580,
"y": 575,
"type": "common"
},
{
"x": 430,
"y": 545,
"type": "pokey"
},
{
"x": 460,
"y": 545,
"type": "anchor"
},
{
"x": 490,
"y": 545,
"type": "common"
},
{
"x": 520,
"y": 545,
"type": "pokey"
},
{
"x": 550,
"y": 545,
"type": "common"
},
{
"x": 580,
"y": 545,
"type": "pokey"
},
{
"x": 430,
"y": 515,
"type": "common"
},
{
"x": 460,
"y": 515,
"type": "pokey"
},
{
"x": 490,
"y": 515,
"type": "common"
},
{
"x": 520,
"y": 515,
"type": "common"
},
{
"x": 550,
"y": 515,
"type": "common"
},
{
"x": 580,
"y": 515,
"type": "common"
},
{
"x": 430,
"y": 485,
"type": "common"
},
{
"x": 460,
"y": 485,
"type": "common"
},
{
"x": 490,
"y": 485,
"type": "common"
},
{
"x": 520,
"y": 485,
"type": "common"
},
{
"x": 550,
"y": 485,
"type": "common"
},
{
"x": 580,
"y": 485,
"type": "common"
},
{
"x": 430,
"y": 455,
"type": "common"
},
{
"x": 460,
"y": 455,
"type": "common"
},
{
"x": 490,
"y": 455,
"type": "common"
},
{
"x": 520,
"y": 455,
"type": "common"
},
{
"x": 550,
"y": 455,
"type": "common"
}
],
"pipe": {
"x": 1150,
"y": 443,
"r": 46
},
"waypoints": [
{
"x": 740,
"y": 438
}
],
"required": 5,
"ocdTarget": 10
}

View File

@ -0,0 +1,383 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 51,
"name": "Traverse",
"chapter": 4,
"tip": "Pokey goo grips bare rock and needs no friends. Start from the wall.",
"element": "anchor",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
210,
180
],
[
300,
180
],
[
300,
800
],
[
210,
800
]
]
},
{
"kind": "solid",
"poly": [
[
1200,
180
],
[
1290,
180
],
[
1290,
800
],
[
1200,
800
]
]
},
{
"kind": "spike",
"poly": [
[
300,
930
],
[
1200,
930
],
[
1200,
1000
],
[
300,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
300,
610
],
[
600,
610
],
[
600,
686
],
[
300,
686
]
]
}
],
"balls": [
{
"x": 340,
"y": 566,
"type": "pokey",
"pinned": true
},
{
"x": 340,
"y": 504,
"type": "pokey",
"pinned": true
},
{
"x": 398,
"y": 535,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 430,
"y": 594,
"type": "pokey"
},
{
"x": 460,
"y": 594,
"type": "anchor"
},
{
"x": 490,
"y": 594,
"type": "common"
},
{
"x": 520,
"y": 594,
"type": "pokey"
},
{
"x": 550,
"y": 594,
"type": "anchor"
},
{
"x": 580,
"y": 594,
"type": "common"
},
{
"x": 430,
"y": 564,
"type": "pokey"
},
{
"x": 460,
"y": 564,
"type": "anchor"
},
{
"x": 490,
"y": 564,
"type": "common"
},
{
"x": 520,
"y": 564,
"type": "pokey"
},
{
"x": 550,
"y": 564,
"type": "anchor"
},
{
"x": 580,
"y": 564,
"type": "common"
},
{
"x": 430,
"y": 534,
"type": "pokey"
},
{
"x": 460,
"y": 534,
"type": "anchor"
},
{
"x": 490,
"y": 534,
"type": "common"
},
{
"x": 520,
"y": 534,
"type": "pokey"
},
{
"x": 550,
"y": 534,
"type": "common"
},
{
"x": 580,
"y": 534,
"type": "pokey"
},
{
"x": 430,
"y": 504,
"type": "common"
},
{
"x": 460,
"y": 504,
"type": "pokey"
},
{
"x": 490,
"y": 504,
"type": "common"
},
{
"x": 520,
"y": 504,
"type": "common"
},
{
"x": 550,
"y": 504,
"type": "common"
},
{
"x": 580,
"y": 504,
"type": "common"
},
{
"x": 430,
"y": 474,
"type": "common"
},
{
"x": 460,
"y": 474,
"type": "common"
},
{
"x": 490,
"y": 474,
"type": "common"
},
{
"x": 520,
"y": 474,
"type": "common"
},
{
"x": 550,
"y": 474,
"type": "common"
},
{
"x": 580,
"y": 474,
"type": "common"
},
{
"x": 430,
"y": 444,
"type": "common"
},
{
"x": 460,
"y": 444,
"type": "common"
},
{
"x": 490,
"y": 444,
"type": "common"
},
{
"x": 520,
"y": 444,
"type": "common"
},
{
"x": 550,
"y": 444,
"type": "common"
}
],
"pipe": {
"x": 1150,
"y": 435,
"r": 46
},
"waypoints": [
{
"x": 740,
"y": 433
}
],
"required": 6,
"ocdTarget": 12
}

View File

@ -0,0 +1,383 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 52,
"name": "Grip",
"chapter": 4,
"tip": "Pokey goo grips bare rock and needs no friends. Start from the wall.",
"element": "anchor",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
210,
180
],
[
300,
180
],
[
300,
800
],
[
210,
800
]
]
},
{
"kind": "solid",
"poly": [
[
1200,
180
],
[
1290,
180
],
[
1290,
800
],
[
1200,
800
]
]
},
{
"kind": "spike",
"poly": [
[
300,
930
],
[
1200,
930
],
[
1200,
1000
],
[
300,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
300,
605
],
[
600,
605
],
[
600,
681
],
[
300,
681
]
]
}
],
"balls": [
{
"x": 340,
"y": 561,
"type": "pokey",
"pinned": true
},
{
"x": 340,
"y": 499,
"type": "pokey",
"pinned": true
},
{
"x": 398,
"y": 530,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 430,
"y": 589,
"type": "pokey"
},
{
"x": 460,
"y": 589,
"type": "anchor"
},
{
"x": 490,
"y": 589,
"type": "common"
},
{
"x": 520,
"y": 589,
"type": "pokey"
},
{
"x": 550,
"y": 589,
"type": "anchor"
},
{
"x": 580,
"y": 589,
"type": "common"
},
{
"x": 430,
"y": 559,
"type": "pokey"
},
{
"x": 460,
"y": 559,
"type": "anchor"
},
{
"x": 490,
"y": 559,
"type": "common"
},
{
"x": 520,
"y": 559,
"type": "pokey"
},
{
"x": 550,
"y": 559,
"type": "anchor"
},
{
"x": 580,
"y": 559,
"type": "common"
},
{
"x": 430,
"y": 529,
"type": "pokey"
},
{
"x": 460,
"y": 529,
"type": "anchor"
},
{
"x": 490,
"y": 529,
"type": "common"
},
{
"x": 520,
"y": 529,
"type": "pokey"
},
{
"x": 550,
"y": 529,
"type": "common"
},
{
"x": 580,
"y": 529,
"type": "pokey"
},
{
"x": 430,
"y": 499,
"type": "common"
},
{
"x": 460,
"y": 499,
"type": "pokey"
},
{
"x": 490,
"y": 499,
"type": "common"
},
{
"x": 520,
"y": 499,
"type": "common"
},
{
"x": 550,
"y": 499,
"type": "common"
},
{
"x": 580,
"y": 499,
"type": "common"
},
{
"x": 430,
"y": 469,
"type": "common"
},
{
"x": 460,
"y": 469,
"type": "common"
},
{
"x": 490,
"y": 469,
"type": "common"
},
{
"x": 520,
"y": 469,
"type": "common"
},
{
"x": 550,
"y": 469,
"type": "common"
},
{
"x": 580,
"y": 469,
"type": "common"
},
{
"x": 430,
"y": 439,
"type": "common"
},
{
"x": 460,
"y": 439,
"type": "common"
},
{
"x": 490,
"y": 439,
"type": "common"
},
{
"x": 520,
"y": 439,
"type": "common"
},
{
"x": 550,
"y": 439,
"type": "common"
}
],
"pipe": {
"x": 1150,
"y": 431,
"r": 46
},
"waypoints": [
{
"x": 740,
"y": 431
}
],
"required": 6,
"ocdTarget": 12
}

View File

@ -0,0 +1,292 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 53,
"name": "Overhanging",
"chapter": 4,
"tip": "Brace as you go. An unbraced column leans, and once it leans it keeps leaning.",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
}
],
"balls": [
{
"x": 730,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 792,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 761,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 1021,
"y": 834,
"type": "pokey"
},
{
"x": 1051,
"y": 834,
"type": "anchor"
},
{
"x": 1081,
"y": 834,
"type": "common"
},
{
"x": 1111,
"y": 834,
"type": "pokey"
},
{
"x": 1141,
"y": 834,
"type": "anchor"
},
{
"x": 1171,
"y": 834,
"type": "common"
},
{
"x": 1201,
"y": 834,
"type": "pokey"
},
{
"x": 1231,
"y": 834,
"type": "anchor"
},
{
"x": 1261,
"y": 834,
"type": "common"
},
{
"x": 1291,
"y": 834,
"type": "pokey"
},
{
"x": 1321,
"y": 834,
"type": "anchor"
},
{
"x": 1351,
"y": 834,
"type": "common"
},
{
"x": 1021,
"y": 804,
"type": "pokey"
},
{
"x": 1051,
"y": 804,
"type": "anchor"
},
{
"x": 1081,
"y": 804,
"type": "common"
},
{
"x": 1111,
"y": 804,
"type": "pokey"
},
{
"x": 1141,
"y": 804,
"type": "common"
},
{
"x": 1171,
"y": 804,
"type": "pokey"
},
{
"x": 1201,
"y": 804,
"type": "common"
},
{
"x": 1231,
"y": 804,
"type": "pokey"
},
{
"x": 1261,
"y": 804,
"type": "common"
},
{
"x": 1291,
"y": 804,
"type": "common"
},
{
"x": 1321,
"y": 804,
"type": "common"
},
{
"x": 1351,
"y": 804,
"type": "common"
},
{
"x": 1021,
"y": 774,
"type": "common"
},
{
"x": 1051,
"y": 774,
"type": "common"
},
{
"x": 1081,
"y": 774,
"type": "common"
},
{
"x": 1111,
"y": 774,
"type": "common"
},
{
"x": 1141,
"y": 774,
"type": "common"
},
{
"x": 1171,
"y": 774,
"type": "common"
},
{
"x": 1201,
"y": 774,
"type": "common"
},
{
"x": 1231,
"y": 774,
"type": "common"
},
{
"x": 1261,
"y": 774,
"type": "common"
},
{
"x": 1291,
"y": 774,
"type": "common"
},
{
"x": 1321,
"y": 774,
"type": "common"
}
],
"pipe": {
"x": 761,
"y": 425,
"r": 46
},
"required": 6,
"ocdTarget": 13
}

View File

@ -0,0 +1,292 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 54,
"name": "Cliffhanger",
"chapter": 4,
"tip": "Brace as you go. An unbraced column leans, and once it leans it keeps leaning.",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
}
],
"balls": [
{
"x": 692,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 754,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 723,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 983,
"y": 834,
"type": "pokey"
},
{
"x": 1013,
"y": 834,
"type": "anchor"
},
{
"x": 1043,
"y": 834,
"type": "common"
},
{
"x": 1073,
"y": 834,
"type": "pokey"
},
{
"x": 1103,
"y": 834,
"type": "anchor"
},
{
"x": 1133,
"y": 834,
"type": "common"
},
{
"x": 1163,
"y": 834,
"type": "pokey"
},
{
"x": 1193,
"y": 834,
"type": "anchor"
},
{
"x": 1223,
"y": 834,
"type": "common"
},
{
"x": 1253,
"y": 834,
"type": "pokey"
},
{
"x": 1283,
"y": 834,
"type": "anchor"
},
{
"x": 1313,
"y": 834,
"type": "common"
},
{
"x": 983,
"y": 804,
"type": "pokey"
},
{
"x": 1013,
"y": 804,
"type": "anchor"
},
{
"x": 1043,
"y": 804,
"type": "common"
},
{
"x": 1073,
"y": 804,
"type": "pokey"
},
{
"x": 1103,
"y": 804,
"type": "common"
},
{
"x": 1133,
"y": 804,
"type": "pokey"
},
{
"x": 1163,
"y": 804,
"type": "common"
},
{
"x": 1193,
"y": 804,
"type": "pokey"
},
{
"x": 1223,
"y": 804,
"type": "common"
},
{
"x": 1253,
"y": 804,
"type": "common"
},
{
"x": 1283,
"y": 804,
"type": "common"
},
{
"x": 1313,
"y": 804,
"type": "common"
},
{
"x": 983,
"y": 774,
"type": "common"
},
{
"x": 1013,
"y": 774,
"type": "common"
},
{
"x": 1043,
"y": 774,
"type": "common"
},
{
"x": 1073,
"y": 774,
"type": "common"
},
{
"x": 1103,
"y": 774,
"type": "common"
},
{
"x": 1133,
"y": 774,
"type": "common"
},
{
"x": 1163,
"y": 774,
"type": "common"
},
{
"x": 1193,
"y": 774,
"type": "common"
},
{
"x": 1223,
"y": 774,
"type": "common"
},
{
"x": 1253,
"y": 774,
"type": "common"
},
{
"x": 1283,
"y": 774,
"type": "common"
}
],
"pipe": {
"x": 723,
"y": 379,
"r": 46
},
"required": 7,
"ocdTarget": 15
}

View File

@ -0,0 +1,383 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 55,
"name": "The Chimney",
"chapter": 4,
"tip": "Pokey goo grips bare rock and needs no friends. Start from the wall.",
"element": "anchor",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
210,
180
],
[
300,
180
],
[
300,
800
],
[
210,
800
]
]
},
{
"kind": "solid",
"poly": [
[
1200,
180
],
[
1290,
180
],
[
1290,
800
],
[
1200,
800
]
]
},
{
"kind": "spike",
"poly": [
[
300,
930
],
[
1200,
930
],
[
1200,
1000
],
[
300,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
300,
606
],
[
600,
606
],
[
600,
682
],
[
300,
682
]
]
}
],
"balls": [
{
"x": 340,
"y": 562,
"type": "pokey",
"pinned": true
},
{
"x": 340,
"y": 500,
"type": "pokey",
"pinned": true
},
{
"x": 398,
"y": 531,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 430,
"y": 590,
"type": "pokey"
},
{
"x": 460,
"y": 590,
"type": "anchor"
},
{
"x": 490,
"y": 590,
"type": "common"
},
{
"x": 520,
"y": 590,
"type": "pokey"
},
{
"x": 550,
"y": 590,
"type": "anchor"
},
{
"x": 580,
"y": 590,
"type": "common"
},
{
"x": 430,
"y": 560,
"type": "pokey"
},
{
"x": 460,
"y": 560,
"type": "anchor"
},
{
"x": 490,
"y": 560,
"type": "common"
},
{
"x": 520,
"y": 560,
"type": "pokey"
},
{
"x": 550,
"y": 560,
"type": "anchor"
},
{
"x": 580,
"y": 560,
"type": "common"
},
{
"x": 430,
"y": 530,
"type": "pokey"
},
{
"x": 460,
"y": 530,
"type": "anchor"
},
{
"x": 490,
"y": 530,
"type": "common"
},
{
"x": 520,
"y": 530,
"type": "pokey"
},
{
"x": 550,
"y": 530,
"type": "common"
},
{
"x": 580,
"y": 530,
"type": "pokey"
},
{
"x": 430,
"y": 500,
"type": "common"
},
{
"x": 460,
"y": 500,
"type": "pokey"
},
{
"x": 490,
"y": 500,
"type": "common"
},
{
"x": 520,
"y": 500,
"type": "common"
},
{
"x": 550,
"y": 500,
"type": "common"
},
{
"x": 580,
"y": 500,
"type": "common"
},
{
"x": 430,
"y": 470,
"type": "common"
},
{
"x": 460,
"y": 470,
"type": "common"
},
{
"x": 490,
"y": 470,
"type": "common"
},
{
"x": 520,
"y": 470,
"type": "common"
},
{
"x": 550,
"y": 470,
"type": "common"
},
{
"x": 580,
"y": 470,
"type": "common"
},
{
"x": 430,
"y": 440,
"type": "common"
},
{
"x": 460,
"y": 440,
"type": "common"
},
{
"x": 490,
"y": 440,
"type": "common"
},
{
"x": 520,
"y": 440,
"type": "common"
},
{
"x": 550,
"y": 440,
"type": "common"
}
],
"pipe": {
"x": 1150,
"y": 432,
"r": 46
},
"waypoints": [
{
"x": 740,
"y": 431
}
],
"required": 6,
"ocdTarget": 12
}

View File

@ -0,0 +1,292 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 56,
"name": "Freeclimb",
"chapter": 4,
"tip": "Brace as you go. An unbraced column leans, and once it leans it keeps leaning.",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
}
],
"balls": [
{
"x": 690,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 752,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 721,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 981,
"y": 834,
"type": "pokey"
},
{
"x": 1011,
"y": 834,
"type": "anchor"
},
{
"x": 1041,
"y": 834,
"type": "common"
},
{
"x": 1071,
"y": 834,
"type": "pokey"
},
{
"x": 1101,
"y": 834,
"type": "anchor"
},
{
"x": 1131,
"y": 834,
"type": "common"
},
{
"x": 1161,
"y": 834,
"type": "pokey"
},
{
"x": 1191,
"y": 834,
"type": "anchor"
},
{
"x": 1221,
"y": 834,
"type": "common"
},
{
"x": 1251,
"y": 834,
"type": "pokey"
},
{
"x": 1281,
"y": 834,
"type": "anchor"
},
{
"x": 1311,
"y": 834,
"type": "common"
},
{
"x": 981,
"y": 804,
"type": "pokey"
},
{
"x": 1011,
"y": 804,
"type": "anchor"
},
{
"x": 1041,
"y": 804,
"type": "common"
},
{
"x": 1071,
"y": 804,
"type": "pokey"
},
{
"x": 1101,
"y": 804,
"type": "common"
},
{
"x": 1131,
"y": 804,
"type": "pokey"
},
{
"x": 1161,
"y": 804,
"type": "common"
},
{
"x": 1191,
"y": 804,
"type": "pokey"
},
{
"x": 1221,
"y": 804,
"type": "common"
},
{
"x": 1251,
"y": 804,
"type": "common"
},
{
"x": 1281,
"y": 804,
"type": "common"
},
{
"x": 1311,
"y": 804,
"type": "common"
},
{
"x": 981,
"y": 774,
"type": "common"
},
{
"x": 1011,
"y": 774,
"type": "common"
},
{
"x": 1041,
"y": 774,
"type": "common"
},
{
"x": 1071,
"y": 774,
"type": "common"
},
{
"x": 1101,
"y": 774,
"type": "common"
},
{
"x": 1131,
"y": 774,
"type": "common"
},
{
"x": 1161,
"y": 774,
"type": "common"
},
{
"x": 1191,
"y": 774,
"type": "common"
},
{
"x": 1221,
"y": 774,
"type": "common"
},
{
"x": 1251,
"y": 774,
"type": "common"
},
{
"x": 1281,
"y": 774,
"type": "common"
}
],
"pipe": {
"x": 721,
"y": 432,
"r": 46
},
"required": 6,
"ocdTarget": 13
}

View File

@ -0,0 +1,292 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 57,
"name": "The Notch",
"chapter": 4,
"tip": "Brace as you go. An unbraced column leans, and once it leans it keeps leaning.",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
}
],
"balls": [
{
"x": 699,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 761,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 730,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 990,
"y": 834,
"type": "pokey"
},
{
"x": 1020,
"y": 834,
"type": "anchor"
},
{
"x": 1050,
"y": 834,
"type": "common"
},
{
"x": 1080,
"y": 834,
"type": "pokey"
},
{
"x": 1110,
"y": 834,
"type": "anchor"
},
{
"x": 1140,
"y": 834,
"type": "common"
},
{
"x": 1170,
"y": 834,
"type": "pokey"
},
{
"x": 1200,
"y": 834,
"type": "anchor"
},
{
"x": 1230,
"y": 834,
"type": "common"
},
{
"x": 1260,
"y": 834,
"type": "pokey"
},
{
"x": 1290,
"y": 834,
"type": "anchor"
},
{
"x": 1320,
"y": 834,
"type": "common"
},
{
"x": 990,
"y": 804,
"type": "pokey"
},
{
"x": 1020,
"y": 804,
"type": "anchor"
},
{
"x": 1050,
"y": 804,
"type": "common"
},
{
"x": 1080,
"y": 804,
"type": "pokey"
},
{
"x": 1110,
"y": 804,
"type": "common"
},
{
"x": 1140,
"y": 804,
"type": "pokey"
},
{
"x": 1170,
"y": 804,
"type": "common"
},
{
"x": 1200,
"y": 804,
"type": "pokey"
},
{
"x": 1230,
"y": 804,
"type": "common"
},
{
"x": 1260,
"y": 804,
"type": "common"
},
{
"x": 1290,
"y": 804,
"type": "common"
},
{
"x": 1320,
"y": 804,
"type": "common"
},
{
"x": 990,
"y": 774,
"type": "common"
},
{
"x": 1020,
"y": 774,
"type": "common"
},
{
"x": 1050,
"y": 774,
"type": "common"
},
{
"x": 1080,
"y": 774,
"type": "common"
},
{
"x": 1110,
"y": 774,
"type": "common"
},
{
"x": 1140,
"y": 774,
"type": "common"
},
{
"x": 1170,
"y": 774,
"type": "common"
},
{
"x": 1200,
"y": 774,
"type": "common"
},
{
"x": 1230,
"y": 774,
"type": "common"
},
{
"x": 1260,
"y": 774,
"type": "common"
},
{
"x": 1290,
"y": 774,
"type": "common"
}
],
"pipe": {
"x": 730,
"y": 404,
"r": 46
},
"required": 7,
"ocdTarget": 14
}

View File

@ -0,0 +1,382 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 58,
"name": "Crevasse",
"chapter": 4,
"tip": "Triangles carry weight across a gap. Long chains just sag into the spikes.",
"terrain": [
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
0,
700
],
[
602,
700
],
[
602,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
863,
700
],
[
1600,
700
],
[
1600,
1000
],
[
863,
1000
]
]
},
{
"kind": "spike",
"poly": [
[
602,
930
],
[
863,
930
],
[
863,
1000
],
[
602,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
0,
610
],
[
44,
610
],
[
44,
700
],
[
0,
700
]
]
},
{
"kind": "solid",
"poly": [
[
558,
610
],
[
602,
610
],
[
602,
700
],
[
558,
700
]
]
}
],
"balls": [
{
"x": 381,
"y": 686,
"type": "common",
"pinned": true
},
{
"x": 443,
"y": 686,
"type": "common",
"pinned": true
},
{
"x": 412,
"y": 632,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 90,
"y": 684,
"type": "pokey"
},
{
"x": 120,
"y": 684,
"type": "anchor"
},
{
"x": 150,
"y": 684,
"type": "common"
},
{
"x": 180,
"y": 684,
"type": "pokey"
},
{
"x": 210,
"y": 684,
"type": "anchor"
},
{
"x": 240,
"y": 684,
"type": "common"
},
{
"x": 90,
"y": 654,
"type": "pokey"
},
{
"x": 120,
"y": 654,
"type": "anchor"
},
{
"x": 150,
"y": 654,
"type": "common"
},
{
"x": 180,
"y": 654,
"type": "pokey"
},
{
"x": 210,
"y": 654,
"type": "anchor"
},
{
"x": 240,
"y": 654,
"type": "common"
},
{
"x": 90,
"y": 624,
"type": "pokey"
},
{
"x": 120,
"y": 624,
"type": "anchor"
},
{
"x": 150,
"y": 624,
"type": "common"
},
{
"x": 180,
"y": 624,
"type": "pokey"
},
{
"x": 210,
"y": 624,
"type": "common"
},
{
"x": 240,
"y": 624,
"type": "pokey"
},
{
"x": 90,
"y": 594,
"type": "common"
},
{
"x": 120,
"y": 594,
"type": "pokey"
},
{
"x": 150,
"y": 594,
"type": "common"
},
{
"x": 180,
"y": 594,
"type": "common"
},
{
"x": 210,
"y": 594,
"type": "common"
},
{
"x": 240,
"y": 594,
"type": "common"
},
{
"x": 90,
"y": 564,
"type": "common"
},
{
"x": 120,
"y": 564,
"type": "common"
},
{
"x": 150,
"y": 564,
"type": "common"
},
{
"x": 180,
"y": 564,
"type": "common"
},
{
"x": 210,
"y": 564,
"type": "common"
},
{
"x": 240,
"y": 564,
"type": "common"
},
{
"x": 90,
"y": 534,
"type": "common"
},
{
"x": 120,
"y": 534,
"type": "common"
},
{
"x": 150,
"y": 534,
"type": "common"
},
{
"x": 180,
"y": 534,
"type": "common"
},
{
"x": 210,
"y": 534,
"type": "common"
}
],
"pipe": {
"x": 973,
"y": 640,
"r": 46
},
"waypoints": [
{
"x": 732.5,
"y": 605
}
],
"required": 6,
"ocdTarget": 13
}

View File

@ -0,0 +1,382 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 59,
"name": "Exposure",
"chapter": 4,
"tip": "Triangles carry weight across a gap. Long chains just sag into the spikes.",
"terrain": [
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
0,
700
],
[
638,
700
],
[
638,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
922,
700
],
[
1600,
700
],
[
1600,
1000
],
[
922,
1000
]
]
},
{
"kind": "spike",
"poly": [
[
638,
930
],
[
922,
930
],
[
922,
1000
],
[
638,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
0,
610
],
[
44,
610
],
[
44,
700
],
[
0,
700
]
]
},
{
"kind": "solid",
"poly": [
[
594,
610
],
[
638,
610
],
[
638,
700
],
[
594,
700
]
]
}
],
"balls": [
{
"x": 417,
"y": 686,
"type": "common",
"pinned": true
},
{
"x": 479,
"y": 686,
"type": "common",
"pinned": true
},
{
"x": 448,
"y": 632,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 90,
"y": 684,
"type": "pokey"
},
{
"x": 120,
"y": 684,
"type": "anchor"
},
{
"x": 150,
"y": 684,
"type": "common"
},
{
"x": 180,
"y": 684,
"type": "pokey"
},
{
"x": 210,
"y": 684,
"type": "anchor"
},
{
"x": 240,
"y": 684,
"type": "common"
},
{
"x": 90,
"y": 654,
"type": "pokey"
},
{
"x": 120,
"y": 654,
"type": "anchor"
},
{
"x": 150,
"y": 654,
"type": "common"
},
{
"x": 180,
"y": 654,
"type": "pokey"
},
{
"x": 210,
"y": 654,
"type": "anchor"
},
{
"x": 240,
"y": 654,
"type": "common"
},
{
"x": 90,
"y": 624,
"type": "pokey"
},
{
"x": 120,
"y": 624,
"type": "anchor"
},
{
"x": 150,
"y": 624,
"type": "common"
},
{
"x": 180,
"y": 624,
"type": "pokey"
},
{
"x": 210,
"y": 624,
"type": "common"
},
{
"x": 240,
"y": 624,
"type": "pokey"
},
{
"x": 90,
"y": 594,
"type": "common"
},
{
"x": 120,
"y": 594,
"type": "pokey"
},
{
"x": 150,
"y": 594,
"type": "common"
},
{
"x": 180,
"y": 594,
"type": "common"
},
{
"x": 210,
"y": 594,
"type": "common"
},
{
"x": 240,
"y": 594,
"type": "common"
},
{
"x": 90,
"y": 564,
"type": "common"
},
{
"x": 120,
"y": 564,
"type": "common"
},
{
"x": 150,
"y": 564,
"type": "common"
},
{
"x": 180,
"y": 564,
"type": "common"
},
{
"x": 210,
"y": 564,
"type": "common"
},
{
"x": 240,
"y": 564,
"type": "common"
},
{
"x": 90,
"y": 534,
"type": "common"
},
{
"x": 120,
"y": 534,
"type": "common"
},
{
"x": 150,
"y": 534,
"type": "common"
},
{
"x": 180,
"y": 534,
"type": "common"
},
{
"x": 210,
"y": 534,
"type": "common"
}
],
"pipe": {
"x": 1032,
"y": 640,
"r": 46
},
"waypoints": [
{
"x": 780,
"y": 605
}
],
"required": 7,
"ocdTarget": 14
}

View File

@ -0,0 +1,292 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 60,
"name": "Summit",
"chapter": 4,
"tip": "Brace as you go. An unbraced column leans, and once it leans it keeps leaning.",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
}
],
"balls": [
{
"x": 426,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 488,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 457,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 717,
"y": 834,
"type": "pokey"
},
{
"x": 747,
"y": 834,
"type": "anchor"
},
{
"x": 777,
"y": 834,
"type": "common"
},
{
"x": 807,
"y": 834,
"type": "pokey"
},
{
"x": 837,
"y": 834,
"type": "anchor"
},
{
"x": 867,
"y": 834,
"type": "common"
},
{
"x": 897,
"y": 834,
"type": "pokey"
},
{
"x": 927,
"y": 834,
"type": "anchor"
},
{
"x": 957,
"y": 834,
"type": "common"
},
{
"x": 987,
"y": 834,
"type": "pokey"
},
{
"x": 1017,
"y": 834,
"type": "anchor"
},
{
"x": 1047,
"y": 834,
"type": "common"
},
{
"x": 717,
"y": 804,
"type": "pokey"
},
{
"x": 747,
"y": 804,
"type": "anchor"
},
{
"x": 777,
"y": 804,
"type": "common"
},
{
"x": 807,
"y": 804,
"type": "pokey"
},
{
"x": 837,
"y": 804,
"type": "common"
},
{
"x": 867,
"y": 804,
"type": "pokey"
},
{
"x": 897,
"y": 804,
"type": "common"
},
{
"x": 927,
"y": 804,
"type": "pokey"
},
{
"x": 957,
"y": 804,
"type": "common"
},
{
"x": 987,
"y": 804,
"type": "common"
},
{
"x": 1017,
"y": 804,
"type": "common"
},
{
"x": 1047,
"y": 804,
"type": "common"
},
{
"x": 717,
"y": 774,
"type": "common"
},
{
"x": 747,
"y": 774,
"type": "common"
},
{
"x": 777,
"y": 774,
"type": "common"
},
{
"x": 807,
"y": 774,
"type": "common"
},
{
"x": 837,
"y": 774,
"type": "common"
},
{
"x": 867,
"y": 774,
"type": "common"
},
{
"x": 897,
"y": 774,
"type": "common"
},
{
"x": 927,
"y": 774,
"type": "common"
},
{
"x": 957,
"y": 774,
"type": "common"
},
{
"x": 987,
"y": 774,
"type": "common"
},
{
"x": 1017,
"y": 774,
"type": "common"
}
],
"pipe": {
"x": 457,
"y": 400,
"r": 46
},
"required": 7,
"ocdTarget": 14
}

View File

@ -0,0 +1,338 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 61,
"name": "Descent",
"chapter": 5,
"tip": "The ceiling bites. Stop short of it.",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "spike",
"poly": [
[
212,
282
],
[
1052,
282
],
[
1052,
342
],
[
212,
342
]
]
}
],
"balls": [
{
"x": 601,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 663,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 632,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 912,
"y": 834,
"type": "common"
},
{
"x": 942,
"y": 834,
"type": "skull"
},
{
"x": 972,
"y": 834,
"type": "bit"
},
{
"x": 1002,
"y": 834,
"type": "balloon"
},
{
"x": 1032,
"y": 834,
"type": "block"
},
{
"x": 1062,
"y": 834,
"type": "common"
},
{
"x": 1092,
"y": 834,
"type": "skull"
},
{
"x": 1122,
"y": 834,
"type": "bit"
},
{
"x": 1152,
"y": 834,
"type": "balloon"
},
{
"x": 1182,
"y": 834,
"type": "block"
},
{
"x": 1212,
"y": 834,
"type": "common"
},
{
"x": 1242,
"y": 834,
"type": "skull"
},
{
"x": 1272,
"y": 834,
"type": "bit"
},
{
"x": 912,
"y": 804,
"type": "balloon"
},
{
"x": 942,
"y": 804,
"type": "block"
},
{
"x": 972,
"y": 804,
"type": "common"
},
{
"x": 1002,
"y": 804,
"type": "skull"
},
{
"x": 1032,
"y": 804,
"type": "bit"
},
{
"x": 1062,
"y": 804,
"type": "balloon"
},
{
"x": 1092,
"y": 804,
"type": "block"
},
{
"x": 1122,
"y": 804,
"type": "common"
},
{
"x": 1152,
"y": 804,
"type": "skull"
},
{
"x": 1182,
"y": 804,
"type": "bit"
},
{
"x": 1212,
"y": 804,
"type": "common"
},
{
"x": 1242,
"y": 804,
"type": "skull"
},
{
"x": 1272,
"y": 804,
"type": "bit"
},
{
"x": 912,
"y": 774,
"type": "common"
},
{
"x": 942,
"y": 774,
"type": "common"
},
{
"x": 972,
"y": 774,
"type": "common"
},
{
"x": 1002,
"y": 774,
"type": "common"
},
{
"x": 1032,
"y": 774,
"type": "common"
},
{
"x": 1062,
"y": 774,
"type": "common"
},
{
"x": 1092,
"y": 774,
"type": "common"
},
{
"x": 1122,
"y": 774,
"type": "common"
},
{
"x": 1152,
"y": 774,
"type": "common"
},
{
"x": 1182,
"y": 774,
"type": "common"
},
{
"x": 1212,
"y": 774,
"type": "common"
},
{
"x": 1242,
"y": 774,
"type": "common"
},
{
"x": 1272,
"y": 774,
"type": "common"
},
{
"x": 912,
"y": 744,
"type": "common"
}
],
"pipe": {
"x": 632,
"y": 447,
"r": 46
},
"required": 6,
"ocdTarget": 13
}

View File

@ -0,0 +1,338 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 62,
"name": "Low Roof",
"chapter": 5,
"tip": "The ceiling bites. Stop short of it.",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "spike",
"poly": [
[
251,
261
],
[
1091,
261
],
[
1091,
321
],
[
251,
321
]
]
}
],
"balls": [
{
"x": 640,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 702,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 671,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 951,
"y": 834,
"type": "common"
},
{
"x": 981,
"y": 834,
"type": "skull"
},
{
"x": 1011,
"y": 834,
"type": "bit"
},
{
"x": 1041,
"y": 834,
"type": "balloon"
},
{
"x": 1071,
"y": 834,
"type": "block"
},
{
"x": 1101,
"y": 834,
"type": "common"
},
{
"x": 1131,
"y": 834,
"type": "skull"
},
{
"x": 1161,
"y": 834,
"type": "bit"
},
{
"x": 1191,
"y": 834,
"type": "balloon"
},
{
"x": 1221,
"y": 834,
"type": "block"
},
{
"x": 1251,
"y": 834,
"type": "common"
},
{
"x": 1281,
"y": 834,
"type": "skull"
},
{
"x": 1311,
"y": 834,
"type": "bit"
},
{
"x": 951,
"y": 804,
"type": "balloon"
},
{
"x": 981,
"y": 804,
"type": "block"
},
{
"x": 1011,
"y": 804,
"type": "common"
},
{
"x": 1041,
"y": 804,
"type": "skull"
},
{
"x": 1071,
"y": 804,
"type": "bit"
},
{
"x": 1101,
"y": 804,
"type": "balloon"
},
{
"x": 1131,
"y": 804,
"type": "block"
},
{
"x": 1161,
"y": 804,
"type": "common"
},
{
"x": 1191,
"y": 804,
"type": "skull"
},
{
"x": 1221,
"y": 804,
"type": "bit"
},
{
"x": 1251,
"y": 804,
"type": "common"
},
{
"x": 1281,
"y": 804,
"type": "skull"
},
{
"x": 1311,
"y": 804,
"type": "bit"
},
{
"x": 951,
"y": 774,
"type": "common"
},
{
"x": 981,
"y": 774,
"type": "common"
},
{
"x": 1011,
"y": 774,
"type": "common"
},
{
"x": 1041,
"y": 774,
"type": "common"
},
{
"x": 1071,
"y": 774,
"type": "common"
},
{
"x": 1101,
"y": 774,
"type": "common"
},
{
"x": 1131,
"y": 774,
"type": "common"
},
{
"x": 1161,
"y": 774,
"type": "common"
},
{
"x": 1191,
"y": 774,
"type": "common"
},
{
"x": 1221,
"y": 774,
"type": "common"
},
{
"x": 1251,
"y": 774,
"type": "common"
},
{
"x": 1281,
"y": 774,
"type": "common"
},
{
"x": 1311,
"y": 774,
"type": "common"
},
{
"x": 951,
"y": 744,
"type": "common"
}
],
"pipe": {
"x": 671,
"y": 426,
"r": 46
},
"required": 7,
"ocdTarget": 15
}

View File

@ -0,0 +1,338 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 63,
"name": "The Squeeze",
"chapter": 5,
"tip": "The ceiling bites. Stop short of it.",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "spike",
"poly": [
[
297,
255
],
[
1137,
255
],
[
1137,
315
],
[
297,
315
]
]
}
],
"balls": [
{
"x": 686,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 748,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 717,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 997,
"y": 834,
"type": "common"
},
{
"x": 1027,
"y": 834,
"type": "skull"
},
{
"x": 1057,
"y": 834,
"type": "bit"
},
{
"x": 1087,
"y": 834,
"type": "balloon"
},
{
"x": 1117,
"y": 834,
"type": "block"
},
{
"x": 1147,
"y": 834,
"type": "common"
},
{
"x": 1177,
"y": 834,
"type": "skull"
},
{
"x": 1207,
"y": 834,
"type": "bit"
},
{
"x": 1237,
"y": 834,
"type": "balloon"
},
{
"x": 1267,
"y": 834,
"type": "block"
},
{
"x": 1297,
"y": 834,
"type": "common"
},
{
"x": 1327,
"y": 834,
"type": "skull"
},
{
"x": 1357,
"y": 834,
"type": "bit"
},
{
"x": 997,
"y": 804,
"type": "balloon"
},
{
"x": 1027,
"y": 804,
"type": "block"
},
{
"x": 1057,
"y": 804,
"type": "common"
},
{
"x": 1087,
"y": 804,
"type": "skull"
},
{
"x": 1117,
"y": 804,
"type": "bit"
},
{
"x": 1147,
"y": 804,
"type": "balloon"
},
{
"x": 1177,
"y": 804,
"type": "block"
},
{
"x": 1207,
"y": 804,
"type": "common"
},
{
"x": 1237,
"y": 804,
"type": "skull"
},
{
"x": 1267,
"y": 804,
"type": "bit"
},
{
"x": 1297,
"y": 804,
"type": "common"
},
{
"x": 1327,
"y": 804,
"type": "skull"
},
{
"x": 1357,
"y": 804,
"type": "bit"
},
{
"x": 997,
"y": 774,
"type": "common"
},
{
"x": 1027,
"y": 774,
"type": "common"
},
{
"x": 1057,
"y": 774,
"type": "common"
},
{
"x": 1087,
"y": 774,
"type": "common"
},
{
"x": 1117,
"y": 774,
"type": "common"
},
{
"x": 1147,
"y": 774,
"type": "common"
},
{
"x": 1177,
"y": 774,
"type": "common"
},
{
"x": 1207,
"y": 774,
"type": "common"
},
{
"x": 1237,
"y": 774,
"type": "common"
},
{
"x": 1267,
"y": 774,
"type": "common"
},
{
"x": 1297,
"y": 774,
"type": "common"
},
{
"x": 1327,
"y": 774,
"type": "common"
},
{
"x": 1357,
"y": 774,
"type": "common"
},
{
"x": 997,
"y": 744,
"type": "common"
}
],
"pipe": {
"x": 717,
"y": 420,
"r": 46
},
"required": 7,
"ocdTarget": 15
}

View File

@ -0,0 +1,419 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 64,
"name": "Deep Wind",
"chapter": 5,
"tip": "The updraft takes weight off everything inside it. Spans reach further in the wind.",
"element": "fan",
"terrain": [
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
0,
700
],
[
560,
700
],
[
560,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
985,
700
],
[
1600,
700
],
[
1600,
1000
],
[
985,
1000
]
]
},
{
"kind": "spike",
"poly": [
[
560,
930
],
[
985,
930
],
[
985,
1000
],
[
560,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
0,
610
],
[
44,
610
],
[
44,
700
],
[
0,
700
]
]
},
{
"kind": "solid",
"poly": [
[
516,
610
],
[
560,
610
],
[
560,
700
],
[
516,
700
]
]
}
],
"balls": [
{
"x": 339,
"y": 686,
"type": "common",
"pinned": true
},
{
"x": 401,
"y": 686,
"type": "common",
"pinned": true
},
{
"x": 370,
"y": 632,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 90,
"y": 684,
"type": "common"
},
{
"x": 120,
"y": 684,
"type": "skull"
},
{
"x": 150,
"y": 684,
"type": "bit"
},
{
"x": 180,
"y": 684,
"type": "balloon"
},
{
"x": 210,
"y": 684,
"type": "block"
},
{
"x": 240,
"y": 684,
"type": "common"
},
{
"x": 90,
"y": 654,
"type": "skull"
},
{
"x": 120,
"y": 654,
"type": "bit"
},
{
"x": 150,
"y": 654,
"type": "balloon"
},
{
"x": 180,
"y": 654,
"type": "block"
},
{
"x": 210,
"y": 654,
"type": "common"
},
{
"x": 240,
"y": 654,
"type": "skull"
},
{
"x": 90,
"y": 624,
"type": "bit"
},
{
"x": 120,
"y": 624,
"type": "balloon"
},
{
"x": 150,
"y": 624,
"type": "block"
},
{
"x": 180,
"y": 624,
"type": "common"
},
{
"x": 210,
"y": 624,
"type": "skull"
},
{
"x": 240,
"y": 624,
"type": "bit"
},
{
"x": 90,
"y": 594,
"type": "balloon"
},
{
"x": 120,
"y": 594,
"type": "block"
},
{
"x": 150,
"y": 594,
"type": "common"
},
{
"x": 180,
"y": 594,
"type": "skull"
},
{
"x": 210,
"y": 594,
"type": "bit"
},
{
"x": 240,
"y": 594,
"type": "common"
},
{
"x": 90,
"y": 564,
"type": "skull"
},
{
"x": 120,
"y": 564,
"type": "bit"
},
{
"x": 150,
"y": 564,
"type": "common"
},
{
"x": 180,
"y": 564,
"type": "common"
},
{
"x": 210,
"y": 564,
"type": "common"
},
{
"x": 240,
"y": 564,
"type": "common"
},
{
"x": 90,
"y": 534,
"type": "common"
},
{
"x": 120,
"y": 534,
"type": "common"
},
{
"x": 150,
"y": 534,
"type": "common"
},
{
"x": 180,
"y": 534,
"type": "common"
},
{
"x": 210,
"y": 534,
"type": "common"
},
{
"x": 240,
"y": 534,
"type": "common"
},
{
"x": 90,
"y": 504,
"type": "common"
},
{
"x": 120,
"y": 504,
"type": "common"
},
{
"x": 150,
"y": 504,
"type": "common"
},
{
"x": 180,
"y": 504,
"type": "common"
}
],
"pipe": {
"x": 1095,
"y": 640,
"r": 46
},
"fans": [
{
"x": 560,
"y": 260,
"w": 425,
"h": 660,
"dx": 0,
"dy": -1,
"force": 1327
}
],
"waypoints": [
{
"x": 772.5,
"y": 580
}
],
"required": 6,
"ocdTarget": 13
}

View File

@ -0,0 +1,419 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 65,
"name": "The Shaft",
"chapter": 5,
"tip": "The updraft takes weight off everything inside it. Spans reach further in the wind.",
"element": "fan",
"terrain": [
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
0,
700
],
[
560,
700
],
[
560,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1006,
700
],
[
1600,
700
],
[
1600,
1000
],
[
1006,
1000
]
]
},
{
"kind": "spike",
"poly": [
[
560,
930
],
[
1006,
930
],
[
1006,
1000
],
[
560,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
0,
610
],
[
44,
610
],
[
44,
700
],
[
0,
700
]
]
},
{
"kind": "solid",
"poly": [
[
516,
610
],
[
560,
610
],
[
560,
700
],
[
516,
700
]
]
}
],
"balls": [
{
"x": 339,
"y": 686,
"type": "common",
"pinned": true
},
{
"x": 401,
"y": 686,
"type": "common",
"pinned": true
},
{
"x": 370,
"y": 632,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 90,
"y": 684,
"type": "common"
},
{
"x": 120,
"y": 684,
"type": "skull"
},
{
"x": 150,
"y": 684,
"type": "bit"
},
{
"x": 180,
"y": 684,
"type": "balloon"
},
{
"x": 210,
"y": 684,
"type": "block"
},
{
"x": 240,
"y": 684,
"type": "common"
},
{
"x": 90,
"y": 654,
"type": "skull"
},
{
"x": 120,
"y": 654,
"type": "bit"
},
{
"x": 150,
"y": 654,
"type": "balloon"
},
{
"x": 180,
"y": 654,
"type": "block"
},
{
"x": 210,
"y": 654,
"type": "common"
},
{
"x": 240,
"y": 654,
"type": "skull"
},
{
"x": 90,
"y": 624,
"type": "bit"
},
{
"x": 120,
"y": 624,
"type": "balloon"
},
{
"x": 150,
"y": 624,
"type": "block"
},
{
"x": 180,
"y": 624,
"type": "common"
},
{
"x": 210,
"y": 624,
"type": "skull"
},
{
"x": 240,
"y": 624,
"type": "bit"
},
{
"x": 90,
"y": 594,
"type": "balloon"
},
{
"x": 120,
"y": 594,
"type": "block"
},
{
"x": 150,
"y": 594,
"type": "common"
},
{
"x": 180,
"y": 594,
"type": "skull"
},
{
"x": 210,
"y": 594,
"type": "bit"
},
{
"x": 240,
"y": 594,
"type": "common"
},
{
"x": 90,
"y": 564,
"type": "skull"
},
{
"x": 120,
"y": 564,
"type": "bit"
},
{
"x": 150,
"y": 564,
"type": "common"
},
{
"x": 180,
"y": 564,
"type": "common"
},
{
"x": 210,
"y": 564,
"type": "common"
},
{
"x": 240,
"y": 564,
"type": "common"
},
{
"x": 90,
"y": 534,
"type": "common"
},
{
"x": 120,
"y": 534,
"type": "common"
},
{
"x": 150,
"y": 534,
"type": "common"
},
{
"x": 180,
"y": 534,
"type": "common"
},
{
"x": 210,
"y": 534,
"type": "common"
},
{
"x": 240,
"y": 534,
"type": "common"
},
{
"x": 90,
"y": 504,
"type": "common"
},
{
"x": 120,
"y": 504,
"type": "common"
},
{
"x": 150,
"y": 504,
"type": "common"
},
{
"x": 180,
"y": 504,
"type": "common"
}
],
"pipe": {
"x": 1116,
"y": 640,
"r": 46
},
"fans": [
{
"x": 560,
"y": 260,
"w": 446,
"h": 660,
"dx": 0,
"dy": -1,
"force": 1310
}
],
"waypoints": [
{
"x": 783,
"y": 580
}
],
"required": 7,
"ocdTarget": 15
}

View File

@ -0,0 +1,419 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 66,
"name": "Downdraft",
"chapter": 5,
"tip": "The updraft takes weight off everything inside it. Spans reach further in the wind.",
"element": "fan",
"terrain": [
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
0,
700
],
[
560,
700
],
[
560,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1023,
700
],
[
1600,
700
],
[
1600,
1000
],
[
1023,
1000
]
]
},
{
"kind": "spike",
"poly": [
[
560,
930
],
[
1023,
930
],
[
1023,
1000
],
[
560,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
0,
610
],
[
44,
610
],
[
44,
700
],
[
0,
700
]
]
},
{
"kind": "solid",
"poly": [
[
516,
610
],
[
560,
610
],
[
560,
700
],
[
516,
700
]
]
}
],
"balls": [
{
"x": 339,
"y": 686,
"type": "common",
"pinned": true
},
{
"x": 401,
"y": 686,
"type": "common",
"pinned": true
},
{
"x": 370,
"y": 632,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 90,
"y": 684,
"type": "common"
},
{
"x": 120,
"y": 684,
"type": "skull"
},
{
"x": 150,
"y": 684,
"type": "bit"
},
{
"x": 180,
"y": 684,
"type": "balloon"
},
{
"x": 210,
"y": 684,
"type": "block"
},
{
"x": 240,
"y": 684,
"type": "common"
},
{
"x": 90,
"y": 654,
"type": "skull"
},
{
"x": 120,
"y": 654,
"type": "bit"
},
{
"x": 150,
"y": 654,
"type": "balloon"
},
{
"x": 180,
"y": 654,
"type": "block"
},
{
"x": 210,
"y": 654,
"type": "common"
},
{
"x": 240,
"y": 654,
"type": "skull"
},
{
"x": 90,
"y": 624,
"type": "bit"
},
{
"x": 120,
"y": 624,
"type": "balloon"
},
{
"x": 150,
"y": 624,
"type": "block"
},
{
"x": 180,
"y": 624,
"type": "common"
},
{
"x": 210,
"y": 624,
"type": "skull"
},
{
"x": 240,
"y": 624,
"type": "bit"
},
{
"x": 90,
"y": 594,
"type": "balloon"
},
{
"x": 120,
"y": 594,
"type": "block"
},
{
"x": 150,
"y": 594,
"type": "common"
},
{
"x": 180,
"y": 594,
"type": "skull"
},
{
"x": 210,
"y": 594,
"type": "bit"
},
{
"x": 240,
"y": 594,
"type": "common"
},
{
"x": 90,
"y": 564,
"type": "skull"
},
{
"x": 120,
"y": 564,
"type": "bit"
},
{
"x": 150,
"y": 564,
"type": "common"
},
{
"x": 180,
"y": 564,
"type": "common"
},
{
"x": 210,
"y": 564,
"type": "common"
},
{
"x": 240,
"y": 564,
"type": "common"
},
{
"x": 90,
"y": 534,
"type": "common"
},
{
"x": 120,
"y": 534,
"type": "common"
},
{
"x": 150,
"y": 534,
"type": "common"
},
{
"x": 180,
"y": 534,
"type": "common"
},
{
"x": 210,
"y": 534,
"type": "common"
},
{
"x": 240,
"y": 534,
"type": "common"
},
{
"x": 90,
"y": 504,
"type": "common"
},
{
"x": 120,
"y": 504,
"type": "common"
},
{
"x": 150,
"y": 504,
"type": "common"
},
{
"x": 180,
"y": 504,
"type": "common"
}
],
"pipe": {
"x": 1133,
"y": 640,
"r": 46
},
"fans": [
{
"x": 560,
"y": 260,
"w": 463,
"h": 660,
"dx": 0,
"dy": -1,
"force": 1296
}
],
"waypoints": [
{
"x": 791.5,
"y": 580
}
],
"required": 8,
"ocdTarget": 17
}

View File

@ -0,0 +1,327 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 67,
"name": "Deep Cogs",
"chapter": 5,
"tip": "The cog is solid and it is turning. Whatever it touches gets dragged along.",
"element": "gear",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
}
],
"balls": [
{
"x": 298,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 360,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 329,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 1000,
"y": 834,
"type": "common"
},
{
"x": 1030,
"y": 834,
"type": "skull"
},
{
"x": 1060,
"y": 834,
"type": "bit"
},
{
"x": 1090,
"y": 834,
"type": "balloon"
},
{
"x": 1120,
"y": 834,
"type": "block"
},
{
"x": 1150,
"y": 834,
"type": "common"
},
{
"x": 1180,
"y": 834,
"type": "skull"
},
{
"x": 1210,
"y": 834,
"type": "bit"
},
{
"x": 1240,
"y": 834,
"type": "balloon"
},
{
"x": 1000,
"y": 804,
"type": "block"
},
{
"x": 1030,
"y": 804,
"type": "common"
},
{
"x": 1060,
"y": 804,
"type": "skull"
},
{
"x": 1090,
"y": 804,
"type": "bit"
},
{
"x": 1120,
"y": 804,
"type": "balloon"
},
{
"x": 1150,
"y": 804,
"type": "block"
},
{
"x": 1180,
"y": 804,
"type": "common"
},
{
"x": 1210,
"y": 804,
"type": "skull"
},
{
"x": 1240,
"y": 804,
"type": "bit"
},
{
"x": 1000,
"y": 774,
"type": "balloon"
},
{
"x": 1030,
"y": 774,
"type": "block"
},
{
"x": 1060,
"y": 774,
"type": "common"
},
{
"x": 1090,
"y": 774,
"type": "skull"
},
{
"x": 1120,
"y": 774,
"type": "bit"
},
{
"x": 1150,
"y": 774,
"type": "common"
},
{
"x": 1180,
"y": 774,
"type": "skull"
},
{
"x": 1210,
"y": 774,
"type": "bit"
},
{
"x": 1240,
"y": 774,
"type": "common"
},
{
"x": 1000,
"y": 744,
"type": "common"
},
{
"x": 1030,
"y": 744,
"type": "common"
},
{
"x": 1060,
"y": 744,
"type": "common"
},
{
"x": 1090,
"y": 744,
"type": "common"
},
{
"x": 1120,
"y": 744,
"type": "common"
},
{
"x": 1150,
"y": 744,
"type": "common"
},
{
"x": 1180,
"y": 744,
"type": "common"
},
{
"x": 1210,
"y": 744,
"type": "common"
},
{
"x": 1240,
"y": 744,
"type": "common"
},
{
"x": 1000,
"y": 714,
"type": "common"
},
{
"x": 1030,
"y": 714,
"type": "common"
},
{
"x": 1060,
"y": 714,
"type": "common"
},
{
"x": 1090,
"y": 714,
"type": "common"
}
],
"pipe": {
"x": 1241,
"y": 577,
"r": 46
},
"gears": [
{
"x": 726,
"y": 477,
"r": 114,
"teeth": 9,
"omega": -1.657384972431697
}
],
"required": 6,
"ocdTarget": 13
}

View File

@ -0,0 +1,327 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 68,
"name": "The Grinder",
"chapter": 5,
"tip": "The cog is solid and it is turning. Whatever it touches gets dragged along.",
"element": "gear",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
}
],
"balls": [
{
"x": 315,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 377,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 346,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 1000,
"y": 834,
"type": "common"
},
{
"x": 1030,
"y": 834,
"type": "skull"
},
{
"x": 1060,
"y": 834,
"type": "bit"
},
{
"x": 1090,
"y": 834,
"type": "balloon"
},
{
"x": 1120,
"y": 834,
"type": "block"
},
{
"x": 1150,
"y": 834,
"type": "common"
},
{
"x": 1180,
"y": 834,
"type": "skull"
},
{
"x": 1210,
"y": 834,
"type": "bit"
},
{
"x": 1240,
"y": 834,
"type": "balloon"
},
{
"x": 1000,
"y": 804,
"type": "block"
},
{
"x": 1030,
"y": 804,
"type": "common"
},
{
"x": 1060,
"y": 804,
"type": "skull"
},
{
"x": 1090,
"y": 804,
"type": "bit"
},
{
"x": 1120,
"y": 804,
"type": "balloon"
},
{
"x": 1150,
"y": 804,
"type": "block"
},
{
"x": 1180,
"y": 804,
"type": "common"
},
{
"x": 1210,
"y": 804,
"type": "skull"
},
{
"x": 1240,
"y": 804,
"type": "bit"
},
{
"x": 1000,
"y": 774,
"type": "balloon"
},
{
"x": 1030,
"y": 774,
"type": "block"
},
{
"x": 1060,
"y": 774,
"type": "common"
},
{
"x": 1090,
"y": 774,
"type": "skull"
},
{
"x": 1120,
"y": 774,
"type": "bit"
},
{
"x": 1150,
"y": 774,
"type": "common"
},
{
"x": 1180,
"y": 774,
"type": "skull"
},
{
"x": 1210,
"y": 774,
"type": "bit"
},
{
"x": 1240,
"y": 774,
"type": "common"
},
{
"x": 1000,
"y": 744,
"type": "common"
},
{
"x": 1030,
"y": 744,
"type": "common"
},
{
"x": 1060,
"y": 744,
"type": "common"
},
{
"x": 1090,
"y": 744,
"type": "common"
},
{
"x": 1120,
"y": 744,
"type": "common"
},
{
"x": 1150,
"y": 744,
"type": "common"
},
{
"x": 1180,
"y": 744,
"type": "common"
},
{
"x": 1210,
"y": 744,
"type": "common"
},
{
"x": 1240,
"y": 744,
"type": "common"
},
{
"x": 1000,
"y": 714,
"type": "common"
},
{
"x": 1030,
"y": 714,
"type": "common"
},
{
"x": 1060,
"y": 714,
"type": "common"
},
{
"x": 1090,
"y": 714,
"type": "common"
}
],
"pipe": {
"x": 1260,
"y": 566,
"r": 46
},
"gears": [
{
"x": 809,
"y": 466,
"r": 118,
"teeth": 9,
"omega": 1.7896977431932464
}
],
"required": 7,
"ocdTarget": 15
}

View File

@ -0,0 +1,327 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 69,
"name": "Millstone",
"chapter": 5,
"tip": "The cog is solid and it is turning. Whatever it touches gets dragged along.",
"element": "gear",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
}
],
"balls": [
{
"x": 312,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 374,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 343,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 1000,
"y": 834,
"type": "common"
},
{
"x": 1030,
"y": 834,
"type": "skull"
},
{
"x": 1060,
"y": 834,
"type": "bit"
},
{
"x": 1090,
"y": 834,
"type": "balloon"
},
{
"x": 1120,
"y": 834,
"type": "block"
},
{
"x": 1150,
"y": 834,
"type": "common"
},
{
"x": 1180,
"y": 834,
"type": "skull"
},
{
"x": 1210,
"y": 834,
"type": "bit"
},
{
"x": 1240,
"y": 834,
"type": "balloon"
},
{
"x": 1000,
"y": 804,
"type": "block"
},
{
"x": 1030,
"y": 804,
"type": "common"
},
{
"x": 1060,
"y": 804,
"type": "skull"
},
{
"x": 1090,
"y": 804,
"type": "bit"
},
{
"x": 1120,
"y": 804,
"type": "balloon"
},
{
"x": 1150,
"y": 804,
"type": "block"
},
{
"x": 1180,
"y": 804,
"type": "common"
},
{
"x": 1210,
"y": 804,
"type": "skull"
},
{
"x": 1240,
"y": 804,
"type": "bit"
},
{
"x": 1000,
"y": 774,
"type": "balloon"
},
{
"x": 1030,
"y": 774,
"type": "block"
},
{
"x": 1060,
"y": 774,
"type": "common"
},
{
"x": 1090,
"y": 774,
"type": "skull"
},
{
"x": 1120,
"y": 774,
"type": "bit"
},
{
"x": 1150,
"y": 774,
"type": "common"
},
{
"x": 1180,
"y": 774,
"type": "skull"
},
{
"x": 1210,
"y": 774,
"type": "bit"
},
{
"x": 1240,
"y": 774,
"type": "common"
},
{
"x": 1000,
"y": 744,
"type": "common"
},
{
"x": 1030,
"y": 744,
"type": "common"
},
{
"x": 1060,
"y": 744,
"type": "common"
},
{
"x": 1090,
"y": 744,
"type": "common"
},
{
"x": 1120,
"y": 744,
"type": "common"
},
{
"x": 1150,
"y": 744,
"type": "common"
},
{
"x": 1180,
"y": 744,
"type": "common"
},
{
"x": 1210,
"y": 744,
"type": "common"
},
{
"x": 1240,
"y": 744,
"type": "common"
},
{
"x": 1000,
"y": 714,
"type": "common"
},
{
"x": 1030,
"y": 714,
"type": "common"
},
{
"x": 1060,
"y": 714,
"type": "common"
},
{
"x": 1090,
"y": 714,
"type": "common"
}
],
"pipe": {
"x": 1290,
"y": 550,
"r": 46
},
"gears": [
{
"x": 811,
"y": 450,
"r": 125,
"teeth": 9,
"omega": -2
}
],
"required": 8,
"ocdTarget": 17
}

View File

@ -0,0 +1,367 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 70,
"name": "Deep Rock",
"chapter": 5,
"tip": "Drop a bomb by the fire and the soft rock goes with it. Or take the long way over.",
"element": "bomb",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
681,
662
],
[
761,
662
],
[
761,
850
],
[
681,
850
]
],
"destructible": true
},
{
"kind": "fire",
"poly": [
[
571,
806
],
[
651,
806
],
[
651,
850
],
[
571,
850
]
]
}
],
"balls": [
{
"x": 355,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 417,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 386,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 96,
"y": 834,
"type": "common"
},
{
"x": 126,
"y": 834,
"type": "skull"
},
{
"x": 156,
"y": 834,
"type": "bit"
},
{
"x": 186,
"y": 834,
"type": "balloon"
},
{
"x": 216,
"y": 834,
"type": "block"
},
{
"x": 246,
"y": 834,
"type": "common"
},
{
"x": 276,
"y": 834,
"type": "skull"
},
{
"x": 96,
"y": 804,
"type": "bit"
},
{
"x": 126,
"y": 804,
"type": "balloon"
},
{
"x": 156,
"y": 804,
"type": "block"
},
{
"x": 186,
"y": 804,
"type": "common"
},
{
"x": 216,
"y": 804,
"type": "skull"
},
{
"x": 246,
"y": 804,
"type": "bit"
},
{
"x": 276,
"y": 804,
"type": "balloon"
},
{
"x": 96,
"y": 774,
"type": "block"
},
{
"x": 126,
"y": 774,
"type": "common"
},
{
"x": 156,
"y": 774,
"type": "skull"
},
{
"x": 186,
"y": 774,
"type": "bit"
},
{
"x": 216,
"y": 774,
"type": "balloon"
},
{
"x": 246,
"y": 774,
"type": "block"
},
{
"x": 276,
"y": 774,
"type": "common"
},
{
"x": 96,
"y": 744,
"type": "skull"
},
{
"x": 126,
"y": 744,
"type": "bit"
},
{
"x": 156,
"y": 744,
"type": "common"
},
{
"x": 186,
"y": 744,
"type": "skull"
},
{
"x": 216,
"y": 744,
"type": "bit"
},
{
"x": 246,
"y": 744,
"type": "common"
},
{
"x": 276,
"y": 744,
"type": "common"
},
{
"x": 96,
"y": 714,
"type": "common"
},
{
"x": 126,
"y": 714,
"type": "common"
},
{
"x": 156,
"y": 714,
"type": "common"
},
{
"x": 186,
"y": 714,
"type": "common"
},
{
"x": 216,
"y": 714,
"type": "common"
},
{
"x": 246,
"y": 714,
"type": "common"
},
{
"x": 276,
"y": 714,
"type": "common"
},
{
"x": 96,
"y": 684,
"type": "common"
},
{
"x": 126,
"y": 684,
"type": "common"
},
{
"x": 156,
"y": 684,
"type": "common"
},
{
"x": 186,
"y": 684,
"type": "common"
},
{
"x": 216,
"y": 684,
"type": "common"
}
],
"pipe": {
"x": 1069,
"y": 700,
"r": 46
},
"waypoints": [
{
"x": 721,
"y": 587
}
],
"required": 7,
"ocdTarget": 14
}

View File

@ -0,0 +1,367 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 71,
"name": "Cave-In",
"chapter": 5,
"tip": "Drop a bomb by the fire and the soft rock goes with it. Or take the long way over.",
"element": "bomb",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
692,
652
],
[
772,
652
],
[
772,
850
],
[
692,
850
]
],
"destructible": true
},
{
"kind": "fire",
"poly": [
[
582,
806
],
[
662,
806
],
[
662,
850
],
[
582,
850
]
]
}
],
"balls": [
{
"x": 409,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 471,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 440,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 120,
"y": 834,
"type": "common"
},
{
"x": 150,
"y": 834,
"type": "skull"
},
{
"x": 180,
"y": 834,
"type": "bit"
},
{
"x": 210,
"y": 834,
"type": "balloon"
},
{
"x": 240,
"y": 834,
"type": "block"
},
{
"x": 270,
"y": 834,
"type": "common"
},
{
"x": 300,
"y": 834,
"type": "skull"
},
{
"x": 120,
"y": 804,
"type": "bit"
},
{
"x": 150,
"y": 804,
"type": "balloon"
},
{
"x": 180,
"y": 804,
"type": "block"
},
{
"x": 210,
"y": 804,
"type": "common"
},
{
"x": 240,
"y": 804,
"type": "skull"
},
{
"x": 270,
"y": 804,
"type": "bit"
},
{
"x": 300,
"y": 804,
"type": "balloon"
},
{
"x": 120,
"y": 774,
"type": "block"
},
{
"x": 150,
"y": 774,
"type": "common"
},
{
"x": 180,
"y": 774,
"type": "skull"
},
{
"x": 210,
"y": 774,
"type": "bit"
},
{
"x": 240,
"y": 774,
"type": "balloon"
},
{
"x": 270,
"y": 774,
"type": "block"
},
{
"x": 300,
"y": 774,
"type": "common"
},
{
"x": 120,
"y": 744,
"type": "skull"
},
{
"x": 150,
"y": 744,
"type": "bit"
},
{
"x": 180,
"y": 744,
"type": "common"
},
{
"x": 210,
"y": 744,
"type": "skull"
},
{
"x": 240,
"y": 744,
"type": "bit"
},
{
"x": 270,
"y": 744,
"type": "common"
},
{
"x": 300,
"y": 744,
"type": "common"
},
{
"x": 120,
"y": 714,
"type": "common"
},
{
"x": 150,
"y": 714,
"type": "common"
},
{
"x": 180,
"y": 714,
"type": "common"
},
{
"x": 210,
"y": 714,
"type": "common"
},
{
"x": 240,
"y": 714,
"type": "common"
},
{
"x": 270,
"y": 714,
"type": "common"
},
{
"x": 300,
"y": 714,
"type": "common"
},
{
"x": 120,
"y": 684,
"type": "common"
},
{
"x": 150,
"y": 684,
"type": "common"
},
{
"x": 180,
"y": 684,
"type": "common"
},
{
"x": 210,
"y": 684,
"type": "common"
},
{
"x": 240,
"y": 684,
"type": "common"
}
],
"pipe": {
"x": 1092,
"y": 700,
"r": 46
},
"waypoints": [
{
"x": 732,
"y": 577
}
],
"required": 7,
"ocdTarget": 15
}

View File

@ -0,0 +1,367 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 72,
"name": "The Last Charge",
"chapter": 5,
"tip": "Drop a bomb by the fire and the soft rock goes with it. Or take the long way over.",
"element": "bomb",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
751,
643
],
[
831,
643
],
[
831,
850
],
[
751,
850
]
],
"destructible": true
},
{
"kind": "fire",
"poly": [
[
641,
806
],
[
721,
806
],
[
721,
850
],
[
641,
850
]
]
}
],
"balls": [
{
"x": 359,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 421,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 390,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 100,
"y": 834,
"type": "common"
},
{
"x": 130,
"y": 834,
"type": "skull"
},
{
"x": 160,
"y": 834,
"type": "bit"
},
{
"x": 190,
"y": 834,
"type": "balloon"
},
{
"x": 220,
"y": 834,
"type": "block"
},
{
"x": 250,
"y": 834,
"type": "common"
},
{
"x": 280,
"y": 834,
"type": "skull"
},
{
"x": 100,
"y": 804,
"type": "bit"
},
{
"x": 130,
"y": 804,
"type": "balloon"
},
{
"x": 160,
"y": 804,
"type": "block"
},
{
"x": 190,
"y": 804,
"type": "common"
},
{
"x": 220,
"y": 804,
"type": "skull"
},
{
"x": 250,
"y": 804,
"type": "bit"
},
{
"x": 280,
"y": 804,
"type": "balloon"
},
{
"x": 100,
"y": 774,
"type": "block"
},
{
"x": 130,
"y": 774,
"type": "common"
},
{
"x": 160,
"y": 774,
"type": "skull"
},
{
"x": 190,
"y": 774,
"type": "bit"
},
{
"x": 220,
"y": 774,
"type": "balloon"
},
{
"x": 250,
"y": 774,
"type": "block"
},
{
"x": 280,
"y": 774,
"type": "common"
},
{
"x": 100,
"y": 744,
"type": "skull"
},
{
"x": 130,
"y": 744,
"type": "bit"
},
{
"x": 160,
"y": 744,
"type": "common"
},
{
"x": 190,
"y": 744,
"type": "skull"
},
{
"x": 220,
"y": 744,
"type": "bit"
},
{
"x": 250,
"y": 744,
"type": "common"
},
{
"x": 280,
"y": 744,
"type": "common"
},
{
"x": 100,
"y": 714,
"type": "common"
},
{
"x": 130,
"y": 714,
"type": "common"
},
{
"x": 160,
"y": 714,
"type": "common"
},
{
"x": 190,
"y": 714,
"type": "common"
},
{
"x": 220,
"y": 714,
"type": "common"
},
{
"x": 250,
"y": 714,
"type": "common"
},
{
"x": 280,
"y": 714,
"type": "common"
},
{
"x": 100,
"y": 684,
"type": "common"
},
{
"x": 130,
"y": 684,
"type": "common"
},
{
"x": 160,
"y": 684,
"type": "common"
},
{
"x": 190,
"y": 684,
"type": "common"
},
{
"x": 220,
"y": 684,
"type": "common"
}
],
"pipe": {
"x": 1114,
"y": 700,
"r": 46
},
"waypoints": [
{
"x": 791,
"y": 568
}
],
"required": 8,
"ocdTarget": 17
}

View File

@ -0,0 +1,317 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 73,
"name": "The Long Way Up",
"chapter": 5,
"tip": "Brace as you go. An unbraced column leans, and once it leans it keeps leaning.",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
}
],
"balls": [
{
"x": 615,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 677,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 646,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 906,
"y": 834,
"type": "common"
},
{
"x": 936,
"y": 834,
"type": "skull"
},
{
"x": 966,
"y": 834,
"type": "bit"
},
{
"x": 996,
"y": 834,
"type": "balloon"
},
{
"x": 1026,
"y": 834,
"type": "block"
},
{
"x": 1056,
"y": 834,
"type": "common"
},
{
"x": 1086,
"y": 834,
"type": "skull"
},
{
"x": 1116,
"y": 834,
"type": "bit"
},
{
"x": 1146,
"y": 834,
"type": "balloon"
},
{
"x": 1176,
"y": 834,
"type": "block"
},
{
"x": 1206,
"y": 834,
"type": "common"
},
{
"x": 1236,
"y": 834,
"type": "skull"
},
{
"x": 1266,
"y": 834,
"type": "bit"
},
{
"x": 906,
"y": 804,
"type": "balloon"
},
{
"x": 936,
"y": 804,
"type": "block"
},
{
"x": 966,
"y": 804,
"type": "common"
},
{
"x": 996,
"y": 804,
"type": "skull"
},
{
"x": 1026,
"y": 804,
"type": "bit"
},
{
"x": 1056,
"y": 804,
"type": "balloon"
},
{
"x": 1086,
"y": 804,
"type": "block"
},
{
"x": 1116,
"y": 804,
"type": "common"
},
{
"x": 1146,
"y": 804,
"type": "skull"
},
{
"x": 1176,
"y": 804,
"type": "bit"
},
{
"x": 1206,
"y": 804,
"type": "common"
},
{
"x": 1236,
"y": 804,
"type": "skull"
},
{
"x": 1266,
"y": 804,
"type": "bit"
},
{
"x": 906,
"y": 774,
"type": "common"
},
{
"x": 936,
"y": 774,
"type": "common"
},
{
"x": 966,
"y": 774,
"type": "common"
},
{
"x": 996,
"y": 774,
"type": "common"
},
{
"x": 1026,
"y": 774,
"type": "common"
},
{
"x": 1056,
"y": 774,
"type": "common"
},
{
"x": 1086,
"y": 774,
"type": "common"
},
{
"x": 1116,
"y": 774,
"type": "common"
},
{
"x": 1146,
"y": 774,
"type": "common"
},
{
"x": 1176,
"y": 774,
"type": "common"
},
{
"x": 1206,
"y": 774,
"type": "common"
},
{
"x": 1236,
"y": 774,
"type": "common"
},
{
"x": 1266,
"y": 774,
"type": "common"
},
{
"x": 906,
"y": 744,
"type": "common"
}
],
"pipe": {
"x": 646,
"y": 420,
"r": 46
},
"required": 6,
"ocdTarget": 13
}

View File

@ -0,0 +1,317 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 74,
"name": "Ascent",
"chapter": 5,
"tip": "Brace as you go. An unbraced column leans, and once it leans it keeps leaning.",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
}
],
"balls": [
{
"x": 780,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 842,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 811,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 1071,
"y": 834,
"type": "common"
},
{
"x": 1101,
"y": 834,
"type": "skull"
},
{
"x": 1131,
"y": 834,
"type": "bit"
},
{
"x": 1161,
"y": 834,
"type": "balloon"
},
{
"x": 1191,
"y": 834,
"type": "block"
},
{
"x": 1221,
"y": 834,
"type": "common"
},
{
"x": 1251,
"y": 834,
"type": "skull"
},
{
"x": 1281,
"y": 834,
"type": "bit"
},
{
"x": 1311,
"y": 834,
"type": "balloon"
},
{
"x": 1341,
"y": 834,
"type": "block"
},
{
"x": 1371,
"y": 834,
"type": "common"
},
{
"x": 1401,
"y": 834,
"type": "skull"
},
{
"x": 1431,
"y": 834,
"type": "bit"
},
{
"x": 1071,
"y": 804,
"type": "balloon"
},
{
"x": 1101,
"y": 804,
"type": "block"
},
{
"x": 1131,
"y": 804,
"type": "common"
},
{
"x": 1161,
"y": 804,
"type": "skull"
},
{
"x": 1191,
"y": 804,
"type": "bit"
},
{
"x": 1221,
"y": 804,
"type": "balloon"
},
{
"x": 1251,
"y": 804,
"type": "block"
},
{
"x": 1281,
"y": 804,
"type": "common"
},
{
"x": 1311,
"y": 804,
"type": "skull"
},
{
"x": 1341,
"y": 804,
"type": "bit"
},
{
"x": 1371,
"y": 804,
"type": "common"
},
{
"x": 1401,
"y": 804,
"type": "skull"
},
{
"x": 1431,
"y": 804,
"type": "bit"
},
{
"x": 1071,
"y": 774,
"type": "common"
},
{
"x": 1101,
"y": 774,
"type": "common"
},
{
"x": 1131,
"y": 774,
"type": "common"
},
{
"x": 1161,
"y": 774,
"type": "common"
},
{
"x": 1191,
"y": 774,
"type": "common"
},
{
"x": 1221,
"y": 774,
"type": "common"
},
{
"x": 1251,
"y": 774,
"type": "common"
},
{
"x": 1281,
"y": 774,
"type": "common"
},
{
"x": 1311,
"y": 774,
"type": "common"
},
{
"x": 1341,
"y": 774,
"type": "common"
},
{
"x": 1371,
"y": 774,
"type": "common"
},
{
"x": 1401,
"y": 774,
"type": "common"
},
{
"x": 1431,
"y": 774,
"type": "common"
},
{
"x": 1071,
"y": 744,
"type": "common"
}
],
"pipe": {
"x": 811,
"y": 349,
"r": 46
},
"required": 7,
"ocdTarget": 15
}

View File

@ -0,0 +1,317 @@
{
"world": {
"w": 1600,
"h": 1000
},
"level": 75,
"name": "Out",
"chapter": 5,
"tip": "Brace as you go. An unbraced column leans, and once it leans it keeps leaning.",
"terrain": [
{
"kind": "solid",
"poly": [
[
0,
850
],
[
1600,
850
],
[
1600,
1000
],
[
0,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
-30,
0
],
[
6,
0
],
[
6,
1000
],
[
-30,
1000
]
]
},
{
"kind": "solid",
"poly": [
[
1594,
0
],
[
1630,
0
],
[
1630,
1000
],
[
1594,
1000
]
]
}
],
"balls": [
{
"x": 589,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 651,
"y": 836,
"type": "common",
"pinned": true
},
{
"x": 620,
"y": 782,
"type": "common"
}
],
"strands": [
[
2,
0
],
[
2,
1
],
[
0,
1
]
],
"pile": [
{
"x": 880,
"y": 834,
"type": "common"
},
{
"x": 910,
"y": 834,
"type": "skull"
},
{
"x": 940,
"y": 834,
"type": "bit"
},
{
"x": 970,
"y": 834,
"type": "balloon"
},
{
"x": 1000,
"y": 834,
"type": "block"
},
{
"x": 1030,
"y": 834,
"type": "common"
},
{
"x": 1060,
"y": 834,
"type": "skull"
},
{
"x": 1090,
"y": 834,
"type": "bit"
},
{
"x": 1120,
"y": 834,
"type": "balloon"
},
{
"x": 1150,
"y": 834,
"type": "block"
},
{
"x": 1180,
"y": 834,
"type": "common"
},
{
"x": 1210,
"y": 834,
"type": "skull"
},
{
"x": 1240,
"y": 834,
"type": "bit"
},
{
"x": 880,
"y": 804,
"type": "balloon"
},
{
"x": 910,
"y": 804,
"type": "block"
},
{
"x": 940,
"y": 804,
"type": "common"
},
{
"x": 970,
"y": 804,
"type": "skull"
},
{
"x": 1000,
"y": 804,
"type": "bit"
},
{
"x": 1030,
"y": 804,
"type": "balloon"
},
{
"x": 1060,
"y": 804,
"type": "block"
},
{
"x": 1090,
"y": 804,
"type": "common"
},
{
"x": 1120,
"y": 804,
"type": "skull"
},
{
"x": 1150,
"y": 804,
"type": "bit"
},
{
"x": 1180,
"y": 804,
"type": "common"
},
{
"x": 1210,
"y": 804,
"type": "skull"
},
{
"x": 1240,
"y": 804,
"type": "bit"
},
{
"x": 880,
"y": 774,
"type": "common"
},
{
"x": 910,
"y": 774,
"type": "common"
},
{
"x": 940,
"y": 774,
"type": "common"
},
{
"x": 970,
"y": 774,
"type": "common"
},
{
"x": 1000,
"y": 774,
"type": "common"
},
{
"x": 1030,
"y": 774,
"type": "common"
},
{
"x": 1060,
"y": 774,
"type": "common"
},
{
"x": 1090,
"y": 774,
"type": "common"
},
{
"x": 1120,
"y": 774,
"type": "common"
},
{
"x": 1150,
"y": 774,
"type": "common"
},
{
"x": 1180,
"y": 774,
"type": "common"
},
{
"x": 1210,
"y": 774,
"type": "common"
},
{
"x": 1240,
"y": 774,
"type": "common"
},
{
"x": 880,
"y": 744,
"type": "common"
}
],
"pipe": {
"x": 620,
"y": 361,
"r": 46
},
"required": 7,
"ocdTarget": 15
}

View File

@ -1,6 +1,6 @@
{
"version": 1,
"generatedAt": "1970-01-01T00:00:00.000Z",
"version": 2,
"seed": 6294814,
"levels": [
{
"level": 1,
@ -52,73 +52,623 @@
},
{
"level": 7,
"name": "Anchors Aweigh",
"chapter": 2,
"name": "Uphill",
"chapter": 1,
"file": "level-007.json",
"required": 5,
"ocdTarget": 12,
"sandbox": true
"required": 4,
"ocdTarget": 9
},
{
"level": 8,
"name": "Sticking Point",
"chapter": 2,
"name": "Higher Ground",
"chapter": 1,
"file": "level-008.json",
"required": 5,
"ocdTarget": 12,
"sandbox": true
"ocdTarget": 10
},
{
"level": 9,
"name": "Demolition",
"chapter": 2,
"name": "The Long Climb",
"chapter": 1,
"file": "level-009.json",
"required": 5,
"ocdTarget": 12,
"sandbox": true
"required": 6,
"ocdTarget": 12
},
{
"level": 10,
"name": "Updraft",
"chapter": 2,
"name": "Across",
"chapter": 1,
"file": "level-010.json",
"required": 4,
"ocdTarget": 12,
"sandbox": true
"ocdTarget": 8
},
{
"level": 11,
"name": "Cogs",
"chapter": 2,
"name": "Wider Still",
"chapter": 1,
"file": "level-011.json",
"required": 5,
"ocdTarget": 13,
"sandbox": true
"ocdTarget": 10
},
{
"level": 12,
"name": "Lighter Than Air",
"chapter": 2,
"name": "The Drop",
"chapter": 1,
"file": "level-012.json",
"required": 6,
"ocdTarget": 12
},
{
"level": 13,
"name": "Under It",
"chapter": 1,
"file": "level-013.json",
"required": 5,
"ocdTarget": 10
},
{
"level": 14,
"name": "Round the Back",
"chapter": 1,
"file": "level-014.json",
"required": 5,
"ocdTarget": 10
},
{
"level": 15,
"name": "Out and Up",
"chapter": 1,
"file": "level-015.json",
"required": 6,
"ocdTarget": 13
},
{
"level": 16,
"name": "Light Head",
"chapter": 2,
"file": "level-016.json",
"required": 6,
"ocdTarget": 12
},
{
"level": 17,
"name": "Buoyant",
"chapter": 2,
"file": "level-017.json",
"required": 6,
"ocdTarget": 12
},
{
"level": 18,
"name": "Low Ceiling",
"chapter": 2,
"file": "level-018.json",
"required": 5,
"ocdTarget": 10
},
{
"level": 19,
"name": "Mind Your Head",
"chapter": 2,
"file": "level-019.json",
"required": 6,
"ocdTarget": 12
},
{
"level": 20,
"name": "Overhead",
"chapter": 2,
"file": "level-020.json",
"required": 6,
"ocdTarget": 13
},
{
"level": 21,
"name": "First Gust",
"chapter": 2,
"file": "level-021.json",
"required": 4,
"ocdTarget": 9
},
{
"level": 22,
"name": "Updraft",
"chapter": 2,
"file": "level-022.json",
"required": 5,
"ocdTarget": 10
},
{
"level": 23,
"name": "Riding the Wind",
"chapter": 2,
"file": "level-023.json",
"required": 6,
"ocdTarget": 12,
"sandbox": true
"element": "fan"
},
{
"level": 24,
"name": "Thermals",
"chapter": 2,
"file": "level-024.json",
"required": 6,
"ocdTarget": 13,
"element": "fan"
},
{
"level": 25,
"name": "Long Reach",
"chapter": 2,
"file": "level-025.json",
"required": 6,
"ocdTarget": 12
},
{
"level": 26,
"name": "The Wide Crossing",
"chapter": 2,
"file": "level-026.json",
"required": 6,
"ocdTarget": 13
},
{
"level": 27,
"name": "Windswept",
"chapter": 2,
"file": "level-027.json",
"required": 7,
"ocdTarget": 15
},
{
"level": 28,
"name": "Gale",
"chapter": 2,
"file": "level-028.json",
"required": 6,
"ocdTarget": 13,
"element": "fan"
},
{
"level": 29,
"name": "Squall",
"chapter": 2,
"file": "level-029.json",
"required": 6,
"ocdTarget": 13
},
{
"level": 30,
"name": "Headwind",
"chapter": 2,
"file": "level-030.json",
"required": 5,
"ocdTarget": 11
},
{
"level": 31,
"name": "First Cog",
"chapter": 3,
"file": "level-031.json",
"required": 4,
"ocdTarget": 8,
"element": "gear"
},
{
"level": 32,
"name": "Gearworks",
"chapter": 3,
"file": "level-032.json",
"required": 5,
"ocdTarget": 10,
"element": "gear"
},
{
"level": 33,
"name": "Clockwise",
"chapter": 3,
"file": "level-033.json",
"required": 5,
"ocdTarget": 11,
"element": "gear"
},
{
"level": 34,
"name": "Widdershins",
"chapter": 3,
"file": "level-034.json",
"required": 6,
"ocdTarget": 12,
"element": "gear"
},
{
"level": 35,
"name": "Rigid Thinking",
"chapter": 3,
"file": "level-035.json",
"required": 6,
"ocdTarget": 13
},
{
"level": 36,
"name": "Girders",
"chapter": 3,
"file": "level-036.json",
"required": 7,
"ocdTarget": 15
},
{
"level": 37,
"name": "Soft Rock",
"chapter": 3,
"file": "level-037.json",
"required": 4,
"ocdTarget": 8,
"element": "bomb"
},
{
"level": 38,
"name": "Demolition",
"chapter": 3,
"file": "level-038.json",
"required": 5,
"ocdTarget": 10,
"element": "bomb"
},
{
"level": 39,
"name": "Blast Radius",
"chapter": 3,
"file": "level-039.json",
"required": 6,
"ocdTarget": 12,
"element": "bomb"
},
{
"level": 40,
"name": "Controlled Burn",
"chapter": 3,
"file": "level-040.json",
"required": 6,
"ocdTarget": 13,
"element": "bomb"
},
{
"level": 41,
"name": "The Machine",
"chapter": 3,
"file": "level-041.json",
"required": 6,
"ocdTarget": 13,
"element": "gear"
},
{
"level": 42,
"name": "Grinding Gears",
"chapter": 3,
"file": "level-042.json",
"required": 7,
"ocdTarget": 15,
"element": "gear"
},
{
"level": 43,
"name": "Flywheel",
"chapter": 3,
"file": "level-043.json",
"required": 8,
"ocdTarget": 17,
"element": "gear"
},
{
"level": 44,
"name": "Under the Works",
"chapter": 3,
"file": "level-044.json",
"required": 6,
"ocdTarget": 13
},
{
"level": 45,
"name": "Assembly",
"chapter": 3,
"file": "level-045.json",
"required": 7,
"ocdTarget": 15
},
{
"level": 46,
"name": "Handhold",
"chapter": 4,
"file": "level-046.json",
"required": 5,
"ocdTarget": 10,
"element": "anchor"
},
{
"level": 47,
"name": "Two Pillars",
"chapter": 4,
"file": "level-047.json",
"required": 5,
"ocdTarget": 10,
"element": "anchor"
},
{
"level": 48,
"name": "Stepping Up",
"chapter": 4,
"file": "level-048.json",
"required": 6,
"ocdTarget": 12,
"element": "anchor"
},
{
"level": 49,
"name": "The Face",
"chapter": 4,
"file": "level-049.json",
"required": 5,
"ocdTarget": 10,
"element": "anchor"
},
{
"level": 50,
"name": "Sheer",
"chapter": 4,
"file": "level-050.json",
"required": 5,
"ocdTarget": 10,
"element": "anchor"
},
{
"level": 51,
"name": "Traverse",
"chapter": 4,
"file": "level-051.json",
"required": 6,
"ocdTarget": 12,
"element": "anchor"
},
{
"level": 52,
"name": "Grip",
"chapter": 4,
"file": "level-052.json",
"required": 6,
"ocdTarget": 12,
"element": "anchor"
},
{
"level": 53,
"name": "Overhanging",
"chapter": 4,
"file": "level-053.json",
"required": 6,
"ocdTarget": 13
},
{
"level": 54,
"name": "Cliffhanger",
"chapter": 4,
"file": "level-054.json",
"required": 7,
"ocdTarget": 15
},
{
"level": 55,
"name": "The Chimney",
"chapter": 4,
"file": "level-055.json",
"required": 6,
"ocdTarget": 12,
"element": "anchor"
},
{
"level": 56,
"name": "Freeclimb",
"chapter": 4,
"file": "level-056.json",
"required": 6,
"ocdTarget": 13
},
{
"level": 57,
"name": "The Notch",
"chapter": 4,
"file": "level-057.json",
"required": 7,
"ocdTarget": 14
},
{
"level": 58,
"name": "Crevasse",
"chapter": 4,
"file": "level-058.json",
"required": 6,
"ocdTarget": 13
},
{
"level": 59,
"name": "Exposure",
"chapter": 4,
"file": "level-059.json",
"required": 7,
"ocdTarget": 14
},
{
"level": 60,
"name": "Summit",
"chapter": 4,
"file": "level-060.json",
"required": 7,
"ocdTarget": 14
},
{
"level": 61,
"name": "Descent",
"chapter": 5,
"file": "level-061.json",
"required": 6,
"ocdTarget": 13
},
{
"level": 62,
"name": "Low Roof",
"chapter": 5,
"file": "level-062.json",
"required": 7,
"ocdTarget": 15
},
{
"level": 63,
"name": "The Squeeze",
"chapter": 5,
"file": "level-063.json",
"required": 7,
"ocdTarget": 15
},
{
"level": 64,
"name": "Deep Wind",
"chapter": 5,
"file": "level-064.json",
"required": 6,
"ocdTarget": 13,
"element": "fan"
},
{
"level": 65,
"name": "The Shaft",
"chapter": 5,
"file": "level-065.json",
"required": 7,
"ocdTarget": 15,
"element": "fan"
},
{
"level": 66,
"name": "Downdraft",
"chapter": 5,
"file": "level-066.json",
"required": 8,
"ocdTarget": 17,
"element": "fan"
},
{
"level": 67,
"name": "Deep Cogs",
"chapter": 5,
"file": "level-067.json",
"required": 6,
"ocdTarget": 13,
"element": "gear"
},
{
"level": 68,
"name": "The Grinder",
"chapter": 5,
"file": "level-068.json",
"required": 7,
"ocdTarget": 15,
"element": "gear"
},
{
"level": 69,
"name": "Millstone",
"chapter": 5,
"file": "level-069.json",
"required": 8,
"ocdTarget": 17,
"element": "gear"
},
{
"level": 70,
"name": "Deep Rock",
"chapter": 5,
"file": "level-070.json",
"required": 7,
"ocdTarget": 14,
"element": "bomb"
},
{
"level": 71,
"name": "Cave-In",
"chapter": 5,
"file": "level-071.json",
"required": 7,
"ocdTarget": 15,
"element": "bomb"
},
{
"level": 72,
"name": "The Last Charge",
"chapter": 5,
"file": "level-072.json",
"required": 8,
"ocdTarget": 17,
"element": "bomb"
},
{
"level": 73,
"name": "The Long Way Up",
"chapter": 5,
"file": "level-073.json",
"required": 6,
"ocdTarget": 13
},
{
"level": 74,
"name": "Ascent",
"chapter": 5,
"file": "level-074.json",
"required": 7,
"ocdTarget": 15
},
{
"level": 75,
"name": "Out",
"chapter": 5,
"file": "level-075.json",
"required": 7,
"ocdTarget": 15
}
],
"chapters": [
{
"id": 1,
"name": "The Goo Filled Hills",
"blurb": "Learn to build.",
"name": "The Rolling Hills",
"blurb": "Learn to build. Everything after this assumes you can.",
"from": 1,
"to": 6
"to": 15
},
{
"id": 2,
"name": "Sandbox",
"blurb": "One level per mechanic — throwaway, replaced in Wave 4.",
"from": 7,
"to": 12
"name": "Windward",
"blurb": "Wind, balloons, and things that would rather float away.",
"from": 16,
"to": 30
},
{
"id": 3,
"name": "The Works",
"blurb": "Machinery. It does not care what you built.",
"from": 31,
"to": 45
},
{
"id": 4,
"name": "The Sticky Cliffs",
"blurb": "No ground worth standing on. Grip the rock.",
"from": 46,
"to": 60
},
{
"id": 5,
"name": "Down the Deep",
"blurb": "Everything you have learned, all at once.",
"from": 61,
"to": 75
}
]
}

View File

@ -3,11 +3,11 @@
Living plan doc. Survives context clears: **read this file first**, pick the next unchecked
item, update the checkboxes and the "Status" line as work lands.
**Status:** **Waves 03 complete (2026-07-26).** All nine goo types and every hazard are
live, with a 6-level sandbox tier on top of the 6-level teaching chapter
`node tools/verifyGooTower.js`**303 checks green**, including a reference player that
beats all **12** levels headlessly. **Never opened in a browser** — Brian playtests, and
Waves 13 are not signed off until he has.
**Status:** **COMPLETE — all five waves done (2026-07-26).** Nine goo types, every hazard,
a level editor, and a **75-level campaign in 5 chapters**
`node tools/verifyGooTower.js`**1061 checks green**, including a reference player that
beats every one of the 75 levels headlessly. **Never opened in a browser** — Brian
playtests, and nothing here is signed off until he has.
---
@ -29,9 +29,9 @@ Waves 13 are not signed off until he has.
| `src/games/gootower/tutorial.md` | `hasTutorial: true` | done |
| `src/games/gootower/GooTowerEditor.js` | Level editor, `?gootower-editor=1` | Wave 2 done |
| `src/games/gootower/GooTowerAuto.js` | Greedy reference player = the winnability gate | done |
| `tools/verifyGooTower.js` | Regression harness, **303 checks** | Waves 03 done |
| `tools/genGooTower.js` | Level bank writer (12 hand-tuned levels) | Wave 3 done |
| `assets/gamedata/gootower/levels.json` | Manifest + per-level `level-NNN.json` | 12 levels |
| `tools/verifyGooTower.js` | Regression harness, **1061 checks** | all waves |
| `tools/genGooTower.js` | Curriculum generator (5 chapters x 15) | Wave 4 done |
| `assets/gamedata/gootower/levels.json` | Manifest + per-level `level-NNN.json` | **75 levels** |
`GooTowerAuto.js` lives in `src/`, not `tools/`, because the editor's "Test Winnable"
button must run exactly the gate the verifier runs.

View File

@ -40,17 +40,30 @@ const GOO_COLOR = {
anchor: 0x5a4a3a,
};
// Phaser Containers render children in insertion order and IGNORE child depth,
// so every layer here is a root-level object with its own setDepth.
// Phaser Containers render children in insertion order and IGNORE child depth.
// The HUD and overlays are root-level objects ordered by these depths; the
// board's own layers live inside `this.board` and are ordered by insertion.
const D = {
sky: -10, terrain: 0, pipe: 4, strand: 8, ball: 10, ghost: 14,
hud: 30, overlay: 60, overlayUI: 62,
};
// World-space -> screen-space. The world is 1600x1000 on a 1920x1080 canvas,
// so it fits outright and there is no camera to drive.
const OX = 160;
const OY = 70;
// World-space -> screen-space.
//
// Everything on the board is drawn at RAW WORLD COORDINATES into `this.board`,
// a container whose position and scale are the view transform. That is what
// makes zoom free: no drawing code knows the view exists.
//
// Phaser containers ignore child depth and render in insertion order, so the
// board's layers are added in the order they must paint: terrain, then the
// per-frame layer, then the drag ghost.
const WORLD_W = 1600;
const WORLD_H = 1000;
const VIEW_HOME = { scale: 1, ox: 160, oy: 70 };
const ZOOM_MIN = 0.45;
const ZOOM_MAX = 9;
const ZOOM_STEP = 1.15;
const VIEW_KEEP = 0.35; // fraction of the viewport that must stay over the board
const shade = (color, f) => {
const ch = (s) => Math.min(255, Math.round(((color >> s) & 0xff) * f));
@ -79,7 +92,7 @@ export default class GooTowerGame extends Phaser.Scene {
this.canPersist = true;
this.levelCache = new Map();
this.view = 'select';
this.viewMode = 'select';
this.level = 0;
this.levelDef = null;
this.state = null;
@ -88,6 +101,8 @@ export default class GooTowerGame extends Phaser.Scene {
this.boardObjs = [];
this.overlayUp = false;
this.finished = false;
this.view = { ...VIEW_HOME };
this.panFrom = null;
}
async create() {
@ -134,6 +149,8 @@ export default class GooTowerGame extends Phaser.Scene {
this.dyn = null;
this.ghost = null;
this.terrainG = null;
this.board = null;
this.panFrom = null;
this.needText = null;
this.hudText = null;
}
@ -150,75 +167,80 @@ export default class GooTowerGame extends Phaser.Scene {
}
showSelect() {
this.view = 'select';
this.viewMode = 'select';
this.state = null;
this.held = null;
this.clearBoard();
const cx = GAME_WIDTH / 2;
this.track(this.add.text(cx, 70, 'Goo Tower', {
fontFamily: 'Righteous', fontSize: '58px', color: COLORS.textHex,
this.track(this.add.text(cx, 56, 'Goo Tower', {
fontFamily: 'Righteous', fontSize: '46px', color: COLORS.textHex,
}).setOrigin(0.5).setDepth(D.hud));
this.tooltip = new Tooltip(this);
let y = 190;
// Five chapters of fifteen. Tiles are compact and evenly spread; the
// level's name lives in the hover tooltip rather than on the tile, because
// fifteen across leaves no room for it.
const TILE_W = 92;
const TILE_H = 66;
const STEP = 106;
let y = 148;
for (const ch of this.chapters) {
this.track(this.add.text(140, y, ch.name, {
fontFamily: 'Righteous', fontSize: '30px', color: COLORS.goldHex,
const levels = this.manifest.filter((m) => m.level >= ch.from && m.level <= ch.to);
this.track(this.add.text(70, y, ch.name, {
fontFamily: 'Righteous', fontSize: '26px', color: COLORS.goldHex,
}).setDepth(D.hud));
if (ch.blurb) {
this.track(this.add.text(140, y + 36, ch.blurb, {
fontFamily: '"Julius Sans One"', fontSize: '20px', color: '#9aa7b4',
this.track(this.add.text(70, y + 32, ch.blurb, {
fontFamily: '"Julius Sans One"', fontSize: '16px', color: '#8b98a6',
}).setDepth(D.hud));
}
const levels = this.manifest.filter((m) => m.level >= ch.from && m.level <= ch.to);
let x = 150;
const rowW = (levels.length - 1) * STEP;
let x = GAME_WIDTH / 2 - rowW / 2;
for (const m of levels) {
const unlocked = m.level <= this.levelsCompleted + 1;
const cleared = m.level <= this.levelsCompleted;
this.makeLevelTile(x, y + 110, m, unlocked, cleared);
x += 175;
this.makeLevelTile(x, y + 70, m, unlocked, cleared, TILE_W, TILE_H);
x += STEP;
}
y += 260;
y += 168;
}
this.track(new Button(this, cx, GAME_HEIGHT - 70, 'Back', () => this.scene.start('GameMenu'),
{ variant: 'ghost', width: 200 }).setDepth(D.hud));
this.track(new Button(this, cx, GAME_HEIGHT - 46, 'Back', () => this.scene.start('GameMenu'),
{ variant: 'ghost', width: 180, height: 52 }).setDepth(D.hud));
if (this.levelsCompleted > 0) {
this.track(new Button(this, 210, GAME_HEIGHT - 70, 'Reset Progress',
() => this.resetProgress(), { variant: 'ghost', width: 260, fontSize: 20 }).setDepth(D.hud));
this.track(new Button(this, 210, GAME_HEIGHT - 46, 'Reset Progress',
() => this.resetProgress(), { variant: 'ghost', width: 240, height: 52, fontSize: 19 }).setDepth(D.hud));
}
}
makeLevelTile(x, y, m, unlocked, cleared) {
const w = 150;
const h = 120;
makeLevelTile(x, y, m, unlocked, cleared, w = 92, h = 66) {
const g = this.add.graphics().setDepth(D.hud);
const base = cleared ? 0x2b4a3a : unlocked ? 0x2a3547 : 0x1b2029;
g.fillStyle(base, 1);
g.fillRoundedRect(x - w / 2, y - h / 2, w, h, 10);
g.fillRoundedRect(x - w / 2, y - h / 2, w, h, 8);
g.lineStyle(2, cleared ? 0x63c132 : unlocked ? 0x5b7fa8 : 0x2a3038, 1);
g.strokeRoundedRect(x - w / 2, y - h / 2, w, h, 10);
g.strokeRoundedRect(x - w / 2, y - h / 2, w, h, 8);
this.track(g);
this.track(this.add.text(x, y - 30, String(m.level), {
fontFamily: 'Righteous', fontSize: '34px',
color: unlocked ? COLORS.textHex : '#4a5560',
}).setOrigin(0.5).setDepth(D.hud));
this.track(this.add.text(x, y + 12, unlocked ? m.name : 'Locked', {
fontFamily: '"Julius Sans One"', fontSize: '15px',
color: unlocked ? '#b9c6d2' : '#4a5560',
wordWrap: { width: w - 16 }, align: 'center',
const best = this.bestFor(m.level);
this.track(this.add.text(x, y - 10, String(m.level), {
fontFamily: 'Righteous', fontSize: '26px',
color: unlocked ? COLORS.textHex : '#455060',
}).setOrigin(0.5).setDepth(D.hud));
const best = this.bestFor(m.level);
if (best.count > 0) {
this.track(this.add.text(x, y + 44, best.ocd ? ` ${best.count}` : `${best.count}`, {
fontFamily: '"Julius Sans One"', fontSize: '16px',
this.track(this.add.text(x, y + 18, best.ocd ? `\u2605 ${best.count}` : `${best.count}`, {
fontFamily: '"Julius Sans One"', fontSize: '14px',
color: best.ocd ? '#ffd166' : '#7f8c99',
}).setOrigin(0.5).setDepth(D.hud));
} else if (unlocked && m.element) {
// A pip naming the mechanic this level is built around.
this.track(this.add.text(x, y + 18, m.element, {
fontFamily: '"Julius Sans One"', fontSize: '12px', color: '#6f7c8a',
}).setOrigin(0.5).setDepth(D.hud));
}
if (!unlocked) return;
@ -228,8 +250,12 @@ export default class GooTowerGame extends Phaser.Scene {
hit.on('pointerup', () => this.startLevel(m.level));
if (this.tooltip) {
this.tooltip.attachTo(hit, () => ({
title: m.name,
lines: [`Collect ${m.required} to finish`, `OCD target: ${m.ocdTarget}`],
title: `${m.level}. ${m.name}`,
lines: [
`Collect ${m.required} to finish`,
`OCD target: ${m.ocdTarget}`,
...(best.count ? [`Best: ${best.count}${best.ocd ? ' \u2605 OCD' : ''}`] : []),
],
}));
}
this.track(hit);
@ -282,7 +308,7 @@ export default class GooTowerGame extends Phaser.Scene {
if (!def) { this.showSelect(); return; }
this.clearBoard();
this.view = 'play';
this.viewMode = 'play';
this.level = level;
this.levelDef = def;
this.state = createState(def, 0x60071e + level);
@ -291,10 +317,17 @@ export default class GooTowerGame extends Phaser.Scene {
this.overlayUp = false;
this.finished = false;
this.terrainG = this.track(this.add.graphics().setDepth(D.terrain));
// One container for the whole board; its transform is the view. Children
// are added in paint order because containers ignore child depth.
this.board = this.track(this.add.container(0, 0).setDepth(D.terrain));
this.terrainG = this.add.graphics();
this.dyn = this.add.graphics();
this.ghost = this.add.graphics();
this.board.add([this.terrainG, this.dyn, this.ghost]);
this.view = { ...VIEW_HOME };
this.applyView();
this.drawTerrain();
this.dyn = this.track(this.add.graphics().setDepth(D.strand));
this.ghost = this.track(this.add.graphics().setDepth(D.ghost));
this.buildHud();
}
@ -305,7 +338,7 @@ export default class GooTowerGame extends Phaser.Scene {
g.clear();
for (const t of this.state.terrain) {
if (t.gear) continue; // gears rotate; they are drawn per-frame instead
const pts = t.poly.map(([x, y]) => ({ x: x + OX, y: y + OY }));
const pts = t.poly.map(([x, y]) => ({ x, y }));
if (t.kind === 'solid') {
g.fillStyle(DIRT, 1);
g.fillPoints(pts, true);
@ -324,8 +357,7 @@ export default class GooTowerGame extends Phaser.Scene {
g.lineStyle(1, 0xd9a066, 0.5);
const bb = t.bounds;
for (let x = bb.minX; x < bb.maxX + (bb.maxY - bb.minY); x += 16) {
g.lineBetween(x + OX, bb.minY + OY,
x - (bb.maxY - bb.minY) + OX, bb.maxY + OY);
g.lineBetween(x, bb.minY, x - (bb.maxY - bb.minY), bb.maxY);
}
}
}
@ -335,15 +367,15 @@ export default class GooTowerGame extends Phaser.Scene {
drawFans(g) {
for (const f of this.state.fans) {
g.fillStyle(0x8fd0e8, 0.07);
g.fillRect(f.x + OX, f.y + OY, f.w, f.h);
g.fillRect(f.x, f.y, f.w, f.h);
g.lineStyle(1, 0x8fd0e8, 0.28);
g.strokeRect(f.x + OX, f.y + OY, f.w, f.h);
g.strokeRect(f.x, f.y, f.w, f.h);
// Chevrons pointing the way the wind blows.
const step = 56;
for (let x = f.x + step / 2; x < f.x + f.w; x += step) {
for (let y = f.y + step / 2; y < f.y + f.h; y += step) {
const cx = x + OX;
const cy = y + OY;
const cx = x;
const cy = y;
const ax = f.dx * 12;
const ay = f.dy * 12;
g.lineStyle(2, 0x8fd0e8, 0.32);
@ -358,13 +390,13 @@ export default class GooTowerGame extends Phaser.Scene {
drawGears(g) {
for (const t of this.state.terrain) {
if (!t.gear) continue;
const pts = t.poly.map(([x, y]) => ({ x: x + OX, y: y + OY }));
const pts = t.poly.map(([x, y]) => ({ x, y }));
g.fillStyle(0x4a4260, 1);
g.fillPoints(pts, true);
g.lineStyle(3, 0x8a7fb0, 1);
g.strokePoints(pts, true);
const cx = t.gear.cx + OX;
const cy = t.gear.cy + OY;
const cx = t.gear.cx;
const cy = t.gear.cy;
g.fillStyle(0x2a2438, 1);
g.fillCircle(cx, cy, t.gear.r * 0.3);
// A spoke, so the rotation is legible.
@ -394,9 +426,9 @@ export default class GooTowerGame extends Phaser.Scene {
const x0 = ax + step * k;
const x1 = x0 + step;
g.fillTriangle(
x0 + OX, mid + OY,
x1 + OX, mid + OY,
(x0 + x1) / 2 + OX, mid + OY + up * 20,
x0, mid,
x1, mid,
(x0 + x1) / 2, mid + up * 20,
);
}
}
@ -407,6 +439,9 @@ export default class GooTowerGame extends Phaser.Scene {
this.hudText = this.track(this.add.text(40, 26, '', {
fontFamily: '"Julius Sans One"', fontSize: '26px', color: COLORS.textHex,
}).setDepth(D.hud));
this.track(this.add.text(40, 58, 'wheel: zoom to cursor · right-drag: pan · 0: reset view', {
fontFamily: '"Julius Sans One"', fontSize: '15px', color: '#5f6b78',
}).setDepth(D.hud));
this.tipText = this.track(this.add.text(GAME_WIDTH / 2, 30, this.levelDef.tip || '', {
fontFamily: '"Julius Sans One"', fontSize: '19px', color: '#9aa7b4',
wordWrap: { width: 760 }, align: 'center',
@ -428,20 +463,83 @@ export default class GooTowerGame extends Phaser.Scene {
);
}
// ── View: zoom and pan ────────────────────────────────────────────────────
applyView() {
this.clampView();
if (!this.board) return;
this.board.setScale(this.view.scale);
this.board.setPosition(this.view.ox, this.view.oy);
}
// Keep at least VIEW_KEEP of the viewport covered by board, rather than
// forcing the whole board on screen. Forcing it leaves the clamp fighting the
// zoom anchor near the edges -- the point under the cursor slides away, which
// is exactly what zoom-to-cursor is supposed to prevent. With this the anchor
// is pixel-exact everywhere except when you push past the bounds.
clampView() {
const clampAxis = (v, span, viewport) => Math.max(
viewport * VIEW_KEEP - span,
Math.min(viewport * (1 - VIEW_KEEP), v),
);
this.view.ox = clampAxis(this.view.ox, WORLD_W * this.view.scale, GAME_WIDTH);
this.view.oy = clampAxis(this.view.oy, WORLD_H * this.view.scale, GAME_HEIGHT);
}
// Zoom about a screen point: the world position under the cursor must stay
// under the cursor, which is the whole point of zooming to the mouse.
zoomAt(screenX, screenY, factor) {
const before = this.toWorld({ x: screenX, y: screenY });
const next = Math.max(ZOOM_MIN, Math.min(ZOOM_MAX, this.view.scale * factor));
if (next === this.view.scale) return;
this.view.scale = next;
this.view.ox = screenX - before.x * next;
this.view.oy = screenY - before.y * next;
this.applyView();
}
resetView() {
this.view = { ...VIEW_HOME };
this.applyView();
}
// ── Input ─────────────────────────────────────────────────────────────────
bindInput() {
this.input.mouse?.disableContextMenu();
this.input.on('pointerdown', (p) => this.onDown(p));
this.input.on('pointermove', (p) => this.onMove(p));
this.input.on('pointerup', (p) => this.onUp(p));
this.input.keyboard?.on('keydown-R', () => { if (this.view === 'play') this.startLevel(this.level); });
this.input.keyboard?.on('keydown-ESC', () => { if (this.view === 'play') this.exitLevel(); });
this.input.on('wheel', (p, over, dx, dy) => {
if (this.viewMode !== 'play' || !this.state || this.overlayUp) return;
if (dy === 0) return;
this.zoomAt(p.x, p.y, dy < 0 ? ZOOM_STEP : 1 / ZOOM_STEP);
});
this.input.keyboard?.on('keydown-ZERO', () => this.resetView());
this.input.keyboard?.on('keydown-HOME', () => this.resetView());
this.input.keyboard?.on('keydown-R', () => { if (this.viewMode === 'play') this.startLevel(this.level); });
this.input.keyboard?.on('keydown-ESC', () => { if (this.viewMode === 'play') this.exitLevel(); });
}
toWorld(p) { return { x: p.x - OX, y: p.y - OY }; }
// Screen <-> world. The board container holds the forward transform; these
// are it and its inverse.
tx(x) { return x * this.view.scale + this.view.ox; }
ty(y) { return y * this.view.scale + this.view.oy; }
toWorld(p) {
return { x: (p.x - this.view.ox) / this.view.scale, y: (p.y - this.view.oy) / this.view.scale };
}
onDown(p) {
if (this.view !== 'play' || this.overlayUp || !this.state) return;
if (this.viewMode !== 'play' || this.overlayUp || !this.state) return;
// Right-drag pans. Zoomed in, you need a way to get around, and the left
// button is already spoken for by dragging goo.
if (p.rightButtonDown()) {
this.panFrom = { x: p.x, y: p.y, ox: this.view.ox, oy: this.view.oy };
return;
}
const w = this.toWorld(p);
const ball = pickBallAt(this.state, w.x, w.y, 46);
if (!ball) return;
@ -452,12 +550,19 @@ export default class GooTowerGame extends Phaser.Scene {
}
onMove(p) {
if (this.panFrom) {
this.view.ox = this.panFrom.ox + (p.x - this.panFrom.x);
this.view.oy = this.panFrom.oy + (p.y - this.panFrom.y);
this.applyView();
return;
}
if (!this.held || !this.state) return;
const w = this.toWorld(p);
dragTo(this.state, this.held, w.x, w.y);
}
onUp(p) {
if (this.panFrom) { this.panFrom = null; return; }
if (!this.held || !this.state) return;
const w = this.toWorld(p);
const ball = this.held;
@ -471,7 +576,7 @@ export default class GooTowerGame extends Phaser.Scene {
// ── Frame ─────────────────────────────────────────────────────────────────
update(time, delta) {
if (this.view !== 'play' || !this.state) return;
if (this.viewMode !== 'play' || !this.state) return;
// Fixed-timestep accumulator; the sim substeps internally at 240Hz.
const dt = Math.min(delta / 1000, 0.05);
@ -519,7 +624,7 @@ export default class GooTowerGame extends Phaser.Scene {
const color = lerpColor(STRAND, STRAND_HOT, stress);
const width = 7 - 3 * stress; // strands thin as they are pulled taut
g.lineStyle(width, color, 1);
g.lineBetween(a.x + OX, a.y + OY, b.x + OX, b.y + OY);
g.lineBetween(a.x, a.y, b.x, b.y);
}
// Balls.
@ -534,8 +639,8 @@ export default class GooTowerGame extends Phaser.Scene {
drawBall(g, b) {
const base = GOO_COLOR[b.type] ?? GOO_COLOR.common;
const x = b.x + OX;
const y = b.y + OY;
const x = b.x;
const y = b.y;
// Squash along the direction of travel, so goo reads as soft.
const vx = b.x - b.px;
@ -592,8 +697,8 @@ export default class GooTowerGame extends Phaser.Scene {
drawPipe(g) {
const p = this.state.pipe;
if (!p) return;
const x = p.x + OX;
const y = p.y + OY;
const x = p.x;
const y = p.y;
const open = p.open;
g.fillStyle(PIPE_BODY, 1);
@ -626,19 +731,22 @@ export default class GooTowerGame extends Phaser.Scene {
// a perfectly valid placement that kills it on contact.
const color = !ok ? GHOST_NO : hazard ? 0xffb347 : GHOST_OK;
// Ghost strokes are UI, not physical: keep them a constant width on screen
// rather than letting 9x zoom turn them into slabs.
const px = 1 / this.view.scale;
for (const id of targets) {
const t = this.state.balls[id];
if (!t) continue;
g.lineStyle(3, color, 0.8);
g.lineBetween(b.x + OX, b.y + OY, t.x + OX, t.y + OY);
g.lineStyle(3 * px, color, 0.8);
g.lineBetween(b.x, b.y, t.x, t.y);
}
g.lineStyle(2, color, 0.85);
g.strokeCircle(b.x + OX, b.y + OY, b.r + 8);
g.lineStyle(2 * px, color, 0.85);
g.strokeCircle(b.x, b.y, b.r + 8 * px);
if (!ok || hazard) {
const need = requiredStrands(this.state, b.x, b.y, b.type);
g.lineStyle(1, color, 0.35);
g.strokeCircle(b.x + OX, b.y + OY, TUNING.ATTACH_R);
g.lineStyle(1 * px, color, 0.35);
g.strokeCircle(b.x, b.y, TUNING.ATTACH_R);
if (!this.needText) {
this.needText = this.track(this.add.text(0, 0, '', {
fontFamily: '"Julius Sans One"', fontSize: '18px', color: '#ff9d9d',
@ -647,7 +755,7 @@ export default class GooTowerGame extends Phaser.Scene {
const label = !ok
? (need === 0 ? 'no hold' : `needs ${need}`)
: (hazard === 'fire' && gooType(b.type).explodes ? 'will light!' : `${hazard}!`);
this.needText.setPosition(b.x + OX, b.y + OY - b.r - 26)
this.needText.setPosition(this.tx(b.x), this.ty(b.y) - b.r * this.view.scale - 26)
.setColor(ok ? '#ffb347' : '#ff9d9d')
.setText(label)
.setVisible(true);

View File

@ -485,7 +485,12 @@ function integrate(state, dt) {
const def = gooType(b.type);
const fan = state.fans.length ? fanAccel(state, b) : null;
const ax = fan ? fan.ax : 0;
const ay = TUNING.GRAVITY * def.buoyancy + (fan ? fan.ay : 0);
// Buoyancy only applies once the goo is part of a structure. Loose goo
// sits in the heap like everything else -- otherwise every balloon in a
// level's pile drifts off on frame one and dies on the nearest ceiling,
// and the level is unwinnable before the player has touched anything.
const lift = b.attached ? def.buoyancy : 1;
const ay = TUNING.GRAVITY * lift + (fan ? fan.ay : 0);
let vx = (b.x - b.px) * TUNING.DRAG;
let vy = (b.y - b.py) * TUNING.DRAG;

View File

@ -65,4 +65,11 @@ once it's down.
- **OCD** is a separate, higher target for collecting far more than you needed. Reaching
the required count doesn't end the level — hit *Keep Playing* and go for it.
## Getting a closer look
- **Mouse wheel** zooms in and out, centred on whatever is under the cursor — so point at the
join you care about and roll in. It goes from a wide view right down to individual strands.
- **Right-click and drag** pans.
- **0** (or Home) snaps the view back.
Press **R** to retry, **Esc** for the level list.

View File

@ -1,44 +1,77 @@
// Goo Tower — level bank writer.
// Goo Tower — level bank generator.
//
// Wave 1: the six hand-designed teaching levels below are authored here and
// emitted verbatim. They are HAND-TUNED, not generated -- the script exists so
// the repetitive parts (goo piles, spike strips, the manifest) are constructed
// rather than typed, and so the bank is byte-reproducible.
// Wave 4 replaced the flat 12-level bank with a CURRICULUM: five named
// chapters of fifteen levels, built from blocks that introduce one mechanic,
// drill it, then combine it with what came before.
//
// Wave 4 will add generated drill/sandbox tiers alongside these; when it does,
// levels 1-6 must be carried over untouched, exactly as genPeggleLevels.js
// freezes Peggle's hand-tuned 1-25.
// A physics sandbox has no BFS solver, so levels are not random-filled the way
// Jell-o Monsters' are. Instead each level is instantiated from a HAND-DESIGNED
// TEMPLATE (tower, bridge, overhang, updraft, cogs, demolition, cliff…) with
// its parameters swept across a difficulty band, and then has to survive four
// gates:
//
// Usage: node tools/genGooTower.js [outDir]
// 1. CLEAN — settles without snapping a strand, losing goo, starting
// anything inside terrain, or starting two goo overlapping.
// 2. WINNABLE — the reference player in GooTowerAuto.js beats it. The
// gate is one-directional: if a naive builder can win, a
// human can. A failure means "redesign", never "impossible".
// 3. LOAD-BEARING — for enabling mechanics (updraft, wall-anchors), strip the
// element and the level must STOP being winnable. This is
// what keeps a "fan level" from being an ordinary level
// with a fan blowing somewhere irrelevant.
// 4. GENTLE — a teaching level may not open with an instant-fail: no
// hazard within reach of the starting structure.
//
// Levels 1-6 are the original hand-tuned teaching levels and are emitted
// VERBATIM, exactly as genPeggleLevels.js freezes Peggle's hand-tuned 1-25.
//
// Usage:
// node tools/genGooTower.js [seed] [outDir]
//
// Deterministic: same seed -> same bank.
import { writeFileSync, mkdirSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import {
createState, settlePhysics, insideSolid, gooType, liveStrands,
} from '../src/games/gootower/GooTowerLogic.js';
import { autoPlay } from '../src/games/gootower/GooTowerAuto.js';
const __dirname = dirname(fileURLToPath(import.meta.url));
const outDir = process.argv[2] || join(__dirname, '..', 'assets', 'gamedata', 'gootower');
const SEED = process.argv[2] ? Number(process.argv[2]) >>> 0 : 0x600d1e;
const outDir = process.argv[3] || join(__dirname, '..', 'assets', 'gamedata', 'gootower');
const W = 1600;
const H = 1000;
const GROUND = 850;
// ── Seeded RNG (mulberry32) ─────────────────────────────────────────────────
function mulberry32(seed) {
let a = seed >>> 0;
return function rng() {
a = (a + 0x6d2b79f5) >>> 0;
let t = a;
t = Math.imul(t ^ (t >>> 15), t | 1);
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};
}
const lerp = (a, b, t) => a + (b - a) * t;
const clamp = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
const rect = (x1, y1, x2, y2, kind = 'solid') => ({ kind, poly: [[x1, y1], [x2, y1], [x2, y2], [x1, y2]] });
const ground = (top = GROUND) => rect(0, top, W, H);
// A loose heap of goo resting on a surface. Laid out in rows so the balls start
// apart -- dumping them on one spot just makes the collision solver do work.
function pile(type, n, x, surfaceY, { perRow = 8, gap = 30 } = {}) {
const out = [];
for (let i = 0; i < n; i += 1) {
const row = Math.floor(i / perRow);
const col = i % perRow;
out.push({ x: x + col * gap, y: surfaceY - 16 - row * 30, type });
}
return out;
}
// Side walls. EVERY template includes these: a heap that topples and rolls off
// the edge of the world loses goo before the player has touched anything, and
// it is always the top row of the heap that goes -- which is exactly where the
// scarce goo types sit.
const bounds = () => [rect(-30, 0, 6, H), rect(W - 6, 0, W + 30, H)];
// A small planted tripod: two pinned feet and a free apex, already triangulated
// so the player has something legal to attach to on frame one.
// A planted tripod: two pinned feet and a free apex, already triangulated so
// the player has something legal to attach to on frame one.
function footing(x, y, type = 'common') {
return {
balls: [
@ -50,255 +83,634 @@ function footing(x, y, type = 'common') {
};
}
const LEVELS = [];
// ── 1 ───────────────────────────────────────────────────────────────────────
{
const f = footing(771, GROUND - 14);
LEVELS.push({
level: 1, name: 'Ground Floor', chapter: 1,
tip: 'Drag goo from the heap onto the structure. Each ball needs two nearby friends to hold on to.',
terrain: [ground()],
...f,
pipe: { x: 771, y: 600, r: 46 },
pile: pile('common', 16, 980, GROUND),
required: 4, ocdTarget: 9,
});
// A heap of loose goo. `mix` is [[type, count], ...]. Laid out in rows and kept
// clear of `avoid` (the footing's x): goo that starts inside other goo is
// ejected hard enough to snap its own strands.
function heap(mix, startX, surfaceY, { perRow = null, gap = 30, avoid = null } = {}) {
const out = [];
const total = mix.reduce((n, [, c]) => n + c, 0);
// Wide and low: a tall narrow heap topples and spills. Roughly 3 rows.
const cols = perRow || clamp(Math.round(total / 3), 6, 14);
// Interleave the types. Laid out in blocks, the rarest goo ends up in the
// top row -- the row most likely to roll away.
const order = [];
const pools = mix.map(([type, count]) => ({ type, left: count }));
while (pools.some((p) => p.left > 0)) {
for (const p of pools) {
if (p.left > 0) { order.push(p.type); p.left -= 1; }
}
}
let i = 0;
for (const [, count] of [[null, order.length]]) {
for (let k = 0; k < count; k += 1, i += 1) {
const type = order[k];
const row = Math.floor(i / cols);
const col = i % cols;
out.push({ x: startX + col * gap, y: surfaceY - 16 - row * 30, type });
}
}
// Shift the WHOLE heap clear of the footing rather than nudging individual
// balls: nudging piles two columns onto each other, and overlapping goo is
// ejected hard enough to snap strands.
if (avoid != null && out.length) {
const lo = Math.min(...out.map((b) => b.x));
const hi = Math.max(...out.map((b) => b.x));
const clearL = avoid - 110;
const clearR = avoid + 110;
if (hi > clearL && lo < clearR) {
const shift = (lo + hi) / 2 < avoid ? clearL - hi : clearR - lo;
for (const b of out) b.x += shift;
}
}
return out.filter((b) => b.x > 30 && b.x < W - 30);
}
// ── 2 ───────────────────────────────────────────────────────────────────────
{
const f = footing(430, 686);
LEVELS.push({
level: 2, name: 'Mind the Gap', chapter: 1,
tip: 'Spikes below. Build ACROSS — triangles carry weight, long chains do not.',
terrain: [
rect(0, 700, 600, H),
rect(860, 700, W, H),
rect(600, 930, 860, H, 'spike'),
// Lip on the outer rim. Without it the heap spreads left, rolls off the
// edge of the world and the level quietly loses goo before the player
// has touched anything.
rect(0, 620, 40, 700),
const heapSize = (mix) => mix.reduce((n, [, c]) => n + c, 0);
// ── Templates ───────────────────────────────────────────────────────────────
// Each returns a level body. `d` is difficulty in 0..1 within its block.
// `gate` says how the load-bearing check should treat the featured element.
export const TEMPLATES = {
// Straight-up climb. The bread and butter.
tower(rng, d, mix) {
const x = Math.round(lerp(430, 860, rng()));
const climb = Math.round(lerp(200, 470, d));
const pileX = x + 260 < W - 300 ? x + 260 : x - 420;
return {
element: null, gate: 'none',
terrain: [ground(), ...bounds()],
...footing(x, GROUND - 14),
pipe: { x, y: GROUND - 68 - climb, r: 46 },
pile: heap(mix, clamp(pileX, 60, W - 300), GROUND, { avoid: x }),
tip: 'Brace as you go. An unbraced column leans, and once it leans it keeps leaning.',
};
},
// A spike pit to bridge.
bridge(rng, d, mix) {
const ledgeY = 700;
const gap = Math.round(lerp(190, 330, d));
const left = Math.round(lerp(560, 640, rng()));
const right = left + gap;
const fx = left - 190;
return {
element: null, gate: 'none',
terrain: [
...bounds(),
rect(0, ledgeY, left, H),
rect(right, ledgeY, W, H),
rect(left, 930, right, H, 'spike'),
rect(0, ledgeY - 90, 44, ledgeY),
rect(left - 44, ledgeY - 90, left, ledgeY),
],
...footing(fx, ledgeY - 14),
pipe: { x: right + 110, y: ledgeY - 60, r: 46 },
pile: heap(mix, 90, ledgeY, { perRow: 6, avoid: fx }),
waypoints: [{ x: (left + right) / 2, y: ledgeY - 95 }],
tip: 'Triangles carry weight across a gap. Long chains just sag into the spikes.',
};
},
// A slab overhead: come out from under it before climbing.
overhang(rng, d, mix) {
const fx = Math.round(lerp(470, 600, rng()));
const slabY = Math.round(lerp(620, 540, d));
const slabR = Math.round(lerp(740, 860, d));
return {
element: null, gate: 'none',
terrain: [ground(), ...bounds(), rect(260, slabY, slabR, slabY + 70)],
...footing(fx, GROUND - 14),
pipe: { x: slabR + 150, y: slabY - 60, r: 46 },
pile: heap(mix, slabR + 120, GROUND, { avoid: fx }),
waypoints: [{ x: slabR + 40, y: slabY + 20 }],
tip: 'You cannot build through rock. Come out from under it first.',
};
},
// Spiked ceiling: stop short of it.
ceiling(rng, d, mix) {
const x = Math.round(lerp(500, 900, rng()));
const ceilY = Math.round(lerp(340, 240, d));
return {
element: null, gate: 'none',
terrain: [ground(), ...bounds(), rect(clamp(x - 420, 0, W), ceilY, clamp(x + 420, 0, W), ceilY + 60, 'spike')],
...footing(x, GROUND - 14),
pipe: { x, y: ceilY + 165, r: 46 },
pile: heap(mix, clamp(x + 280, 60, W - 300), GROUND, { avoid: x }),
tip: 'The ceiling bites. Stop short of it.',
};
},
// An updraft that lightens everything inside it, so the span reaches further
// than bare goo could manage.
updraft(rng, d, mix) {
const ledgeY = 700;
const gap = Math.round(lerp(360, 470, d));
const left = 560;
const right = left + gap;
const fx = left - 190;
return {
element: 'fan', gate: 'enabling',
terrain: [
...bounds(),
rect(0, ledgeY, left, H),
rect(right, ledgeY, W, H),
rect(left, 930, right, H, 'spike'),
rect(0, ledgeY - 90, 44, ledgeY),
rect(left - 44, ledgeY - 90, left, ledgeY),
],
fans: [{
x: left, y: 260, w: gap, h: 660, dx: 0, dy: -1,
force: Math.round(lerp(1380, 1290, d)),
}],
...footing(fx, ledgeY - 14),
pipe: { x: clamp(right + 110, 0, W - 70), y: ledgeY - 60, r: 46 },
pile: heap(mix, 90, ledgeY, { perRow: 6, avoid: fx }),
waypoints: [{ x: (left + right) / 2, y: ledgeY - 120 }],
tip: 'The updraft takes weight off everything inside it. Spans reach further in the wind.',
};
},
// A turning cog in the way.
cogs(rng, d, mix) {
const fx = Math.round(lerp(280, 380, rng()));
const gx = Math.round(lerp(720, 820, rng()));
const omega = (rng() < 0.5 ? -1 : 1) * lerp(1.1, 2.0, d);
return {
element: 'gear', gate: 'obstructing',
terrain: [ground(), ...bounds()],
gears: [{
x: gx, y: Math.round(lerp(520, 450, d)),
r: Math.round(lerp(95, 125, d)), teeth: 9, omega,
}],
...footing(fx, GROUND - 14),
pipe: { x: Math.round(lerp(1160, 1290, d)), y: Math.round(lerp(620, 550, d)), r: 46 },
pile: heap(mix, 1000, GROUND, { perRow: 9, avoid: fx }),
tip: 'The cog is solid and it is turning. Whatever it touches gets dragged along.',
};
},
// Soft rock in the way, a fire pit beside it, bombs in the heap. The bomb is
// a SHORTCUT, never the only route -- a mechanic that is the sole solution is
// a level nobody can find their way through.
demolition(rng, d, mix) {
const fx = Math.round(lerp(360, 440, rng()));
const rockX = Math.round(lerp(680, 760, rng()));
const rockTop = Math.round(lerp(700, 640, d));
return {
element: 'bomb', gate: 'obstructing',
terrain: [
ground(), ...bounds(),
{ ...rect(rockX, rockTop, rockX + 80, GROUND), destructible: true },
rect(rockX - 110, GROUND - 44, rockX - 30, GROUND, 'fire'),
],
...footing(fx, GROUND - 14),
pipe: { x: Math.round(lerp(980, 1120, d)), y: 700, r: 46 },
pile: heap(mix, 120, GROUND, { perRow: 7, avoid: fx }),
waypoints: [{ x: rockX + 40, y: rockTop - 75 }],
tip: 'Drop a bomb by the fire and the soft rock goes with it. Or take the long way over.',
};
},
// A wall start: no ground worth building from, so goo that grips rock is the
// only way to begin.
cliff(rng, d, mix) {
const wallX = 300;
const startY = Math.round(lerp(600, 520, d));
return {
element: 'anchor', gate: 'enabling',
terrain: [
ground(), ...bounds(),
rect(wallX - 90, 180, wallX, 800),
rect(1200, 180, 1290, 800),
rect(wallX, 930, 1200, H, 'spike'),
// A shelf directly under the starting structure. Without it the heap
// sits on the ground far below a wall-mounted start, loose goo walks to
// the foot of the wall and can never climb, and the pipe drinks nothing.
rect(wallX, startY + 44, wallX + 300, startY + 120),
],
balls: [
{ x: wallX + 40, y: startY, type: 'pokey', pinned: true },
{ x: wallX + 40, y: startY - 62, type: 'pokey', pinned: true },
{ x: wallX + 98, y: startY - 31, type: 'common' },
],
strands: [[2, 0], [2, 1], [0, 1]],
pipe: { x: 1150, y: Math.round(lerp(460, 400, d)), r: 46 },
pile: heap(mix, wallX + 130, startY + 44, { perRow: 6 }),
waypoints: [{ x: 740, y: Math.round(lerp(450, 410, d)) }],
tip: 'Pokey goo grips bare rock and needs no friends. Start from the wall.',
};
},
// Pillars to anchor off on the way up.
pillars(rng, d, mix) {
const fx = 760;
const top = Math.round(lerp(360, 280, d));
return {
element: 'anchor', gate: 'none',
terrain: [ground(), ...bounds(), rect(420, top, 480, GROUND), rect(1040, top, 1100, GROUND)],
...footing(fx, GROUND - 14),
pipe: { x: fx, y: Math.round(lerp(420, 340, d)), r: 46 },
pile: heap(mix, 830, GROUND, { perRow: 6, avoid: fx }),
tip: 'Anchor goo sticks straight to rock. The pillars are fair game.',
};
},
};
// ── The curriculum ──────────────────────────────────────────────────────────
export const MIX = {
basic: [['common', 24]],
ivy: [['common', 18], ['ivy', 10]],
airy: [['common', 20], ['balloon', 6]],
windy: [['common', 22], ['balloon', 5], ['ivy', 4]],
works: [['common', 22], ['block', 8], ['bomb', 4]],
cog: [['common', 24], ['block', 8]],
sticky: [['pokey', 8], ['anchor', 5], ['common', 22]],
deep: [['common', 20], ['skull', 6], ['bit', 6], ['balloon', 4], ['block', 4]],
};
const CHAPTERS = [
{
id: 1,
name: 'The Rolling Hills',
blurb: 'Learn to build. Everything after this assumes you can.',
frozen: 6,
blocks: [
{ template: 'tower', count: 3, d0: 0.15, d1: 0.45, mix: 'basic' },
{ template: 'bridge', count: 3, d0: 0.10, d1: 0.40, mix: 'ivy' },
{ template: 'overhang', count: 3, d0: 0.10, d1: 0.45, mix: 'ivy' },
],
...f,
pipe: { x: 980, y: 640, r: 46 },
// perRow 7 keeps the heap clear of the footing at x=430; at 10 the last
// column landed 9px from a foot and the two were ejected apart on frame one.
pile: pile('common', 20, 150, 700, { perRow: 7 }),
required: 5, ocdTarget: 12,
});
}
// ── 3 ───────────────────────────────────────────────────────────────────────
{
// The footing sits UNDER the overhang, so the only way up is to walk the
// structure out sideways first. Keep the run short -- this is level 3, and
// an earlier draft asked for a 677px diagonal that nothing could build.
const f = footing(560, GROUND - 14);
LEVELS.push({
level: 3, name: 'Headroom', chapter: 1,
tip: 'You cannot build through the slab. Come out from under it first.',
terrain: [ground(), rect(300, 540, 820, 610)],
...f,
pipe: { x: 980, y: 470, r: 46 },
pile: pile('common', 24, 1020, GROUND, { perRow: 8 }),
required: 5, ocdTarget: 12,
});
}
// ── 4 ───────────────────────────────────────────────────────────────────────
{
const f = footing(331, GROUND - 14, 'common');
LEVELS.push({
level: 4, name: 'Second Thoughts', chapter: 1,
tip: 'Green ivy goo can be pulled back off and used again. Grey goo is there for good.',
terrain: [ground()],
...f,
// The heap must comfortably outlast the climb. An earlier draft gave
// exactly enough goo to REACH the pipe and nothing to feed it, so the
// level opened the pipe and was then unwinnable.
pipe: { x: 660, y: 560, r: 46 },
pile: [
...pile('ivy', 12, 540, GROUND, { perRow: 6 }),
...pile('common', 8, 860, GROUND, { perRow: 8 }),
names: ['Uphill', 'Higher Ground', 'The Long Climb',
'Across', 'Wider Still', 'The Drop',
'Under It', 'Round the Back', 'Out and Up'],
},
{
id: 2,
name: 'Windward',
blurb: 'Wind, balloons, and things that would rather float away.',
blocks: [
{ template: 'tower', count: 2, d0: 0.35, d1: 0.55, mix: 'airy', teach: true },
{ template: 'ceiling', count: 3, d0: 0.20, d1: 0.55, mix: 'airy' },
{ template: 'updraft', count: 4, d0: 0.10, d1: 0.55, mix: 'windy', teach: true },
{ template: 'bridge', count: 3, d0: 0.45, d1: 0.70, mix: 'windy' },
{ template: 'updraft', count: 3, d0: 0.55, d1: 0.85, mix: 'windy' },
],
required: 4, ocdTarget: 9,
});
}
// ── 5 ───────────────────────────────────────────────────────────────────────
{
const f = footing(791, GROUND - 14);
LEVELS.push({
level: 5, name: 'Overhead', chapter: 1,
tip: 'The ceiling bites. Stop short of it.',
terrain: [ground(), rect(400, 180, 1200, 240, 'spike')],
...f,
pipe: { x: 791, y: 340, r: 46 },
pile: pile('common', 18, 1000, GROUND, { perRow: 9 }),
required: 5, ocdTarget: 11,
});
}
// ── 6 ───────────────────────────────────────────────────────────────────────
{
const f = footing(791, GROUND - 14);
LEVELS.push({
level: 6, name: 'Tall Order', chapter: 1,
tip: 'A tower stands on compression and falls on sway. Brace every level.',
terrain: [ground()],
...f,
pipe: { x: 791, y: 180, r: 46 },
pile: pile('common', 26, 1020, GROUND, { perRow: 9 }),
required: 6, ocdTarget: 14,
});
}
// ── Sandbox tier (7-12) ─────────────────────────────────────────────────────
// One level per Wave 3 mechanic, so each can be played and judged on its own.
// This is THROWAWAY content, explicitly not the final curriculum -- Wave 4
// replaces it with a designed 5-chapter ramp.
// ── 7 · anchors ─────────────────────────────────────────────────────────────
{
const f = footing(780, GROUND - 14);
LEVELS.push({
level: 7, name: 'Anchors Aweigh', chapter: 2, sandbox: true,
tip: 'Brown anchor goo sticks straight to rock and needs no friends. Start a span from a wall.',
// Pillars must not stand BETWEEN the heap and the structure: loose goo
// walks along the ground, and a 550px wall is a wall.
terrain: [ground(), rect(400, 300, 460, GROUND), rect(1120, 300, 1180, GROUND)],
...f,
pipe: { x: 780, y: 400, r: 46 },
pile: [
...pile('anchor', 6, 860, GROUND, { perRow: 6 }),
...pile('common', 20, 860, GROUND - 30, { perRow: 6 }),
names: ['Light Head', 'Buoyant', 'Low Ceiling', 'Mind Your Head', 'Overhead',
'First Gust', 'Updraft', 'Riding the Wind', 'Thermals',
'Long Reach', 'The Wide Crossing', 'Windswept', 'Gale', 'Squall', 'Headwind'],
},
{
id: 3,
name: 'The Works',
blurb: 'Machinery. It does not care what you built.',
blocks: [
{ template: 'cogs', count: 4, d0: 0.10, d1: 0.55, mix: 'cog', teach: true },
{ template: 'tower', count: 2, d0: 0.55, d1: 0.75, mix: 'cog' },
{ template: 'demolition', count: 4, d0: 0.10, d1: 0.55, mix: 'works', teach: true },
{ template: 'cogs', count: 3, d0: 0.55, d1: 0.85, mix: 'works' },
{ template: 'overhang', count: 2, d0: 0.55, d1: 0.80, mix: 'works' },
],
required: 5, ocdTarget: 12,
});
names: ['First Cog', 'Gearworks', 'Clockwise', 'Widdershins', 'Rigid Thinking',
'Girders', 'Soft Rock', 'Demolition', 'Blast Radius', 'Controlled Burn',
'The Machine', 'Grinding Gears', 'Flywheel', 'Under the Works', 'Assembly'],
},
{
id: 4,
name: 'The Sticky Cliffs',
blurb: 'No ground worth standing on. Grip the rock.',
blocks: [
{ template: 'pillars', count: 3, d0: 0.10, d1: 0.45, mix: 'sticky', teach: true },
{ template: 'cliff', count: 4, d0: 0.10, d1: 0.50, mix: 'sticky', teach: true },
{ template: 'tower', count: 2, d0: 0.60, d1: 0.80, mix: 'sticky' },
{ template: 'cliff', count: 3, d0: 0.50, d1: 0.85, mix: 'sticky' },
{ template: 'bridge', count: 3, d0: 0.55, d1: 0.85, mix: 'sticky' },
],
names: ['Handhold', 'Two Pillars', 'Stepping Up', 'The Face', 'Sheer',
'Traverse', 'Grip', 'Overhanging', 'Cliffhanger', 'The Chimney',
'Freeclimb', 'The Notch', 'Crevasse', 'Exposure', 'Summit'],
},
{
id: 5,
name: 'Down the Deep',
blurb: 'Everything you have learned, all at once.',
blocks: [
{ template: 'ceiling', count: 3, d0: 0.60, d1: 0.90, mix: 'deep' },
{ template: 'updraft', count: 3, d0: 0.60, d1: 0.90, mix: 'deep' },
{ template: 'cogs', count: 3, d0: 0.65, d1: 0.95, mix: 'deep' },
{ template: 'demolition', count: 3, d0: 0.60, d1: 0.90, mix: 'deep' },
{ template: 'tower', count: 3, d0: 0.70, d1: 1.00, mix: 'deep' },
],
names: ['Descent', 'Low Roof', 'The Squeeze', 'Deep Wind', 'The Shaft',
'Downdraft', 'Deep Cogs', 'The Grinder', 'Millstone', 'Deep Rock',
'Cave-In', 'The Last Charge', 'The Long Way Up', 'Ascent', 'Out'],
},
];
// ── Gates ───────────────────────────────────────────────────────────────────
function cleanCheck(def) {
const st = createState(def);
for (const b of st.balls) {
if (insideSolid(st, b.x, b.y)) return 'goo starts inside terrain';
}
for (let i = 0; i < st.balls.length; i += 1) {
for (let j = i + 1; j < st.balls.length; j += 1) {
const a = st.balls[i];
const b = st.balls[j];
if (Math.hypot(b.x - a.x, b.y - a.y) < (a.r + b.r) * 0.6) return 'goo starts overlapping';
}
}
if (st.pipe.open) return 'pipe starts open';
settlePhysics(st, 10);
if (liveStrands(st).length !== st.strands.length) return 'a strand snaps on its own';
const lost = st.balls.filter((b) => b.dead);
if (lost.length) {
const kinds = [...new Set(lost.map((b) => b.type))].join('/');
return `goo dies before the player touches anything (${lost.length} ${kinds})`;
}
if (st.pile.length < def.ocdTarget) return 'not enough goo left for OCD';
return null;
}
// ── 8 · pokey (wall starts) ─────────────────────────────────────────────────
{
LEVELS.push({
level: 8, name: 'Sticking Point', chapter: 2, sandbox: true,
tip: 'Pokey goo grips rock. There is no ground here worth building from.',
terrain: [ground(), rect(240, 200, 320, 760), rect(1120, 200, 1200, 760)],
balls: [
{ x: 340, y: 560, type: 'pokey', pinned: true },
{ x: 340, y: 498, type: 'pokey', pinned: true },
{ x: 398, y: 530, type: 'common' },
],
strands: [[2, 0], [2, 1], [0, 1]],
pipe: { x: 1080, y: 430, r: 46 },
pile: [
...pile('pokey', 6, 620, GROUND, { perRow: 6 }),
...pile('common', 22, 620, GROUND - 30, { perRow: 8 }),
],
required: 5, ocdTarget: 12,
});
// A teaching level may not open with an instant-fail: nothing lethal within
// reach of the starting structure.
function gentleCheck(def) {
const st = createState(def);
const start = st.balls.filter((b) => b.attached);
for (const t of st.terrain) {
if (t.kind !== 'spike' && t.kind !== 'fire') continue;
for (const b of start) {
const bb = t.bounds;
const dx = Math.max(bb.minX - b.x, 0, b.x - bb.maxX);
const dy = Math.max(bb.minY - b.y, 0, b.y - bb.maxY);
if (Math.hypot(dx, dy) < 140) return 'a hazard sits on the doorstep';
}
}
return null;
}
// ── 9 · bombs, fire and destructible rock ───────────────────────────────────
{
const f = footing(400, GROUND - 14);
LEVELS.push({
level: 9, name: 'Demolition', chapter: 2, sandbox: true,
tip: 'Drop a bomb by the fire and the soft rock goes with it. Or take the long way over.',
terrain: [
ground(),
// Soft rock in the way -- blow it, or climb over. The fire sits BESIDE
// the rock at ground level, not on the climbing route: an earlier draft
// had it capping the rock, which made the bomb the only survivable way
// through and left the level unwinnable by ordinary building.
{ ...rect(700, 660, 780, GROUND), destructible: true },
rect(600, 806, 680, GROUND, 'fire'),
],
...f,
pipe: { x: 980, y: 700, r: 46 },
// Greedy will not climb a wall unprompted -- that means building away from
// the pipe first -- so route it over the top.
waypoints: [{ x: 740, y: 590 }],
pile: [
...pile('bomb', 4, 160, GROUND, { perRow: 4 }),
...pile('common', 24, 160, GROUND - 30, { perRow: 7 }),
],
required: 5, ocdTarget: 12,
});
// Strip the featured element; an "enabling" level must stop being winnable.
function loadBearingCheck(def, element) {
const stripped = JSON.parse(JSON.stringify(def));
if (element === 'fan') stripped.fans = [];
else if (element === 'anchor') {
stripped.pile = stripped.pile.filter((p) => !gooType(p.type).sticksToTerrain);
stripped.balls = stripped.balls.map((b) => (gooType(b.type).sticksToTerrain
? { ...b, type: 'common', pinned: false } : b));
} else return null;
const r = autoPlay(stripped, { maxBalls: 50, maxSeconds: 30 });
return r.won ? 'winnable without its own mechanic' : null;
}
// ── 10 · fans ───────────────────────────────────────────────────────────────
{
const f = footing(360, 686);
LEVELS.push({
level: 10, name: 'Updraft', chapter: 2, sandbox: true,
tip: 'The updraft takes weight off everything inside it. Spans reach further in the wind.',
terrain: [
rect(0, 700, 600, H),
rect(940, 700, W, H),
rect(600, 930, 940, H, 'spike'),
rect(0, 620, 40, 700),
],
fans: [{ x: 600, y: 300, w: 340, h: 630, dx: 0, dy: -1, force: 1150 }],
...f,
pipe: { x: 1060, y: 630, r: 46 },
pile: pile('common', 26, 120, 700, { perRow: 6 }),
required: 4, ocdTarget: 12,
});
// ── Build ───────────────────────────────────────────────────────────────────
const rng = mulberry32(SEED);
const levels = frozenLevels();
const stats = { tried: 0, rejected: {} };
const reject = (why) => { stats.rejected[why] = (stats.rejected[why] || 0) + 1; };
for (const chapter of CHAPTERS) {
let nameIdx = 0;
const wanted = 15 - (chapter.frozen || 0);
let made = 0;
for (const block of chapter.blocks) {
for (let k = 0; k < block.count && made < wanted; k += 1) {
const d = block.count > 1 ? lerp(block.d0, block.d1, k / (block.count - 1)) : block.d0;
const mix = MIX[block.mix];
let accepted = null;
for (let attempt = 0; attempt < 14 && !accepted; attempt += 1) {
stats.tried += 1;
// Jitter difficulty per attempt so retries actually differ.
const dd = clamp(d + (rng() - 0.5) * 0.12, 0, 1);
const body = TEMPLATES[block.template](rng, dd, mix);
const size = heapSize(mix);
const required = Math.round(lerp(4, 8, dd));
const ocdTarget = clamp(Math.round(lerp(required + 4, required + 9, dd)), required, size - 5);
const def = {
world: { w: W, h: H },
level: levels.length + 1,
name: chapter.names[nameIdx] || `${chapter.name} ${nameIdx + 1}`,
chapter: chapter.id,
tip: body.tip,
element: body.element || undefined,
terrain: body.terrain,
balls: body.balls,
strands: body.strands,
pile: body.pile,
pipe: body.pipe,
fans: body.fans,
gears: body.gears,
waypoints: body.waypoints,
required,
ocdTarget,
};
const dirty = cleanCheck(def);
if (dirty) { reject(dirty); continue; }
if (block.teach) {
const harsh = gentleCheck(def);
if (harsh) { reject(harsh); continue; }
}
const r = autoPlay(def, { maxBalls: 70, maxSeconds: 45 });
if (!r.won) { reject(`unwinnable (${r.pipeOpen ? 'pipe open' : 'pipe shut'})`); continue; }
if (body.gate === 'enabling') {
const weak = loadBearingCheck(def, body.element);
if (weak) { reject(weak); continue; }
}
accepted = def;
}
if (!accepted) {
// Never leave a hole in the curriculum: fall back to a plain tower at
// the same difficulty rather than shipping a 13-level chapter.
for (let attempt = 0; attempt < 10 && !accepted; attempt += 1) {
const dd = clamp(d * 0.8 + (rng() - 0.5) * 0.1, 0, 1);
const body = TEMPLATES.tower(rng, dd, mix);
const size = heapSize(mix);
const required = Math.round(lerp(4, 8, dd));
const def = {
world: { w: W, h: H },
level: levels.length + 1,
name: chapter.names[nameIdx] || `${chapter.name} ${nameIdx + 1}`,
chapter: chapter.id,
tip: body.tip,
terrain: body.terrain,
balls: body.balls,
strands: body.strands,
pile: body.pile,
pipe: body.pipe,
required,
ocdTarget: clamp(Math.round(lerp(required + 4, required + 9, dd)), required, size - 5),
};
if (cleanCheck(def)) continue;
if (!autoPlay(def, { maxBalls: 70, maxSeconds: 45 }).won) continue;
accepted = def;
}
if (accepted) reject(`fell back to tower (${block.template})`);
}
if (!accepted) {
console.warn(`\n[gen] ! ch${chapter.id} ${block.template} slot ${k} — no candidate survived`);
continue;
}
levels.push(accepted);
nameIdx += 1;
made += 1;
process.stdout.write(`\r[gen] ${levels.length} levels… `);
}
}
// Top-up: every chapter ships exactly fifteen. If the blocks came up short,
// fill the remainder with plain towers rather than a ragged chapter.
let guard = 0;
while (made < wanted && guard < 60) {
guard += 1;
const dd = clamp(0.3 + rng() * 0.4, 0, 1);
const mix = MIX[chapter.blocks[0].mix];
const body = TEMPLATES.tower(rng, dd, mix);
const size = heapSize(mix);
const required = Math.round(lerp(4, 8, dd));
const def = {
world: { w: W, h: H },
level: levels.length + 1,
name: chapter.names[nameIdx] || `${chapter.name} ${nameIdx + 1}`,
chapter: chapter.id,
tip: body.tip,
terrain: body.terrain,
balls: body.balls,
strands: body.strands,
pile: body.pile,
pipe: body.pipe,
required,
ocdTarget: clamp(Math.round(lerp(required + 4, required + 9, dd)), required, size - 5),
};
if (cleanCheck(def)) continue;
if (!autoPlay(def, { maxBalls: 70, maxSeconds: 45 }).won) continue;
levels.push(def);
nameIdx += 1;
made += 1;
reject('top-up tower');
process.stdout.write(`\r[gen] ${levels.length} levels… `);
}
}
// ── 11 · gears ──────────────────────────────────────────────────────────────
{
const f = footing(300, GROUND - 14);
LEVELS.push({
level: 11, name: 'Cogs', chapter: 2, sandbox: true,
tip: 'The cog is solid and it is turning. Anything it touches gets dragged along.',
terrain: [ground()],
gears: [{ x: 800, y: 470, r: 110, teeth: 9, omega: 1.4 }],
...f,
pipe: { x: 1240, y: 560, r: 46 },
pile: pile('common', 28, 1000, GROUND, { perRow: 9 }),
required: 5, ocdTarget: 13,
});
}
// ── 12 · balloons, blocks and bits ──────────────────────────────────────────
{
const f = footing(400, GROUND - 14);
LEVELS.push({
level: 12, name: 'Lighter Than Air', chapter: 2, sandbox: true,
tip: 'Balloons pull up, blocks hold rigid, bits are cheap and weak. Mix them.',
terrain: [ground()],
...f,
pipe: { x: 400, y: 300, r: 46 },
pile: [
...pile('balloon', 6, 700, GROUND, { perRow: 6 }),
...pile('block', 8, 700, GROUND - 34, { perRow: 8 }),
...pile('bit', 6, 700, GROUND - 68, { perRow: 6 }),
...pile('common', 18, 700, GROUND - 100, { perRow: 9 }),
],
required: 5, ocdTarget: 12,
});
}
// ── Emit ────────────────────────────────────────────────────────────────────
mkdirSync(outDir, { recursive: true });
const manifest = { version: 1, generatedAt: new Date(0).toISOString(), levels: [] };
for (const lv of LEVELS) {
const manifest = { version: 2, seed: SEED, levels: [] };
for (let i = 0; i < levels.length; i += 1) {
const lv = levels[i];
lv.level = i + 1;
const file = `level-${String(lv.level).padStart(3, '0')}.json`;
const body = { world: { w: W, h: H }, ...lv };
writeFileSync(join(outDir, file), `${JSON.stringify(body, null, 2)}\n`);
writeFileSync(join(outDir, file), `${JSON.stringify(lv, null, 2)}\n`);
manifest.levels.push({
level: lv.level, name: lv.name, chapter: lv.chapter, file,
required: lv.required, ocdTarget: lv.ocdTarget,
sandbox: lv.sandbox || undefined,
element: lv.element || undefined,
});
}
manifest.chapters = [
{ id: 1, name: 'The Goo Filled Hills', blurb: 'Learn to build.', from: 1, to: 6 },
{ id: 2, name: 'Sandbox', blurb: 'One level per mechanic — throwaway, replaced in Wave 4.', from: 7, to: LEVELS.length },
];
manifest.chapters = CHAPTERS.map((c) => {
const own = manifest.levels.filter((m) => m.chapter === c.id);
return {
id: c.id,
name: c.name,
blurb: c.blurb,
from: own.length ? own[0].level : 0,
to: own.length ? own[own.length - 1].level : 0,
};
}).filter((c) => c.from > 0);
writeFileSync(join(outDir, 'levels.json'), `${JSON.stringify(manifest, null, 2)}\n`);
console.log(`[gen] wrote ${LEVELS.length} levels + manifest to ${outDir}`);
console.log(`\n[gen] wrote ${levels.length} levels + manifest to ${outDir}`);
console.log(`[gen] ${stats.tried} candidates tried`);
for (const [why, n] of Object.entries(stats.rejected).sort((a, b) => b[1] - a[1])) {
console.log(`[gen] rejected ${String(n).padStart(4)} ${why}`);
}
// ── The frozen hand-tuned openers ───────────────────────────────────────────
// Emitted verbatim. These were authored as the teaching set; the generator must
// never rewrite them.
function frozenLevels() {
const out = [];
{
const f = footing(771, GROUND - 14);
out.push({
world: { w: W, h: H }, level: 1, name: 'Ground Floor', chapter: 1,
tip: 'Drag goo from the heap onto the structure. Each ball needs two nearby friends to hold on to.',
terrain: [ground()], ...f,
pipe: { x: 771, y: 600, r: 46 },
pile: heap([['common', 16]], 980, GROUND),
required: 4, ocdTarget: 9,
});
}
{
const f = footing(430, 686);
out.push({
world: { w: W, h: H }, level: 2, name: 'Mind the Gap', chapter: 1,
tip: 'Spikes below. Build ACROSS — triangles carry weight, long chains do not.',
terrain: [
rect(0, 700, 600, H), rect(860, 700, W, H), rect(600, 930, 860, H, 'spike'),
// Lip on the outer rim: without it the heap spreads left, rolls off the
// edge of the world and the level quietly loses goo.
rect(0, 620, 40, 700),
],
...f,
pipe: { x: 980, y: 640, r: 46 },
pile: heap([['common', 20]], 150, 700, { perRow: 7 }),
required: 5, ocdTarget: 12,
});
}
{
const f = footing(560, GROUND - 14);
out.push({
world: { w: W, h: H }, level: 3, name: 'Headroom', chapter: 1,
tip: 'You cannot build through the slab. Come out from under it first.',
terrain: [ground(), rect(300, 540, 820, 610)], ...f,
pipe: { x: 980, y: 470, r: 46 },
pile: heap([['common', 24]], 1020, GROUND, { perRow: 8 }),
required: 5, ocdTarget: 12,
});
}
{
const f = footing(331, GROUND - 14);
out.push({
world: { w: W, h: H }, level: 4, name: 'Second Thoughts', chapter: 1,
tip: 'Green ivy goo can be pulled back off and used again. Grey goo is there for good.',
terrain: [ground()], ...f,
pipe: { x: 660, y: 560, r: 46 },
pile: [
...heap([['ivy', 12]], 540, GROUND, { perRow: 6 }),
...heap([['common', 8]], 860, GROUND, { perRow: 8 }),
],
required: 4, ocdTarget: 9,
});
}
{
const f = footing(791, GROUND - 14);
out.push({
world: { w: W, h: H }, level: 5, name: 'Overhead', chapter: 1,
tip: 'The ceiling bites. Stop short of it.',
terrain: [ground(), rect(400, 180, 1200, 240, 'spike')], ...f,
pipe: { x: 791, y: 340, r: 46 },
pile: heap([['common', 18]], 1000, GROUND, { perRow: 9 }),
required: 5, ocdTarget: 11,
});
}
{
const f = footing(791, GROUND - 14);
out.push({
world: { w: W, h: H }, level: 6, name: 'Tall Order', chapter: 1,
tip: 'A tower stands on compression and falls on sway. Brace every level.',
terrain: [ground()], ...f,
pipe: { x: 791, y: 180, r: 46 },
pile: heap([['common', 26]], 1020, GROUND, { perRow: 9 }),
required: 6, ocdTarget: 14,
});
}
return out;
}

View File

@ -848,6 +848,25 @@ section('4g. Balloon, block, bit');
`${(GOO_TYPES.balloon.mass * -GOO_TYPES.balloon.buoyancy).toFixed(2)} ball-weights`);
check('balloon goo takes a single strand', GOO_TYPES.balloon.maxStrands === 1);
// Buoyancy is a property of ATTACHED goo only. Loose balloons that drift
// away take every balloon in a level's heap with them -- they float up,
// hit whatever ceiling the level has, and die before the player has
// touched anything, leaving the level unwinnable.
const heap = createState(baseLevel({
terrain: [ground(), { kind: 'spike', poly: [[300, 300], [1300, 300], [1300, 360], [300, 360]] }],
// Resting ON the ground: GROUND_Y here is 800, not the generator's 850.
pile: [
{ x: 600, y: GROUND_Y - 16, type: 'balloon' }, { x: 640, y: GROUND_Y - 16, type: 'balloon' },
{ x: 680, y: GROUND_Y - 16, type: 'common' },
],
}));
settle(heap, 12);
check('loose balloons stay in the heap', heap.balls.every((b) => !b.dead),
`${heap.balls.filter((b) => b.dead).length} floated off and died`);
check('loose balloons rest on the ground',
heap.balls.filter((b) => b.type === 'balloon').every((b) => b.y > GROUND_Y - 40),
heap.balls.filter((b) => b.type === 'balloon').map((b) => b.y.toFixed(0)).join(','));
// Block goo is stiffer, so the same span sags less.
const span = (type) => {
const balls = [{ x: 300, y: 300, type, pinned: true }];