Warmth – an attention engineering game

Core Concept

This is an idea for a shared awareness based exploration and building game called Warmth. The core concept of Warmth is cultivating, directing and then using a magical mana-like resource called “Warmth.” The mechanics of warmth generation, collection, and use encourage emergent game play that creates cozy, fractal patterns of building and interaction. Warmth itself manifests as a faint fire like glow which can be collected by the player for various uses.


Warmth is generated when game entities share awareness or direct awareness toward “catalysts.” Everything in the game has awareness of varying degrees (humans high, rocks low). Awareness is directed by internal attention function native to each type of entity. Trees direct attention toward sunlight and water. Water directs attention toward acceleration vector (downward or inward of turns). Animals direct attention toward plants and humans. Humans direct attention toward humans, symbols, and animals or exceptional plants or terrain features. Buildings direct attention to inhabitants or other structures. By engineering the environment the player can cause convergence of attention which generates warmth.

Warmth can also be generated by catalysts. Catalysts are unique to each entity type. Unlike normal warmth generation which requires convergence of attention catalysts only require one way attention. For example gazing at the sun or a fire generates warmth because fire is a catalyst for humans. Happy humans (not hungry, not cold, not wet, not alone, and high warmth) are a catalyst for humans. This permits more creativity with warmth systems.


Both animals and humans can absorb and carry warmth in them and then transmit it to objects of attention. This allows for the players to engineer networks of warmth collection and storage using natural movement/attention patterns of animals and humans. For example cows graze in a pasture absorbing warmth from grass which generates it from sun attention. Later cows return to barn to rest and human collects warmth from animals by petting them.  The shared attention between cow and human during petting generates further warmth. The human returns home and sits by the fire, depositing the warmth into the hearth. Festivals, totems, buildings, water flow etc can all be use to generate warmth generation and collection networks.

Dream World

When the player goes to sleep at night he is transported to the dream world. Unlike the safe and pastoral real world (RW) the dream world (DW) is fraught with danger. However in the DW the player can use warmth as a magical resource to fight enemies, transform the terrain, and interact with the dreamscape. The DW is initially nearly featureless blank whiteness. The only visible ares are exact copies of the RL where sufficient warmth has accumulated. In the DW warmth acts like beacons which illuminate and populate the landscape. The DW warmth spots manifest as floating islands in an otherwise white void.

The DW permits a number of novel interactions specifically related to linking and networking warmth. In the DW a player can travel to warmth hotspots and record them in dream memories. Upon waking the player retains this memory and can embed it in arts and buildings. When a memory is embedded in art or building it links the warmth of the source to the art piece. For example the player discovers a natural waterfall which attracts the attention of huge trees in the vicinity producing a large amount of natural warmth. The player then travels the DW from his bed to this waterfall and records it as a dream memory. Upon waking he draws a mural of the memory on his bedroom wall. Now whenever he looks at the mural he gains a portion of the warmth of the object.

The DW is also fraught with danger. Nightmare monsters, unpredictable dream weather of darkness and fog, and other terrors lurk here. The worst that can happen is the player is drained of warmth and awakes from the dream to the real world. The player can craft and use magical armor and weapons using warmth from the RW. The meta game then become attempting to generate sufficient warmth in the RW to empower voyages into the DW to further expand the players systems of warmth and safety.

The DW and RW can be futher linked through monuments and totems. Monuments in the RW cause attraction between warmth areas in the DW. For example let’s return to the waterfall described earlier. The player initially wakes on his own island of warmth corresponding to his home. He wants to tranverse to the waterfall in the dream world but since the dreamworld is floating islands and dream flight requires too much warmth the player needs another solution. To solve this he returns to the RW and erects two monuments. One at his home and another at the waterfall. Then he returns to the DW. The monuments generates an attractive force between the warmth islands so when he spawns in the DW he finds his home island and the waterfall island are now contiguous. He can then easily walk to the waterfall and record his dream memory.


Certain events can cause negative warmth (chill). Chill is generated by negative catalysts. These are objects which when given attention generate chill. Example may be death, hunger, destruction, or exclusion. Chill generates chaotic and destructive zones in the dream world. Some otherwise neutral objects can become negative catalysts through events in the DW. For example lets say a poltergiest spirit in the dream world enters a chair. Now in the RW the chair randomly shakes drawing attention. However the chair is also embued as a negative catalyst so any drawn attention generates chill. Given time the chill will generate a chill spot in the DWat this dangerous to the player. The player can solve this problem by destroying the chair in the RW or battling the spirit in the DW.

Death creates corpses and ghosts. Corses are negative catalysts. Ghosts can possess entities and make them into negative catalysts. In order to avoid this the player can bury the corpse and erect a grave. The ghost will then possess the grave but make it into a positive catalyst. Another option is to enter the DW and drive the ghost away. The makes death both a liability and asset to the player depending on their actions.

Endgame content

The end game is four parts.

  1. Emergent complexity from scaling issues. As warmth systems grow they are increasingly difficult to manage. Warmth attracts predators and spirits in the DW that must be warded away or fought off. Sufficiently high warmth generates chill halos around them that represent exclusion from the warmth. Warmth also attract RW evil humans who are natural warmth vampires, generating no warmth but sucking up existing warmth. These must be driven out using DW methods. At volume warmth transport also generates chill turbulence that must be managed. Super predators attracted by high warmth accumulation will come and absorb warmth and produce chill. They must be defeated or warded away uses player weapons, powers, or DW defensive structures. If left undefeated they will drain warmth and chill will start to poison the RW (unhappy people, plants die, animals get sick).
  2. Wonders and spirit bosses. Natural wonders of great natural warmth exist in the RW and DW but are guarded by powerful spirits. A high level player can use massive amounts of warmth to generate epic weapons and powers to defeat these spirits and unlock special powers and great sources of warmth.
  3. The dream dream. Super concentrations of warmth generate locations in the dream dream. The dream dream is accessible by meditating within a dream (low cost of warmth) or meditating in the RW (high cost of warmth). Only the most potent warmth deposits (such as unlocked wonders after you defeat spirit bosses or the central warmth deposits of player produced super networks) produce copies in this realm.Special warmth engineering can be conducted on this level not possible on lower levels. Exceptionally dangerous enemies also predate upon warmth in the realm.
  4. Planets. The original planet consists of a spherical world that can be traversed within a few game days. However a high level character with large amounts of warmth at her disposal can go to the DW and fly to the planet’s star (all stars are natural warmth hotspots and so exist within DW). From there the player can navigate to other stars and other worlds. The other worlds will mostly be blank except natural points of warmth. Here the player can use powers unlocked to generate a dream memory. This dream memory can then be returned to the RW and embedded within a powerful artifact or building. Powered by massive amounts of warmth this object will create a portal to the new world and permit a fresh land to be explored.

Python Scripts


Over the years I’ve written quite a few python utilities. Most of them are really short, and too specific to be useful to others. Those that aren’t are so long that they don’t feel elegant enough to share.

And then, between these two extremes, are the gems that I find myself coming back to time and again. I thought I’d share these with you. Keep in mind that all of these are covered by the Paul Spooner “IP is Wicked Nonsense” license, and you are encouraged to evaluate them on their own merits as distinct from their history. If you insist that the origins of ideas are important, then go pledge your support to my efforts.

TextOddifier.py is a text manipulation script to convert letters in UTF-8 to fairly similar looking letters. It makes text that looks like this ḽӧœĸ ŀįҟԙ ҭԡ༑ṩ ѩʼnᵴťӕаԂ. You can find the source below, or through the link at the start of the description.

# Similar letter substituter
# To make text look a bit strange

from random import choice

SLD = { 'A':'ĀĂĄАѦѨӐӒӔḀẲⰡ⍲ᗗ','a':'āăąаѧѩӑӓӕḁẳ⎀',

def oddify(text):
    result = ""
    for i in text:
        try: result += choice(SLD[i])
        except: result += i
    return result

s = input("enter the text you want to oddify: ")
#s = "I don't even really know how this is going to work any more"

input("Press enter when done:")

BaseConverter_py.py is a number base converter that we collaborated on to convert numbers to and from arbitrary radix. The neat thing about it is it works on floating point numbers as well as integers. The example (and test case) is 135.5 converted to base 12 is B3.6. Going the other way around, S4 in base 35 is 984 in decimal! You can find the source below, or through the link at the start of the description.

# dozinal.py

BASE = 12
PREC = 8

def compute_glyphs():
	GLYPHS = {}
	VALUES = {}

	for i in range(BASE):
		if i < 10: GLYPHS[i] = str(i)
		else: GLYPHS[i] = chr(i+55)

	for i in range(len(GLYPHS)):

def rebase(num):
	if len(GLYPHS) != BASE: compute_glyphs()
	if num < 0:
		sign = '-'
		num = -num
	else: sign = ''
	whole = int(num)
	frac = num - whole

	whole_parts = []
	frac_parts = []
	prec = PREC
	while prec > 0:
		prec -= 1
		frac *= BASE

		part = int(frac)
		frac -= part
		if part == 0: break


	while whole > 0:
		mod = whole % BASE
		whole = whole // BASE
	if len(whole_parts) == 0:
	if len(frac_parts) == 0:
		return sign + "".join(reversed(whole_parts))

	return sign + "{}.{}".format("".join(reversed(whole_parts)),

def debase(string):
	if len(GLYPHS) != BASE: compute_glyphs()
	if string[0] == '-':
		negative = True
		string = string[1:]
	else: negative = False
		whole_parts, frac_parts = string.split(".")
		whole_parts = string
		frac_parts = ''

	whole = 0

	for idx in range(len(whole_parts)):
		whole += VALUES[whole_parts[idx]]
		if idx < len(whole_parts) - 1:
			whole *= BASE

	frac = 0
	max_idx = len(frac_parts) - 1

	for idx in range(len(frac_parts)):
		part = frac_parts[max_idx - idx]
		frac += VALUES[part] / BASE

		if idx < max_idx:
			frac /= BASE

	result = whole + round(frac,PREC)
	if negative: return -result
	return result

TestConvert = 135.5
TestDozenal = rebase(TestConvert)
print("{} converted to base {} is".format(TestConvert,BASE), TestDozenal)
ConvertedBack = debase(TestDozenal)
print("{} in base {} is".format(TestDozenal,BASE), ConvertedBack, "in decimal")
if TestConvert == ConvertedBack: print("success!")
else: print("Something went wrong")
print("Assign BASE to set the number base,\nand PREC to set the precision.\nCall rebase() to convert,\nand debase() to convert back to decimal.")

Renamer.py Is a short program I wrote to do simple renaming operations on files. It only operates on the files in the folder, so it’s pretty easy to target. I include it here mostly as a syntax reminder.

# Rename files to add "_"

from os import rename, listdir
thesefiles = listdir()
target = "Prefix"
tlen = len(target)
	for f in thesefiles:
	if f[:tlen] == target:
		n = f
		n = n[:tlen] + '_' + n[tlen:]
		rename(f, n)

mcm_page.py is kind of an odd one. I really like the McMaster-Carr website, and enjoy browsing their catalog for inspiration. Time was when the catalog was paper that you could turn to a random page and peruse it. However, the online catalog is so efficient at delivering what you want that this becomes difficult. I’d also like to ensure that I don’t keep seeing the same page over again, at least until I’ve gone through the whole catalog. This script does all of that, opening a random page of the catalog when you start it, and allowing a save file listing all the pages you haven’t visited yet. Could be easily modified for other things… monte-carlo webcomic binges for example.

# opens a random McMaster Carr catalog page
from random import choice
import webbrowser

# 3873 fetched on 2017-09-20

    f = open('mcm_page_numbers.txt','r')
    maxpgraw = f.readline()
    raw = f.readline()
    maxpg = int(maxpgraw)
    rem_pgs = eval(raw)
    if maxpg == HIGHEST_PAGE_NUMBER: pass
    elif maxpg > HIGHEST_PAGE_NUMBER:
        while len(rem_pgs)>0:
            if rem_pgs[-1] > HIGHEST_PAGE_NUMBER: rem_pgs.pop()
            else: break
    elif maxpg < HIGHEST_PAGE_NUMBER:
        for i in range(maxpg,HIGHEST_PAGE_NUMBER+1):
    else: print("Something went terribly wrong")
    rem_pgs = [i for i in range(1,HIGHEST_PAGE_NUMBER+1)]

inchoice = ""
print('Enter to bring up a McMaster page\n"s" to save, "sc" to save and close, "p" to print')
while len(rem_pgs) > 0:
    printflag = False
    if len(inchoice)!= 0:
        inchoice = inchoice.lower()
        initial = inchoice[0]
        if initial == 's':
            f = open('mcm_page_numbers.txt','w')
            if inchoice == 'sc': break
            inchoice = input('Saved :')
        elif initial == 'p':
            inchoice = input('Those are the currently loaded indicies :')
    idx = choice(range(len(rem_pgs)))
    chosen_page = rem_pgs.pop(idx)
    inchoice = input('Page {} queued:'.format(chosen_page))