jbilcke-hf HF staff commited on
Commit
a438bb5
1 Parent(s): bf8d4d8
src/app/games/city.ts CHANGED
@@ -49,10 +49,12 @@ export const game: Game = {
49
  initialActionnables,
50
  getScenePrompt: (situation?: string) => [
51
  `isometrical bird view of 3D rendered city`,
52
- situation || initialSituation,
53
  `game screenshot`,
 
 
54
  `isometric`,
55
  `unreal engine`,
56
  `high res`,
 
57
  ]
58
  }
 
49
  initialActionnables,
50
  getScenePrompt: (situation?: string) => [
51
  `isometrical bird view of 3D rendered city`,
 
52
  `game screenshot`,
53
+ `strategy game`,
54
+ `simulator`,
55
  `isometric`,
56
  `unreal engine`,
57
  `high res`,
58
+ situation || initialSituation,
59
  ]
60
  }
src/app/games/doom.ts CHANGED
@@ -22,8 +22,11 @@ export const game: Game = {
22
  initialActionnables,
23
  getScenePrompt: (situation?: string) => [
24
  `Screenshot from Doom`,
 
 
 
 
25
  situation || initialSituation,
26
- `first person, beautiful, unreal engine`
27
  ]
28
  }
29
 
 
22
  initialActionnables,
23
  getScenePrompt: (situation?: string) => [
24
  `Screenshot from Doom`,
25
+ `first person`,
26
+ `shooter game`,
27
+ `science fiction`,
28
+ `unreal engine`,
29
  situation || initialSituation,
 
30
  ]
31
  }
32
 
src/app/games/dungeon.ts CHANGED
@@ -1,5 +1,5 @@
1
  import { amatic } from "@/lib/fonts"
2
- import { Game, Scene } from "./types"
3
 
4
  const actions = [
5
  "not moving",
@@ -52,10 +52,11 @@ export const game: Game = {
52
  initialSituation,
53
  initialActionnables,
54
  getScenePrompt: (situation?: string) => [
55
- `screenshot from an adventure videogame`,
56
  // `first-person footage`,
57
- situation || initialSituation,
58
- `medieval`,
59
  `unreal engine`,
 
60
  ]
61
  }
 
1
  import { amatic } from "@/lib/fonts"
2
+ import { Game } from "./types"
3
 
4
  const actions = [
5
  "not moving",
 
52
  initialSituation,
53
  initialActionnables,
54
  getScenePrompt: (situation?: string) => [
55
+ `screenshot from adventure videogame`,
56
  // `first-person footage`,
57
+ `medieval dungeon`,
58
+ `adventure`,
59
  `unreal engine`,
60
+ situation || initialSituation,
61
  ]
62
  }
src/app/games/enchanters.ts ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { macondo } from "@/lib/fonts"
2
+ import { Game } from "./types"
3
+
4
+ const initialSituation = [
5
+ `looking at a beautiful medieval castle on a lake, with a metallic gate, during golden house, surrounded by mountain, with a flying dragon visible afar`,
6
+ ].join(", ")
7
+
8
+ const initialActionnables = [
9
+ "trees",
10
+ "dragon",
11
+ "castle",
12
+ "gate",
13
+ "stone wall",
14
+ "lake",
15
+ "roof"
16
+ ]
17
+
18
+ export const game: Game = {
19
+ title: "Enchanters",
20
+ type: "enchanters",
21
+ className: macondo.className,
22
+ initialSituation,
23
+ initialActionnables,
24
+ getScenePrompt: (situation?: string) => [
25
+ `Screenshot from a videogame`,
26
+ `unreal engine`,
27
+ `magical wizard world`,
28
+ `first person`,
29
+ situation || initialSituation,
30
+ ]
31
+ }
32
+
src/app/games/index.ts CHANGED
@@ -4,9 +4,11 @@ import { game as pirates } from "./pirates"
4
  import { game as city } from "./city"
5
  import { game as dungeon } from "./dungeon"
6
  import { game as doom } from "./doom"
 
 
7
 
8
- export const games = { pirates, city, dungeon, doom }
9
 
10
- export const defaultGame: GameType = "pirates"
11
 
12
  export const getGame = (type?: GameType) => games[type || defaultGame] || games[defaultGame]
 
4
  import { game as city } from "./city"
5
  import { game as dungeon } from "./dungeon"
6
  import { game as doom } from "./doom"
7
+ import { game as vernian } from "./vernian"
8
+ import { game as enchanters } from "./enchanters"
9
 
10
+ export const games = { pirates, city, dungeon, doom, vernian, enchanters}
11
 
12
+ export const defaultGame: GameType = "enchanters"
13
 
14
  export const getGame = (type?: GameType) => games[type || defaultGame] || games[defaultGame]
src/app/games/pirates.ts CHANGED
@@ -62,7 +62,10 @@ export const game: Game = {
62
  // this prompt is beautiful:
63
  // screenshot from an adventure videogame, inside the hold of a pirate ship, with a pirate chest in the center, at sunset, beautiful, award winning, unreal engine, intricate details
64
  `screenshot from an adventure videogame`,
65
- situation || initialSituation,
66
  `unreal engine`,
 
 
 
67
  ],
68
  }
 
62
  // this prompt is beautiful:
63
  // screenshot from an adventure videogame, inside the hold of a pirate ship, with a pirate chest in the center, at sunset, beautiful, award winning, unreal engine, intricate details
64
  `screenshot from an adventure videogame`,
65
+ `pirate themed`,
66
  `unreal engine`,
67
+ `pixar style`,
68
+ `goofy and comedical`,
69
+ situation || initialSituation,
70
  ],
71
  }
src/app/games/types.ts CHANGED
@@ -1,6 +1,5 @@
1
- import { FontName } from "@/lib/fonts"
2
 
3
- export type GameType = 'pirates' | 'city' | 'dungeon' | 'doom'
4
 
5
  export interface Scene {
6
  actionnables: string[]
 
 
1
 
2
+ export type GameType = "pirates" | "city" | "dungeon" | "doom" | "vernian" | "enchanters"
3
 
4
  export interface Scene {
5
  actionnables: string[]
src/app/games/vernian.ts ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { imfell } from "@/lib/fonts"
2
+ import { Game } from "./types"
3
+
4
+ const initialSituation = [
5
+ `inside a secret workshop inspired by Jules Verne`,
6
+ `with mysterious machines, keys, boxes, blueprints, gears`
7
+ ].join(", ")
8
+
9
+ const initialActionnables = [
10
+ "key",
11
+ "box",
12
+ "door",
13
+ "table",
14
+ "blueprint",
15
+ "gear",
16
+ "machine"
17
+ ]
18
+
19
+ export const game: Game = {
20
+ title: "Vernian",
21
+ type: "vernian",
22
+ className: imfell.className,
23
+ initialSituation,
24
+ initialActionnables,
25
+ getScenePrompt: (situation?: string) => [
26
+ `Screenshot from a videogame`,
27
+ `steam punk`,
28
+ `jules verne architecture and design`,
29
+ `mysterious machines and mechanisms`,
30
+ `first person`,
31
+ `unreal engine`,
32
+ situation || initialSituation,
33
+ ]
34
+ }
35
+
src/app/main.tsx CHANGED
@@ -58,16 +58,18 @@ export default function Main() {
58
  console.log("Rendering a scene for " + game.type)
59
 
60
  // console.log(`rendering scene..`)
61
- const newRendered = await render(
 
 
62
  // SCENE PROMPT
63
- game.getScenePrompt(nextSituation).join(", "),
64
 
65
  // ACTIONNABLES
66
- (Array.isArray(nextActionnables) && nextActionnables.length
67
  ? nextActionnables
68
  : game.initialActionnables
69
  ).slice(0, 6) // too many can slow us down it seems
70
- )
71
 
72
  // detect if type game type changed while we were busy
73
  if (game?.type !== gameRef?.current) {
@@ -153,8 +155,11 @@ export default function Main() {
153
  router.replace(`${pathname}${query}`, { })
154
 
155
  // workaround.. but it is strange that router.replace doesn't work..
156
- let newurl = window.location.protocol + "//" + window.location.host + window.location.pathname + '?' + search.toString()
157
- window.history.pushState({path: newurl}, '', newurl)
 
 
 
158
  }
159
 
160
 
@@ -170,16 +175,19 @@ export default function Main() {
170
  router.replace(`${pathname}${query}`, { })
171
 
172
  // workaround.. but it is strange that router.replace doesn't work..
173
- let newurl = window.location.protocol + "//" + window.location.host + window.location.pathname + '?' + search.toString()
174
- window.history.pushState({path: newurl}, '', newurl)
 
 
 
175
  }
176
 
177
  return (
178
  <div
179
- className="flex flex-col w-full"
180
  >
181
  <div className="flex flex-row w-full justify-between items-center px-2 py-2 border-b-1 border-gray-50 bg-gray-800">
182
- <div className="flex flex-row items-center space-x-3 font-mono">
183
  <label className="flex text-sm">Select a story:</label>
184
  <Select
185
  defaultValue={gameRef.current}
@@ -210,6 +218,7 @@ export default function Main() {
210
  </Select>
211
  </div>
212
  </div>
 
213
  <div className={[
214
  "flex flex-col w-full pt-4 space-y-3 px-2",
215
  getGame(gameRef.current).className // apply the game theme
@@ -223,17 +232,17 @@ export default function Main() {
223
  {i < (clickables.length - 1) ? <div>,</div> : null}
224
  </div>)}
225
  </div>
226
- <p className="text-xl font-normal">You are looking at: <span className="font-bold">{hoveredActionnable || "nothing"}</span></p>
 
 
 
 
 
 
 
 
 
227
  </div>
228
- <Renderer
229
- rendered={rendered}
230
- onUserAction={handleUserAction}
231
- onUserHover={setHoveredActionnable}
232
- isLoading={isLoading}
233
- game={game}
234
- engine={engine}
235
- />
236
- <p className="text-xl">{dialogue}</p>
237
  </div>
238
  )
239
  }
 
58
  console.log("Rendering a scene for " + game.type)
59
 
60
  // console.log(`rendering scene..`)
61
+ const newRendered = await render({
62
+ engine,
63
+
64
  // SCENE PROMPT
65
+ prompt: game.getScenePrompt(nextSituation).join(", "),
66
 
67
  // ACTIONNABLES
68
+ actionnables: (Array.isArray(nextActionnables) && nextActionnables.length
69
  ? nextActionnables
70
  : game.initialActionnables
71
  ).slice(0, 6) // too many can slow us down it seems
72
+ })
73
 
74
  // detect if type game type changed while we were busy
75
  if (game?.type !== gameRef?.current) {
 
155
  router.replace(`${pathname}${query}`, { })
156
 
157
  // workaround.. but it is strange that router.replace doesn't work..
158
+ //let newurl = window.location.protocol + "//" + window.location.host + window.location.pathname + '?' + search.toString()
159
+ //window.history.pushState({path: newurl}, '', newurl)
160
+
161
+ // actually we don't handle partial reload very well, so let's reload the whole page
162
+ window.location = `${window.location.protocol + "//" + window.location.host + window.location.pathname + '?' + search.toString()}` as any
163
  }
164
 
165
 
 
175
  router.replace(`${pathname}${query}`, { })
176
 
177
  // workaround.. but it is strange that router.replace doesn't work..
178
+ // let newurl = window.location.protocol + "//" + window.location.host + window.location.pathname + '?' + search.toString()
179
+ // window.history.pushState({path: newurl}, '', newurl)
180
+
181
+ // actually we don't handle partial reload very well, so let's reload the whole page
182
+ window.location = `${window.location.protocol + "//" + window.location.host + window.location.pathname + '?' + search.toString()}` as any
183
  }
184
 
185
  return (
186
  <div
187
+ className="flex flex-col w-full max-w-5xl"
188
  >
189
  <div className="flex flex-row w-full justify-between items-center px-2 py-2 border-b-1 border-gray-50 bg-gray-800">
190
+ <div className="flex flex-row items-center space-x-3 font-mono">
191
  <label className="flex text-sm">Select a story:</label>
192
  <Select
193
  defaultValue={gameRef.current}
 
218
  </Select>
219
  </div>
220
  </div>
221
+
222
  <div className={[
223
  "flex flex-col w-full pt-4 space-y-3 px-2",
224
  getGame(gameRef.current).className // apply the game theme
 
232
  {i < (clickables.length - 1) ? <div>,</div> : null}
233
  </div>)}
234
  </div>
235
+ <p className="text-xl">You are looking at: <span className="font-bold">{hoveredActionnable || "nothing"}</span></p>
236
+ <Renderer
237
+ rendered={rendered}
238
+ onUserAction={handleUserAction}
239
+ onUserHover={setHoveredActionnable}
240
+ isLoading={isLoading}
241
+ game={game}
242
+ engine={engine}
243
+ />
244
+ <p className="text-xl">{dialogue}</p>
245
  </div>
 
 
 
 
 
 
 
 
 
246
  </div>
247
  )
248
  }
src/app/render.ts CHANGED
@@ -3,6 +3,7 @@
3
  import Gorgon from "@gorgonjs/gorgon"
4
 
5
  import { RenderedScene } from "./types"
 
6
 
7
  // note: there is no / at the end in the variable
8
  // so we have to add it ourselves if needed
@@ -11,8 +12,29 @@ const apiUrl = process.env.RENDERING_ENGINE_API
11
 
12
  const cacheDurationInSec = 30 * 60 // 30 minutes
13
 
14
- export async function render(prompt: string, actionnables: string[] = []) {
15
- return await Gorgon.get(`render/${JSON.stringify(prompt, actionnables)}`, async () => {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  let defaulResult: RenderedScene = {
17
  assetUrl: "",
18
  maskBase64: "",
@@ -32,7 +54,7 @@ export async function render(prompt: string, actionnables: string[] = []) {
32
  body: JSON.stringify({
33
  prompt,
34
  // nbFrames: 8 and nbSteps: 15 --> ~10 sec generation
35
- nbFrames: 1, // when nbFrames is 1, we will only generate static images
36
  nbSteps: 20,
37
  actionnables,
38
  segmentation: "firstframe", // one day we will remove this param, to make it automatic
@@ -57,6 +79,7 @@ export async function render(prompt: string, actionnables: string[] = []) {
57
  return response
58
  } catch (err) {
59
  console.error(err)
 
60
  return defaulResult
61
  }
62
  }, cacheDurationInSec * 1000)
 
3
  import Gorgon from "@gorgonjs/gorgon"
4
 
5
  import { RenderedScene } from "./types"
6
+ import { Engine, EngineType } from "./engines"
7
 
8
  // note: there is no / at the end in the variable
9
  // so we have to add it ourselves if needed
 
12
 
13
  const cacheDurationInSec = 30 * 60 // 30 minutes
14
 
15
+ export async function render({
16
+ prompt,
17
+ actionnables = [],
18
+ engine,
19
+ }: {
20
+ prompt: string
21
+ actionnables: string[]
22
+ engine: Engine
23
+ }) {
24
+ if (!prompt) {
25
+ console.error(`cannot call the rendering API without a prompt, aborting..`)
26
+ throw new Error(`cannot call the rendering API without a prompt, aborting..`)
27
+ }
28
+ if (!Array.isArray(actionnables) || !actionnables.length) {
29
+ console.error(`cannot call the rendering API without actionnables, aborting..`)
30
+ throw new Error(`cannot call the rendering API without actionnables, aborting..`)
31
+ }
32
+
33
+ const nbFrames = engine.type === "video" ? 8 : 1
34
+
35
+ const cacheKey = `render/${JSON.stringify({ prompt, actionnables, nbFrames, type: engine.type })}`
36
+
37
+ return await Gorgon.get(cacheKey, async () => {
38
  let defaulResult: RenderedScene = {
39
  assetUrl: "",
40
  maskBase64: "",
 
54
  body: JSON.stringify({
55
  prompt,
56
  // nbFrames: 8 and nbSteps: 15 --> ~10 sec generation
57
+ nbFrames, // when nbFrames is 1, we will only generate static images
58
  nbSteps: 20,
59
  actionnables,
60
  segmentation: "firstframe", // one day we will remove this param, to make it automatic
 
79
  return response
80
  } catch (err) {
81
  console.error(err)
82
+ Gorgon.clear(cacheKey)
83
  return defaulResult
84
  }
85
  }, cacheDurationInSec * 1000)
src/components/business/renderer.tsx CHANGED
@@ -213,12 +213,12 @@ export const Renderer = ({
213
 
214
  return (
215
  <div className={[
216
- "w-full py-8 px-2",
217
  // isLoading ? "animate-pulse" : ""
218
  ].join(" ")
219
  }>
220
  <div className="relative w-[1024px] h-[512px] border-2 border-gray-50 rounded-xl overflow-hidden">
221
- {assetUrl === null ?
222
  null
223
  : engine.type === "video"
224
  ? <video
 
213
 
214
  return (
215
  <div className={[
216
+ "w-full py-8",
217
  // isLoading ? "animate-pulse" : ""
218
  ].join(" ")
219
  }>
220
  <div className="relative w-[1024px] h-[512px] border-2 border-gray-50 rounded-xl overflow-hidden">
221
+ {!assetUrl ?
222
  null
223
  : engine.type === "video"
224
  ? <video
src/lib/fonts.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Inter, Edu_SA_Beginner, Orbitron, Amatic_SC } from "next/font/google"
2
  import localFont from "next/font/local"
3
 
4
  export const inter = Inter({
@@ -22,6 +22,18 @@ export const amatic = Amatic_SC({
22
  variable: "--font-amatic"
23
  })
24
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  export const lugrasimo = localFont({
26
  src: "../fonts/Lugrasimo-Regular.woff2",
27
  variable: "--font-lugrasimo"
@@ -39,6 +51,7 @@ export const fontList = [
39
  edu,
40
  orbitron,
41
  amatic,
 
42
  lugrasimo,
43
  ]
44
 
@@ -46,4 +59,4 @@ export const classNames = fontList.map(font => font.className)
46
 
47
  export const className = classNames.join(" ")
48
 
49
- export type FontName = "font-inter" | "font-sans" | "font-edu" | "font-orbitron" | "font-amatic" | "font-lugrasimo"
 
1
+ import { Inter, Edu_SA_Beginner, Orbitron, Amatic_SC, Macondo_Swash_Caps, IM_Fell_English_SC } from "next/font/google"
2
  import localFont from "next/font/local"
3
 
4
  export const inter = Inter({
 
22
  variable: "--font-amatic"
23
  })
24
 
25
+ export const macondo = Macondo_Swash_Caps({
26
+ subsets: ["latin"],
27
+ weight: "400",
28
+ variable: "--font-macondo"
29
+ })
30
+
31
+ export const imfell = IM_Fell_English_SC({
32
+ subsets: ["latin"],
33
+ weight: "400",
34
+ variable: "--font-imfell"
35
+ })
36
+
37
  export const lugrasimo = localFont({
38
  src: "../fonts/Lugrasimo-Regular.woff2",
39
  variable: "--font-lugrasimo"
 
51
  edu,
52
  orbitron,
53
  amatic,
54
+ macondo,
55
  lugrasimo,
56
  ]
57
 
 
59
 
60
  export const className = classNames.join(" ")
61
 
62
+ export type FontName = "font-inter" | "font-sans" | "font-edu" | "font-orbitron" | "font-amatic" | "font-macondo" | "font-lugrasimo"