NERDDISCO commited on
Commit
2d85080
•
1 Parent(s): 35d05d3

feat: renamed a few components, added cancel, changed the default button

Browse files
public/js/utils.js CHANGED
@@ -49,7 +49,7 @@ function answer(window_, channel, targetOrigin = "*") {
49
  }
50
 
51
  function handleTemplate(template) {
52
- Function("Template", `${template};`)();
53
  }
54
 
55
  subscribe("2DGameGPT", event => {
 
49
  }
50
 
51
  function handleTemplate(template) {
52
+ Function("Template", `${template}`)();
53
  }
54
 
55
  subscribe("2DGameGPT", event => {
src/components/Examples.tsx CHANGED
@@ -17,6 +17,7 @@ import {
17
  } from "@mui/material";
18
  import { DividerBox, SectionBox } from "./base/boxes";
19
  import { DynamicFeed, PrecisionManufacturing } from "@mui/icons-material";
 
20
 
21
  export default function Examples() {
22
  return (
@@ -27,12 +28,38 @@ export default function Examples() {
27
  <Typography component="h3" variant="h2">
28
  Example Games
29
  </Typography>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  </SectionBox>
31
 
32
  <Grid container>
33
  <Grid item sm={4}>
34
  <Card>
35
- <CardHeader title="Space Invaders Extreme"></CardHeader>
 
 
 
 
 
 
 
 
 
 
36
  <CardMedia
37
  component="img"
38
  image="img/space_invaders_extreme.jpg"
@@ -50,7 +77,7 @@ export default function Examples() {
50
  target="_blank"
51
  rel="noopener"
52
  >
53
- via Codesandbox
54
  </Link>
55
  </TableCell>
56
  </TableRow>
 
17
  } from "@mui/material";
18
  import { DividerBox, SectionBox } from "./base/boxes";
19
  import { DynamicFeed, PrecisionManufacturing } from "@mui/icons-material";
20
+ import theme from "@/lib/theme";
21
 
22
  export default function Examples() {
23
  return (
 
28
  <Typography component="h3" variant="h2">
29
  Example Games
30
  </Typography>
31
+ <Typography variant="body1">
32
+ We re-created some of our favorite games! You want to share your game with the
33
+ community? Then head over to our{" "}
34
+ <Link
35
+ href="https://discord.com/invite/m3TBB9XEkb"
36
+ target="_blank"
37
+ rel="noopener"
38
+ sx={{ verticalAlign: "bottom" }}
39
+ >
40
+ <img
41
+ style={{ verticalAlign: "bottom" }}
42
+ src="https://img.shields.io/discord/1091306623819059300?color=7289da&label=Discord&logo=discord&logoColor=fff&style=for-the-badge"
43
+ />
44
+ </Link>
45
+ , post it in #showcase and we might add it to this section as well!
46
+ </Typography>
47
  </SectionBox>
48
 
49
  <Grid container>
50
  <Grid item sm={4}>
51
  <Card>
52
+ <CardHeader
53
+ title="Space Invaders Extreme"
54
+ subheader={
55
+ <>
56
+ by{" "}
57
+ <Link href="https://nerddis.co" target="_blank" rel="noopener">
58
+ NERDDISCO
59
+ </Link>
60
+ </>
61
+ }
62
+ ></CardHeader>
63
  <CardMedia
64
  component="img"
65
  image="img/space_invaders_extreme.jpg"
 
77
  target="_blank"
78
  rel="noopener"
79
  >
80
+ on CodeSandbox
81
  </Link>
82
  </TableCell>
83
  </TableRow>
src/components/GameCreator.tsx CHANGED
@@ -1,15 +1,12 @@
1
- import { SyntheticEvent, useEffect, useMemo, useRef, useState } from "react";
2
 
3
- import axios, { AxiosError } from "axios";
4
- import KeyIcon from "@mui/icons-material/Key";
5
- import SmartButtonIcon from "@mui/icons-material/SmartButton";
6
  import AcUnitIcon from "@mui/icons-material/AcUnit";
7
  import LocalFireDepartmentIcon from "@mui/icons-material/LocalFireDepartment";
8
  import CheckIcon from "@mui/icons-material/Check";
9
  import ClearIcon from "@mui/icons-material/Clear";
10
  import CodeIcon from "@mui/icons-material/Code";
11
  import CodeOffIcon from "@mui/icons-material/CodeOff";
12
- import EditIcon from "@mui/icons-material/Edit";
13
  import VisibilityIcon from "@mui/icons-material/Visibility";
14
  import DeleteForeverIcon from "@mui/icons-material/DeleteForever";
15
  import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
@@ -36,7 +33,6 @@ import ListItemButton from "@mui/material/ListItemButton";
36
  import ListItemText from "@mui/material/ListItemText";
37
  import { useHost } from "esdeka/react";
38
  import CircularProgress from "@mui/material/CircularProgress";
39
- import CssBaseline from "@mui/material/CssBaseline";
40
  import Slider from "@mui/material/Slider";
41
  import { useAtom } from "jotai";
42
  import Button from "@mui/material/Button";
@@ -61,23 +57,14 @@ import {
61
  COMMAND_REMOVE_FEATURE,
62
  } from "@/constants";
63
  import { baseGame } from "@/constants/baseGame";
64
- import { EditTitle } from "@/components/EditTitle";
65
- import theme, { fontMono } from "@/lib/theme";
66
  import { Codesandbox } from "@/components/Codesandbox";
67
- import { Codepen } from "@/components/Codepen";
68
- import { InfoMenu } from "@/components/InfoMenu";
69
- import SimpleSnackbar from "@/components/SimpleSnackbar";
70
  import ExampleButton from "@/components/base/ExampleButton";
71
- import { Container, Grid, Link, ListSubheader } from "@mui/material";
72
  import Secret from "@/components/base/secret";
73
- import Footer from "@/components/footer";
74
- import Title from "@/components/title";
75
- import { RunCircle } from "@mui/icons-material";
76
- import Introduction from "@/components/Introduction";
77
- import Instructions from "@/components/Instructions";
78
- import Examples from "@/components/Examples";
79
  import { toOpenAI } from "@/services/api";
80
  import { createClient } from "@/services/api/openai";
 
81
  const MonacoEditor = dynamic(import("@monaco-editor/react"), { ssr: false });
82
 
83
  export interface ShareProps {
@@ -87,6 +74,8 @@ export interface ShareProps {
87
 
88
  export default function GameCreator() {
89
  const ref = useRef<HTMLIFrameElement>(null);
 
 
90
  const [prompt, setPrompt] = useState("");
91
  const [template, setTemplate] = useState(prettify(baseGame.default));
92
  const [runningId, setRunningId] = useState("1");
@@ -96,7 +85,6 @@ export default function GameCreator() {
96
  const [showCode, setShowCode] = useAtom(showCodeAtom);
97
  const [loading, setLoading] = useState(false);
98
  const [loadingLive, setLoadingLive] = useState(true);
99
- const [showError, setShowError] = useState(false);
100
  const [errorMessage, setErrorMessage] = useState("");
101
 
102
  const { mode, systemMode } = useColorScheme();
@@ -150,6 +138,14 @@ export default function GameCreator() {
150
  };
151
  }, [subscribe, loadingLive]);
152
 
 
 
 
 
 
 
 
 
153
  const sortedAnswers = useMemo(() => {
154
  return [...answers].sort((a, b) => {
155
  if (a.id === "1") return -1;
@@ -160,14 +156,6 @@ export default function GameCreator() {
160
 
161
  const current = answers.find(({ id }) => id === activeId);
162
 
163
- const handleSnackbarClose = (event: SyntheticEvent | Event, reason?: string) => {
164
- if (reason === "clickaway") {
165
- return;
166
- }
167
-
168
- setShowError(false);
169
- };
170
-
171
  function reload() {
172
  connection.current = false;
173
  if (ref.current) {
@@ -186,7 +174,7 @@ export default function GameCreator() {
186
  inset: 0,
187
  overflow: "hidden",
188
  flexDirection: { md: "row" },
189
- height: "100vh",
190
  }}
191
  >
192
  <Stack
@@ -199,10 +187,14 @@ export default function GameCreator() {
199
  >
200
  <AppBar position="static" elevation={0} color="default">
201
  <Toolbar>
202
- <Typography variant="h5" component="h2" sx={{ flex: 1, m: 0 }}>
203
  2D GameCreator-GPT
204
  </Typography>
205
 
 
 
 
 
206
  <IconButton
207
  color="inherit"
208
  aria-label={showCode ? "Hide Code" : "Show Code"}
@@ -212,19 +204,6 @@ export default function GameCreator() {
212
  >
213
  {showCode ? <CodeOffIcon /> : <CodeIcon />}
214
  </IconButton>
215
- {/* <IconButton
216
- edge="end"
217
- color="inherit"
218
- aria-label="Clear Prompt"
219
- onClick={async () => {
220
- setActiveId("1");
221
- setRunningId("1");
222
- setTemplate(prettify(baseGame.default));
223
- reload();
224
- }}
225
- >
226
- <ClearIcon />
227
- </IconButton> */}
228
  </Toolbar>
229
  </AppBar>
230
  {showCode && (
@@ -279,6 +258,8 @@ export default function GameCreator() {
279
  try {
280
  setLoading(true);
281
 
 
 
282
  const {
283
  command,
284
  prompt,
@@ -299,17 +280,22 @@ export default function GameCreator() {
299
  model: model as string,
300
  maxTokens: maxTokens as string,
301
  client,
 
302
  });
303
 
304
  setAnswers(previousAnswers => [answer, ...previousAnswers]);
305
  setRunningId(answer.id);
306
  setActiveId(answer.id);
307
  setTemplate(prettify(answer.content));
 
308
  reload();
309
  } catch (error) {
310
- setShowError(true);
311
- setErrorMessage((error as AxiosError).message);
312
- console.error(error);
 
 
 
313
  } finally {
314
  setLoading(false);
315
  }
@@ -322,13 +308,14 @@ export default function GameCreator() {
322
  <TextField
323
  multiline
324
  fullWidth
 
325
  required
326
  id="prompt"
327
  name="prompt"
328
  label="Prompt"
329
  value={prompt}
330
  onChange={e => setPrompt(e.target.value)}
331
- minRows={5}
332
  InputProps={{
333
  style: fontMono.style,
334
  }}
@@ -364,36 +351,49 @@ export default function GameCreator() {
364
  </Select>
365
  </FormControl>
366
 
367
- <Button
368
- form="gpt-form"
369
- type="submit"
370
  variant="contained"
371
  fullWidth
372
- aria-label={loading ? "Loading" : "Run"}
373
- aria-disabled={loading}
374
- disabled={loading}
375
- startIcon={
376
- loading ? (
377
- <CircularProgress size={20} />
378
- ) : (
379
- <PlayArrowIcon />
380
- )
381
- }
382
- sx={{
383
- pl: 5,
384
- pr: 5,
385
- flexGrow: 1,
386
- overflow: "auto",
387
- }}
388
  >
389
- <Typography sx={{ fontWeight: "500" }}>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
390
  Run
391
- </Typography>
392
- </Button>
393
- <Box sx={{ flex: 1 }} />
 
 
 
 
 
 
 
 
 
 
 
394
  </Stack>
395
  </Stack>
396
 
 
 
397
  <Stack direction="row" spacing={1} alignItems="center">
398
  <Typography>Examples</Typography>
399
 
@@ -585,38 +585,73 @@ export default function GameCreator() {
585
  }
586
  disablePadding
587
  >
588
- <ListItemButton
589
- dense
590
- selected={activeId === answer.id}
591
- // disabled={activeId === answer.id}
592
- role={undefined}
593
- onClick={() => {
594
- setActiveId(answer.id);
595
- setRunningId(answer.id);
596
- setTemplate(prettify(answer.content));
597
- reload();
598
- }}
599
- >
600
- <ListItemIcon>
601
- {runningId === answer.id ? (
602
- <CheckIcon />
603
- ) : (
604
- <VisibilityIcon />
605
- )}
606
- </ListItemIcon>
607
-
608
- <ListItemText
609
- primary={answer.task}
610
- primaryTypographyProps={{
611
- sx: {
612
- overflow: "hidden",
613
- textOverflow: "ellipsis",
614
- whiteSpace: "nowrap",
615
- fontSize: 16,
616
- },
617
  }}
618
- />
619
- </ListItemButton>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
620
  </ListItem>
621
  );
622
  })}
@@ -697,12 +732,6 @@ export default function GameCreator() {
697
  </Stack>
698
  </Stack>
699
  </Paper>
700
-
701
- <SimpleSnackbar
702
- handleClose={handleSnackbarClose}
703
- showError={showError}
704
- message={errorMessage}
705
- />
706
  </>
707
  );
708
  }
 
1
+ import { useEffect, useMemo, useRef, useState } from "react";
2
 
3
+ import { AxiosError } from "axios";
 
 
4
  import AcUnitIcon from "@mui/icons-material/AcUnit";
5
  import LocalFireDepartmentIcon from "@mui/icons-material/LocalFireDepartment";
6
  import CheckIcon from "@mui/icons-material/Check";
7
  import ClearIcon from "@mui/icons-material/Clear";
8
  import CodeIcon from "@mui/icons-material/Code";
9
  import CodeOffIcon from "@mui/icons-material/CodeOff";
 
10
  import VisibilityIcon from "@mui/icons-material/Visibility";
11
  import DeleteForeverIcon from "@mui/icons-material/DeleteForever";
12
  import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
 
33
  import ListItemText from "@mui/material/ListItemText";
34
  import { useHost } from "esdeka/react";
35
  import CircularProgress from "@mui/material/CircularProgress";
 
36
  import Slider from "@mui/material/Slider";
37
  import { useAtom } from "jotai";
38
  import Button from "@mui/material/Button";
 
57
  COMMAND_REMOVE_FEATURE,
58
  } from "@/constants";
59
  import { baseGame } from "@/constants/baseGame";
60
+ import { fontMono } from "@/lib/theme";
 
61
  import { Codesandbox } from "@/components/Codesandbox";
 
 
 
62
  import ExampleButton from "@/components/base/ExampleButton";
63
+ import { Alert, ButtonGroup, ListSubheader } from "@mui/material";
64
  import Secret from "@/components/base/secret";
 
 
 
 
 
 
65
  import { toOpenAI } from "@/services/api";
66
  import { createClient } from "@/services/api/openai";
67
+ import { RainbowListItemButton } from "./base/boxes";
68
  const MonacoEditor = dynamic(import("@monaco-editor/react"), { ssr: false });
69
 
70
  export interface ShareProps {
 
74
 
75
  export default function GameCreator() {
76
  const ref = useRef<HTMLIFrameElement>(null);
77
+ const abortController = useRef<AbortController | null>(null);
78
+
79
  const [prompt, setPrompt] = useState("");
80
  const [template, setTemplate] = useState(prettify(baseGame.default));
81
  const [runningId, setRunningId] = useState("1");
 
85
  const [showCode, setShowCode] = useAtom(showCodeAtom);
86
  const [loading, setLoading] = useState(false);
87
  const [loadingLive, setLoadingLive] = useState(true);
 
88
  const [errorMessage, setErrorMessage] = useState("");
89
 
90
  const { mode, systemMode } = useColorScheme();
 
138
  };
139
  }, [subscribe, loadingLive]);
140
 
141
+ const handleCancel = async () => {
142
+ if (abortController.current) {
143
+ abortController.current.abort();
144
+ }
145
+ setLoading(false);
146
+ reload();
147
+ };
148
+
149
  const sortedAnswers = useMemo(() => {
150
  return [...answers].sort((a, b) => {
151
  if (a.id === "1") return -1;
 
156
 
157
  const current = answers.find(({ id }) => id === activeId);
158
 
 
 
 
 
 
 
 
 
159
  function reload() {
160
  connection.current = false;
161
  if (ref.current) {
 
174
  inset: 0,
175
  overflow: "hidden",
176
  flexDirection: { md: "row" },
177
+ height: "90vh",
178
  }}
179
  >
180
  <Stack
 
187
  >
188
  <AppBar position="static" elevation={0} color="default">
189
  <Toolbar>
190
+ <Typography variant="h5" component="h2" sx={{ m: 0 }}>
191
  2D GameCreator-GPT
192
  </Typography>
193
 
194
+ <Typography variant="body2" sx={{ ml: 1, flex: 1 }}>
195
+ v0.0.1
196
+ </Typography>
197
+
198
  <IconButton
199
  color="inherit"
200
  aria-label={showCode ? "Hide Code" : "Show Code"}
 
204
  >
205
  {showCode ? <CodeOffIcon /> : <CodeIcon />}
206
  </IconButton>
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  </Toolbar>
208
  </AppBar>
209
  {showCode && (
 
258
  try {
259
  setLoading(true);
260
 
261
+ abortController.current = new AbortController();
262
+
263
  const {
264
  command,
265
  prompt,
 
280
  model: model as string,
281
  maxTokens: maxTokens as string,
282
  client,
283
+ signal: abortController.current.signal,
284
  });
285
 
286
  setAnswers(previousAnswers => [answer, ...previousAnswers]);
287
  setRunningId(answer.id);
288
  setActiveId(answer.id);
289
  setTemplate(prettify(answer.content));
290
+ setErrorMessage("");
291
  reload();
292
  } catch (error) {
293
+ if (
294
+ (error as { message?: string }).message !== "canceled"
295
+ ) {
296
+ setErrorMessage((error as AxiosError).message);
297
+ console.error(error);
298
+ }
299
  } finally {
300
  setLoading(false);
301
  }
 
308
  <TextField
309
  multiline
310
  fullWidth
311
+ variant="outlined"
312
  required
313
  id="prompt"
314
  name="prompt"
315
  label="Prompt"
316
  value={prompt}
317
  onChange={e => setPrompt(e.target.value)}
318
+ minRows={3}
319
  InputProps={{
320
  style: fontMono.style,
321
  }}
 
351
  </Select>
352
  </FormControl>
353
 
354
+ <ButtonGroup
 
 
355
  variant="contained"
356
  fullWidth
357
+ sx={{ flexGrow: 1, maxHeight: "96px" }}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
358
  >
359
+ <Button
360
+ form="gpt-form"
361
+ type="submit"
362
+ aria-label={loading ? "Loading" : "Run"}
363
+ aria-disabled={loading}
364
+ disabled={loading}
365
+ startIcon={
366
+ loading ? (
367
+ <CircularProgress size={20} />
368
+ ) : (
369
+ <PlayArrowIcon />
370
+ )
371
+ }
372
+ sx={{
373
+ pl: 5,
374
+ pr: 5,
375
+ }}
376
+ >
377
  Run
378
+ </Button>
379
+ <Button
380
+ aria-label="Cancel"
381
+ aria-disabled={!loading}
382
+ disabled={!loading}
383
+ onClick={handleCancel}
384
+ startIcon={<ClearIcon />}
385
+ color="error"
386
+ sx={{
387
+ pl: 0,
388
+ pr: 0,
389
+ }}
390
+ ></Button>
391
+ </ButtonGroup>
392
  </Stack>
393
  </Stack>
394
 
395
+ {errorMessage && <Alert severity="error">{errorMessage}</Alert>}
396
+
397
  <Stack direction="row" spacing={1} alignItems="center">
398
  <Typography>Examples</Typography>
399
 
 
585
  }
586
  disablePadding
587
  >
588
+ {activeId === answer.id ? (
589
+ <RainbowListItemButton
590
+ dense
591
+ selected={activeId === answer.id}
592
+ // disabled={activeId === answer.id}
593
+ role={undefined}
594
+ onClick={() => {
595
+ setActiveId(answer.id);
596
+ setRunningId(answer.id);
597
+ setTemplate(prettify(answer.content));
598
+ reload();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
599
  }}
600
+ >
601
+ <ListItemIcon>
602
+ {runningId === answer.id ? (
603
+ <CheckIcon />
604
+ ) : (
605
+ <VisibilityIcon />
606
+ )}
607
+ </ListItemIcon>
608
+
609
+ <ListItemText
610
+ primary={answer.task}
611
+ primaryTypographyProps={{
612
+ sx: {
613
+ overflow: "hidden",
614
+ textOverflow: "ellipsis",
615
+ whiteSpace: "nowrap",
616
+ fontSize: 16,
617
+ },
618
+ }}
619
+ />
620
+ </RainbowListItemButton>
621
+ ) : (
622
+ <ListItemButton
623
+ dense
624
+ selected={activeId === answer.id}
625
+ // disabled={activeId === answer.id}
626
+ role={undefined}
627
+ onClick={() => {
628
+ setActiveId(answer.id);
629
+ setRunningId(answer.id);
630
+ setTemplate(prettify(answer.content));
631
+ reload();
632
+ }}
633
+ >
634
+ <ListItemIcon>
635
+ {runningId === answer.id ? (
636
+ <CheckIcon />
637
+ ) : (
638
+ <VisibilityIcon />
639
+ )}
640
+ </ListItemIcon>
641
+
642
+ <ListItemText
643
+ primary={answer.task}
644
+ primaryTypographyProps={{
645
+ sx: {
646
+ overflow: "hidden",
647
+ textOverflow: "ellipsis",
648
+ whiteSpace: "nowrap",
649
+ fontSize: 16,
650
+ },
651
+ }}
652
+ />
653
+ </ListItemButton>
654
+ )}
655
  </ListItem>
656
  );
657
  })}
 
732
  </Stack>
733
  </Stack>
734
  </Paper>
 
 
 
 
 
 
735
  </>
736
  );
737
  }
src/components/{Workflow.tsx → HowToUse.tsx} RENAMED
@@ -1,4 +1,4 @@
1
- import { PlayArrow, Code, Replay, CropSquare } from "@mui/icons-material";
2
  import {
3
  Button,
4
  Grid,
@@ -7,12 +7,24 @@ import {
7
  ListItem,
8
  ListSubheader,
9
  Paper,
 
10
  Typography,
11
  } from "@mui/material";
12
  import { OutlinedBox, SectionBox, RainbowBox } from "@/components/base/boxes";
13
  import { Key } from "react";
14
 
15
  const workflowSteps = [
 
 
 
 
 
 
 
 
 
 
 
16
  {
17
  title: "Create a New Game",
18
  steps: [
@@ -94,7 +106,7 @@ const workflowSteps = [
94
  "Open the Options by clicking on them",
95
  "Switch the model between gpt-4 and gpt-3.5-turbo (default)",
96
  "Update the max_tokens to 4096 (gpt-4), default is 2048 (gpt-3.5-turbo)",
97
- "Make changes to the temperature if you want more random results, default is 0.2",
98
  ],
99
  },
100
  ];
@@ -130,6 +142,18 @@ function parseString(string: string) {
130
  &nbsp;
131
  </>
132
  ),
 
 
 
 
 
 
 
 
 
 
 
 
133
  "source code button": (item: string, index: Key | null | undefined) => (
134
  <>
135
  &nbsp;
@@ -205,7 +229,7 @@ function parseString(string: string) {
205
  });
206
  }
207
 
208
- export default function Workflow() {
209
  return (
210
  <>
211
  <SectionBox>
 
1
+ import { PlayArrow, Code, Replay, CropSquare, Clear } from "@mui/icons-material";
2
  import {
3
  Button,
4
  Grid,
 
7
  ListItem,
8
  ListSubheader,
9
  Paper,
10
+ Stack,
11
  Typography,
12
  } from "@mui/material";
13
  import { OutlinedBox, SectionBox, RainbowBox } from "@/components/base/boxes";
14
  import { Key } from "react";
15
 
16
  const workflowSteps = [
17
+ {
18
+ title: "Editor Usage Tips",
19
+ steps: [
20
+ "We are limited by the context-size of the selected model, the scope of the game shouldn't be super huge (for example 'asteroids' is a game with small scope while 'fortnite' is way too big)",
21
+ "It's good to start with simple features, main mechanics first using the base game + the create game command.",
22
+ 'Iterate on this. For example "Flappy Bird. Intro screen, start the game by pressing space key."',
23
+ "See if the generated result is what you expect. Continue there, add more features. Either by using the add feature command or by extending the prompt itself and start from scratch (select the base game + create game command).",
24
+ "Make always sure to check the selected game in the games list, as this is used as the foundation for the next iteration.",
25
+ "Cancel generating the game at any time by pressing the cancel button button next to run button.",
26
+ ],
27
+ },
28
  {
29
  title: "Create a New Game",
30
  steps: [
 
106
  "Open the Options by clicking on them",
107
  "Switch the model between gpt-4 and gpt-3.5-turbo (default)",
108
  "Update the max_tokens to 4096 (gpt-4), default is 2048 (gpt-3.5-turbo)",
109
+ "Make changes to the temperature if you want more random (value closer to 1.0) results, default is 0.2 (not very random)",
110
  ],
111
  },
112
  ];
 
142
  &nbsp;
143
  </>
144
  ),
145
+ "cancel button": (item: string, index: Key | null | undefined) => (
146
+ <>
147
+ &nbsp;
148
+ <Button
149
+ variant="contained"
150
+ color="error"
151
+ startIcon={<Clear />}
152
+ key={index}
153
+ ></Button>
154
+ &nbsp;
155
+ </>
156
+ ),
157
  "source code button": (item: string, index: Key | null | undefined) => (
158
  <>
159
  &nbsp;
 
229
  });
230
  }
231
 
232
+ export default function HowToUse() {
233
  return (
234
  <>
235
  <SectionBox>
src/components/Introduction.tsx CHANGED
@@ -9,42 +9,48 @@ import {
9
  ListItemIcon,
10
  ListItemText,
11
  Link,
 
12
  } from "@mui/material";
13
  import KeyIcon from "@mui/icons-material/Key";
14
  import SmartButtonIcon from "@mui/icons-material/SmartButton";
15
  import PlayArrowIcon from "@mui/icons-material/PlayArrow";
 
16
 
17
  export default function Introduction() {
18
  return (
19
  <Stack direction="row" spacing={2}>
20
  <Grid container gap={2} sx={{ justifyContent: "center" }}>
21
  <Grid item md={4}>
22
- <Typography sx={{ mb: 1 }}>
23
- Your job is to provide a prompt that describes the game you want, so that
24
- your skilled 2D Game Developer can built it for you using JavaScript on
25
- Canvas2D.
26
- </Typography>
 
27
 
28
- <Typography>
29
- We would love to use open-source models for this (for example{" "}
30
- <Link
31
- href="https://huggingface.co/HuggingFaceH4/starchat-alpha"
32
- target="_blank"
33
- rel="noopener"
34
- >
35
- starchat-alpha
36
- </Link>
37
- ), but running a private Inference Endpoint is too expensive for us. If you
38
- would love to help us, then{" "}
39
- <Link
40
- href="https://discord.com/invite/m3TBB9XEkb"
41
- target="_blank"
42
- rel="noopener"
43
- >
44
- let&apos;s talk
45
- </Link>
46
- !
47
- </Typography>
 
 
 
48
  </Grid>
49
  <Grid item md={4}>
50
  <Paper>
@@ -71,7 +77,7 @@ export default function Introduction() {
71
  <SmartButtonIcon />
72
  </ListItemIcon>
73
  <ListItemText>
74
- Select one of the <b>examples</b>
75
  </ListItemText>
76
  </ListItem>
77
  <ListItem>
@@ -79,7 +85,11 @@ export default function Introduction() {
79
  <PlayArrowIcon />
80
  </ListItemIcon>
81
  <ListItemText>
82
- Click on <b>Run</b>
 
 
 
 
83
  </ListItemText>
84
  </ListItem>
85
  </List>
 
9
  ListItemIcon,
10
  ListItemText,
11
  Link,
12
+ Button,
13
  } from "@mui/material";
14
  import KeyIcon from "@mui/icons-material/Key";
15
  import SmartButtonIcon from "@mui/icons-material/SmartButton";
16
  import PlayArrowIcon from "@mui/icons-material/PlayArrow";
17
+ import { PlayArrow } from "@mui/icons-material";
18
 
19
  export default function Introduction() {
20
  return (
21
  <Stack direction="row" spacing={2}>
22
  <Grid container gap={2} sx={{ justifyContent: "center" }}>
23
  <Grid item md={4}>
24
+ <Stack spacing={2}>
25
+ <Typography>
26
+ You provide a prompt that describes the game you want, so that your
27
+ skilled 2D Game Developer can built it for you. The game runs directly
28
+ in your browser (thanks to JavaScript on Canvas2D).
29
+ </Typography>
30
 
31
+ <Typography>
32
+ You are stuck?{" "}
33
+ <Link
34
+ href="https://huggingface.co/spaces/failfast/2D-GameCreator-GPT/discussions"
35
+ target="_blank"
36
+ rel="noopener"
37
+ >
38
+ We are here to help!
39
+ </Link>
40
+ </Typography>
41
+
42
+ <Typography>
43
+ We are looking into integrating open-source models (for example{" "}
44
+ <Link
45
+ href="https://huggingface.co/HuggingFaceH4/starchat-alpha"
46
+ target="_blank"
47
+ rel="noopener"
48
+ >
49
+ starchat-alpha
50
+ </Link>
51
+ ) next, so stay tuned!
52
+ </Typography>
53
+ </Stack>
54
  </Grid>
55
  <Grid item md={4}>
56
  <Paper>
 
77
  <SmartButtonIcon />
78
  </ListItemIcon>
79
  <ListItemText>
80
+ Select one of the <b>Examples</b>
81
  </ListItemText>
82
  </ListItem>
83
  <ListItem>
 
85
  <PlayArrowIcon />
86
  </ListItemIcon>
87
  <ListItemText>
88
+ Click on &nbsp;
89
+ <Button variant="contained" startIcon={<PlayArrow />}>
90
+ <Typography sx={{ fontWeight: "500" }}>Run</Typography>
91
+ </Button>
92
+ &nbsp;
93
  </ListItemText>
94
  </ListItem>
95
  </List>
src/components/Troubleshooting.tsx ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Typography, Paper, Alert, Link } from "@mui/material";
2
+ import { SectionBox, DividerBox } from "./base/boxes";
3
+
4
+ export default function Troubleshooting() {
5
+ return (
6
+ <>
7
+ <SectionBox>
8
+ <Typography component="h3" variant="h2">
9
+ Troubleshooting
10
+ </Typography>
11
+ </SectionBox>
12
+
13
+ <Paper sx={{ p: 1 }}>
14
+ <Alert severity="error" sx={{ fontSize: "1.25rem", mb: 1 }}>
15
+ Unhandled Runtime Error: SyntaxError: Unexpected identifier
16
+ </Alert>
17
+
18
+ <Typography variant="body1">
19
+ The generated output was interrupted, as it was too long and the OpenAI API
20
+ delivered not everything. If you can, switch to GPT-4 as it allows a bigger
21
+ context size (change it in the options and also increase the max_tokens). If you
22
+ can&apos;t do this, then please help us extend the GameCreator so that it can
23
+ also resume when the output is interrupted.
24
+ </Typography>
25
+ </Paper>
26
+
27
+ <DividerBox />
28
+
29
+ <Paper sx={{ p: 1 }}>
30
+ <Typography>
31
+ You need help? Something is not working?{" "}
32
+ <Link
33
+ href="https://huggingface.co/spaces/failfast/2D-GameCreator-GPT/discussions"
34
+ target="_blank"
35
+ rel="noopener"
36
+ >
37
+ Please let us know!
38
+ </Link>
39
+ </Typography>
40
+ </Paper>
41
+ </>
42
+ );
43
+ }
src/components/{Instructions.tsx → UnderTheHood.tsx} RENAMED
@@ -2,7 +2,7 @@ import { Alert, Link, List, ListItem, ListItemText, Paper, Typography } from "@m
2
  import { DividerBox, SectionBox, OutlinedBox } from "@/components/base/boxes";
3
  import { systemMessage } from "@/constants";
4
 
5
- export default function Instructions() {
6
  return (
7
  <>
8
  <DividerBox />
@@ -83,41 +83,6 @@ TEMPLATE:`}
83
  </ListItem>
84
  </List>
85
  </Paper>
86
-
87
- <SectionBox>
88
- <Typography component="h3" variant="h2">
89
- Troubleshooting
90
- </Typography>
91
- </SectionBox>
92
-
93
- <Paper sx={{ p: 1 }}>
94
- <Alert severity="error" sx={{ fontSize: "1.25rem", mb: 1 }}>
95
- Unhandled Runtime Error: SyntaxError: Unexpected identifier
96
- </Alert>
97
-
98
- <Typography variant="body1">
99
- The generated output was interrupted, as it was too long and the OpenAI API
100
- delivered not everything. If you can, switch to GPT-4 as it allows a bigger
101
- context size (change it in the options and also increase the max_tokens). If you
102
- can&apos;t do this, then please help us extend the GameCreator so that it can
103
- also resume when the output is interrupted.
104
- </Typography>
105
- </Paper>
106
-
107
- <DividerBox />
108
-
109
- <Paper sx={{ p: 1 }}>
110
- <Typography>
111
- You need help? Something is not working?{" "}
112
- <Link
113
- href="https://huggingface.co/spaces/failfast/2D-GameCreator-GPT/discussions"
114
- target="_blank"
115
- rel="noopener"
116
- >
117
- Please let us know!
118
- </Link>
119
- </Typography>
120
- </Paper>
121
  </>
122
  );
123
  }
 
2
  import { DividerBox, SectionBox, OutlinedBox } from "@/components/base/boxes";
3
  import { systemMessage } from "@/constants";
4
 
5
+ export default function UnderTheHood() {
6
  return (
7
  <>
8
  <DividerBox />
 
83
  </ListItem>
84
  </List>
85
  </Paper>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  </>
87
  );
88
  }
src/components/base/boxes.tsx CHANGED
@@ -1,8 +1,17 @@
1
- import { Divider, DividerProps, Paper, PaperProps } from "@mui/material";
 
 
 
 
 
 
 
2
  import { styled } from "@mui/material/styles";
3
 
4
  export const SectionBox = styled(Paper)<PaperProps>(({ theme }) => ({
5
  display: "flex",
 
 
6
  padding: 15,
7
  paddingTop: 30,
8
  paddingBottom: 30,
@@ -26,6 +35,12 @@ export const RainbowBox = styled("div")(({ theme }) => ({
26
  borderImageSlice: 1,
27
  }));
28
 
 
 
 
 
 
 
29
  export const DividerBox = styled(Divider)<DividerProps>(({ theme }) => ({
30
  marginTop: 20,
31
  marginBottom: 20,
 
1
+ import {
2
+ Divider,
3
+ DividerProps,
4
+ ListItemButton,
5
+ ListItemButtonProps,
6
+ Paper,
7
+ PaperProps,
8
+ } from "@mui/material";
9
  import { styled } from "@mui/material/styles";
10
 
11
  export const SectionBox = styled(Paper)<PaperProps>(({ theme }) => ({
12
  display: "flex",
13
+ flexDirection: "column",
14
+ gap: 10,
15
  padding: 15,
16
  paddingTop: 30,
17
  paddingBottom: 30,
 
35
  borderImageSlice: 1,
36
  }));
37
 
38
+ export const RainbowListItemButton = styled(ListItemButton)<ListItemButtonProps>(({ theme }) => ({
39
+ border: `1px solid transparent`,
40
+ borderImage: `linear-gradient(to bottom right, #b827fc 0%, #2c90fc 25%, #b8fd33 50%, #fec837 75%, #fd1892 100%)`,
41
+ borderImageSlice: 1,
42
+ }));
43
+
44
  export const DividerBox = styled(Divider)<DividerProps>(({ theme }) => ({
45
  marginTop: 20,
46
  marginBottom: 20,
src/components/title.tsx CHANGED
@@ -13,7 +13,7 @@ export default function Title() {
13
  p: 4,
14
  }}
15
  >
16
- <Typography variant="h1" component="h1">
17
  2D GameCreator-GPT
18
  </Typography>
19
 
 
13
  p: 4,
14
  }}
15
  >
16
+ <Typography variant="h1" component="h1" sx={{ fontSize: { xs: "2em", md: "5em" } }}>
17
  2D GameCreator-GPT
18
  </Typography>
19
 
src/lib/theme.ts CHANGED
@@ -58,6 +58,18 @@ const theme = extendTheme({
58
  },
59
  },
60
  },
 
 
 
 
 
 
 
 
 
 
 
 
61
  },
62
  });
63
 
 
58
  },
59
  },
60
  },
61
+ MuiButton: {
62
+ styleOverrides: {
63
+ startIcon: ({ ownerState }) => ({
64
+ ...(ownerState.children
65
+ ? {}
66
+ : {
67
+ // if no button label, center icon (e.g mobile)
68
+ marginRight: 0,
69
+ }),
70
+ }),
71
+ },
72
+ },
73
  },
74
  });
75
 
src/pages/index.tsx CHANGED
@@ -4,10 +4,11 @@ import { Container } from "@mui/material";
4
  import Footer from "@/components/footer";
5
  import Title from "@/components/title";
6
  import Introduction from "@/components/Introduction";
7
- import Instructions from "@/components/Instructions";
8
  import Examples from "@/components/Examples";
9
  import GameCreator from "@/components/GameCreator";
10
- import Workflow from "@/components/Workflow";
 
11
 
12
  export default function Home() {
13
  return (
@@ -24,9 +25,11 @@ export default function Home() {
24
 
25
  <Examples />
26
 
27
- <Workflow />
28
 
29
- <Instructions />
 
 
30
 
31
  <Footer />
32
  </Container>
 
4
  import Footer from "@/components/footer";
5
  import Title from "@/components/title";
6
  import Introduction from "@/components/Introduction";
7
+ import UnderTheHood from "@/components/UnderTheHood";
8
  import Examples from "@/components/Examples";
9
  import GameCreator from "@/components/GameCreator";
10
+ import HowToUse from "@/components/HowToUse";
11
+ import Troubleshooting from "@/components/Troubleshooting";
12
 
13
  export default function Home() {
14
  return (
 
25
 
26
  <Examples />
27
 
28
+ <HowToUse />
29
 
30
+ <UnderTheHood />
31
+
32
+ <Troubleshooting />
33
 
34
  <Footer />
35
  </Container>
src/services/api/index.ts CHANGED
@@ -11,6 +11,7 @@ interface ToOpenAIProps {
11
  model: string;
12
  maxTokens: string;
13
  client: OpenAIApi | null;
 
14
  }
15
 
16
  export async function toOpenAI({
@@ -21,6 +22,7 @@ export async function toOpenAI({
21
  model = "gpt-3.5-turbo",
22
  maxTokens = "2048",
23
  client = null,
 
24
  }: ToOpenAIProps) {
25
  if (client === null) {
26
  throw new Error("OpenAI client is not defined");
@@ -50,12 +52,15 @@ export async function toOpenAI({
50
  ];
51
 
52
  try {
53
- const response = await client.createChatCompletion({
54
- model,
55
- messages,
56
- max_tokens: Number.parseInt(maxTokens),
57
- temperature: Number.parseFloat(temperature),
58
- });
 
 
 
59
 
60
  const { message } = response.data.choices[0];
61
 
 
11
  model: string;
12
  maxTokens: string;
13
  client: OpenAIApi | null;
14
+ signal?: AbortSignal;
15
  }
16
 
17
  export async function toOpenAI({
 
22
  model = "gpt-3.5-turbo",
23
  maxTokens = "2048",
24
  client = null,
25
+ signal,
26
  }: ToOpenAIProps) {
27
  if (client === null) {
28
  throw new Error("OpenAI client is not defined");
 
52
  ];
53
 
54
  try {
55
+ const response = await client.createChatCompletion(
56
+ {
57
+ model,
58
+ messages,
59
+ max_tokens: Number.parseInt(maxTokens),
60
+ temperature: Number.parseFloat(temperature),
61
+ },
62
+ { signal }
63
+ );
64
 
65
  const { message } = response.data.choices[0];
66
 
src/services/api/openai.ts CHANGED
@@ -1,5 +1,10 @@
1
  import { Configuration, OpenAIApi } from "openai";
2
 
3
  export const createClient = (apiKey: string): OpenAIApi => {
4
- return new OpenAIApi(new Configuration({ apiKey }));
 
 
 
 
 
5
  };
 
1
  import { Configuration, OpenAIApi } from "openai";
2
 
3
  export const createClient = (apiKey: string): OpenAIApi => {
4
+ const configuration = new Configuration({ apiKey });
5
+
6
+ // See https://github.com/openai/openai-node/issues/6#issuecomment-1492814621
7
+ delete configuration.baseOptions.headers["User-Agent"];
8
+
9
+ return new OpenAIApi(configuration);
10
  };