TerraTinker: Crafting Playful Geospatial Visualizations: Supplementary Material
Abstract
This is a package with the supplementary material for a paper titled "TerraTinker: Crafting Playful Geospatial Visualizations", submitted to EuroVis 2026.
Full text
TerraTinker: Crafting Playful Geospatial VisualizationsSupplementary MaterialJ. Rosecký1, A. Štěpánek1, A. Rychlý1, B. Kozlíková11Visitlab, Department of Visual Computing, Faculty of Informatics, Masaryk University, Czech RepublicI.AboutThis document contains the supplementary material for TerraTinker: Crafting Playful Geospatial Visualizations, a paper about an open-source tool designed to engage younger audiences by transforming real-world geospatial data into interactive, customizable visualizations within the Minecraft video game.The full supplementary material package is available digi-tally from DOI 10.5281/zenodo.17790531.The package contains the following files:•codebase.zip — source code of TerraTinker•build.zip — Docker images with a build of the tool•docker-compose.yml — Docker Compose file used to deploy the tool•case_study.zip — TerraTinker configurations used for the case studies (Section 4 of the paper)•user_study.yml — TerraTinker configuration used for the user study (Section 5 of the paper)•teaser.mp4 — video showcasing the tool’s usage•supplementary_material.pdf — this documentII.User TestingThe following text contains the task instructions provided to the participants of the user study described in Section 5 of the paper. The text in parentheses lists the concepts each step introduces and tests. The configuration used throughout the user testing is available alongside this document.A.RoadsStarting with a simple configuration that loads roads from OpenStreetMaps (OSM) and draws them at 𝑌=0.•Select different area (region selection, understanding map).•Change the scale so the preview fits more roads (region selection).•Change the block the roads are built from (parameter modification, understanding thegraph).•Change the thickness of the roads (parameter modification).B.TerrainStarting with a simple configuration that renders a single layer of blocks on a terrain loaded from a GeoTIFF.•Change the scale so that the variations in terrain are more prominent (region selection).•Fill the rest of the map under the terrain with dirt (execution flow).•Modify the “Roads” layer so the buildings are placed on the terrain (adding multiple nodes, complex graph).C.BuildingsDepending on the time, add buildings on your own, using the provided steps, or use a template.•Load terrain from GeoTIFF and place buildings on top of it.•Buildings should be loaded from OpenStreetMaps using the “building” key.•Buildings should be drawn as boxes with a height of 5 blocks relative to the lowest point of the terrain.Optionally provided steps:1)Load buildings from OpenStreetMaps using the “build-ing” key.2)Rasterize the buildings with infill.3)Set the rasterized pixels at 𝑌=0 (for now) with white concrete.4)“You should see buildings being drawn as flat.”5)Modify the graph so that the buildings have height. Replace the Set Block with Fill and fill the buildings to a specific height.6)Now load the terrain from a GeoTIFF and place the buildings on the terrain (using the Sample Raster node).7)It is not perfect as the buildings are now following the terrain. This can be fixed using the Aggregate Raster node.III.Complete List of NodesAs described in Section 3.2 of the paper, the application contains 45 distinct node types usable in its node graph. These are the following:A.Geometry nodesGeometry nodes are intended for working with geometry.•Bounding Box — Calculates the bounding box of the input geometry.•Create Point — Creates a simple geometry consisting of a single point at the specified coordinates.•Create Rectangle — Creates a simple geometry con-sisting of four points forming a rectangle at the specified coordinates.•Geometry Overlap — Returns true if the two input geometries overlap.•Rasterize — Rasterize node is a fork node, converting a region into individual pixels. It can be used for filling blocks corresponding to a given geometry.
2 of 5•Selected Region — This is a passive input node con-taining information about the selected region and its properties.•Transformation nodes — Transform values between the real world and Minecraft coordinates.‣Blocks to Meters, Meters to Blocks — This pair of nodes transforms distances along horizontal axes between Minecraft and the real world.‣Y to Altitude, Altitude to Y — This pair of nodes transforms altitudes between Minecraft and the real world.‣Y to Height, Height to Y — This pair of nodes transforms heights between Minecraft and the real world.B.Raster nodesNodes intended for working with rasters.•Raster Info — Provides information about a raster.•Sample Raster — Fetches a value from a raster at given coordinates.•Aggregate Raster — Aggregates values of a raster bounded by a geometry.C.Loader nodesLoader nodes group nodes that use external files or services to provide data. Includes loaders of both vector data (e.g., Open-StreetMap, GeoJSON, etc.) and raster data (e.g., GeoTIFF).•GeoJSON Loader•ESRI Shapefile Loader•GeoTIFF Loader•OpenStreetMap Overpass API — Loads data from OpenStreetMap using Overpass API.•Local file — Allows selecting a data file from your computer and uploading it to the generator.D.Material nodesMaterial nodes are used to work with Minecraft materials.•Material by Name — Allows selection of a material by its name.•Material Scale — Allows selection of a material from a value scale. You can create the scale yourself or use one of the presets.E.Minecraft nodesMinecraft nodes are intended for interacting with the Minecraft world. Nodes marked with are action nodes.•Set Block — Sets a block at the specified location.•Fill — Fills the selected region with a material.•Replace — Replaces blocks matching the specified material with another material.•Place Tree — Places a default Minecraft tree at the specified location.•World Info — A passive input node containing infor-mation about the world.•Highest Block At — Returns the highest block at the specified location.F.Number nodesA set of nodes intended for manipulating numbers. This in-cludes arithmetic operations, rounding, and generating random numbers.•Math — Performs a mathematical operation on one or two numbers.•Random Number — Generates a random number be-tween two values.•Sequence — Sequence node is a fork node that generates a sequence of numbers.•Comparison — Compares two numbers and outputs a boolean value.G.Boolean nodesBoolean nodes are intended for working with boolean values.•Boolean Operator — Performs a boolean operation on two boolean values.•Not — Performs a boolean negation operation on a boolean value.H.String nodesNodes for manipulating strings.•To String — Converts a value to a string.I.Conditional nodesConditional nodes are intended for working with null values and also for selecting a value based on input.•Switch — This node has a Switch value and multiple Case values it chooses from. It returns the Use input from the first Case value that matches the Switch value. If none of the Case values match, it returns the Default value.•Is Null — Checks if the input is null and outputs a boolean value.•Null — Generates a null value of a given type.•Null Switch — Takes multiple inputs and outputs the first one that is not null. If all inputs are null, it outputs a null value.•Force Not Null — Does not modify the input value. It only shows the output as not null. This can be useful for visually indicating that a value is not null.J.Miscellaneous nodes•Comment — Comment node is a passive node that does nothing. It is used to add comments to the graph.•Constant — Constant nodes return unmodified input values. They are available for all data types.IV.In-game ImagesTo give a closer idea of the final visualizations’ look from the perspective of a Minecraft player, we provide Figures1–3, showing each of the case studies from Section4 of the paper.
3 of 5Fig.1: Screenshots of the Noise Levels case study described in Section 4.1 of the paper.Fig.2: Screenshots of the Rising Sea Levels case study described in Section 4.2 of the paper.Fig.3: Screenshots of the City on Fire case study described in Section 4.3 of the paper.V.Node Graph Evaluation AlgorithmFor TerraTinker, we implemented a custom algorithm for the node graph evaluation. The following describes some of its details, which were beyond the scope of the paper (see its Section 3.4). Listing1 contains a pseudo-code of the algorithm.The program (A), including all the nodes and their connections, gets recursively traversed (C) from a selected start node (B) towards its prerequisites. Upon returning from the recursion, each node is evaluated using the values of the prerequisites (D), and its result is stored in a common dictionary called tree. If anode is a fork, it cannot be evaluated immediately. Rather, it returns a reference to itself (E), indicating that a fork has been visited and the rest of the tree needs to be evaluated for each of its outputs (F).VI.Case Study LayersThis section showcases the layers utilized in case studies from Section4 of the paper. We provide Figures4and5 display-ing the implementation of layers from Section4.2and4.3 respectively.
4 of 5# The root function, that evaluates the program # - program: A Dictionary with the individual nodes from the graph # - startNode: ID of an action node, that the evaluation starts from function EvaluateProgram(program (A), startNode (B)) tree <- {} EvaluateForTree(program, startNode, tree) end # A function, that starts the evaluation for a specific result tree, the tree can be empty # (when calling from EvaluateProgram) or partially full (when calling from EvaluateFork) # - tree: A dictionary with the results of individual nodes function EvaluateForTree(program, startNode, tree) fork <- program[startNode].Evaluate(program, tree) if fork != null then EvaluateFork(program, startNode, tree, fork) end end # Evaluate the program for all rows of a specific fork node # - fork: ID of a fork node, for which the node graph will be completely evaluated function EvaluateFork(program, startNode, tree, fork) # While the specified fork node has more values to return, continue the evaluation while program[fork].EvaluateNext(program, tree.Copy()) do EvaluateForTree(program, startNode, treeCopy) end end # A function of fork nodes, sets its next outputs into the tree # If all values were already evaluated, return false to indicate it function Node.EvaluateNext(program, tree) (F) if not evaluated all do tree[this.id] <- result return true end return false end # Evaluate a specific node function Node.Evaluate(program, tree) # Traverse all the prerequisites and evaluate them, if they are not already for input in this.input do if !tree.contains(input) then fork <- program[input].Evaluate(program, tree) (C) if fork != null then # If the prerequisites contain an unevaluated fork node, # we return its ID return fork end end end # If this node is a fork, it should be evaluated individually,so we return its ID if this.isFork do return this.id (E) end # Evaluate the node here using the values stored in the tree (tree[input]) tree[this.id] <- result (D) # This node is not a fork, so we return null return null end Listing1: Pseudocode of the custom node graph evaluation algorithm.
5 of 5Fig.4: A layer defining risen water levels to 40 m of altitude, replacing only empty blocks described in Section 4.2 of the paper.Fig.5: A layer for placing the fire patches in the spots of the firefighter report events described in Section 4.3 of the paper.