From 2e1282bc2d4b6e89a5dbd7d679cebf8c6589a672 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Wed, 22 Nov 2023 22:20:19 -0600 Subject: [PATCH] Render a Game Boy player for GB/GBC attachments --- package.json | 1 + src/components/gameboy.tsx | 47 ++++++++++++++++++++++++++++++++ src/components/media-gallery.tsx | 24 ++++++++++++---- yarn.lock | 26 +++++++++++++++++- 4 files changed, 92 insertions(+), 6 deletions(-) create mode 100644 src/components/gameboy.tsx diff --git a/package.json b/package.json index a6cfd4f56..b6144c5e9 100644 --- a/package.json +++ b/package.json @@ -174,6 +174,7 @@ "vite-plugin-html": "^3.2.0", "vite-plugin-require": "^1.1.10", "vite-plugin-static-copy": "^0.17.0", + "wasmboy": "^0.7.1", "wicg-inert": "^3.1.1", "zod": "^3.21.4" }, diff --git a/src/components/gameboy.tsx b/src/components/gameboy.tsx new file mode 100644 index 000000000..ec6617304 --- /dev/null +++ b/src/components/gameboy.tsx @@ -0,0 +1,47 @@ +import React, { useEffect, useRef } from 'react'; +// @ts-ignore No types available +import { WasmBoy } from 'wasmboy'; + +interface IGameboy extends React.CanvasHTMLAttributes { + /** URL to the ROM. */ + src: string; +} + +/** Component to display a playable Gameboy emulator. */ +const Gameboy: React.FC = ({ src, ...rest }) => { + const canvas = useRef(null); + + async function init() { + await WasmBoy.config(WasmBoyOptions, canvas.current!); + await WasmBoy.loadROM(src); + await WasmBoy.play(); + } + + useEffect(() => { + init(); + }, []); + + return ( + + ); +}; + +const WasmBoyOptions = { + headless: false, + useGbcWhenOptional: true, + isAudioEnabled: false, + frameSkip: 1, + audioBatchProcessing: true, + timersBatchProcessing: false, + audioAccumulateSamples: true, + graphicsBatchProcessing: false, + graphicsDisableScanlineRendering: false, + tileRendering: true, + tileCaching: true, + gameboyFPSCap: 60, + updateGraphicsCallback: false, + updateAudioCallback: false, + saveStateCallback: false, +}; + +export { Gameboy }; \ No newline at end of file diff --git a/src/components/media-gallery.tsx b/src/components/media-gallery.tsx index 0d8e48683..2cf8ee139 100644 --- a/src/components/media-gallery.tsx +++ b/src/components/media-gallery.tsx @@ -12,6 +12,8 @@ import { truncateFilename } from 'soapbox/utils/media'; import { isIOS } from '../is-mobile'; import { isPanoramic, isPortrait, isNonConformingRatio, minimumAspectRatio, maximumAspectRatio } from '../utils/media-aspect-ratio'; +import { Gameboy } from './gameboy'; + import type { Property } from 'csstype'; import type { List as ImmutableList } from 'immutable'; @@ -141,8 +143,22 @@ const Item: React.FC = ({ } let thumbnail: React.ReactNode = ''; + const ext = attachment.url.split('.').pop()?.toLowerCase(); - if (attachment.type === 'unknown') { + if (attachment.type === 'unknown' && ['gb', 'gbc'].includes(ext!)) { + return ( +
1, + })} + key={attachment.id} + style={{ position, float, left, top, right, bottom, height, width: `${width}%` }} + > + +
+ ); + } else if (attachment.type === 'unknown') { const filename = truncateFilename(attachment.url, MAX_FILENAME_LENGTH); const attachmentIcon = ( = ({ ); } else if (attachment.type === 'audio') { - const ext = attachment.url.split('.').pop()?.toUpperCase(); thumbnail = ( = ({ title={attachment.description} > - {ext} + {ext} ); } else if (attachment.type === 'video') { - const ext = attachment.url.split('.').pop()?.toUpperCase(); thumbnail = ( = ({ > - {ext} + {ext} ); } diff --git a/yarn.lock b/yarn.lock index a2d4c7e5d..79e9ac9e2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3108,6 +3108,10 @@ at-least-node@^1.0.0: resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== +"audiobuffer-to-wav@git+https://github.com/torch2424/audiobuffer-to-wav.git#es-module-rollup": + version "1.0.0" + resolved "git+https://github.com/torch2424/audiobuffer-to-wav.git#8878a20c5cc7e457b113dabfb1781ad4178f9c62" + autoprefixer@^10.4.15: version "10.4.15" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.15.tgz#a1230f4aeb3636b89120b34a1f513e2f6834d530" @@ -5197,6 +5201,11 @@ iconv-lite@0.6.3: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" +idb@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/idb/-/idb-2.1.3.tgz#7b295fa1a46ab7851e42dd85543a271435f87fee" + integrity sha512-1He6QAuavrD38HCiJasi4lEEK87Y22ldFuM+ZHkp433n4Fd5jXjWKutClYFp8w4mgx3zgrjnWxL8dpjMzcQ+WQ== + idb@^7.0.1: version "7.1.1" resolved "https://registry.yarnpkg.com/idb/-/idb-7.1.1.tgz#d910ded866d32c7ced9befc5bfdf36f572ced72b" @@ -7138,7 +7147,7 @@ quick-lru@^5.1.1: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== -raf@^3.1.0: +raf@^3.1.0, raf@^3.4.0: version "3.4.1" resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA== @@ -7709,6 +7718,11 @@ responselike@^2.0.0: dependencies: lowercase-keys "^2.0.0" +responsive-gamepad@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/responsive-gamepad/-/responsive-gamepad-1.1.0.tgz#0173d05199e3c41c09f3b1b9fa8eb811dad8e585" + integrity sha512-njsJuKvany9eYjywXm8iorTeXeAAPqwMNaRWOo8jlh0iQboXgGPf6Z6bLGntELrfU+vR94jTPJYRW0Zzb2gaRA== + restore-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" @@ -9040,6 +9054,16 @@ warning@^4.0.0, warning@^4.0.1, warning@^4.0.2: dependencies: loose-envify "^1.0.0" +wasmboy@^0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/wasmboy/-/wasmboy-0.7.1.tgz#5bbf0f0f386f8e9ea322a611689b889f9c3495d2" + integrity sha512-qgA3bIFAqioYs8kYXtsanIvedgZlZQf382zs3gNlZHIItsAnRzV70/Vp6cJxbK4FyaiG58ah8/g7OW3orrs9Lg== + dependencies: + audiobuffer-to-wav "git+https://github.com/torch2424/audiobuffer-to-wav.git#es-module-rollup" + idb "^2.1.3" + raf "^3.4.0" + responsive-gamepad "1.1.0" + watchpack@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d"