auto-generate card images

This commit is contained in:
Judah 2026-04-01 21:07:20 -06:00
parent d7421e6c5f
commit 0987a54851
23 changed files with 104 additions and 32 deletions

View file

@ -6,7 +6,7 @@
"name": "Rapid Response", "name": "Rapid Response",
"type": "Passive", "type": "Passive",
"cost": 0, "cost": 0,
"image": "https://docs.brut.systems/judah/entropy/passive-base.png", "image": "https://docs.brut.systems/judah/entropy/000.png",
"isHorizontal": true "isHorizontal": true
} }
}, },
@ -28,7 +28,7 @@
"name": "Breaker", "name": "Breaker",
"type": "Passive", "type": "Passive",
"cost": 0, "cost": 0,
"image": "https://docs.brut.systems/judah/entropy/passive-base.png", "image": "https://docs.brut.systems/judah/entropy/001.png",
"isHorizontal": true "isHorizontal": true
} }
}, },
@ -50,7 +50,7 @@
"name": "Inverse Entropy", "name": "Inverse Entropy",
"type": "Passive", "type": "Passive",
"cost": 0, "cost": 0,
"image": "https://docs.brut.systems/judah/entropy/passive-base.png", "image": "https://docs.brut.systems/judah/entropy/002.png",
"isHorizontal": true "isHorizontal": true
} }
}, },
@ -69,14 +69,14 @@
"id": "003", "id": "003",
"face": { "face": {
"front": { "front": {
"name": "SoftReflex", "name": "SpentReflex",
"type": "Unit", "type": "Unit",
"cost": 1, "cost": 1,
"image": "https://docs.brut.systems/judah/entropy/red-base.png", "image": "https://docs.brut.systems/judah/entropy/003.png",
"isHorizontal": true "isHorizontal": true
} }
}, },
"name": "SoftReflex", "name": "SpentReflex",
"type": "Unit", "type": "Unit",
"cost": 1, "cost": 1,
"isToken": false, "isToken": false,
@ -91,14 +91,14 @@
"id": "004", "id": "004",
"face": { "face": {
"front": { "front": {
"name": "CivicContour", "name": "InlandAperture",
"type": "Unit", "type": "Unit",
"cost": 2, "cost": 2,
"image": "https://docs.brut.systems/judah/entropy/red-base.png", "image": "https://docs.brut.systems/judah/entropy/004.png",
"isHorizontal": true "isHorizontal": true
} }
}, },
"name": "CivicContour", "name": "InlandAperture",
"type": "Unit", "type": "Unit",
"cost": 2, "cost": 2,
"isToken": false, "isToken": false,
@ -113,14 +113,14 @@
"id": "005", "id": "005",
"face": { "face": {
"front": { "front": {
"name": "FlatDividend", "name": "ObliqueCortex",
"type": "Unit", "type": "Unit",
"cost": 3, "cost": 3,
"image": "https://docs.brut.systems/judah/entropy/red-base.png", "image": "https://docs.brut.systems/judah/entropy/005.png",
"isHorizontal": true "isHorizontal": true
} }
}, },
"name": "FlatDividend", "name": "ObliqueCortex",
"type": "Unit", "type": "Unit",
"cost": 3, "cost": 3,
"isToken": false, "isToken": false,
@ -135,14 +135,14 @@
"id": "006", "id": "006",
"face": { "face": {
"front": { "front": {
"name": "AbsentFilament", "name": "FormerDividend",
"type": "Unit", "type": "Unit",
"cost": 4, "cost": 4,
"image": "https://docs.brut.systems/judah/entropy/red-base.png", "image": "https://docs.brut.systems/judah/entropy/006.png",
"isHorizontal": true "isHorizontal": true
} }
}, },
"name": "AbsentFilament", "name": "FormerDividend",
"type": "Unit", "type": "Unit",
"cost": 4, "cost": 4,
"isToken": false, "isToken": false,
@ -157,20 +157,20 @@
"id": "007", "id": "007",
"face": { "face": {
"front": { "front": {
"name": "SoftSubstrate", "name": "SoftReflex",
"type": "Unit", "type": "Unit",
"cost": 5, "cost": 10,
"image": "https://docs.brut.systems/judah/entropy/red-base.png", "image": "https://docs.brut.systems/judah/entropy/007.png",
"isHorizontal": true "isHorizontal": true
} }
}, },
"name": "SoftSubstrate", "name": "SoftReflex",
"type": "Unit", "type": "Unit",
"cost": 5, "cost": 10,
"isToken": false, "isToken": false,
"Lane": "🟥 Red", "Lane": "🟥 Red",
"Entropy": 5, "Entropy": 10,
"Force": 5, "Force": 10,
"_legal": { "_legal": {
"playtest": true "playtest": true
} }

View file

@ -24,6 +24,6 @@ var CARDS = []struct {
desc: ``}, desc: ``},
{typ: Unit, lane: Red, entropy: 4, force: 4, {typ: Unit, lane: Red, entropy: 4, force: 4,
desc: ``}, desc: ``},
{typ: Unit, lane: Red, entropy: 5, force: 5, {typ: Unit, lane: Red, entropy: 10, force: 10,
desc: ``}, desc: ``},
} }

BIN
docs/000.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
docs/001.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
docs/002.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
docs/003.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
docs/004.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
docs/005.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
docs/006.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
docs/007.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
docs/Krungthep.ttf Normal file

Binary file not shown.

BIN
docs/SFCamera.ttf Normal file

Binary file not shown.

BIN
docs/base-blue.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
docs/base-green.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
docs/base-passive.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
docs/base-red.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 714 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 983 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 493 KiB

6
go.mod
View file

@ -1,3 +1,9 @@
module tcg module tcg
go 1.26.1 go 1.26.1
require (
github.com/fogleman/gg v1.3.0 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
golang.org/x/image v0.38.0 // indirect
)

6
go.sum Normal file
View file

@ -0,0 +1,6 @@
github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
golang.org/x/image v0.38.0 h1:5l+q+Y9JDC7mBOMjo4/aPhMDcxEptsX+Tt3GgRQRPuE=
golang.org/x/image v0.38.0/go.mod h1:/3f6vaXC+6CEanU4KJxbcUZyEePbyKbaLoDOe4ehFYY=

78
main.go
View file

@ -3,8 +3,12 @@ package main
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"math"
"math/rand/v2" "math/rand/v2"
"os" "os"
"strings"
"github.com/fogleman/gg"
) )
type Lane int type Lane int
@ -88,21 +92,77 @@ func main() {
card.name = generateTemporaryName() card.name = generateTemporaryName()
} }
baseurl := "https://docs.brut.systems/judah/entropy/" var (
baseimg string
var imgurl string color [3]float64
)
switch card.lane { switch card.lane {
case Red: case Red:
imgurl = baseurl + "red-base.png" baseimg = "base-red.png"
case Blue: color = [3]float64{248.0 / 255.0, 120.0 / 255.0, 143.0 / 255.0}
imgurl = baseurl + "blue-base.png"
case Green: case Green:
imgurl = baseurl + "green-base.png" baseimg = "base-green.png"
color = [3]float64{120.0 / 255.0, 190.0 / 255.0, 248.0 / 255.0}
case Blue:
baseimg = "base-blue.png"
color = [3]float64{120.0 / 255.0, 248.0 / 255.0, 178.0 / 255.0}
default: default:
imgurl = baseurl + "passive-base.png" color = [3]float64{184.0 / 255.0, 184.0 / 255.0, 184.0 / 255.0}
baseimg = "base-passive.png"
} }
img, err := gg.LoadImage("docs/" + baseimg)
if err != nil {
panic(err)
}
ctx := gg.NewContextForImage(img)
if err := ctx.LoadFontFace("docs/Krungthep.ttf", 48); err != nil {
panic(err)
}
// Draw force
if card.typ != Passive {
ctx.SetRGB(1, 1, 1)
ctx.Push()
{
ctx.Translate(120, 115)
ctx.Rotate(270 * math.Pi / 180)
ctx.DrawStringAnchored(fmt.Sprintf("%d", card.force), 0, 0, 0.5, 0.5)
}
ctx.Pop()
}
// Draw entropy
ctx.SetRGB(color[0], color[1], color[2])
ctx.Push()
{
ctx.Translate(273, 115)
ctx.Rotate(270 * math.Pi / 180)
ctx.DrawStringAnchored(fmt.Sprintf("%d", card.entropy), 0, 0, 0.5, 0.5)
}
ctx.Pop()
if err := ctx.LoadFontFace("docs/SFCamera.ttf", 30); err != nil {
panic(err)
}
// Draw description
cleandesc := strings.NewReplacer("{{", "", "}}", "").Replace(card.desc)
ctx.SetRGBA(0, 0, 0, 0.9)
ctx.Push()
{
ctx.Translate(435, 985)
ctx.Rotate(270 * math.Pi / 180)
ctx.DrawStringWrapped(fmt.Sprintf("%s -\n%s", card.name, cleandesc), 0, 0, 0.0, 0.0, 900, 1.70, gg.AlignLeft)
}
ctx.Pop()
id := fmt.Sprintf("%03d", i) id := fmt.Sprintf("%03d", i)
if err := ctx.SavePNG("docs/" + id + ".png"); err != nil {
panic(err)
}
thejson[id] = jsoncard{ thejson[id] = jsoncard{
Id: id, Id: id,
Face: struct { Face: struct {
@ -111,7 +171,7 @@ func main() {
jsonfront{ jsonfront{
Name: card.name, Name: card.name,
Type: card.typ.String(), Type: card.typ.String(),
Image: imgurl, Image: fmt.Sprintf("https://docs.brut.systems/judah/entropy/%s.png", id),
Cost: card.entropy, Cost: card.entropy,
Horizontal: true, Horizontal: true,
}, },