Text Mapper

Text Mapper is a web app to quickly generate a map based on a textual description of the map. The result is an SVG file and therefore scalable.

There’s a Mastodon bot posting maps: @textmapper!

The source is available.

2021-09-01 Hex Describe and Text Mapper get their own repositories

It’s dark outside, clouds prevent the moon from reaching me. I sit in front of the glowing laptop and type and type and type. Bad posture. Bad posture.

I’m excited. I tried to explain to somebody how to run their own instances of Hex Describe and Text Mapper, and it got so complicated that I realized: this is not good. Both are part of a repository called Hex Mapping. It contains many of my earlier experiments. It’s a mess. It grew over time. It grew over a long time. A really long time. Yikes!

So I’ve started moving both of them to separate repositories, with infrastructure that makes it possible to submit them to CPAN. This means that installing them will install all their dependencies, too. They have separate README files explaining the dependencies and the config file.

I feel better already. 😁

The Face Generator already has its own repository.

Comments on 2021-09-01 Hex Describe and Text Mapper get their own repositories

I think I fixed the last few issues for the new Hex Describe and Text Mapper applications – and I deployed them on my server. If you notice anything that’s wrong, let me know.

– Alex 2021-09-02 14:49 UTC

Add Comment

2021-03-18 Hekadungeon using Text Mapper

The Gridmapper algorithm for Text Mapper to generate small dungeons was based on the blog post The Nine Forms of the Five Room Dungeon, by Matthew J. Neagley, which I then extended to 7-room dungeons, and then I added the combination of the two, which led to 10 (5+5), 12 (5+7), and 14 (7+7) room dungeons. It worked surprisingly well, see 2019-10-09 Ten random dungeons generated, and 2019-08-23 Gridmapper inside Text Mapper. It definitely worked better than the failed Megadungeon project I was working on a long time ago. Reload it a few times until you more than just one level and then click on the last image to open it in Gridmapper.

A few days ago I started wondering whether I could scale that up… and it turns out that I can!

Here’s an example with 200 rooms. It definitely needs fewer entrances – and the latest version of Text Mapper does that, of course. See 200 rooms.

Dungeon map with 200 rooms

Comments on 2021-03-18 Hekadungeon using Text Mapper

This is really great! I like the shape of these dungeons better than the random results I tend to get out of e.g. donjon.sh. And editing the results in Gridmapper is fantastic!

I’m confused about one thing – does this ever generate multi-level dungeons? You seem to imply so in your post, but I haven’t seen it do so.

acodispo 2021-03-22 20:33 UTC

Sadly it does not. I keep thinking about it, though…

– Alex 2021-03-22 20:54 UTC

Right now the problem is that text mapper doesn’t have a Z axis. Maybe it should. Then we could generate an overworld and an underworld that lines up.

– Alex 2021-03-23 07:51 UTC

The more I think about it the better I like it. But how to show this? It would probably have to be a new “page” and that’s not how SVG works. Just appending the second map below the first one might work, though. Hm.

– Alex 2021-03-23 08:45 UTC

For what it’s worth: when I was checking to see if it would do multiple levels, I assumed that I would see the 2nd level below the first on the page, as you suggest. This is probably intuitive! And I think it would work for the way Hex Describe uses these dungeon maps?

Me, I think I’m always going to open the maps in Gridmapper, edit to my liking, and then export in the format I need whether for online play, web display, or printing. I can stitch together multiple levels if I need to create multi-level dungeons.

I wish I knew more about how to work with SVG in this way. I’ve been making an attempt to add “modal GM notes” to Gridmapper and don’t quite have the chops for it! 😀

acodispo 2021-03-24 14:51 UTC

You mean, like those notes for cells in spreadsheet software, one corner is red or something, and if you hover over it, whatever you wrote there pops up?

– Alex 2021-03-24 20:05 UTC

That’s an idea I hadn’t thought of for UI! I was thinking of expanding Gridmapper’s labels. Specifically the behavior where when you type ' while the cursor is on an existing label, the label’s text pops up for editing.

So the GM note behavior would be similar to that, but:

  1. The content of the GM note isn’t displayed on the map, there’s a stand-in symbol. Perhaps +.
  2. When you type e.g. + while the cursor is over a + on the map, that note’s content is placed into an editing box. If there is no existing note, then a new one is created (just like a label).
  3. The editing area for notes is a larger textarea. (I was considering simply using the existing export/import box for this.)

The idea is that I like to put as much data about dungeon contents onto the map itself as possible (so I don’t have to reference a separate room key during play), but using labels can be a bit cumbersome depending on the amount of content. Being able to store longer notes that don’t get displayed on the map would help with this.

I’m fiddling with it off and on but haven’t made much progress! 😀

acodispo 2021-03-25 14:23 UTC

Add Comment

2021-01-30 Traveller Subsector Description

On paper, it’s a match made in heaven: Traveller subsector generation, a well established practice, easily translated into a program, and I implemented it once or twice. Once such app is hosted on Campaign Wiki. It was based on Mongoose Publishing’s Traveller 1st ed., because that’s what I was using at the time. Then somebody asked for Classic Traveller, and then somebody else asked for the Merchant Princes extension. Sure, why not.

The problem is that the map is based on the Universal World Profile (UWP) list, and the UWP list is pretty austere. When running a game, the information can be used to infer some information, but it takes some familiarity. It’d be great if we could “expand” these codes into something that can be used at the table. And by that I don’t mean to say that we should expand the following to “Starport class A, 3200km diameter, no atmosphere, no water, a few ten thousand people, representative republic, weapons of a strict military nature are forbidden (machine guns, automatic rifles).” The trade codes are derived from the numbers given. In the example I’ve been using, those dry stats result in the trade goods “high Tech, non-industrial, vacuum.”

And of course, there are the bases and the presence of gas giants: in the example given, we have “an imperial consulate, an establishment by the Travellers’ Aid Society (TAS), a naval base, and a gas giant.”

Sogeeran          0502 A200443-14  CT N G  Ht Ni Va
                       ||||||| |    |
Ag Agricultural        ||||||| |    Bases     In Industrial
As Asteroid            ||||||| +- Tech        Lo Low Population
Ba Barren              ||||||+- Law           Lt Low Technology
De Desert              |||||+- Government     Na Non-Agricultural
Fl Fluid Oceans        ||||+- Population      Ni Non-Industrial
Ga Garden              |||+- Hydro            Po Poor
Hi High Population     ||+- Atmosphere        Ri Rich
Ht High Technology     |+- Size               Va Vacuum
Ic Ice-Capped          +- Starport            Wa Water World

Bases: Naval – Scout – Research – TAS – Consulate – Pirate – Gas Giant

All of that we could surely turn into a “hex description” … but I had a problem: Hex Describe doesn’t parse the UWP – it parses the output of Text Mapper. So either I had to adapt Hex Describe so it parses the UWP of my Traveller Subsector Generator (and other UWP generators), or I’d change Text Mapper to produce output I could use in Hex Describe.

I chose the second option: Text Mapper already has various algorithms, and I already had an experimental “Stars” algorithm based on some Stars Without Numbers ideas, but it hadn’t gone anywhere. I started making another effort.

It is all work in progress, but here’s the current state of affairs.

Text Mapper now has an algorithm for subsector generation, based on Classic Traveller. As I wrote previously, I have bought all this old stuff on PDF. So now I’m using the info in The Traveller Book (TTB) and in Merchant Prince (MP). Ironically, the Traveller Subsector Generator I linked to above also generates Sector maps. 🙄 The code in Text Mapper does not. Furthermore, the Traveller Subsector Generator also generates multiple colour-coded “spheres of influence” with their own “languages”. The current Text Mapper code does not. The current Text Mapper code also doesn’t generate the kind of routes I’m looking for, but I’m going to work on it.

With that in place, I could turn to Hex Describe, at last. I started a new proof of concept set of random tables, beginning with starports. I went back to Text Mapper and tweaked the output so that the textual representation of the map also included suitable tokens for Hex Describe (such as “starport-A”) which I could then refer to. And soon I was really into it. A starport must have some buildings that indicate the presence of fuel tanks and refineries, shipyards where new ships can be constructed, dockyards where ships can be unloaded, landing panels, names of companies involved, a building for the administration, be it a harbour master or a toll station, security, and so on. And all of those need new tables!

If you want to give it a try:

  • visit the Hex Describe site
  • click the link to load random Traveller data (which gets the from Text Mapper)
  • click the radio button to use the Traveller tables
  • click the submit button at the very end

Better routes is done! I indicate good trade routes based on what it says in Merchant Prince. The text description is a bunch of paragraphs like the following but I’m just using the table on page 37: if there’s a positive modifier, it’s a trade route, independent of direction, for distances 1–2.

Agricultural: The world has climate and conditions which allow extensive farming and ranching. It is a producer of relatively inexpensive foodstuffs. Agricultural goods market well t o worlds which cannot produce their own agricultural goods (Desert, Fluid Seas, Poor, Water Worlds, lndustrial Worlds). Agricultural worlds are good markets for goods from lndustrial worlds, other Agricultural worlds, Barren worlds (for new plant and animal strains), and Rich worlds.

I also connect all the class A starports and navy bases. I remember working out that minimal spanning tree based on a Wikipedia article. What a nightmare! But I still use it, so it was time well spent!

Things I want to work on: more tables. Things I’d like to add is naming the actual products for sale. I’d like to have a table that generates actual ships, with crew and loads. I’d like to have a character generator. I’d like to have a patron generator. I’d like to have plot ideas using the above. “Find the Blue Heron and bring it back. They’ve been missing their payments.” Whatever. Start simple, as always. 😇

I also need to get the name and UWP from the map into the hex description itself. Some more programming required, I guess.

If you want to help out, here’s how to do it:

  • get a copy of the tables (see above)
  • make changes
  • return to Hex Describe
  • click the link to load random Traveller data (which gets the from Text Mapper)
  • click the radio button to “only use the data provided below”
  • paste your modified tables into the text area
  • click the submit button at the very end
  • send me the modified file by mail

Or just work out your own random tables.

Comments on 2021-01-30 Traveller Subsector Description

Adding a little bit more to system descriptions. Adding random ships (no details, yet), naming captains. So much stuff to think about: randomly equipping ships, randomly creating non-player characters for crews.

– Alex 2021-01-31 21:52 UTC

Working on crews:

The Rose Crane is a type A free trader (200t, streamlined). The pilot of this ship is Sisika. A76376. Vacc Suit-1 Pilot-1. The engineer is Kusakawa Masuo. 8958B8. Electronics-1 Medical-1 Engineer-2. The medic is Eguchi Kotomi. 5BA875. Gunnery-1 Medic-4. The steward is Kalila Shariq. 979A96. Jack-o-T-1 Vacc Suit-1 Steward-1.

I like it!

– Alex 2021-02-01 21:17 UTC

Add Comment

2020-10-10 Adding rivers to the post-apocalyptic maps

Still unsure about the colour of rivers but there are now rivers in the post-apocalyptic maps. As this map algorithm doesn’t have an underlying height model (unlike the Alpine maps), the river flow is much more random:

  • every mountain is a source, every swamp is a sink (this is where all rivers end)
  • no rivers flow into mountains or into deserts
  • rivers merge if they run into each other
  • rivers never flow off the map

For such a simplistic algorithm, it doesn’t even look so bad!

Image 1


Add Comment

2020-08-28 New Text Mapper feature: map size adjustments

Eric Scheid sent me some feedback regarding Text Mapper and we ended up talking about a new feature to add or trim rows and columns to the map. Until now, adding rows at the top and columns at the left was a problem: you had to do some clever search and replace operations using your text editor if you wanted to do it.

Now, there are more options available to you: below the “Generate Map” button there’s now the following

Add (or remove if negative) rows or columns: top _ left _ right _ bottom _ add empty [ ]

And it seems to work! We’re still testing it, but if you notice something amiss, let me know.

Some strange things that I’m aware of:

  • if you add or remove an odd number of columns on the left, you’re going to change how the columns stack – not too much of a problem, I think, but probably surprising!
  • if you remove rows or columns containing “lines” (rivers, trails, roads), then those stay if they’re not entirely outside the map – meaning that they can now potentially extend beyond the edges of the map if you trimmed some of the regions these passed through and you’ll have to trim them yourself

Feel free to share links to your maps in the comments. I always love to see them.

If you don’t know what Text Mapper can be used for, check out the @textmapper bot. It posts a new map every week.

Add Comment

2020-05-01 Island map generator and Text Mapper

OK, I’ve added code to my J program to print the map in Text Mapper format to stdout so that I can start taking a look at it. I added printing of a Text Mapper compatible output to my script... And I know how to generate the SVG from the command line... OK, let’s try!

The file I’m working on in JQt can be run from a terminal emulator.

jconsole '~user/temp/2.ijs'

To URL-encode the output, more or less:

jconsole '~user/temp/2.ijs'
| perl -p -e 's/ +$//ge;' -e 's/([^a-zA-Z0-9_.!~()-])/sprintf("%%%02X",ord($1))/ge'

So let’s store that in a variable:

map=$( \
  jconsole '~user/temp/2.ijs' \
  | perl -p -e 's/ +$//ge;' \
            -e 's/([^a-zA-Z0-9_.!~()-])/sprintf("%%%02X",ord($1))/ge')

This is what the viewer shows us:

Image 1

And now to call Text Mapper from the command line:

perl src/hex-mapping/text-mapper.pl get \
  --header 'Content-Type:application/x-www-form-urlencoded' \
  --method POST --content "map=$map&type=square" /render \
  2>/dev/null \
  > test.svg

Convert the SVG to PNG:

inkscape --without-gui --file=test.svg --export-png=test.png

There you go:

Image 2

Looks like the J preview does not use quite the same colours. Perhaps because of auto-scaling?

Also, hex maps. Different, of course, but still islands. Strangely familiar, but also … wrong … I think? In some weird way? If you don’t know the map using squares, it’s OK. But now that you do, it’s hard to think of this as some sort of torn land. Was there an earth quake that split of this little island on the right?

Image 3

I think what I can also say right now is that I need to work on the colour palette.

Here’s an image of the Galapagos, thanks to the visible earth project at NASA).


Here’s an image of Hawaii, thanks to the visible earth project at NASA).


I’m not sure I want to use these colours but clearly my impression on the ground on Seymore, where I felt everything was black or brown or rusty red does not match these green images from space.

I need to think about this some more.

Source Code

I really need to put it into a repository. 🙂

mx =: 30
my =: 20

NB. a table of complex numbers
c =: (i. my) j./ i. mx

NB. starting position of the hotspot
hr =: 5
hy =: >. hr % 2
hx =: <. 0.5 + (my % 3) + ? <. 0.5 + my % 3
hc =: hx j. hy

NB. a function to compute altitude changes based on where the hotspot is
change =: 3 : 0
  h =. hr > {. & *. c - y     NB. hotspot = 1
  u =. 0.8 < ? (my, mx) $ 0  NB. regions atop the hotspot might move up
  d =. 0.9 < ? (my, mx) $ 0  NB. regions off the hotspot might move down
  (u * h) - d * -. h

NB. a biased list of steps to take
d =: _1j1 1j1 0j1 0j1 0j1

NB. a table of altitudes
a =: (my, mx) $ 0

NB. compute the meandering path of the hotspot across the map
NB. compute the change for each step and add it to the altitude
NB. no negative values
3 : 0''
for. i. mx - 2  * hr do.
  hc =: hc+(?#d){d
  a =: 0 & >. a + change hc

NB. print map for text-mapper
colors =: ('ocean', 'water', 'sand', 'dark-soil', 'soil', 'green', 'dark-green',: 'grey')
3 : 0''
for_i. i. my do.
  for_j. i. mx do.
    color =. (j { i { a) { colors
    smoutput (>'r<0>2.d' 8!:0 j) , (>'r<0>2.d' 8!:0 i) , ' ', color
smoutput 'include https://campaignwiki.org/contrib/gnomeyland.txt'

NB. display map for visuals
decimal =:16"_#.'0123456789abcdef'"_ i.]

rgb =: 3 : 0
  n =. decimal }. y     NB. strip leading #
  (<.n % 65536), ((<.n % 256) |~ 256), (n |~ 256)
ocean  =: rgb '#1c86ee' NB. 0
water  =: rgb '#6ebae7' NB. 1
sand   =: rgb '#e3bea3' NB. 2
dry    =: rgb '#c97457' NB. 3
nice   =: rgb '#b0b446' NB. 4
green  =: rgb '#77904c' NB. 5
humid  =: rgb '#2d501a' NB. 6
rocky  =: rgb '#dcddbe' NB. 7
colors =: (ocean, water, sand, dry, nice, green, humid,: rocky)

load 'viewmat'
colors viewmat a
exit 0


Add Comment

2019-10-21 Metainformation for an image

Recently, asked me whether it was possible to get from a dungeon map in Hex Describe to an editable map in Gridmapper. There wasn’t, but I liked the idea and so I started thinking about it. It should be doable in theory even though I am generating the dungeon maps using Text Mapper and all they have in common with Gridmapper maps is that they look similar.

So yesterday I started writing the code that transforms the Text Mapper data into a Gridmapper link. Once I could see it in the log output, I was happy. But what next?

I decided to add a HTTP header with that link, hoping that Hex Describe would be able to extract it, and I told J. Alan Henning that I had these instructions for him:

  1. generate map using Hex Describe
  2. use View Image to look at a dungeon map
  3. use Inspect Element to get to the development tools
  4. switch to the Network tab
  5. click the Reload button
  6. click on the new request line to see details
  7. in the Headers tab, there’s a section called Response headers
  8. in that list there’s a header called X-Link
  9. the value of that header is the Gridmapper link

It was late, I was tired, and I needed to sleep, obviously. 🙂

As the rendered image uses the SVG format, I alread had the input used in a comment at the end. Therefore, the link I just mentioned can be found right there. The X-Link code I had written was unnecessary and I removed it.

The instructions were in fact much simpler!

  1. generate map using Hex Describe
  2. use View Image to look at a dungeon map
  3. use View Page Source to look at the SVG code
  4. scroll to the end until you see the Gridmapper link

But then I realized that I could simply add the information the SVG output as a link! Within Hex Describe it’s hard to spot the link. It’s tiny:

Hex Describe output with link

If you use View Image, however, it gets bigger:

View Image

(If you click the image above, you might get taken to a different image because the seed I used is only guaranteed to work for as long as the code doesn’t change. My guess is that this won’t be stable for long!)

If you click the link in the top left corner, you’re taken to Gridmapper:

Image 3

I also need a way to add nice arrows to images using Gimp. Surely there is a better way!


Comments on 2019-10-21 Metainformation for an image

I was playing with Gridmapper the other day and was wondering about Switch Background and Toggle Floor commands. I couldn’t figure them out. Any hints?

– Ruprecht 2019-10-30 19:02 UTC

The Switch Background command (capital Z) toggles between various background options:

  • grey background (the default)
  • black background
  • white background
  • white background with grid
  • blue

The Toggle Floor command (hold Alt and use the arrow keys to move around) simply toggles the floor on or off. In other words, it’s the equivalent of pressing f and and arrow key repeatedly – it’s simply faster.

– Alex Schroeder 2019-10-30 22:46 UTC

Add Comment

2019-10-09 Ten random dungeons generated

With the random tables of J. Alan Henning and ktrey parker and Text Mapper with the Gridmapper algorithm (which knows how to create five room and seven room dungeons), and Face Generator, we have a funny little thing, now:

There are probably a gazillion things we could still add, but it’s already interesting. 🙂

Talk to us on Diaspora!

If you’re reading this in the future, check my profile for the latest thread called “Hex Describe, Face Generator, Text Mapper, and more” (see this old post for context).


Comments on 2019-10-09 Ten random dungeons generated

I like it! Looks very usable, especially with the yellow highlighting.

Jensan 2019-10-09 12:09 UTC

Thanks! Now that I look at the maps a bit closer I see that many of them are repeats. I need to think about the random number seed a bit more. I fear it’s simply taking the current time and passing it off to the mapp generator, which thus gets the same seed for every map. That’s not cool.

– Alex Schroeder 2019-10-09 13:50 UTC

This is killer Alex

froth 2019-10-15 18:54 UTC

Heh, all thanks to ktrey parker and J. Alan Henning who pushed me towards it because I was quite skeptical, and they wrote the random tables for it. Beautiful!

– Alex Schroeder 2019-10-15 20:36 UTC

This is another amazing resource for randomness – thank you. I use Hex Describe quite a bit to generate random entries for my D&D wilderness treks (using tables I have created from mash ups of existing material/adventures and my own mind) and am wondering how I would add in a chance of generating one of these dungeons? I’ve done a quick search of your wiki, the source file and can’t see anything specific – is it possible?

– VickyR 2020-01-07 20:27 UTC

It depends on what you want. If you’re already writing your own random tables, then it’s easy to simply add [dungeon] and it’ll add one to your entry.

  • the dungeon table (the tables below that show how the images with the maps are included)
  • the forest-hill table (the last entry uses the [dungeon] table)

– Alex Schroeder 2020-01-07 20:59 UTC

Thanks for this. Looking through the tables it’s an amazing piece of work by you and ktrey parker and J. Alan Henning. Much more complex that I usually create, but full of interesting ways of using code you’ve written. Thanks again.

– VickyR 2020-01-09 06:44 UTC

Thanks. 🙂

– Alex Schroeder 2020-01-09 06:48 UTC

Add Comment

2019-09-20 Ocean Hexes

I’m not interested in ocean hexes, I think. But Hex Describe would treat all water hexes the same: as a lake. And so you’d get the most useless hex descriptions for the open sea. The real problem was of course that Text Mapper would just generate water hexes and not differentiate between big lakes, coastal areas and the ocean. Well, one of these issues has been resolved, now: ocean hexes. And since no such table exists for Hex Describe (at least not in the “Schroeder” tables), this means that no description should get generated. At least I hope that’s what it means. 🙂

And visually:

Map with open ocean

I still have a little bit of a problem picking just the right hue of darker blue. If you have opinions, please comment with a color code. The existing Gnomeyland colours, if I remember correctly, are based on old Russian maps.

To generate maps with more water, set the bottom parameter to some number single digit number, e.g. 6.


Comments on 2019-09-20 Ocean Hexes

I actually really like the colors, and the more vibrant blues are pretty in contrast to the more neutral greens. The yellow on the hills has the same kind of enjoyable contrast.

I’d need to print it on a black-and-white printer to be sure, but it looks like you would be able to tell the hexes apart by tone even if you had trouble distinguishing the shade.

Anne 2019-09-21 04:20 UTC

Thanks for the feedback. 🙂

– Alex Schroeder 2019-09-21 15:24 UTC

Add Comment

2019-08-23 Gridmapper inside Text Mapper

Gridmapper is an interactive web application. You can use it to draw multi-level dungeon maps. The drawback is that you cannot use it to generate images in order to use them elsewhere.

A while ago I wrote a Megadungeon Generator which generates a random dungeon and allows you to open it in Gridmapper. That’s pretty cool, but I was still unhappy. The preview images I generated as part of it seemed to be on the right track: these were images, but much to small, and they didn’t use the Gridmapper tiles.

Recently, I added the ability to generate square maps within Text Mapper. Now all I was missing was the Gridmapper tiles and some encouragement.

The last few days, as I was talking with Brian Green, J. Alan Henning, and ktrey parker on Diaspora the topic turned to mapping again. ktrey parker suggested using the Face Generator or something similar for dungeon maps. Something smaller, combining geomorphs, something like the five room dungeon, not something big like Dave’s Mapper. Robin Green linked to The Nine Forms of the Five Room Dungeon | Gnome Stew, and started drawing sketches of the kinds of geomorphs we could use, how they’d fit together, and so on.

And suddenly... that was the kind of social enthusiasm I needed and I started writing code...

This is a new mapping algorithm for Text Mapper based on all of the above. It doesn’t do the special rooms Brian had sketched, yet; and it doesn’t always place the initial stairs correctly; and there are no “extras” such as pillars, chests, pits, and so on. But all of this can still be added.

As always with these algorithms, you can use them to generate a new text description for you to edit, or you can just keep reloading this link.


Add Comment



Please make sure you contribute only your own work, or work licensed under the GNU Free Documentation License. Note: in order to facilitate peer review and fight vandalism, we will store your IP number for a number of days. See Privacy Policy for more information. See Info for text formatting rules. You can edit the comment page if you need to fix typos. You can subscribe to new comments by email without leaving a comment.

To save this page you must answer this question:

Just say HELLO