Spaces:
Runtime error
Runtime error
Julian Bilcke
commited on
Commit
·
a438bb5
1
Parent(s):
bf8d4d8
fix
Browse files- src/app/games/city.ts +3 -1
- src/app/games/doom.ts +4 -1
- src/app/games/dungeon.ts +5 -4
- src/app/games/enchanters.ts +32 -0
- src/app/games/index.ts +4 -2
- src/app/games/pirates.ts +4 -1
- src/app/games/types.ts +1 -2
- src/app/games/vernian.ts +35 -0
- src/app/main.tsx +29 -20
- src/app/render.ts +26 -3
- src/components/business/renderer.tsx +2 -2
- src/lib/fonts.ts +15 -2
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
|
| 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
|
| 56 |
// `first-person footage`,
|
| 57 |
-
|
| 58 |
-
`
|
| 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 = "
|
| 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 |
-
|
| 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 =
|
| 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 |
-
|
| 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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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(
|
| 15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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
|
| 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
|
| 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
|
|
|
|
| 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"
|