More visual improvements
This commit is contained in:
		| @@ -9,19 +9,23 @@ 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$" | ||||
|  | ||||
| calvin (happy) "Wow, did you know that $a^2+b^2=c^2$?" | ||||
| calvin (mathstruck) "Wow, did you know that $a^2+b^2=c^2$?" | ||||
|  | ||||
| calvin (happy) "Something else" | ||||
| calvin (thinking) "Something else" | ||||
|  | ||||
| bridget (happy) "Me again" | ||||
| bridget (surprised) "Me again" | ||||
|  | ||||
| kit (happy) "I'm Kit!" | ||||
| kit (smiling) "I'm Kit!" | ||||
|  | ||||
| board "" | ||||
|  | ||||
| calvin (happy) "I'm back!" | ||||
|  | ||||
| bridget (happy) "I'm on the right now!" | ||||
| bridget (aha) "I'm on the right now!" | ||||
|  | ||||
| theo (heh) "Oh, hey guys. Didn't see you there." | ||||
|  | ||||
| axelle "Oh, hi." | ||||
|  | ||||
| ` | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,6 @@ | ||||
| import { css } from "@emotion/css"; | ||||
| import { Mathuscript, parseMathuscript } from "./parse"; | ||||
| import katex from "katex"; | ||||
| import { useCallback, useLayoutEffect, useMemo, useRef, useState } from "react"; | ||||
| import { useCallback, useMemo, useRef, useState } from "react"; | ||||
| import { MathText } from "./MathText"; | ||||
| import { characterData } from "./data"; | ||||
|  | ||||
| @@ -9,7 +8,7 @@ type VisualState = { | ||||
| 	turn: number, | ||||
| 	characters: {name: string, emotion: string, side: "left" | "right", lastTurn: number}[], | ||||
| 	board: {text: string}, | ||||
| 	dialog: {name: string | null, text: string}, | ||||
| 	dialog: {name: string | null, emotion: string, text: string}, | ||||
| } | ||||
|  | ||||
| const otherSide = (side: "left" | "right"): "left" | "right" => { | ||||
| @@ -42,6 +41,7 @@ const afterStep = (state: VisualState, step: Mathuscript[number]): VisualState = | ||||
| 		char.lastTurn = newState.turn; | ||||
| 		char.emotion = step.emotion ?? char.emotion; | ||||
| 		dialog.name = step.name; | ||||
| 		dialog.emotion = char.emotion; | ||||
| 		dialog.text = step.text; | ||||
| 	} | ||||
| 	console.log(newState); | ||||
| @@ -55,23 +55,34 @@ const getCharData = (name: string | null) => { | ||||
| 	return null; | ||||
| } | ||||
|  | ||||
| const allChars = Object.keys(characterData) as (keyof typeof characterData)[]; | ||||
|  | ||||
| export const MathuscriptPlayer = (props: { script: string }) => { | ||||
| 	const {script} = props; | ||||
| 	const parsedScript = useMemo(() => parseMathuscript(script), [script]); | ||||
| 	const goAgain = useRef(false); | ||||
| 	const [index, setIndex] = useState(0); | ||||
| 	const [visualState, setVisualState] = useState<VisualState>({turn: 0, characters: [], board: {text: ""}, dialog: {name: null, text: ""}}); | ||||
| 	const [visualState, setVisualState] = useState<VisualState>({turn: 0, characters: [], board: {text: ""}, dialog: {name: null, emotion: "", text: ""}}); | ||||
|  | ||||
| 	const doStep = useCallback(() => { | ||||
| 		goAgain.current = false; | ||||
| 		const step = parsedScript[index]; | ||||
| 		if (step) { | ||||
| 			console.log(step); | ||||
| 			setIndex(i => i+1); | ||||
| 			setVisualState(state => afterStep(state, step)); | ||||
| 			if (step.name === "board") { | ||||
| 				goAgain.current = true; | ||||
| 			} | ||||
| 		} else { | ||||
| 			console.log("the end"); | ||||
| 		} | ||||
| 	}, [index, parsedScript, setIndex, setVisualState]); | ||||
|  | ||||
| 	if (goAgain.current) { | ||||
| 		doStep(); | ||||
| 	} | ||||
|  | ||||
| 	const speakingChar = getCharData(visualState.dialog.name); | ||||
|  | ||||
| 	return ( | ||||
| @@ -99,7 +110,6 @@ export const MathuscriptPlayer = (props: { script: string }) => { | ||||
| 					align-items: center; | ||||
| 					justify-content: center; | ||||
| 					color: white; | ||||
| 					/* background-color: rgba(255, 0, 0, 0.3); */ | ||||
| 					padding: 1em; | ||||
| 				`}> | ||||
| 					<div> | ||||
| @@ -114,26 +124,57 @@ export const MathuscriptPlayer = (props: { script: string }) => { | ||||
| 					left: 0; | ||||
| 				`}> | ||||
| 					{ | ||||
| 						visualState.characters.map(c => { | ||||
| 						allChars.map(name => { | ||||
| 							const visChar = visualState.characters.find(ch => ch.name === name); | ||||
| 							// TODO: make it change with emotion | ||||
| 							const char = getCharData(c.name); | ||||
| 							if (!char) { | ||||
| 							const charDat = getCharData(name); | ||||
| 							if (!charDat) { | ||||
| 								return null; | ||||
| 							} | ||||
| 							return <img | ||||
| 							const visualInactive = visChar && visualState.dialog.name !== name; | ||||
| 							return [ | ||||
| 								<img | ||||
| 									className={css` | ||||
| 										position: absolute; | ||||
| 										transition: all 0.25s; | ||||
| 										left: -60%; | ||||
| 										${ | ||||
| 										c.side === "left" ? css`left: -20%;` : css`right: -20%; transform: scaleX(-1);` | ||||
| 											visChar?.side === "left" && css`left: -20%;` | ||||
| 										} | ||||
| 										height: 90%; | ||||
| 										bottom: 0; | ||||
| 									--outline-color: black; | ||||
| 										${ | ||||
| 											visualInactive && css`bottom: -3%;` | ||||
| 										} | ||||
| 										--outline-color: white; | ||||
| 										/* --outline-color: hsl(300, 45%, 40%); */ | ||||
| 										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"]} | ||||
| 									key={`${name}-left`} | ||||
| 									src={charDat.assets["default"]} | ||||
| 								/>, | ||||
| 								<img | ||||
| 									className={css` | ||||
| 										position: absolute; | ||||
| 										transition: all 0.25s; | ||||
| 										transform: scaleX(-1); | ||||
| 										right: -60%; | ||||
| 										${ | ||||
| 											visChar?.side === "right" && css`right: -20%;` | ||||
| 										} | ||||
| 										height: 90%; | ||||
| 										bottom: 0; | ||||
| 										${ | ||||
| 											visualInactive && css`bottom: -3%;` | ||||
| 										} | ||||
| 										--outline-color: white; | ||||
| 										/* --outline-color: hsl(300, 45%, 40%); */ | ||||
| 										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={`${name}-right`} | ||||
| 									src={charDat.assets["default"]} | ||||
| 								/> | ||||
| 							] | ||||
| 						}) | ||||
| 					} | ||||
| 				</div> | ||||
| @@ -168,7 +209,7 @@ export const MathuscriptPlayer = (props: { script: string }) => { | ||||
| 								`}> | ||||
| 									<strong>{speakingChar.displayName}</strong> | ||||
| 								</div> | ||||
| 								<MathText>{visualState.dialog.text}</MathText> | ||||
| 								{visualState.dialog.emotion && <em>({visualState.dialog.emotion})</em>} <MathText>{visualState.dialog.text}</MathText> | ||||
| 							</> | ||||
| 						} | ||||
| 					</div> | ||||
|   | ||||
| @@ -17,4 +17,16 @@ export const characterData = { | ||||
| 			default: "/assets/kit.png", | ||||
| 		}, | ||||
| 	}, | ||||
| 	theo: { | ||||
| 		displayName: "Theo", | ||||
| 		assets: { | ||||
| 			default: "/assets/theo.png", | ||||
| 		}, | ||||
| 	}, | ||||
| 	axelle: { | ||||
| 		displayName: "Axelle", | ||||
| 		assets: { | ||||
| 			default: "/assets/axelle.png", | ||||
| 		}, | ||||
| 	}, | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								src/server/public/assets/axelle.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/server/public/assets/axelle.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 495 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/server/public/assets/theo.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/server/public/assets/theo.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 773 KiB | 
		Reference in New Issue
	
	Block a user
	 dylan
					dylan