preliminary stuff
This commit is contained in:
		| @@ -1,33 +1,27 @@ | ||||
| import { css } from "@emotion/css"; | ||||
| import { Center, Cover, Stack } from "@firebox/components"; | ||||
| import { MathuscriptPlayer } from "./player/Player"; | ||||
| import { Katex } from "./player/MathText"; | ||||
|  | ||||
| const script = String.raw` | ||||
|  | ||||
| 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$?" | ||||
|  | ||||
| ` | ||||
|  | ||||
| const App = (props: { name: string }) => { | ||||
| 	const {name} = props; | ||||
| 	return ( | ||||
| 		<Stack> | ||||
| 			<div className={css`background-color: floralwhite;`}> | ||||
| 				<Cover gap pad> | ||||
| 					<Center> | ||||
| 						<Stack gap={-1}> | ||||
| 							<h1>Hello, {name}!</h1> | ||||
| 							<p>Welcome to a website with a certain design philosophy. Tell me how it's working out! I want to see this text wrap a few times. Hopefully this sentence will help.</p> | ||||
| 						</Stack> | ||||
| 					</Center> | ||||
| 					<Cover.Footer>A page by Dylan Pizzo</Cover.Footer> | ||||
| 				</Cover> | ||||
| 			</div> | ||||
| 			<div className={css`background-color: aliceblue;`}> | ||||
| 				<Cover gap pad> | ||||
| 					<Center> | ||||
| 						<Stack gap={-1}> | ||||
| 							<h1>Hello, {name}!</h1> | ||||
| 							<p>Welcome to a website with a certain design philosophy. Tell me how it's working out! I want to see this text wrap a few times. Hopefully this sentence will help.</p> | ||||
| 						</Stack> | ||||
| 					</Center> | ||||
| 					<Cover.Footer>A page by Dylan Pizzo</Cover.Footer> | ||||
| 				</Cover> | ||||
| 			</div> | ||||
| 		</Stack> | ||||
| 		<div className={css` | ||||
| 			margin: auto; | ||||
| 		`}> | ||||
| 			<h1>MathU</h1> | ||||
| 			<MathuscriptPlayer script={script} /> | ||||
| 		</div> | ||||
| 	); | ||||
| }; | ||||
|  | ||||
|   | ||||
							
								
								
									
										39
									
								
								src/client/player/MathText.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/client/player/MathText.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| import { css } from "@emotion/css"; | ||||
| import katex from "katex"; | ||||
| import { useLayoutEffect, useRef } from "react"; | ||||
|  | ||||
| export const Katex = (props: { tex: string }) => { | ||||
| 	const {tex} = props; | ||||
| 	const ref = useRef<HTMLDivElement>(null); | ||||
|  | ||||
| 	useLayoutEffect(() => { | ||||
| 		const element = ref.current; | ||||
| 		if (!element) { | ||||
| 			return; | ||||
| 		} | ||||
| 		katex.render(tex, element); | ||||
| 	}, [tex]) | ||||
| 	return ( | ||||
| 		<span ref={ref} className={css` | ||||
| 			math { | ||||
| 				display: none; | ||||
| 			} | ||||
| 		`}></span> | ||||
| 	); | ||||
| }; | ||||
|  | ||||
| export const MathText = (props: { children: string }) => { | ||||
| 	const str = props.children; | ||||
| 	const segments = str.split("$").map((s, i) => (i % 2 === 0 ? {type: "text", value: s} : {type: "math", value: s})); | ||||
| 	const components = segments.map((segment, i) => { | ||||
| 		if (segment.type === "text") { | ||||
| 			return segment.value.split("\\\\").flatMap((s, j) => [<br key={j}/>, s]).slice(1); | ||||
| 		} else if (segment.type === "math") { | ||||
| 			return <Katex key={i} tex={segment.value}/>; | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	return ( | ||||
| 		<>{components}</> | ||||
| 	); | ||||
| }; | ||||
							
								
								
									
										107
									
								
								src/client/player/Player.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								src/client/player/Player.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,107 @@ | ||||
| import { css } from "@emotion/css"; | ||||
| import { Mathuscript, parseMathuscript } from "./parse"; | ||||
| import katex from "katex"; | ||||
| import { useCallback, useLayoutEffect, useMemo, useRef, useState } from "react"; | ||||
| import { MathText } from "./MathText"; | ||||
|  | ||||
| type VisualState = { | ||||
| 	characters: {name: string, emotion: string, x: number}[], | ||||
| 	board: {text: string}, | ||||
| 	dialog: {name: string | null, text: string}, | ||||
| } | ||||
|  | ||||
| const afterStep = (state: VisualState, step: Mathuscript[number]): VisualState => { | ||||
| 	const newState = structuredClone(state); | ||||
| 	const {characters, board, dialog} = newState; | ||||
| 	if (step.name === "board") { | ||||
| 		board.text = step.text; | ||||
| 	} else { | ||||
| 		let char = characters.find(c => c.name === step.name); | ||||
| 		if (!char) { | ||||
| 			char = {name: step.name, emotion: "default", x: 0.5}; | ||||
| 		} | ||||
| 		char.emotion = step.emotion ?? char.emotion; | ||||
| 		dialog.name = step.name; | ||||
| 		dialog.text = step.text; | ||||
| 	} | ||||
| 	console.log(newState); | ||||
| 	return newState; | ||||
| } | ||||
|  | ||||
| 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 doStep = useCallback(() => { | ||||
| 		const step = parsedScript[index]; | ||||
| 		if (step) { | ||||
| 			console.log(step); | ||||
| 			setIndex(i => i+1); | ||||
| 			setVisualState(state => afterStep(state, step)); | ||||
| 		} else { | ||||
| 			console.log("the end"); | ||||
| 		} | ||||
| 	}, [index, parsedScript, setIndex, setVisualState]); | ||||
|  | ||||
| 	return ( | ||||
| 		<> | ||||
| 			<div className={css` | ||||
| 				width: 800px; | ||||
| 				height: 480px; | ||||
| 				border: 1px solid black; | ||||
| 				font-size: 16px; | ||||
| 				margin: auto; | ||||
| 				position: relative; | ||||
| 				background-image: url("/assets/background.png"); | ||||
| 				background-size: 118%; | ||||
| 				background-position-x: center; | ||||
| 				background-position-y: bottom; | ||||
| 			`}> | ||||
| 				<div className={css` | ||||
| 					position: absolute; | ||||
| 					width: 58%; | ||||
| 					top: 7%; | ||||
| 					left: 21%; | ||||
| 					height: 64%; | ||||
| 					display: flex; | ||||
| 					align-items: center; | ||||
| 					justify-content: center; | ||||
| 					color: white; | ||||
| 					/* background-color: rgba(255, 0, 0, 0.3); */ | ||||
| 					padding: 1em; | ||||
| 				`}> | ||||
| 					<div> | ||||
| 						<MathText>{visualState.board.text}</MathText> | ||||
| 					</div> | ||||
| 				</div> | ||||
| 				<div className={css` | ||||
| 					padding: 1em; | ||||
| 					display: flex; | ||||
| 					position: absolute; | ||||
| 					width: 100%; | ||||
| 					height: 25%; | ||||
| 					bottom: 0; | ||||
| 				`}> | ||||
| 					<div className={css` | ||||
| 						flex-basis: 0; | ||||
| 						flex-grow: 1; | ||||
| 						background-color: hsla(220, 50%, 40%, 0.85); | ||||
| 						border: 2px solid hsla(220, 30%, 60%, 0.85); | ||||
| 						border-radius: 0.25em; | ||||
| 						padding: 0.5em; | ||||
| 						color: white; | ||||
| 					`}> | ||||
| 						{ | ||||
| 							visualState.dialog.name && <> | ||||
| 								<strong>{visualState.dialog.name}.</strong> <MathText>{visualState.dialog.text}</MathText> | ||||
| 							</> | ||||
| 						} | ||||
| 					</div> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 			<button onClick={doStep}>Step</button> | ||||
| 		</> | ||||
| 	); | ||||
| }; | ||||
							
								
								
									
										14
									
								
								src/client/player/parse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/client/player/parse.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
|  | ||||
| const lineRegex = /^\s*(?<name>[a-z-]+)\s+(?:\((?<emotion>[a-z-]+)\))?\s*"(?<text>(?:[^"\\]|\\.)*)"\s*$/; | ||||
|  | ||||
| export const parseMathuscript = (script: string) => { | ||||
| 	return script.split("\n").filter(Boolean).map(line => { | ||||
| 		const match = line.match(lineRegex); | ||||
| 		if (!match) { | ||||
| 			throw Error(`Bad Line: ${JSON.stringify(line)}`); | ||||
| 		} | ||||
| 		return match.groups as Mathuscript[number]; | ||||
| 	}).filter(Boolean); | ||||
| } | ||||
|  | ||||
| export type Mathuscript = {name: string, emotion: string | undefined, text: string}[]; | ||||
							
								
								
									
										3
									
								
								src/client/player/render.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/client/player/render.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| // export const render = (str: string) => { | ||||
| // 	str.split("$").map((s, i) => (i % 2 === 0 ? s : katex.)) | ||||
| // } | ||||
							
								
								
									
										8
									
								
								src/client/player/script.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/client/player/script.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
|  | ||||
|  | ||||
| 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$" | ||||
|  | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 dylan
					dylan