This workflow creates an easy to reproduce and reiterate D&D character creation Glif. It uses a mix of User Input, Randomization, Text Generation. JSON Extraction, Image Generation, and HTML.

glif - D&D Character Roulette by araminta_k

Check out and Remix our Example Glif Here!


Step by Step
  1. Click ‘Build’ to start a new project.
  2. Add the two user inputs for text prompt and level.
  3. Add the two text input Multipick blocks and upload the official D&D race list and class list into each. Select the Randomize button.
  4. Add a Text Generation block and adjust to the recommended settings for Character Background.
  5. Add a Text Generation block and adjust to the recommended settings for Stats Blocks.
  6. Add a Text Generation block and adjust to the recommended settings for Image Prompt.
  7. Add a ComfyUI block and adjust the JSON as recommended.
  8. Add two JSON Extractor blocks and set one up to correspond with the Character Background output and another to correspond with the Stat Block output.
  9. Using an HTML block, finish setting up the HTML formatted final character sheet with the provided HTML code and make any necessary changes.
  10. Name and Publish your Glif.

Codes and Content

Text Generation LLM Blocks

Character Background Generation Settings

Prompt

You are tasked to create an amazing new character for a D&D campaign. Using {text-input} {lvl}(absolutely work in these inputs and follow closely), in addition to {race} and {class} , you need to use all of the official d&d published character resources to come up with a character, choose an official sublcass, and give them a really interesting backstory. If the race or class in {text-input}is different from the {race} or {class}, default to {text-input}{lvl}.Do not speak conversationally, you should say just the details of the character and nothing more. You do not need to create a stat block for them, please just focus on personal details. Make sure that official details like race, class, and subclass follow published d&d materials. Keep the backstory to one paragraph in length.Export as a json.

Max Tokens

2000

Model

Claude 3.5 Sonnet

System Prompt

You are an incredibly talented DM. You are a helpful assistant. Your specialty is to come up with the character traits in the following format:

{
    "name": "NAME",
    "race": "RACE",
    "backstory":"BACKSTORY",
    "class":"CLASS",
    "subclass":"SUBCLASS",
    "background":"BACKGROUND",
    "inventory":"INVENTORY",
    "equipment":"EQUIPMENT"
}

Stat Blocks Text Generation Settings

Prompt

Start with this information: {character-background}

Roll a random stat block using this format and assign the stats accordingly: 4d6dl1. Assign the stats accordingly, including modifiers, that the character would have based on it being at level {lvl}. Do not explain what you are doing with the dice, just give the final array with the important information a player would need. Do not say "here is" or anythign like that - just give me the stats!
Export as a json where "stats" includes all the stats parsed out together in a section like "stats":" Str - #,  Dex - #" etc and "skills" includes all the skills parsed together in a section in a similar fashion.

Max Tokens

2000

Model

Claude 3.5 Sonnet

System Prompt

You are a helpful assistant. Your specialty is to come up with rolled d&d stats in the following format. Make sure you always use a RANDOM number generation based on the provided prompt to create a stat block:

{
    "stats": "STATS",
    "level":"LEVEL",
    "skills": "SKILLS",
    "feats":"FEATS",
    "classfeatures":"CLASSFEATURES",
    "racialfeatures":"RACIAL FEATURES",
    "spellscantrip":"SPELLSCANTRIP",
    "spellslevelled":"SPELLSLEVELLED",
    "backgroundfeature":"BACKGROUNDFEATURE",
    "hp":"HP",
    "savingthrow":"SAVINGTHROW",
    "initiative":"INITIATIVE",
    "armorclass":"ARMORCLASS",
    "proficiencybonus":"PROFICIENCYBONUS",
    "spellsave":"SPELLSAVE",
    "castingmodifier":"CASTINGMODIFIER",
    "passiveperception":"PASSIVEPERCEPTION",
    "weaponattack1":"WEAPONATTACK1",
    "weaponattack2":"WEAPONATTACK2"
}

Image Prompt Text Generation Settings

Prompt

Use this info to write a very simple character prompt in a [race][gender][class][describing features] format. You do not need to use the brackets in the final output. Please also add some hair, eye, and skin color descriptions that might match the character. Keep it super simple, and if it is an unusual fantasy race, just add some additional appearance descriptors. Find info below: {character-background}{Stat-blocks}

Max Tokens

200

Model

Claude 3.5 Sonnet

System Prompt

You are a helpful assistant.

Resource: D&D Official Races and Classes

Searchable on 5e.tools

Races

dragonborn
dwarf
elf
gnome
half-elf
halfing
half-orc
human
tiefling
aarakocra
aasimar (celestial)
air genasi
bugbear
changeling
deep gnome
fawn
duergar
earth genasi
eladrin
fairy
firbolg
fire genasi
githyanki
githzerai
goblin
goliath
harengon
hobgoblin
kenku
kobold
lizardfolk
orc
minotaur
satyr
sea elf
shadar-kai
shifter
tabaxi
tortle
triton
water genasi
yuan-ti
owlin
leonin
changling
kalasthar
warforged
verdon
loxodon
simic hybrid
vedalkan
tortle

Classes
barbarian
bard
cleric
druid
fighter
monk
paladin
ranger
rogue
sorcerer
warlock
wizard

ComfyUI Image Generation Prompts & HTML

ComfyUI Workflow JSON

To put in the JSON area:

{
  "3": {
    "inputs": {
      "seed": 270796374588362,
      "steps": 45,
      "cfg": 7,
      "sampler_name": "dpmpp_2m_sde",
      "scheduler": "karras",
      "denoise": 0.9,
      "model": [
        "29",
        0
      ],
      "positive": [
        "6",
        0
      ],
      "negative": [
        "7",
        0
      ],
      "latent_image": [
        "30",
        0
      ]
    },
    "class_type": "KSampler",
    "_meta": {
      "title": "KSampler"
    }
  },
  "4": {
    "inputs": {
      "ckpt_name": "sd_xl_base_1.0.safetensors"
    },
    "class_type": "CheckpointLoaderSimple",
    "_meta": {
      "title": "Load Checkpoint"
    }
  },
  "6": {
    "inputs": {
      "text": "portrait of {prompt}, illustration style",
      "clip": [
        "29",
        1
      ]
    },
    "class_type": "CLIPTextEncode",
    "_meta": {
      "title": "CLIP Text Encode (Prompt)"
    }
  },
  "7": {
    "inputs": {
      "text": "watermark, bad, ugly, messy",
      "clip": [
        "29",
        1
      ]
    },
    "class_type": "CLIPTextEncode",
    "_meta": {
      "title": "CLIP Text Encode (Prompt)"
    }
  },
  "8": {
    "inputs": {
      "samples": [
        "3",
        0
      ],
      "vae": [
        "4",
        2
      ]
    },
    "class_type": "VAEDecode",
    "_meta": {
      "title": "VAE Decode"
    }
  },
  "25": {
    "inputs": {
      "filename_prefix": "ComfyUI",
      "images": [
        "8",
        0
      ]
    },
    "class_type": "SaveImage",
    "_meta": {
      "title": "Save Image"
    }
  },
  "29": {
    "inputs": {
      "repo_id": "alvdansen/midsommarcartoon",
      "subfolder": "",
      "filename": "araminta_k_midsommar_cartoon.safetensors",
      "strength_model": 1,
      "strength_clip": 1,
      "model": [
        "4",
        0
      ],
      "clip": [
        "4",
        1
      ]
    },
    "class_type": "HFHubLoraLoader",
    "_meta": {
      "title": "Load HF Lora"
    }
  },
  "30": {
    "inputs": {
      "width": 1024,
      "height": 1024,
      "batch_size": 1
    },
    "class_type": "EmptyLatentImage",
    "_meta": {
      "title": "Empty Latent Image"
    }
  }
}

HTML Layout Template

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>D&D Character Sheet</title>
    <style>
        body {
            width: 816px;
            height: 1056px;
            margin: 0 auto;
            font-family: 'Arial', sans-serif;
            background-color: #eaeaea;
            padding: 20px;
            color: #333;
        }
        .container {
            background-color: #fff;
            border: 1px solid #ccc;
            padding: 20px;
            box-shadow: 0 4px 8px rgba(0,0,0,0.1);
        }
        .header {
            display: flex;
            justify-content: space-between;
            margin-bottom: 20px;
            border-bottom: 2px solid #ddd;
            padding-bottom: 10px;
        }
        .header img {
            width: 150px;
            height: 150px;
            object-fit: cover;
            border: 2px solid #ddd;
            border-radius: 4px;
        }
        .info {
            margin-left: 20px;
            flex: 1;
        }
        .info h1 {
            margin: 0;
            font-size: 24px;
            color: #555;
        }
        .info p {
            margin: 5px 0;
            font-size: 16px;
            color: #777;
        }
        .section h2 {
            font-size: 20px;
            margin-bottom: 10px;
            color: #444;
        }
        .content-box {
            border: 1px solid #ddd;
            padding: 10px;
            margin-bottom: 10px;
            background-color: #f9f9f9;
            border-radius: 4px;
        }
        .double-column, .triple-column {
            display: flex;
            justify-content: space-between;
            flex-wrap: wrap;
        }
        .double-column .content-box, .triple-column .content-box {
            width: 48%;
            margin-bottom: 10px;
        }
        .triple-column .content-box {
            width: 32%;
        }
        .full-width {
            width: 100%;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <img src="{portrait}" alt="Character Portrait">
            <div class="info">
                <h1>{json1.name}</h1>
                <p><strong>Race:</strong> {json1.race}</p>
                <p><strong>Class:</strong> {json1.class} ({json1.subclass})</p>
                <p><strong>Level:</strong> {json2.level}</p>
                <p><strong>Background:</strong> {json1.background}</p>
            </div>
        </div>
        <div class="section full-width">
            <h2>Backstory</h2>
            <div class="content-box">
                <p>{json1.backstory}</p>
            </div>
        </div>
        <div class="section triple-column">
            <div class="content-box">
                <h2>Stats</h2>
                <p>{json2.stats}</p>
            </div>
            <div class="content-box">
                <h2>HP</h2>
                <p>{json2.hp}</p>
            </div>
            <div class="content-box">
                <h2>Armor Class</h2>
                <p>{json2.armorclass}</p>
            </div>
        </div>
        <div class="section triple-column">
            <div class="content-box">
                <h2>Initiative</h2>
                <p>{json2.initiative}</p>
            </div>
            <div class="content-box">
                <h2>Saving Throws</h2>
                <p>{json2.savingthrow}</p>
            </div>
            <div class="content-box">
                <h2>Passive Perception</h2>
                <p>{json2.passiveperception}</p>
            </div>
        </div>
        <div class="section triple-column">
            <div class="content-box">
                <h2>Weapon Attack 1</h2>
                <p>{json2.weaponattack1}</p>
            </div>
            <div class="content-box">
                <h2>Weapon Attack 2</h2>
                <p>{json2.weaponattack2}</p>
            </div>
            <div class="content-box">
                <h2>Spell Save DC</h2>
                <p>{json2.spellsave}</p>
            </div>
        </div>
        <div class="section double-column">
            <div class="content-box">
                <h2>Casting Modifier</h2>
                <p>{json2.castingmodifier}</p>
            </div>
            <div class="content-box">
                <h2>Proficiency Bonus</h2>
                <p>{json2.proficiencybonus}</p>
            </div>
        </div>
        <div class="section double-column">
            <div class="content-box">
                <h2>Skills</h2>
                <p>{json2.skills}</p>
            </div>
            <div class="content-box">
                <h2>Class Features</h2>
                <p>{json2.classfeatures}</p>
            </div>
        </div>
        <div class="section double-column">
            <div class="content-box">
                <h2>Feats</h2>
                <p>{json2.feats}</p>
            </div>
            <div class="content-box">
                <h2>Racial Features</h2>
                <p>{json2.racialfeatures}</p>
            </div>
        </div>
        <div class="section double-column">
            <div class="content-box">
                <h2>Background Feature</h2>
                <p>{json2.backgroundfeature}</p>
            </div>
            <div class="content-box">
                <h2>Spells (Cantrip)</h2>
                <p>{json2.spellscantrip}</p>
            </div>
        </div>
        <div class="section double-column">
            <div class="content-box">
                <h2>Spells (Levelled)</h2>
                <p>{json2.spellslevelled}</p>
            </div>
            <div class="content-box">
                <h2>Equipment</h2>
                <p>{json1.equipment}</p>
            </div>
        </div>
        <div class="section full-width">
            <div class="content-box">
                <h2>Inventory</h2>
                <p>{json1.inventory}</p>
            </div>
        </div>
    </div>
</body>
</html>
Share this post