Spaces:
Running
Running
Commit
·
5cc7f12
1
Parent(s):
ff82110
need 1 billion dollars for this project
Browse files- package-lock.json +6 -0
- package.json +2 -1
- src/app/page.tsx +1 -1
- src/components/interface/latent-engine/core/engine-clapper.tsx +53 -0
- src/components/interface/latent-engine/core/{engine.tsx → engine-legacy.tsx} +2 -2
- src/components/interface/latent-engine/core/generateClapFromPrompt.ts +11 -1
- src/components/interface/latent-engine/core/useChildController.ts +74 -0
- src/components/interface/latent-engine/core/useSetupIframeOnce.ts +65 -0
- src/components/interface/latent-engine/index.tsx +1 -1
package-lock.json
CHANGED
@@ -54,6 +54,7 @@
|
|
54 |
"alchemy-sdk": "^3.4.1",
|
55 |
"autoprefixer": "10.4.20",
|
56 |
"axios": "^1.7.4",
|
|
|
57 |
"class-variance-authority": "^0.7.0",
|
58 |
"clsx": "^2.1.1",
|
59 |
"cmdk": "^1.0.0",
|
@@ -3537,6 +3538,11 @@
|
|
3537 |
"resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz",
|
3538 |
"integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ=="
|
3539 |
},
|
|
|
|
|
|
|
|
|
|
|
3540 |
"node_modules/binary-extensions": {
|
3541 |
"version": "2.3.0",
|
3542 |
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
|
|
54 |
"alchemy-sdk": "^3.4.1",
|
55 |
"autoprefixer": "10.4.20",
|
56 |
"axios": "^1.7.4",
|
57 |
+
"bellhop-iframe": "^3.5.0",
|
58 |
"class-variance-authority": "^0.7.0",
|
59 |
"clsx": "^2.1.1",
|
60 |
"cmdk": "^1.0.0",
|
|
|
3538 |
"resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz",
|
3539 |
"integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ=="
|
3540 |
},
|
3541 |
+
"node_modules/bellhop-iframe": {
|
3542 |
+
"version": "3.5.0",
|
3543 |
+
"resolved": "https://registry.npmjs.org/bellhop-iframe/-/bellhop-iframe-3.5.0.tgz",
|
3544 |
+
"integrity": "sha512-3KrYh7ZMdNiHvngKyR+3swD0jAiIEOb3clWmmDXMm8KCCNrIy7rGrFUC8mJX/f5X3y8Rwz8lsZeW0i2uUFeVnA=="
|
3545 |
+
},
|
3546 |
"node_modules/binary-extensions": {
|
3547 |
"version": "2.3.0",
|
3548 |
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
package.json
CHANGED
@@ -56,6 +56,7 @@
|
|
56 |
"alchemy-sdk": "^3.4.1",
|
57 |
"autoprefixer": "10.4.20",
|
58 |
"axios": "^1.7.4",
|
|
|
59 |
"class-variance-authority": "^0.7.0",
|
60 |
"clsx": "^2.1.1",
|
61 |
"cmdk": "^1.0.0",
|
@@ -82,6 +83,7 @@
|
|
82 |
"qs": "^6.13.0",
|
83 |
"query-string": "^9.1.0",
|
84 |
"react": "18.2.0",
|
|
|
85 |
"react-circular-progressbar": "^2.1.0",
|
86 |
"react-copy-to-clipboard": "^5.1.0",
|
87 |
"react-dom": "18.2.0",
|
@@ -89,7 +91,6 @@
|
|
89 |
"react-icons": "^4.12.0",
|
90 |
"react-photo-sphere-viewer": "^5.0.2-psv5.7.1",
|
91 |
"react-smooth-scroll-hook": "^1.3.4",
|
92 |
-
"react-avatar": "^5.0.3",
|
93 |
"react-tuby": "^0.1.24",
|
94 |
"react-virtualized-auto-sizer": "^1.0.20",
|
95 |
"react-window-infinite-loader": "^1.0.9",
|
|
|
56 |
"alchemy-sdk": "^3.4.1",
|
57 |
"autoprefixer": "10.4.20",
|
58 |
"axios": "^1.7.4",
|
59 |
+
"bellhop-iframe": "^3.5.0",
|
60 |
"class-variance-authority": "^0.7.0",
|
61 |
"clsx": "^2.1.1",
|
62 |
"cmdk": "^1.0.0",
|
|
|
83 |
"qs": "^6.13.0",
|
84 |
"query-string": "^9.1.0",
|
85 |
"react": "18.2.0",
|
86 |
+
"react-avatar": "^5.0.3",
|
87 |
"react-circular-progressbar": "^2.1.0",
|
88 |
"react-copy-to-clipboard": "^5.1.0",
|
89 |
"react-dom": "18.2.0",
|
|
|
91 |
"react-icons": "^4.12.0",
|
92 |
"react-photo-sphere-viewer": "^5.0.2-psv5.7.1",
|
93 |
"react-smooth-scroll-hook": "^1.3.4",
|
|
|
94 |
"react-tuby": "^0.1.24",
|
95 |
"react-virtualized-auto-sizer": "^1.0.20",
|
96 |
"react-window-infinite-loader": "^1.0.9",
|
src/app/page.tsx
CHANGED
@@ -104,7 +104,7 @@ export default async function Page({ searchParams: { v: videoId } }: AppQueryPro
|
|
104 |
|
105 |
">
|
106 |
<h1 className="text-yellow-400/90 text-6xl font-thin">Say goodbye to static videos.</h1>
|
107 |
-
<p className="mt-6 text-white/80 text-xl font-thin">
|
108 |
</div>
|
109 |
</div>
|
110 |
)
|
|
|
104 |
|
105 |
">
|
106 |
<h1 className="text-yellow-400/90 text-6xl font-thin">Say goodbye to static videos.</h1>
|
107 |
+
<p className="mt-6 text-white/80 text-xl font-thin">Coming in 2025. Follow <a href="https://x.com/@flngr" className="font-normal font-mono text-stone-50/60 hover:text-stone-50/80 hover:underline hover:underline-offset-2" target="_blank">@flngr</a> for updates.</p>
|
108 |
</div>
|
109 |
</div>
|
110 |
)
|
src/components/interface/latent-engine/core/engine-clapper.tsx
ADDED
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"use client"
|
2 |
+
|
3 |
+
import React, { useEffect } from "react"
|
4 |
+
|
5 |
+
import { cn } from "@/lib/utils/cn"
|
6 |
+
import { MediaInfo } from "@/types/general"
|
7 |
+
import { theSimps } from "@/app/latent/samples"
|
8 |
+
import { useChildController } from "./useChildController"
|
9 |
+
import { useSetupIframeOnce } from "./useSetupIframeOnce"
|
10 |
+
|
11 |
+
function LatentEngineClapper({
|
12 |
+
media,
|
13 |
+
width,
|
14 |
+
height,
|
15 |
+
className = "" }: {
|
16 |
+
media: MediaInfo
|
17 |
+
width?: number
|
18 |
+
height?: number
|
19 |
+
className?: string
|
20 |
+
}) {
|
21 |
+
// only call this once per iframe
|
22 |
+
useSetupIframeOnce()
|
23 |
+
|
24 |
+
const hasLoadedBellhop = useChildController(s => s.hasLoadedBellhop)
|
25 |
+
const sendMessage = useChildController(s => s.sendMessage)
|
26 |
+
|
27 |
+
useEffect(() => {
|
28 |
+
console.log('connected to the iframe player, now loading the prompt..')
|
29 |
+
sendMessage('loadPrompt', { prompt: theSimps })
|
30 |
+
}, [media.id, hasLoadedBellhop])
|
31 |
+
|
32 |
+
return (
|
33 |
+
<div
|
34 |
+
style={{ width, height }}
|
35 |
+
className={cn(`
|
36 |
+
relative
|
37 |
+
flex flex-col
|
38 |
+
items-center justify-between
|
39 |
+
w-full h-full
|
40 |
+
rounded-xl overflow-hidden
|
41 |
+
bg-black
|
42 |
+
`, className)}>
|
43 |
+
<iframe
|
44 |
+
className="pointer-events-auto"
|
45 |
+
width={width}
|
46 |
+
height={height}
|
47 |
+
src={`http://localhost:3000/embed?clap=/samples/claps/wasteland.clap`}
|
48 |
+
/>
|
49 |
+
</div>
|
50 |
+
);
|
51 |
+
}
|
52 |
+
|
53 |
+
export default LatentEngineClapper
|
src/components/interface/latent-engine/core/{engine.tsx → engine-legacy.tsx}
RENAMED
@@ -17,7 +17,7 @@ import { useStore } from "@/app/state/useStore"
|
|
17 |
import { theSimps } from "@/app/latent/samples"
|
18 |
import { generateClapFromPrompt } from "./generateClapFromPrompt"
|
19 |
|
20 |
-
function
|
21 |
media,
|
22 |
width,
|
23 |
height,
|
@@ -291,4 +291,4 @@ function LatentEngine({
|
|
291 |
);
|
292 |
}
|
293 |
|
294 |
-
export default
|
|
|
17 |
import { theSimps } from "@/app/latent/samples"
|
18 |
import { generateClapFromPrompt } from "./generateClapFromPrompt"
|
19 |
|
20 |
+
function LatentEngineLegacy({
|
21 |
media,
|
22 |
width,
|
23 |
height,
|
|
|
291 |
);
|
292 |
}
|
293 |
|
294 |
+
export default LatentEngineLegacy
|
src/components/interface/latent-engine/core/generateClapFromPrompt.ts
CHANGED
@@ -85,7 +85,7 @@ export function generateClapFromPrompt({
|
|
85 |
|
86 |
|
87 |
for (let prompt of story) {
|
88 |
-
|
89 |
clap.segments.push(newSegment({
|
90 |
track: 0,
|
91 |
startTimeInMs,
|
@@ -94,6 +94,16 @@ export function generateClapFromPrompt({
|
|
94 |
prompt: "",
|
95 |
label: "video",
|
96 |
outputType: ClapOutputType.VIDEO,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
}))
|
98 |
clap.segments.push(newSegment({
|
99 |
track: 1,
|
|
|
85 |
|
86 |
|
87 |
for (let prompt of story) {
|
88 |
+
/*
|
89 |
clap.segments.push(newSegment({
|
90 |
track: 0,
|
91 |
startTimeInMs,
|
|
|
94 |
prompt: "",
|
95 |
label: "video",
|
96 |
outputType: ClapOutputType.VIDEO,
|
97 |
+
}))
|
98 |
+
*/
|
99 |
+
clap.segments.push(newSegment({
|
100 |
+
track: 0,
|
101 |
+
startTimeInMs,
|
102 |
+
endTimeInMs,
|
103 |
+
category: ClapSegmentCategory.STORYBOARD,
|
104 |
+
prompt: "",
|
105 |
+
label: "movie screencap",
|
106 |
+
outputType: ClapOutputType.IMAGE,
|
107 |
}))
|
108 |
clap.segments.push(newSegment({
|
109 |
track: 1,
|
src/components/interface/latent-engine/core/useChildController.ts
ADDED
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'use client'
|
2 |
+
|
3 |
+
import { create } from 'zustand'
|
4 |
+
import { Bellhop } from 'bellhop-iframe'
|
5 |
+
|
6 |
+
export const useChildController = create<{
|
7 |
+
bellhop: Bellhop
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Whether the communication pipeline seems to be working or not
|
11 |
+
*
|
12 |
+
* Initially we assume that it is, but this can be invalidated
|
13 |
+
* if we know for certain it is not, or in case of exception
|
14 |
+
*/
|
15 |
+
canUseBellhop: boolean
|
16 |
+
|
17 |
+
/**
|
18 |
+
*
|
19 |
+
*/
|
20 |
+
hasLoadedBellhop: boolean
|
21 |
+
|
22 |
+
/**
|
23 |
+
* Whether Clapper is ready
|
24 |
+
*
|
25 |
+
* This will be set upon reception of the event
|
26 |
+
*/
|
27 |
+
clapperIsReady: boolean
|
28 |
+
|
29 |
+
setDomElement: (domElement: HTMLIFrameElement, origin?: string) => void
|
30 |
+
|
31 |
+
setCanUseBellhop: (canUseBellhop: boolean) => void
|
32 |
+
setHasLoadedBellhop: (hasLoadedBellhop: boolean) => void
|
33 |
+
onMessage: (name: string, callback: Function, priority?: number) => void
|
34 |
+
sendMessage: (type: string, data?: any) => void
|
35 |
+
}>((set, get) => ({
|
36 |
+
bellhop: undefined as unknown as Bellhop,
|
37 |
+
canUseBellhop: true,
|
38 |
+
hasLoadedBellhop: false,
|
39 |
+
clapperIsReady: false,
|
40 |
+
setDomElement: (domElement: HTMLIFrameElement, origin?: string) => {
|
41 |
+
const bellhop = new Bellhop()
|
42 |
+
bellhop.connect(domElement, origin)
|
43 |
+
set({
|
44 |
+
bellhop,
|
45 |
+
})
|
46 |
+
},
|
47 |
+
setCanUseBellhop: (canUseBellhop: boolean) => {
|
48 |
+
set({
|
49 |
+
canUseBellhop,
|
50 |
+
})
|
51 |
+
},
|
52 |
+
setHasLoadedBellhop: (hasLoadedBellhop: boolean) => {
|
53 |
+
set({
|
54 |
+
bellhop: hasLoadedBellhop ? new Bellhop() : (undefined as unknown as Bellhop),
|
55 |
+
hasLoadedBellhop,
|
56 |
+
})
|
57 |
+
},
|
58 |
+
onMessage: (name: string, callback: Function, priority?: number) => {
|
59 |
+
const { bellhop } = get()
|
60 |
+
try {
|
61 |
+
bellhop.on(name, callback, priority)
|
62 |
+
} catch (err) {
|
63 |
+
console.log(`failed to subscribe to parent iframe messages:`, err)
|
64 |
+
}
|
65 |
+
},
|
66 |
+
sendMessage: (type: string, data?: any) => {
|
67 |
+
const { bellhop } = get()
|
68 |
+
try {
|
69 |
+
bellhop.send(type, data)
|
70 |
+
} catch (err) {
|
71 |
+
console.log(`failed to send a message to parent iframe:`, err)
|
72 |
+
}
|
73 |
+
},
|
74 |
+
}))
|
src/components/interface/latent-engine/core/useSetupIframeOnce.ts
ADDED
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'use client'
|
2 |
+
|
3 |
+
import { useEffect, useRef } from 'react'
|
4 |
+
import { useChildController } from './useChildController'
|
5 |
+
|
6 |
+
/**
|
7 |
+
* You should only call this once, at the root of the react tree
|
8 |
+
*/
|
9 |
+
export function useSetupIframeOnce() {
|
10 |
+
const ref = useRef<HTMLIFrameElement>(null)
|
11 |
+
const setDomElement = useChildController(s => s.setDomElement)
|
12 |
+
const canUseBellhop = useChildController((s) => s.canUseBellhop)
|
13 |
+
const setCanUseBellhop = useChildController((s) => s.setCanUseBellhop)
|
14 |
+
const isConnectedToChild = useChildController((s) => s.isConnectedToChild)
|
15 |
+
const setHasLoadedBellhop = useChildController((s) => s.setHasLoadedBellhop)
|
16 |
+
const onMessage = useChildController((s) => s.onMessage)
|
17 |
+
const sendMessage = useChildController((s) => s.sendMessage)
|
18 |
+
|
19 |
+
|
20 |
+
// TODO: maybe we should add a JWT token to secure this, make it only embeddable
|
21 |
+
// on a certain website (eg. AiTube.at), and if people want to
|
22 |
+
// embed the player somewhere's else they will have to deploy their own
|
23 |
+
|
24 |
+
const domElement = ref.current
|
25 |
+
|
26 |
+
useEffect(() => {
|
27 |
+
if (!domElement || !isConnectedToChild) {
|
28 |
+
// when we are detecting that we are not in an iframe
|
29 |
+
|
30 |
+
if (canUseBellhop) {
|
31 |
+
setCanUseBellhop(false)
|
32 |
+
}
|
33 |
+
return
|
34 |
+
}
|
35 |
+
|
36 |
+
if (!canUseBellhop) {
|
37 |
+
setCanUseBellhop(true)
|
38 |
+
}
|
39 |
+
|
40 |
+
if (isConnectedToChild) {
|
41 |
+
// no need to connect twice
|
42 |
+
return
|
43 |
+
} else {
|
44 |
+
// we only try this once
|
45 |
+
|
46 |
+
|
47 |
+
try {
|
48 |
+
setDomElement(domElement)
|
49 |
+
setHasLoadedBellhop(true)
|
50 |
+
|
51 |
+
onMessage('something', function (event: any) {
|
52 |
+
// generate the first scene of an OpenClap file from the prompt
|
53 |
+
})
|
54 |
+
|
55 |
+
sendMessage('status', { isReady: true })
|
56 |
+
} catch (err) {
|
57 |
+
console.error(`failed to initialize bellhop`)
|
58 |
+
setHasLoadedBellhop(false)
|
59 |
+
setCanUseBellhop(false)
|
60 |
+
}
|
61 |
+
}
|
62 |
+
}, [domElement, canUseBellhop, isConnectedToChild])
|
63 |
+
|
64 |
+
return useChildController
|
65 |
+
}
|
src/components/interface/latent-engine/index.tsx
CHANGED
@@ -2,6 +2,6 @@
|
|
2 |
|
3 |
import dynamic from "next/dynamic"
|
4 |
|
5 |
-
export const LatentEngine = dynamic(() => import("./core/engine"), {
|
6 |
loading: () => null,
|
7 |
})
|
|
|
2 |
|
3 |
import dynamic from "next/dynamic"
|
4 |
|
5 |
+
export const LatentEngine = dynamic(() => import("./core/engine-clapper"), {
|
6 |
loading: () => null,
|
7 |
})
|