diff --git a/src/cards.ts b/src/cards.ts
index 687344c..dd2d1a0 100644
--- a/src/cards.ts
+++ b/src/cards.ts
@@ -1,8 +1,29 @@
-import { DominionCard, TYPE_TREASURE, TYPE_VICTORY } from "./types.ts";
+import {
+	DominionCard,
+	TYPE_ACTION,
+	TYPE_DURATION,
+	TYPE_NIGHT,
+	TYPE_TREASURE,
+	TYPE_VICTORY,
+} from "./types.ts";
 
 const expansionIcon = "";
 const author = "Dylan";
 
+const sampleCard = {
+	orientation: "card",
+	title: "Sample",
+	description: "",
+	types: [TYPE_ACTION],
+	image: "",
+	artist: "",
+	author,
+	version: "0.1",
+	cost: "$",
+	preview: "",
+	expansionIcon,
+};
+
 export const cards: DominionCard[] = [
 	{
 		orientation: "card",
@@ -21,14 +42,194 @@ export const cards: DominionCard[] = [
 	{
 		orientation: "card",
 		title: "Promising Land",
-		description: "Worth 1% per 3 cards you have that cost $4 or $5.",
+		description: "Worth 1% per 4 cards you have that cost $4 or $5.",
 		types: [TYPE_VICTORY],
 		image: "",
 		artist: "",
 		author,
-		version: "",
+		version: "0.1",
+		cost: "$4",
+		preview: "",
+		expansionIcon,
+	},
+	{
+		orientation: "card",
+		title: "Steelworker",
+		description:
+			"If it's your Action phase, +3 Cards.\n\nIf it's your Buy phase, +1 Buy, and +$1.",
+		types: [TYPE_ACTION, TYPE_TREASURE],
+		image: "",
+		artist: "",
+		author,
+		version: "0.2",
+		cost: "$5",
+		preview: "$?",
+		expansionIcon,
+	},
+	{
+		orientation: "card",
+		title: "Shovel",
+		description:
+			"Play a Treasure card from your hand. Then trash it from play to gain a Treasure card costing up to $3 more than it.",
+		types: [TYPE_TREASURE],
+		image: "",
+		artist: "",
+		author,
+		version: "0.1",
+		cost: "$6",
+		preview: "",
+		expansionIcon,
+	},
+	{
+		orientation: "card",
+		title: "High Council",
+		description:
+			"+2 Cards\n+1 Action\n+1 Buy\n\nEach player (including you) may choose one: +1 Card, or trash a card from their hand.",
+		types: [TYPE_ACTION],
+		image: "",
+		artist: "",
+		author: "Lou + Dylan",
+		version: "0.1",
+		cost: "$7",
+		preview: "",
+		expansionIcon,
+	},
+	{
+		orientation: "card",
+		title: "Productive Village",
+		description:
+			"If it's your Action phase, +3 Actions.\n\nIf it's your Buy phase, +$1 per unused Action you have (Action, not Action card). +$1 if you have no Actions.",
+		types: [TYPE_ACTION, TYPE_TREASURE],
+		image: "",
+		artist: "",
+		author: "Dylan",
+		version: "0.1",
+		cost: "$3",
+		preview: "$?",
+		expansionIcon,
+	},
+	{
+		orientation: "card",
+		title: "Secret Society",
+		description:
+			"+1 Action\n\nIf you have at least 3 copies of Secret Society in play, trash all of them to gain any number of cards costing at least $2, whose total combined cost is at most $50.\n\n-\n\nOn your turn, this costs $3 plus $2 per Secret Society you've gained this game.",
+		types: [TYPE_ACTION],
+		image: "",
+		artist: "",
+		author: "Dylan",
+		version: "0.1",
+		cost: "$?",
+		preview: "",
+		expansionIcon,
+	},
+	{
+		orientation: "card",
+		title: "Eclipse",
+		description:
+			"+1 Card\n\nIf you have no Actions, +1 Action. If you have no Buys, +1 Buy. Return to your Action phase.",
+		types: [TYPE_NIGHT],
+		image: "",
+		artist: "",
+		author: "Dylan",
+		version: "0.1",
+		cost: "$5",
+		preview: "",
+		expansionIcon,
+	},
+	{
+		orientation: "card",
+		title: "Moonlit Scheme",
+		description: "You may play an Action card from your hand.",
+		types: [TYPE_NIGHT],
+		image: "",
+		artist: "",
+		author: "Dylan",
+		version: "0.1",
+		cost: "$2",
+		preview: "",
+		expansionIcon,
+	},
+	{
+		orientation: "card",
+		title: "Beaver",
+		description:
+			"Pay $1. If you did, gain a card costing up to the amount of $ you have.",
+		types: [TYPE_NIGHT],
+		image: "",
+		artist: "",
+		author: "Dylan",
+		version: "0.1",
 		cost: "$3",
 		preview: "",
 		expansionIcon,
 	},
+	{
+		orientation: "card",
+		title: "Silk",
+		description: "Choose one: +$2, or gain a Silver.",
+		types: [TYPE_TREASURE],
+		image: "",
+		artist: "",
+		author,
+		version: "0.1",
+		cost: "$4",
+		preview: "$?",
+		expansionIcon,
+	},
+	{
+		orientation: "card",
+		title: "Foundry",
+		description:
+			"Choose one: +1 Card, +1 Action and +$1; or trash a card from your hand to gain a card that costs up to $2 more than it.",
+		types: [TYPE_ACTION],
+		image: "",
+		artist: "",
+		author,
+		version: "0.1",
+		cost: "$5",
+		preview: "",
+		expansionIcon,
+	},
+	{
+		orientation: "card",
+		title: "Vendor",
+		description:
+			"Choose three different options: +1 Card, +1 Action, +1 Buy, +$1, trash a card from your hand.",
+		types: [TYPE_ACTION],
+		image: "",
+		artist: "",
+		author,
+		version: "0.2",
+		cost: "$5",
+		preview: "",
+		expansionIcon,
+	},
+	{
+		orientation: "card",
+		title: "Chateau",
+		description:
+			"1%\n\n-\n\nWhen you gain this, choose one: gain an Estate; or +1 Card, +1 Action, +1 Buy, +$1, and if it's your Buy phase, return to your Action phase.",
+		types: [TYPE_VICTORY],
+		image: "",
+		artist: "",
+		author,
+		version: "0.1",
+		cost: "$3",
+		preview: "",
+		expansionIcon,
+	},
+	{
+		orientation: "card",
+		title: "Retainer",
+		description:
+			"Set aside a card from your hand (under this).\n\nAt any time during any of your turns, you may take +1 Action, and add the set aside card to your hand, discarding this from play.\n\nAt the start of each of your Buy phases, if the card is still set aside, +@1.",
+		types: [TYPE_ACTION, TYPE_DURATION],
+		image: "",
+		artist: "",
+		author,
+		version: "0.2",
+		cost: "$2",
+		preview: "",
+		expansionIcon,
+	},
 ];
diff --git a/src/colorhelper.ts b/src/colorhelper.ts
new file mode 100644
index 0000000..7ff915a
--- /dev/null
+++ b/src/colorhelper.ts
@@ -0,0 +1,5 @@
+import parseColor1 from "npm:parse-color";
+
+export const parseColor = (c: string): { rgb: [number, number, number] } => {
+	return parseColor1(c);
+};
diff --git a/src/dominiontext.ts b/src/dominiontext.ts
index bc35c5d..a2ced6c 100644
--- a/src/dominiontext.ts
+++ b/src/dominiontext.ts
@@ -391,7 +391,7 @@ export const parse = (
 			pieces.push({ type: "break" });
 		} else if (char in symbolMap) {
 			const c = char as keyof typeof symbolMap;
-			const end = text.slice(i).match(new RegExp(`\\${c}\\w*`))![0]
+			const end = text.slice(i).match(new RegExp(`\\${c}[^ \n.,;]*`))![0]
 				.length;
 			const isBig =
 				isDescription &&
diff --git a/src/draw.ts b/src/draw.ts
index 01bcbd5..a05e567 100644
--- a/src/draw.ts
+++ b/src/draw.ts
@@ -1,3 +1,4 @@
+import { parseColor } from "./colorhelper.ts";
 import {
 	measureDominionText,
 	parse,
@@ -39,6 +40,10 @@ const imageList = [
 		key: "card-color-2",
 		src: "/static/assets/CardColorTwo.png",
 	},
+	{
+		key: "card-color-2-night",
+		src: "/static/assets/CardColorTwoNight.png",
+	},
 	{
 		key: "card-brown",
 		src: "/static/assets/CardBrown.png",
@@ -151,25 +156,74 @@ export const drawCard = (
 	}
 };
 
+const _rgbCache: Record<string, { r: number; g: number; b: number }> = {};
+const getColorRgb = (c: string): { r: number; g: number; b: number } => {
+	const { rgb } = parseColor(c);
+	const [r, g, b] = rgb;
+	return { r, g, b };
+	// if (c in _rgbCache) {
+	// 	return _rgbCache[c]!;
+	// }
+	// const canvas = document.createElement("canvas");
+	// canvas.width = 10;
+	// canvas.height = 10;
+	// const context = canvas.getContext("2d")!;
+	// context.fillRect(0, 0, 10, 10);
+	// const data = context.getImageData(5, 5, 1, 1).data;
+	// console.log(data);
+	// const [r, g, b] = data;
+	// const rgb = { r: r!, g: g!, b: b! };
+	// _rgbCache[c] = rgb;
+	// return rgb;
+};
+
+const getTextColorForBackground = (c: string): string => {
+	// return "black";
+	const { r, g, b } = getColorRgb(c);
+	const avg = (r + g + b) / 3 / 255;
+	console.log([r, g, b], avg);
+	return avg > 0.5 ? "black" : "white";
+};
+
 const getColors = (
 	types: DominionCardType[]
-): { primary: string; secondary: string | null } => {
+): {
+	primary: string;
+	secondary: string | null;
+	description: string | null;
+	descriptionText: string;
+	titleText: string;
+} => {
+	const descriptionType =
+		types.find((t) => t.color?.onConflictDescriptionOnly) ?? null;
 	const byPriority = [...types]
-		.filter((type) => type.color)
+		.filter((type) => type.color && type !== descriptionType)
 		.sort((a, b) => b.color!.priority - a.color!.priority);
 	const priority1 = byPriority[0]!;
-	let primary = priority1.color?.value ?? "white";
-	let secondary = byPriority[1]?.color?.value ?? null;
+	let primaryType: DominionCardType | null = priority1 ?? null;
+	let secondaryType = byPriority[1] ?? null;
 	if (priority1 === TYPE_ACTION) {
 		const overriders = byPriority.filter((t) => t.color!.overridesAction);
 		if (overriders.length) {
-			primary = overriders[0]!.color!.value;
+			primaryType = overriders[0] ?? null;
 		}
-		if (primary === secondary) {
-			secondary = byPriority[2]?.color?.value ?? null;
+		if (primaryType === secondaryType) {
+			secondaryType = byPriority[2] ?? null;
 		}
 	}
-	return { primary, secondary };
+	primaryType = primaryType ?? descriptionType;
+	const primary = primaryType?.color?.value ?? "white";
+	const secondary = secondaryType?.color?.value ?? null;
+	const description = descriptionType?.color?.value ?? null;
+	const descriptionText = getTextColorForBackground(description ?? primary);
+	const titleText = getTextColorForBackground(primary);
+	return {
+		primary,
+		secondary,
+		description,
+		descriptionText,
+		titleText,
+	};
 };
 
 const drawStandardCard = async (
@@ -213,6 +267,17 @@ const drawStandardCard = async (
 			0,
 			0
 		);
+	} else if (colors.description) {
+		context.drawImage(
+			colorImage(getImage("card-color-1"), colors.description),
+			0,
+			0
+		);
+		context.drawImage(
+			colorImage(getImage("card-color-2-night"), colors.primary),
+			0,
+			0
+		);
 	} else {
 		context.drawImage(
 			colorImage(getImage("card-color-1"), colors.primary),
@@ -224,6 +289,7 @@ const drawStandardCard = async (
 	context.drawImage(getImage("card-gray"), 0, 0);
 	context.drawImage(colorImage(getImage("card-brown"), "#ff9911"), 0, 0);
 	// Draw the name
+	context.fillStyle = colors.titleText;
 	size = 78;
 	context.font = `${size}pt DominionTitle`;
 	while (
@@ -234,7 +300,16 @@ const drawStandardCard = async (
 	}
 	await renderDominionText(context, parse(card.title), w / 2, 220);
 	// Draw the description
-	context.font = "60pt DominionText";
+	context.fillStyle = colors.descriptionText;
+	size = 60;
+	context.font = `${size}pt DominionText`;
+	while (
+		(await measureDominionText(context, parse(card.description), 1000))
+			.height > 650
+	) {
+		size -= 1;
+		context.font = `${size}pt DominionText`;
+	}
 	await renderDominionText(
 		context,
 		parse(card.description, { isDescription: true }),
@@ -243,6 +318,7 @@ const drawStandardCard = async (
 		1000
 	);
 	// Draw the types
+	context.fillStyle = colors.titleText;
 	size = 65;
 	context.font = `${size}pt DominionTitle`;
 	while (
@@ -264,6 +340,7 @@ const drawStandardCard = async (
 		800
 	);
 	// Draw the cost
+	context.fillStyle = colors.titleText;
 	context.font = "90pt DominionText";
 	const costMeasure = await measureDominionText(context, parse(card.cost));
 	await renderDominionText(
@@ -273,6 +350,7 @@ const drawStandardCard = async (
 		1940
 	);
 	// Draw the preview
+	context.fillStyle = colors.titleText;
 	if (card.preview) {
 		context.font = "90pt DominionText";
 		await renderDominionText(context, parse(card.preview), 200, 210);
@@ -293,6 +371,7 @@ const drawStandardCard = async (
 		2035
 	);
 	// Draw the artist credit
+	context.fillStyle = "white";
 	const artistMeasure = await measureDominionText(
 		context,
 		parse(card.artist)
diff --git a/src/types.ts b/src/types.ts
index 2fed73a..755df37 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -142,7 +142,7 @@ export const TYPE_NIGHT: DominionBasicCardType = {
 	typeType: "basic",
 	name: "Night",
 	color: {
-		value: "black",
+		value: "#485058",
 		priority: 6,
 		onConflictDescriptionOnly: true,
 	},