diff --git a/src/client/app.tsx b/src/client/app.tsx
index 85e6f82..7a806a1 100644
--- a/src/client/app.tsx
+++ b/src/client/app.tsx
@@ -9,7 +9,19 @@ bridget (happy) "Hi, friends!"
 
 board "Given $f: \mathbb{Q} \to \mathbb{R}$ and $x \in \mathbb{Q}$, there is a unique $y \in \mathbb{N}$ such that $f(x)=y$"
 
-axelle (happy) "Wow, did you know that $a^2+b^2=c^2$?"
+calvin (happy) "Wow, did you know that $a^2+b^2=c^2$?"
+
+calvin (happy) "Something else"
+
+bridget (happy) "Me again"
+
+kit (happy) "I'm Kit!"
+
+board ""
+
+calvin (happy) "I'm back!"
+
+bridget (happy) "I'm on the right now!"
 
 `
 
diff --git a/src/client/player/Player.tsx b/src/client/player/Player.tsx
index 7d73445..a4aa72b 100644
--- a/src/client/player/Player.tsx
+++ b/src/client/player/Player.tsx
@@ -6,22 +6,40 @@ import { MathText } from "./MathText";
 import { characterData } from "./data";
 
 type VisualState = {
-	characters: {name: string, emotion: string, x: number}[],
+	turn: number,
+	characters: {name: string, emotion: string, side: "left" | "right", lastTurn: number}[],
 	board: {text: string},
 	dialog: {name: string | null, text: string},
 }
 
+const otherSide = (side: "left" | "right"): "left" | "right" => {
+	return ({
+		left: "right",
+		right: "left",
+	} as const)[side];
+}
+
 const afterStep = (state: VisualState, step: Mathuscript[number]): VisualState => {
 	const newState = structuredClone(state);
 	const {characters, board, dialog} = newState;
+	newState.turn += 1;
 	if (step.name === "board") {
 		board.text = step.text;
 	} else {
+		characters.sort((a, b) => a.lastTurn - b.lastTurn);
 		let char = characters.find(c => c.name === step.name);
 		if (!char) {
-			char = {name: step.name, emotion: "default", x: 0.5};
+			char = {name: step.name, emotion: "default", side: "left", lastTurn: -1};
+			if (characters.length > 1) {
+				characters.splice(0, characters.length-1);
+			}
+			const otherChar = characters[0];
+			if (otherChar) {
+				char.side = otherSide(otherChar.side);
+			}
 			characters.push(char);
 		}
+		char.lastTurn = newState.turn;
 		char.emotion = step.emotion ?? char.emotion;
 		dialog.name = step.name;
 		dialog.text = step.text;
@@ -41,7 +59,7 @@ export const MathuscriptPlayer = (props: { script: string }) => {
 	const {script} = props;
 	const parsedScript = useMemo(() => parseMathuscript(script), [script]);
 	const [index, setIndex] = useState(0);
-	const [visualState, setVisualState] = useState<VisualState>({characters: [], board: {text: ""}, dialog: {name: null, text: ""}});
+	const [visualState, setVisualState] = useState<VisualState>({turn: 0, characters: [], board: {text: ""}, dialog: {name: null, text: ""}});
 
 	const doStep = useCallback(() => {
 		const step = parsedScript[index];
@@ -105,9 +123,13 @@ export const MathuscriptPlayer = (props: { script: string }) => {
 							return <img
 								className={css`
 									position: absolute;
-									left: -20%;
+									${
+										c.side === "left" ? css`left: -20%;` : css`right: -20%; transform: scaleX(-1);`
+									}
 									height: 90%;
 									bottom: 0;
+									--outline-color: black;
+									filter: drop-shadow(1px 1px 0 var(--outline-color)) drop-shadow(-1px 1px 0 var(--outline-color)) drop-shadow(1px -1px 0 var(--outline-color)) drop-shadow(-1px -1px 0 var(--outline-color));
 								`}
 								key={c.name}
 								src={char.assets["default"]}
@@ -126,6 +148,7 @@ export const MathuscriptPlayer = (props: { script: string }) => {
 					<div className={css`
 						flex-basis: 0;
 						flex-grow: 1;
+						position: relative;
 						background-color: hsla(220, 50%, 40%, 0.85);
 						border: 2px solid hsla(220, 30%, 60%, 0.85);
 						border-radius: 0.25em;
@@ -134,7 +157,18 @@ export const MathuscriptPlayer = (props: { script: string }) => {
 					`}>
 						{
 							speakingChar && <>
-								<strong>{speakingChar.displayName}.</strong> <MathText>{visualState.dialog.text}</MathText>
+								<div className={css`
+									position: absolute;
+									bottom: 100%;
+									left: 0;
+									background-color: hsla(220, 50%, 40%, 0.85);
+									border: 2px solid hsla(220, 30%, 60%, 0.85);
+									border-radius: 0.25em;
+									padding: 0.25em 0.75em;
+								`}>
+									<strong>{speakingChar.displayName}</strong>
+								</div>
+								<MathText>{visualState.dialog.text}</MathText>
 							</>
 						}
 					</div>
diff --git a/src/client/player/data.ts b/src/client/player/data.ts
index 0f72983..558c31d 100644
--- a/src/client/player/data.ts
+++ b/src/client/player/data.ts
@@ -3,14 +3,18 @@ export const characterData = {
 		displayName: "Bridget",
 		assets: {
 			default: "/assets/bridget.png",
-			fallback: "/assets/bridget.png",
 		},
 	},
-	axelle: {
-		displayName: "Axelle",
+	calvin: {
+		displayName: "Calvin",
 		assets: {
-			default: "/assets/bridget.png",
-			fallback: "/assets/bridget.png",
+			default: "/assets/calvin.png",
 		},
-	}
+	},
+	kit: {
+		displayName: "Kit",
+		assets: {
+			default: "/assets/kit.png",
+		},
+	},
 }
\ No newline at end of file
diff --git a/src/server/public/assets/calvin.png b/src/server/public/assets/calvin.png
new file mode 100644
index 0000000..c803b19
Binary files /dev/null and b/src/server/public/assets/calvin.png differ
diff --git a/src/server/public/assets/kit.png b/src/server/public/assets/kit.png
new file mode 100644
index 0000000..f95304b
Binary files /dev/null and b/src/server/public/assets/kit.png differ