From bfcc2e759807a692d8e0353e3bbecd109175032b Mon Sep 17 00:00:00 2001 From: sanine Date: Sun, 17 Sep 2023 04:43:44 +0000 Subject: add yarrow-ui.cgi and theming --- draw.lua | 146 +++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 72 insertions(+), 74 deletions(-) (limited to 'draw.lua') diff --git a/draw.lua b/draw.lua index 586f804..5d39cc5 100644 --- a/draw.lua +++ b/draw.lua @@ -37,14 +37,14 @@ local function pad(top, bottom, f, h) end -local function _divider() +local function _divider(theme) local size = 3 return function(y) return m.rect{ x=0, y=y, width=500, height=size, - style="fill:darkred;", + style="fill:"..theme.flair, } end, size end -local divider = function() return pad(0, 10, _divider()) end +local divider = function(theme) return pad(0, 10, _divider(theme)) end local function empty() @@ -115,41 +115,33 @@ end --===== basic stats =====-- -local function header(stats) +local function header(stats, theme) local f, h = stack( --{pad(10, 10, name(stats))}, {pad(10, 10, text( stats.name, 40, - 'font-variant-caps:small-caps;stroke:black;fill:darkred;font-family:serif' + 'font-variant-caps:small-caps;stroke:'..theme.text..';fill:'..theme.flair..';font-family:serif' ))}, {pad(0, 10, text( string.format("%s %s, %s", capitalize(stats.size), stats.type, stats.alignment), - 14, 'font-style:italic' + 14, 'font-style:italic;fill:'..theme.text ))} ) return f, h end -local function _statline(name, value) - local size = 14 - return function(y) return m.text( - ''..name..' '..value, - { x=10, y=y+size, style="font-size:"..size.."px;fill:darkred;" } - ) end, 14 -end ---local statline = function(name, value) return pad(0, 2, _statline(name, value)) end -local function statline(name, value) +local function statline(name, value, theme) return pad(0, 2, wrapped_text( string.format('%s %s', name, value), - 80, 10, 14, 2, 'fill:darkred' + 80, 10, 14, 2, 'fill:'..theme.flair )) end -local function armor_hp(stats) +local function armor_hp(stats, theme) local f, h = pad(0, 10, stack( - {statline('Armor Class', stats.ac)}, - {statline('Hit Points', stats.hp)}, - {statline('Speed', stats.speed)} + {statline('Armor Class', stats.ac, theme)}, + {statline('Hit Points', stats.hp, theme)}, + {statline('Speed', stats.speed, theme)} )) return f, h end @@ -157,63 +149,63 @@ end local function bonus(ability_score) return math.floor( (ability_score-10)/2 ) end -local function scorebox(name, ability_score, x, y) +local function scorebox(name, ability_score, x, y, theme) local score = tonumber(ability_score) local value = string.format("%d (%s%d)", score, (score<0 and '-') or '+', bonus(score)) return m.g{ - m.text(name, { x=x+10, y=y+15, style="font-weight:bold;font-size:15px;fill:darkred" }), - m.text(value, {x=x, y=y+30, style="font-size:15px;fill:darkred;" }), + m.text(name, { x=x+10, y=y+15, style="font-weight:bold;font-size:15px;fill:"..theme.flair }), + m.text(value, {x=x, y=y+30, style="font-size:15px;fill:"..theme.flair }), } end -local function ability_scores(stats) +local function ability_scores(stats, theme) return function(y) return m.g{ - scorebox('STR', stats.str, 10, y), - scorebox('DEX', stats.dex, 90, y), - scorebox('CON', stats.con, 170, y), - scorebox('INT', stats.int, 250, y), - scorebox('WIS', stats.wis, 330, y), - scorebox('CHA', stats.cha, 410, y), + scorebox('STR', stats.str, 10, y, theme), + scorebox('DEX', stats.dex, 90, y, theme), + scorebox('CON', stats.con, 170, y, theme), + scorebox('INT', stats.int, 250, y, theme), + scorebox('WIS', stats.wis, 330, y, theme), + scorebox('CHA', stats.cha, 410, y, theme), } end, 40 end -local function optional_attribute(stats, name, key) +local function optional_attribute(stats, name, key, theme) local value = stats[key] if value then - local f, h = statline(name, value) + local f, h = statline(name, value, theme) return f, h else local f, h = empty() return f, h end end -local function misc_attributes(stats) +local function misc_attributes(stats, theme) local f, h = stack( - {optional_attribute(stats, 'Saving Throws', 'saving_throws')}, - {optional_attribute(stats, 'Skills', 'skills')}, - {optional_attribute(stats, 'Damage Vulnerabilities', 'vulnerabilities')}, - {optional_attribute(stats, 'Damage Resistances', 'resistances')}, - {optional_attribute(stats, 'Damage Immunities', 'immunities')}, - {optional_attribute(stats, 'Condition Immunities', 'condition_immunities')}, - {optional_attribute(stats, 'Senses', 'senses')}, - {optional_attribute(stats, 'Languages', 'languages')}, - {optional_attribute(stats, 'Challenge', 'cr')} + {optional_attribute(stats, 'Saving Throws', 'saving_throws', theme)}, + {optional_attribute(stats, 'Skills', 'skills', theme)}, + {optional_attribute(stats, 'Damage Vulnerabilities', 'vulnerabilities', theme)}, + {optional_attribute(stats, 'Damage Resistances', 'resistances', theme)}, + {optional_attribute(stats, 'Damage Immunities', 'immunities', theme)}, + {optional_attribute(stats, 'Condition Immunities', 'condition_immunities', theme)}, + {optional_attribute(stats, 'Senses', 'senses', theme)}, + {optional_attribute(stats, 'Languages', 'languages', theme)}, + {optional_attribute(stats, 'Challenge', 'cr', theme)} ) - if h > 0 then return stack({pad(0, 10, f, h)}, {divider()}) + if h > 0 then return stack({pad(0, 10, f, h)}, {divider(theme)}) else return empty(), 0 end end -local function base(stats) +local function base(stats, theme) local f, h = stack( - {header(stats)}, - {divider()}, - {armor_hp(stats)}, - {divider()}, - {ability_scores(stats)}, - {divider()}, - {misc_attributes(stats)} + {header(stats, theme)}, + {divider(theme)}, + {armor_hp(stats, theme)}, + {divider(theme)}, + {ability_scores(stats, theme)}, + {divider(theme)}, + {misc_attributes(stats, theme)} ) return f, h end @@ -221,18 +213,18 @@ end --===== traits =====-- -local function trait(t) +local function trait(t, theme) return pad(0, 10, wrapped_text( string.format('%s. %s', t.name, format(t.value)), - 80, 10, 14, 5 + 80, 10, 14, 5, 'fill:'..theme.text )) end -local function traits(stats) +local function traits(stats, theme) if not stats.traits then return empty() end local tbl = {} for _, t in ipairs(stats.traits) do - table.insert(tbl, {trait(t)}) + table.insert(tbl, {trait(t, theme)}) end return stack(unpack(tbl)) end @@ -240,51 +232,51 @@ end --===== actions =====-- -local function subheader(title) +local function subheader(title, theme) return pad(0, 10, stack( - {pad(0, 5, text(title, 25, 'font-variant-caps:small-caps;stroke:black;fill:darkred'))}, - {divider()} + {pad(0, 5, text(title, 25, 'font-variant-caps:small-caps;stroke:'..theme.text..';fill:'..theme.flair))}, + {divider(theme)} )) end -local function actions(stats) +local function actions(stats, theme) if not stats.actions then return empty() end local tbl = {} for _, action in ipairs(stats.actions) do - table.insert(tbl, {trait(action)}) + table.insert(tbl, {trait(action, theme)}) end return stack( - {subheader('Actions')}, + {subheader('Actions', theme)}, unpack(tbl) ) end -local function reactions(stats) +local function reactions(stats, theme) if not stats.reactions then return empty() end local tbl = {} for _, reaction in ipairs(stats.reactions) do - table.insert(tbl, {trait(reaction)}) + table.insert(tbl, {trait(reaction, theme)}) end return stack( - {subheader('Reactions')}, + {subheader('Reactions', theme)}, unpack(tbl) ) end -local function legendary(stats) +local function legendary(stats, theme) if not stats.legendary then return empty() end local tbl = {} for _, action in ipairs(stats.legendary.actions) do - table.insert(tbl, {trait(action)}) + table.insert(tbl, {trait(action, theme)}) end return stack( - {subheader('Legendary Actions')}, - {pad(0, 10, wrapped_text(stats.legendary.description, 80, 10, 14, 2, ''))}, + {subheader('Legendary Actions', theme)}, + {pad(0, 10, wrapped_text(stats.legendary.description, 80, 10, 14, 2, 'fill:'..theme.text))}, unpack(tbl) ) end @@ -294,19 +286,25 @@ end --===== draw =====-- -function draw(stats) +function draw(stats, theme) + local theme = theme or { + bg = '#020202', + text = 'beige', + flair = 'tomato', + } local f, h = stack( - {base(stats)}, - {traits(stats)}, - {actions(stats)}, - {reactions(stats)}, - {legendary(stats)} + {base(stats, theme)}, + {traits(stats, theme)}, + {actions(stats, theme)}, + {reactions(stats, theme)}, + {legendary(stats, theme)} ) return m.render(m.svg{ viewBox = string.format("0 0 500 %d", h), width = 500, height = height, style = "font-family:sans-serif;", + m.rect{x=0, y=0, width=500, height=h, style='fill:'..theme.bg}, f(0), }) end -- cgit v1.2.1