make react component
This commit is contained in:
		
							
								
								
									
										33
									
								
								TODO.md
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								TODO.md
									
									
									
									
									
								
							| @@ -1,15 +1,20 @@ | |||||||
| TODO | # TODO | ||||||
|  |  | ||||||
| - [ ] User Auth | ## MVP | ||||||
| - [x] Component Pack | - [ ] Update GH Workflow to be by push | ||||||
| - [x] Typescript Pack | - [ ] Add version prop to picobook.json | ||||||
| 	- [ ] Can this be used in a way where it doesn't need to be imported everywhere (lib?) | - [ ] "Compile" carts in server and save them to db | ||||||
| - [ ] Consider making more parts into Packs | - [ ] Load cart by URL in React | ||||||
| 	- [ ] tsconfig with extends |  | ||||||
| 	- [ ] server with wrapper around fastify | ## Later | ||||||
| 	- [ ] scripts from package.json | - [ ] Update pico console handle | ||||||
| - [ ] Streamline spinning up a server | - [ ] Add readme prop to picobook.json (figure out best name) and display it in React | ||||||
| - [ ] Should public be top level? | - [ ] Multiplayer support | ||||||
| - [ ] Clean up .env variable names | - [ ] More console support (touch detected, gamepad count, etc.) | ||||||
| - [ ] use Temporal (polyfill)? | - [ ] User accounts to manage published games, and user accounts for players to save progress | ||||||
| - [ ] Do I want to add testing infrastructure? | - [ ] GPIO Support (maybe gpio prop in picobook.json can have values like "ignore" | "v1") | ||||||
|  |  | ||||||
|  | ## GPIO ideas | ||||||
|  | - RGB background color | ||||||
|  | - Awards | ||||||
|  | - Extra buttons? | ||||||
| @@ -1,34 +1,16 @@ | |||||||
| import { css } from "@emotion/css"; | import { css } from "@emotion/css"; | ||||||
| import { Center, Cover, Stack } from "@firebox/components"; | import { Center, Cover, Stack } from "@firebox/components"; | ||||||
|  | import { Pico8Console } from "./pico8-client/Pico8Console"; | ||||||
|  | import testcarts from "./testcarts"; | ||||||
|  |  | ||||||
| const App = (props: { name: string }) => { | const App = (props: {}) => { | ||||||
| 	const {name} = props; |  | ||||||
| 	return ( | 	return ( | ||||||
| 		<Stack> | 		<div className={css` | ||||||
| 			<div className={css`background-color: floralwhite;`}> | 			min-height: 100vh; | ||||||
| 				<Cover gap pad> | 		`}> | ||||||
| 					<Center> | 			<Pico8Console carts={testcarts.carts} /> | ||||||
| 						<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> | ||||||
| 			<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> |  | ||||||
| 	); | 	); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| export const app = <App name="World" />; | export const app = <App />; | ||||||
|   | |||||||
| @@ -1,8 +1,8 @@ | |||||||
| // import { createRoot } from "react-dom/client"; | import { createRoot } from "react-dom/client"; | ||||||
| // import { app } from "./app.js"; | import { app } from "./app.js"; | ||||||
|  |  | ||||||
| // const domNode = document.getElementById("root")!; | const domNode = document.getElementById("root")!; | ||||||
| // const root = createRoot(domNode); | const root = createRoot(domNode); | ||||||
| // root.render(app); | root.render(app); | ||||||
|  |  | ||||||
| export * from "./pico8-client/index"; | // export * from "./pico8-client/index"; | ||||||
							
								
								
									
										44
									
								
								src/client/pico8-client/Pico8Console.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/client/pico8-client/Pico8Console.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | |||||||
|  | import { css } from "@emotion/css"; | ||||||
|  | import { PicoCart, PicoPlayerHandle, makePicoConsole } from "./renderCart"; | ||||||
|  | import { ForwardedRef, forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from "react"; | ||||||
|  |  | ||||||
|  | type Pico8ConsoleImperatives = { | ||||||
|  | 	getPicoConsoleHandle(): PicoPlayerHandle | null; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const Pico8Console = forwardRef((props: { carts: PicoCart[] }, forwardedRef: ForwardedRef<Pico8ConsoleImperatives>) => { | ||||||
|  | 	const {carts} = props; | ||||||
|  | 	const ref = useRef<HTMLDivElement>(null); | ||||||
|  | 	const [handle, setHandle] = useState<PicoPlayerHandle | null>(null); | ||||||
|  | 	const attachConsole = useCallback(async () => { | ||||||
|  | 		const picoConsole = await makePicoConsole({ | ||||||
|  | 			carts, | ||||||
|  | 		}); | ||||||
|  | 		if (ref.current) { | ||||||
|  | 			ref.current.appendChild(picoConsole.canvas); | ||||||
|  | 		} | ||||||
|  | 		setHandle(picoConsole); | ||||||
|  | 	}, [carts]); | ||||||
|  | 	useImperativeHandle(forwardedRef, () => ({ | ||||||
|  | 		getPicoConsoleHandle() { | ||||||
|  | 			return handle; | ||||||
|  | 		} | ||||||
|  | 	}), [handle]); | ||||||
|  | 	useEffect(() => { | ||||||
|  | 		attachConsole(); | ||||||
|  | 	}, [attachConsole]); | ||||||
|  | 	return ( | ||||||
|  | 		<div ref={ref} className={css` | ||||||
|  | 			width: 100%; | ||||||
|  | 			height: 100%; | ||||||
|  | 			display: flex; | ||||||
|  | 			align-items: center; | ||||||
|  | 			justify-content: center; | ||||||
|  |  | ||||||
|  | 			& > canvas { | ||||||
|  | 				width: 100%; | ||||||
|  | 				height: 100%; | ||||||
|  | 			} | ||||||
|  | 		`}></div> | ||||||
|  | 	); | ||||||
|  | }); | ||||||
| @@ -1,9 +1,9 @@ | |||||||
| // @ts-ignore | // @ts-ignore | ||||||
| import "./build/veryRawRenderCart.js"; | import "./build/veryRawRenderCart.js"; | ||||||
|  |  | ||||||
| type PicoBool = 0 | 1; | export type PicoBool = 0 | 1; | ||||||
|  |  | ||||||
| type RenderCart = (Module: {canvas: HTMLCanvasElement}, cartNames: string[], cartDatas: number[][], audioContext: AudioContext) => { | export type RenderCart = (Module: {canvas: HTMLCanvasElement}, cartNames: string[], cartDatas: number[][], audioContext: AudioContext) => { | ||||||
| 	p8_touch_detected?: PicoBool; | 	p8_touch_detected?: PicoBool; | ||||||
| 	p8_dropped_cart?: string; | 	p8_dropped_cart?: string; | ||||||
| 	p8_dropped_cart_name?: string; | 	p8_dropped_cart_name?: string; | ||||||
|   | |||||||
| @@ -1,8 +1,8 @@ | |||||||
| import { assertNever } from "@firebox/tsutil"; | import { assertNever } from "@firebox/tsutil"; | ||||||
| import { pngToRom } from "./pngToRom"; | import { pngToRom } from "./pngToRom"; | ||||||
| import { renderCart as rawRenderCart } from "./rawRenderCart"; | import { RenderCart, renderCart as rawRenderCart } from "./rawRenderCart"; | ||||||
|  |  | ||||||
| type PicoCart = { | export type PicoCart = { | ||||||
| 	name: string; | 	name: string; | ||||||
| 	src: string; | 	src: string; | ||||||
| } | { | } | { | ||||||
| @@ -20,7 +20,9 @@ type PlayerButtons = { | |||||||
| 	menu: boolean; | 	menu: boolean; | ||||||
| } | } | ||||||
|  |  | ||||||
| type PicoPlayerHandle = { | export type PicoPlayerHandle = { | ||||||
|  | 	raw: ReturnType<RenderCart>; | ||||||
|  | 	rawModule: unknown; | ||||||
| 	// external things | 	// external things | ||||||
| 	readonly canvas: HTMLCanvasElement; | 	readonly canvas: HTMLCanvasElement; | ||||||
|  |  | ||||||
| @@ -35,16 +37,16 @@ type PicoPlayerHandle = { | |||||||
| 	setGamepadCount: (count: number) => void; | 	setGamepadCount: (count: number) => void; | ||||||
| 	readonly gpio: number[]; // read + write (should be 256-tuple) | 	readonly gpio: number[]; // read + write (should be 256-tuple) | ||||||
|  |  | ||||||
| 	// state (all communicated out) | 	// state | ||||||
| 	readonly state: { | 	readonly state: { | ||||||
| 		readonly frameNumber: number; | 		frameNumber: number; | ||||||
| 		readonly isPaused: boolean; | 		isPaused: boolean; | ||||||
| 		readonly hasFocus: boolean; | 		hasFocus: boolean; | ||||||
| 		readonly requestPointerLock: boolean; | 		requestPointerLock: boolean; | ||||||
| 		readonly requirePageNavigateConfirmation: boolean; | 		requirePageNavigateConfirmation: boolean; | ||||||
| 		readonly showDpad: boolean; | 		showDpad: boolean; | ||||||
| 		readonly shutdownRequested: boolean; | 		shutdownRequested: boolean; | ||||||
| 		readonly soundVolume: number; | 		soundVolume: number; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	// misc? | 	// misc? | ||||||
| @@ -109,6 +111,8 @@ export const makePicoConsole = async (props: { | |||||||
| 	]; | 	]; | ||||||
| 	handle.pico8_gamepads = {count: 0}; | 	handle.pico8_gamepads = {count: 0}; | ||||||
| 	return { | 	return { | ||||||
|  | 		raw: handle, | ||||||
|  | 		rawModule: Module, | ||||||
| 		canvas, | 		canvas, | ||||||
| 		state: { | 		state: { | ||||||
| 			frameNumber: handle.pico8_state.frame_number!, | 			frameNumber: handle.pico8_state.frame_number!, | ||||||
|   | |||||||
							
								
								
									
										21
									
								
								src/client/testcarts.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/client/testcarts.ts
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -3,11 +3,6 @@ | |||||||
| <meta name="viewport" content="width=device-width, user-scalable=no"> | <meta name="viewport" content="width=device-width, user-scalable=no"> | ||||||
| <script type="text/javascript"> | <script type="text/javascript"> | ||||||
|  |  | ||||||
| 	console.log(Object.keys(window)); |  | ||||||
| 	setTimeout(() => { |  | ||||||
| 		console.log(Object.keys(window)); |  | ||||||
| 	}, 1000); |  | ||||||
|  |  | ||||||
| 	// Default shell for PICO-8 0.2.2 (includes @weeble's gamepad mod 1.0) | 	// Default shell for PICO-8 0.2.2 (includes @weeble's gamepad mod 1.0) | ||||||
| 	// This file is available under a CC0 license https://creativecommons.org/share-your-work/public-domain/cc0/ | 	// This file is available under a CC0 license https://creativecommons.org/share-your-work/public-domain/cc0/ | ||||||
| 	// (note: "this file" does not include any cartridge or cartridge artwork injected into a derivative html file when using the PICO-8 html exporter) | 	// (note: "this file" does not include any cartridge or cartridge artwork injected into a derivative html file when using the PICO-8 html exporter) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 dylan
					dylan