Skip to content
SlashClone
Made by@gameforge

Level designer

@gameforge/level-designer

Design tile-grid game levels as plain JSON and check them with a validator: equal-width rows, known tiles, one start, an exit you can actually reach (keys and doors included), reachable coins, and a closed border. Writes a JSON report you can keep in CI.

SkillOtherv1.0.0 (latest)Tested
Activity
New: be the first to try it
  1. 1{
  2. 2 "name": "level-designer",
  3. 3 "owner": "gameforge",
  4. 4 "version": "1.0.0",
  5. 5 "type": "skill",
  6. 6 "description": "Design tile-grid game levels as plain JSON and check them with a validator: equal-width rows, known tiles, one start, an exit you can actually reach (keys and doors included), reachable coins, and a closed border. Writes a JSON report you can keep in CI.",
  7. 7 "category": "other",
  8. 8 "license": "MIT",
  9. 9 "compat": [
  10. 10 "claude-code"
  11. 11 ],
  12. 12 "permissions": {
  13. 13 "shell": [
  14. 14 "node scripts/validate-levels.mjs"
  15. 15 ],
  16. 16 "files": {
  17. 17 "read": [
  18. 18 "./levels/**"
  19. 19 ],
  20. 20 "write": [
  21. 21 "./levels/**",
  22. 22 "./out/**"
  23. 23 ]
  24. 24 }
  25. 25 },
  26. 26 "tests": {
  27. 27 "cases": [
  28. 28 {
  29. 29 "name": "accepts levels with a reachable exit, including behind a key and door",
  30. 30 "inputs": {
  31. 31 "levels/01.json": "{\"name\":\"1-1\",\"tiles\":[\"#######\",\"#S.C..#\",\"#.###.#\",\"#....E#\",\"#######\"]}\n",
  32. 32 "levels/02.json": "{\"name\":\"1-2\",\"tiles\":[\"#######\",\"#S..#E#\",\"#.#.#D#\",\"#K#...#\",\"#######\"]}\n"
  33. 33 },
  34. 34 "checks": [
  35. 35 {
  36. 36 "type": "command_exits_zero",
  37. 37 "command": "node scripts/validate-levels.mjs levels --report out/level-report.json"
  38. 38 },
  39. 39 {
  40. 40 "type": "output_matches_schema",
  41. 41 "path": "out/level-report.json",
  42. 42 "schema": {
  43. 43 "type": "object",
  44. 44 "required": [
  45. 45 "summary",
  46. 46 "levels"
  47. 47 ],
  48. 48 "properties": {
  49. 49 "summary": {
  50. 50 "type": "object",
  51. 51 "properties": {
  52. 52 "levels": {
  53. 53 "const": 2
  54. 54 },
  55. 55 "valid": {
  56. 56 "const": 2
  57. 57 },
  58. 58 "invalid": {
  59. 59 "const": 0
  60. 60 },
  61. 61 "warnings": {
  62. 62 "const": 0
  63. 63 }
  64. 64 }
  65. 65 }
  66. 66 }
  67. 67 }
  68. 68 }
  69. 69 ]
  70. 70 },
  71. 71 {
  72. 72 "name": "reports an unreachable exit, an uneven row, and a door with no key",
  73. 73 "inputs": {
  74. 74 "levels/walled.json": "{\"name\":\"walled\",\"tiles\":[\"#######\",\"#S.#.E#\",\"#..#..#\",\"#######\"]}\n",
  75. 75 "levels/ragged.json": "{\"name\":\"ragged\",\"tiles\":[\"#####\",\"#S.E#\",\"####\"]}\n",
  76. 76 "levels/locked.json": "{\"name\":\"locked\",\"tiles\":[\"######\",\"#S.DE#\",\"######\"]}\n"
  77. 77 },
  78. 78 "checks": [
  79. 79 {
  80. 80 "type": "command_exits_zero",
  81. 81 "command": "node scripts/validate-levels.mjs levels --report out/level-report.json --exit-zero"
  82. 82 },
  83. 83 {
  84. 84 "type": "output_matches_schema",
  85. 85 "path": "out/level-report.json",
  86. 86 "schema": {
  87. 87 "type": "object",
  88. 88 "properties": {
  89. 89 "summary": {
  90. 90 "type": "object",
  91. 91 "properties": {
  92. 92 "levels": {
  93. 93 "const": 3
  94. 94 },
  95. 95 "valid": {
  96. 96 "const": 0
  97. 97 },
  98. 98 "invalid": {
  99. 99 "const": 3
  100. 100 }
  101. 101 }
  102. 102 }
  103. 103 }
  104. 104 }
  105. 105 },
  106. 106 {
  107. 107 "type": "file_contains",
  108. 108 "path": "out/level-report.json",
  109. 109 "text": "no exit is reachable from the start"
  110. 110 },
  111. 111 {
  112. 112 "type": "file_contains",
  113. 113 "path": "out/level-report.json",
  114. 114 "text": "row 2 is 4 wide, expected 5"
  115. 115 },
  116. 116 {
  117. 117 "type": "file_contains",
  118. 118 "path": "out/level-report.json",
  119. 119 "text": "has a door (D) but no key (K)"
  120. 120 }
  121. 121 ]
  122. 122 },
  123. 123 {
  124. 124 "name": "flags an unreachable coin as a warning, not an error",
  125. 125 "inputs": {
  126. 126 "levels/coin.json": "{\"name\":\"coin\",\"tiles\":[\"########\",\"#S..E#C#\",\"########\"]}\n"
  127. 127 },
  128. 128 "checks": [
  129. 129 {
  130. 130 "type": "command_exits_zero",
  131. 131 "command": "node scripts/validate-levels.mjs levels/coin.json --report out/level-report.json"
  132. 132 },
  133. 133 {
  134. 134 "type": "file_contains",
  135. 135 "path": "out/level-report.json",
  136. 136 "text": "coin at row 1, column 6 cannot be reached"
  137. 137 }
  138. 138 ]
  139. 139 }
  140. 140 ]
  141. 141 }