Simple map editor

Author Mitja Felicijan <mitja.felicijan@gmail.com> 2026-02-18 19:29:08 +0100
Committer Mitja Felicijan <mitja.felicijan@gmail.com> 2026-02-18 19:29:08 +0100
Commit 201bbf3e917066fb05ff1f10f7166d262b8ed2cf (patch)
-rw-r--r-- mapeditor.html 100
1 files changed, 35 insertions, 65 deletions
diff --git a/mapeditor.html b/mapeditor.html
...
6
    <title>ASCII Map Editor</title>
6
    <title>ASCII Map Editor</title>
7
    <style>
7
    <style>
8
      :root {
8
      :root {
9
        color-scheme: light;
9
        --gridline: rgba(0, 0, 0, 0.15);
10
        --gridline: rgba(0, 0, 0, 0.1);
  
11
        --mono: "SFMono-Regular", Menlo, Consolas, monospace;
10
        --mono: "SFMono-Regular", Menlo, Consolas, monospace;
12
      }
  
13
  
  
14
      * {
  
15
        box-sizing: border-box;
  
16
      }
11
      }
17
  
12
  
18
      body {
13
      body {
19
        margin: 0;
14
        margin: 0;
20
        font-family: system-ui, sans-serif;
15
        font-family: system-ui, sans-serif;
21
        background: #f5f5f5;
  
22
        color: #222;
  
23
        height: 100vh;
16
        height: 100vh;
24
        overflow: hidden;
17
        overflow: hidden;
25
        display: flex;
18
        display: flex;
...
27
      }
20
      }
28
  
21
  
29
      header {
22
      header {
30
        padding: 16px 20px 8px;
23
        padding: 12px 16px 8px;
31
      }
24
      }
32
  
25
  
33
      header h1 {
26
      header h1 {
34
        margin: 0 0 6px;
27
        margin: 0 0 4px;
35
        font-size: 1.2rem;
28
        font-size: 1rem;
36
      }
29
      }
37
  
30
  
38
      header p {
31
      header p {
39
        margin: 0;
32
        margin: 0;
40
        color: #555;
  
41
      }
33
      }
42
  
34
  
43
      .layout {
35
      .layout {
44
        display: grid;
36
        display: grid;
45
        grid-template-columns: 280px 1fr;
37
        grid-template-columns: 280px 1fr;
46
        gap: 16px;
38
        gap: 12px;
47
        padding: 0 20px 20px;
39
        padding: 0 16px 16px;
48
        flex: 1;
40
        flex: 1;
49
        min-height: 0;
41
        min-height: 0;
50
      }
42
      }
51
  
43
  
52
      .panel,
44
      .panel,
53
      .grid-wrap {
45
      .grid-wrap {
54
        background: #fff;
46
        border: 1px solid #ccc;
55
        border: 1px solid #ddd;
47
        padding: 8px;
56
        border-radius: 6px;
  
57
        padding: 12px;
  
58
        overflow: auto;
48
        overflow: auto;
59
        min-height: 0;
49
        min-height: 0;
60
      }
50
      }
61
  
51
  
62
      .panel h2 {
52
      .panel h2 {
63
        font-size: 0.9rem;
53
        font-size: 0.9rem;
64
        margin: 0 0 10px;
54
        margin: 0 0 8px;
65
      }
55
      }
66
  
56
  
67
      .controls {
57
      .controls {
68
        display: grid;
58
        display: grid;
69
        gap: 12px;
59
        gap: 10px;
70
      }
60
      }
71
  
61
  
72
      .control-group {
62
      .control-group {
73
        display: grid;
63
        display: grid;
74
        gap: 8px;
64
        gap: 8px;
75
        padding-bottom: 8px;
  
76
        border-bottom: 1px solid #eee;
  
77
      }
  
78
  
  
79
      .control-group:last-child {
  
80
        border-bottom: 0;
  
81
        padding-bottom: 0;
  
82
      }
65
      }
83
  
66
  
84
      .row {
67
      .row {
85
        display: flex;
68
        display: flex;
86
        align-items: center;
69
        align-items: center;
87
        justify-content: space-between;
  
88
        gap: 8px;
70
        gap: 8px;
89
      }
71
      }
90
  
72
  
91
      .palette {
73
      .palette {
92
        display: grid;
74
        display: grid;
93
        grid-template-columns: repeat(4, 1fr);
75
        grid-template-columns: repeat(4, 1fr);
94
        gap: 6px;
76
        gap: 4px;
95
      }
77
      }
96
  
78
  
97
      .tile-btn {
79
      .tile-btn {
98
        border: 1px solid #ccc;
80
        padding: 4px 0;
99
        border-radius: 4px;
  
100
        padding: 6px 0;
  
101
        background: #f7f7f7;
  
102
        font-family: var(--mono);
81
        font-family: var(--mono);
103
        cursor: pointer;
  
104
      }
  
105
  
  
106
      .tile-btn.active {
  
107
        outline: 2px solid #2b7fff;
  
108
        border-color: #2b7fff;
  
109
      }
82
      }
110
  
83
  
111
      .button {
84
      .button {
112
        background: #2b7fff;
85
        padding: 4px 8px;
113
        color: #fff;
  
114
        border: none;
  
115
        border-radius: 4px;
  
116
        padding: 6px 10px;
  
117
        cursor: pointer;
  
118
      }
  
119
  
  
120
      .button.secondary {
  
121
        background: #fff;
  
122
        color: #222;
  
123
        border: 1px solid #ccc;
  
124
      }
86
      }
125
  
87
  
126
      input[type="range"] {
88
      input[type="range"] {
...
129
  
91
  
130
      .stat {
92
      .stat {
131
        font-family: var(--mono);
93
        font-family: var(--mono);
132
        color: #2b7fff;
  
133
        font-size: 0.85rem;
  
134
      }
94
      }
135
  
95
  
136
      #gridCanvas {
96
      #gridCanvas {
137
        display: block;
97
        display: block;
138
        background: #fff;
  
139
        border: 1px solid #ddd;
  
140
        image-rendering: pixelated;
98
        image-rendering: pixelated;
141
        cursor: crosshair;
99
        cursor: crosshair;
142
      }
100
      }
143
  
101
  
144
      .footer-note {
102
      .footer-note {
145
        color: #666;
  
146
        font-size: 0.85rem;
103
        font-size: 0.85rem;
147
      }
104
      }
148
  
105
  
...
154
    </style>
111
    </style>
155
  </head>
112
  </head>
156
  <body>
113
  <body>
157
    <header>
114
    <header></header>
158
      <h1>ASCII Map Editor</h1>
  
159
      <p>Paint tiles directly onto the grid. Export keeps the same text layout as your map files.</p>
  
160
    </header>
  
161
    <div class="layout">
115
    <div class="layout">
162
      <aside class="panel">
116
      <aside class="panel">
163
        <h2>Tools</h2>
117
        <h2>Tools</h2>
...
211
            </div>
165
            </div>
212
            <div class="footer-note" id="status">Loaded maps/map1.txt</div>
166
            <div class="footer-note" id="status">Loaded maps/map1.txt</div>
213
          </div>
167
          </div>
214
          <div class="control-group">
  
215
            <div class="footer-note">
  
216
              Paint: click or drag. Hold Shift for straight lines. Shortcut: 1-4 to pick tile.
  
217
            </div>
  
218
          </div>
  
219
        </div>
168
        </div>
220
      </aside>
169
      </aside>
221
      <main class="grid-wrap" id="gridWrap">
170
      <main class="grid-wrap" id="gridWrap">
...
240
        "╝",
189
        "╝",
241
        "═",
190
        "═",
242
        "║",
191
        "║",
  
192
        "0",
  
193
        "1",
  
194
        "2",
  
195
        "3",
  
196
        "4",
  
197
        "5",
  
198
        "6",
  
199
        "7",
  
200
        "8",
  
201
        "9",
243
        "#",
202
        "#",
244
        ".",
203
        ".",
245
        "~",
204
        "~",
...
259
        "S": "Red",
218
        "S": "Red",
260
        "G": "Red",
219
        "G": "Red",
261
        "$": "Gold",
220
        "$": "Gold",
  
221
        "0": "Cyan",
  
222
        "1": "Cyan",
  
223
        "2": "Cyan",
  
224
        "3": "Cyan",
  
225
        "4": "Cyan",
  
226
        "5": "Cyan",
  
227
        "6": "Cyan",
  
228
        "7": "Cyan",
  
229
        "8": "Cyan",
  
230
        "9": "Cyan",
262
        " ": "Void",
231
        " ": "Void",
263
        "┌": "Border corner",
232
        "┌": "Border corner",
264
        "┐": "Border corner",
233
        "┐": "Border corner",
...
321
        if ("#┌┐└┘─│╔╗╚╝═║".includes(tile)) return "wall";
290
        if ("#┌┐└┘─│╔╗╚╝═║".includes(tile)) return "wall";
322
        if (tile === ".") return "floor";
291
        if (tile === ".") return "floor";
323
        if (tile === "~") return "water";
292
        if (tile === "~") return "water";
  
293
        if ("0123456789".includes(tile)) return "cyan";
324
        if (tile === "N") return "cyan";
294
        if (tile === "N") return "cyan";
325
        if ("BSG".includes(tile)) return "red";
295
        if ("BSG".includes(tile)) return "red";
326
        if (tile === "$") return "gold";
296
        if (tile === "$") return "gold";
...