jbilcke-hf HF staff commited on
Commit
6311de2
·
1 Parent(s): 502beba
src/app/main.tsx CHANGED
@@ -270,7 +270,7 @@ export default function Main() {
270
  </div>
271
 
272
  <div className={[
273
- "flex flex-col w-full pt-4 space-y-2 px-2 text-gray-50 dark:text-gray-50",
274
  getGame(gameRef.current).className // apply the game theme
275
  ].join(" ")}>
276
  <div className="flex flex-row">
@@ -286,7 +286,9 @@ export default function Main() {
286
  {i < (clickables.length - 1) ? <div>,</div> : null}
287
  </div>)}
288
  </div>
289
- <p className="text-xl">You are looking at: <span className="font-bold">{hoveredActionnable || "nothing"}</span></p>
 
 
290
  <Renderer
291
  rendered={rendered}
292
  onUserAction={handleUserAction}
@@ -295,7 +297,7 @@ export default function Main() {
295
  game={game}
296
  engine={engine}
297
  />
298
- <p className="text-xl">{dialogue}</p>
299
  </div>
300
  </div>
301
  )
 
270
  </div>
271
 
272
  <div className={[
273
+ "flex flex-col w-full pt-4 space-y-3 px-2 text-gray-50 dark:text-gray-50",
274
  getGame(gameRef.current).className // apply the game theme
275
  ].join(" ")}>
276
  <div className="flex flex-row">
 
286
  {i < (clickables.length - 1) ? <div>,</div> : null}
287
  </div>)}
288
  </div>
289
+ <div className="text-xl p-3 rounded-xl backdrop-blur-sm bg-white/30">
290
+ You are looking at: <span className="font-bold">{hoveredActionnable || "nothing"}</span>
291
+ </div>
292
  <Renderer
293
  rendered={rendered}
294
  onUserAction={handleUserAction}
 
297
  game={game}
298
  engine={engine}
299
  />
300
+ <div className="text-xl rounded-xl backdrop-blur-sm bg-white/30">{dialogue}</div>
301
  </div>
302
  </div>
303
  )
src/app/types.ts CHANGED
@@ -44,6 +44,6 @@ export interface RenderedScene {
44
  status: RenderedSceneStatus
45
  assetUrl: string
46
  error: string
47
- maskBase64: string
48
  segments: ImageSegment[]
49
  }
 
44
  status: RenderedSceneStatus
45
  assetUrl: string
46
  error: string
47
+ maskUrl: string
48
  segments: ImageSegment[]
49
  }
src/components/business/cartesian-image.tsx CHANGED
@@ -1,24 +1,21 @@
1
  import { ForwardedRef, forwardRef } from "react"
2
 
3
  import { SceneEventHandler } from "./types"
 
4
 
5
  export const CartesianImage = forwardRef(({
6
- src,
7
- width,
8
- height,
9
  onEvent,
10
  className,
11
  }: {
12
- src: string
13
- width: number | string
14
- height: number | string
15
  onEvent: SceneEventHandler
16
  className?: string
17
- }, ref: ForwardedRef<HTMLImageElement>) => {
18
 
19
- const handleEvent = (event: React.MouseEvent<HTMLImageElement, MouseEvent>, isClick: boolean) => {
20
 
21
- const element = ((ref as any)?.current) as HTMLImageElement
22
 
23
  if (!element) {
24
  console.log("element isn't ready")
@@ -26,23 +23,32 @@ export const CartesianImage = forwardRef(({
26
  }
27
 
28
  const boundingRect = element.getBoundingClientRect()
29
- const x = event.clientX - boundingRect.left
30
- const y = event.clientY - boundingRect.top
31
 
32
  const eventType = isClick ? "click" : "hover"
33
  onEvent(eventType, x, y)
34
  }
35
 
 
 
 
36
  return (
37
- <img
38
- src={src}
39
- ref={ref}
40
- width={width}
41
- height={height}
42
  className={className}
43
  onMouseUp={(event) => handleEvent(event, true)}
44
  onMouseMove={(event) => handleEvent(event, false)}
45
- />
 
 
 
 
 
 
 
 
 
 
46
  )
47
  })
48
 
 
1
  import { ForwardedRef, forwardRef } from "react"
2
 
3
  import { SceneEventHandler } from "./types"
4
+ import { RenderedScene } from "@/app/types"
5
 
6
  export const CartesianImage = forwardRef(({
7
+ rendered,
 
 
8
  onEvent,
9
  className,
10
  }: {
11
+ rendered: RenderedScene
 
 
12
  onEvent: SceneEventHandler
13
  className?: string
14
+ }, ref: ForwardedRef<HTMLDivElement>) => {
15
 
16
+ const handleEvent = (event: React.MouseEvent<HTMLDivElement, MouseEvent>, isClick: boolean) => {
17
 
18
+ const element = ((ref as any)?.current) as HTMLDivElement
19
 
20
  if (!element) {
21
  console.log("element isn't ready")
 
23
  }
24
 
25
  const boundingRect = element.getBoundingClientRect()
26
+ const x = (event.clientX - boundingRect.left) * 1.03
27
+ const y = (event.clientY - boundingRect.top) //* 1.03
28
 
29
  const eventType = isClick ? "click" : "hover"
30
  onEvent(eventType, x, y)
31
  }
32
 
33
+ if (!rendered.assetUrl) {
34
+ return null
35
+ }
36
  return (
37
+ <div
 
 
 
 
38
  className={className}
39
  onMouseUp={(event) => handleEvent(event, true)}
40
  onMouseMove={(event) => handleEvent(event, false)}
41
+ >
42
+ <img
43
+ src={rendered.assetUrl || undefined}
44
+ ref={ref as any}
45
+ className="absolute"
46
+ />
47
+ <img
48
+ src={rendered.maskUrl || undefined}
49
+ className="absolute opacity-50"
50
+ />
51
+ </div>
52
  )
53
  })
54
 
src/components/business/cartesian-video.tsx CHANGED
@@ -1,24 +1,21 @@
1
  import { ForwardedRef, forwardRef } from "react"
2
 
3
  import { SceneEventHandler } from "./types"
 
4
 
5
  export const CartesianVideo = forwardRef(({
6
- src,
7
- width,
8
- height,
9
  onEvent,
10
  className,
11
  }: {
12
- src: string
13
- width: number | string
14
- height: number | string
15
  onEvent: SceneEventHandler
16
  className?: string
17
- }, ref: ForwardedRef<HTMLVideoElement>) => {
18
 
19
- const handleEvent = (event: React.MouseEvent<HTMLVideoElement, MouseEvent>, isClick: boolean) => {
20
 
21
- const element = ((ref as any)?.current) as HTMLVideoElement
22
 
23
  if (!element) {
24
  console.log("element isn't ready")
@@ -34,18 +31,24 @@ export const CartesianVideo = forwardRef(({
34
  }
35
 
36
  return (
37
- <video
38
- src={src}
39
- ref={ref}
 
 
 
 
 
40
  muted
41
  autoPlay
42
  loop
43
- width={width}
44
- height={height}
45
- className={className}
46
- onMouseUp={(event) => handleEvent(event, true)}
47
- onMouseMove={(event) => handleEvent(event, false)}
48
  />
 
 
 
 
 
49
  )
50
  })
51
 
 
1
  import { ForwardedRef, forwardRef } from "react"
2
 
3
  import { SceneEventHandler } from "./types"
4
+ import { RenderedScene } from "@/app/types"
5
 
6
  export const CartesianVideo = forwardRef(({
7
+ rendered,
 
 
8
  onEvent,
9
  className,
10
  }: {
11
+ rendered: RenderedScene
 
 
12
  onEvent: SceneEventHandler
13
  className?: string
14
+ }, ref: ForwardedRef<HTMLDivElement>) => {
15
 
16
+ const handleEvent = (event: React.MouseEvent<HTMLDivElement, MouseEvent>, isClick: boolean) => {
17
 
18
+ const element = ((ref as any)?.current) as HTMLDivElement
19
 
20
  if (!element) {
21
  console.log("element isn't ready")
 
31
  }
32
 
33
  return (
34
+ <div
35
+ className={className}
36
+ ref={ref}
37
+ onMouseUp={(event) => handleEvent(event, true)}
38
+ onMouseMove={(event) => handleEvent(event, false)}
39
+ >
40
+ <video
41
+ src={rendered.assetUrl || undefined}
42
  muted
43
  autoPlay
44
  loop
45
+ className="absolute"
 
 
 
 
46
  />
47
+ <img
48
+ src={rendered.maskUrl || undefined}
49
+ className="absolute opacity-50"
50
+ />
51
+ </div>
52
  )
53
  })
54
 
src/components/business/renderer.tsx CHANGED
@@ -10,11 +10,7 @@ import { CartesianVideo } from "./cartesian-video"
10
  import { SphericalImage } from "./spherical-image"
11
 
12
  export const Renderer = ({
13
- rendered: {
14
- assetUrl = "",
15
- maskBase64 = "",
16
- segments = []
17
- },
18
  onUserAction,
19
  onUserHover,
20
  isLoading,
@@ -29,34 +25,30 @@ export const Renderer = ({
29
  engine: Engine
30
  }) => {
31
  const timeoutRef = useRef<any>()
32
- const imgRef = useRef<HTMLImageElement | HTMLVideoElement | null>(null)
33
  const canvasRef = useRef<HTMLCanvasElement | null>(null)
34
  const contextRef = useRef<CanvasRenderingContext2D | null>(null)
35
  const [actionnable, setActionnable] = useState<string>("")
36
  const [progressPercent, setProcessPercent] = useState(0)
37
  const progressRef = useRef(0)
38
  const isLoadingRef = useRef(isLoading)
39
- const maskUrl = `data:image/png;base64,${maskBase64}`
40
 
41
  useEffect(() => {
42
- if (maskBase64) {
43
- // console.log("maskBase64:", maskBase64)
44
- const img = new Image();
45
- img.onload = function () {
46
- canvasRef.current = document.createElement('canvas');
47
- canvasRef.current.width = img.width;
48
- canvasRef.current.height = img.height;
49
- contextRef.current = canvasRef.current.getContext('2d', {
50
- willReadFrequently: true
51
- });
52
- contextRef.current!.drawImage(img, 0, 0, img.width, img.height);
53
- }
54
- img.src = "data:image/png;base64," + maskBase64;
55
- } else {
56
- // console.log("error, no maskBase64 detected!")
57
  }
58
- }, [maskBase64]);
59
-
 
 
 
 
 
 
 
 
 
 
60
 
61
  const getPixelColor = (x: number, y: number) => {
62
  if (!contextRef.current) {
@@ -74,7 +66,7 @@ export const Renderer = ({
74
 
75
  const getSegmentAt = (x: number, y: number): ImageSegment => {
76
  if (!contextRef.current) throw new Error("Unable to get context from canvas");
77
- if (!maskBase64) throw new Error("Mask is undefined");
78
 
79
  let closestSegment: ImageSegment = {
80
  id: 0,
@@ -92,7 +84,7 @@ export const Renderer = ({
92
 
93
  let minDistance = Infinity;
94
 
95
- segments.forEach(segment => {
96
  const segmentColor = segment.color.slice(0,3); // get the RGB part only
97
 
98
  const distance = Math.sqrt(
@@ -122,7 +114,7 @@ export const Renderer = ({
122
  // sometimes we generate an image, but the segmentation fails
123
  // so if we click anywhere bug there are no segments,
124
  // we inform the rest of the app by passing nothing
125
- if (type === "click" && segments.length == 0) {
126
  onUserAction("nothing, to trigger a scene reload")
127
  return
128
  }
@@ -149,7 +141,7 @@ export const Renderer = ({
149
  } else {
150
  // only trigger hover events if there are segments,
151
  // otherwise it's best to stay silent
152
- if (segments.length) {
153
  onUserHover(actionnable)
154
  }
155
  }
@@ -177,40 +169,7 @@ export const Renderer = ({
177
  if (isLoading) {
178
  timeoutRef.current = setInterval(updateProgressBar, 200)
179
  }
180
- }, [isLoading, assetUrl, engine?.type])
181
-
182
-
183
- /*
184
- <img
185
- src={assetUrl}
186
- ref={imgRef}
187
- width="1024px"
188
- height="512px"
189
- className={
190
- [
191
- "absolute top-0 left-0",
192
- actionnable ? "cursor-pointer" : ""
193
- ].join(" ")
194
- }
195
- onMouseDown={(event) => handleMouseEvent(event, true)}
196
- onMouseMove={handleMouseEvent}
197
- />
198
-
199
- <img
200
- src={"data:image/png;base64," + maskBase64}
201
- ref={imgRef}
202
- width="1024px"
203
- height="512px"
204
- className={
205
- [
206
- "absolute top-0 left-0 opacity-30",
207
- actionnable ? "cursor-pointer" : ""
208
- ].join(" ")
209
- }
210
- onMouseDown={(event) => handleMouseEvent(event, true)}
211
- onMouseMove={handleMouseEvent}
212
- />
213
- */
214
 
215
  return (
216
  <div className="w-full pt-2">
@@ -219,7 +178,7 @@ export const Renderer = ({
219
  "relative border-2 border-gray-50 rounded-xl overflow-hidden",
220
  engine.type === "cartesian_video"
221
  || engine.type === "cartesian_image"
222
- ? "w-[1024px] h-[512px]"
223
  : "w-full h-[800px]",
224
 
225
  isLoading
@@ -228,27 +187,21 @@ export const Renderer = ({
228
  ? "cursor-pointer"
229
  : ""
230
  ].join(" ")}>
231
- {!assetUrl ?
232
- null
233
- : engine.type === "cartesian_video"
234
  ? <CartesianVideo
235
- src={assetUrl}
236
- ref={imgRef as any}
237
- width="1024px"
238
- height="512px"
239
  onEvent={handleMouseEvent}
240
  />
241
  : engine.type === "spherical_image"
242
  ? <SphericalImage
243
- src={assetUrl}
244
- ref={imgRef as any}
245
  onEvent={handleMouseEvent}
246
  />
247
  : <CartesianImage
248
- src={assetUrl}
249
- ref={imgRef as any}
250
- width="1024px"
251
- height="512px"
252
  onEvent={handleMouseEvent}
253
  />
254
  }
 
10
  import { SphericalImage } from "./spherical-image"
11
 
12
  export const Renderer = ({
13
+ rendered,
 
 
 
 
14
  onUserAction,
15
  onUserHover,
16
  isLoading,
 
25
  engine: Engine
26
  }) => {
27
  const timeoutRef = useRef<any>()
28
+ const viewRef = useRef<HTMLDivElement>()
29
  const canvasRef = useRef<HTMLCanvasElement | null>(null)
30
  const contextRef = useRef<CanvasRenderingContext2D | null>(null)
31
  const [actionnable, setActionnable] = useState<string>("")
32
  const [progressPercent, setProcessPercent] = useState(0)
33
  const progressRef = useRef(0)
34
  const isLoadingRef = useRef(isLoading)
 
35
 
36
  useEffect(() => {
37
+ if (!rendered.maskUrl) {
38
+ return
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  }
40
+ const img = new Image()
41
+ img.onload = function () {
42
+ canvasRef.current = document.createElement('canvas')
43
+ canvasRef.current.width = img.width
44
+ canvasRef.current.height = img.height
45
+ contextRef.current = canvasRef.current.getContext('2d', {
46
+ willReadFrequently: true
47
+ })
48
+ contextRef.current!.drawImage(img, 0, 0, img.width, img.height)
49
+ }
50
+ img.src = rendered.maskUrl
51
+ }, [rendered.maskUrl])
52
 
53
  const getPixelColor = (x: number, y: number) => {
54
  if (!contextRef.current) {
 
66
 
67
  const getSegmentAt = (x: number, y: number): ImageSegment => {
68
  if (!contextRef.current) throw new Error("Unable to get context from canvas");
69
+ if (!rendered.maskUrl) throw new Error("Mask is undefined");
70
 
71
  let closestSegment: ImageSegment = {
72
  id: 0,
 
84
 
85
  let minDistance = Infinity;
86
 
87
+ rendered.segments.forEach(segment => {
88
  const segmentColor = segment.color.slice(0,3); // get the RGB part only
89
 
90
  const distance = Math.sqrt(
 
114
  // sometimes we generate an image, but the segmentation fails
115
  // so if we click anywhere bug there are no segments,
116
  // we inform the rest of the app by passing nothing
117
+ if (type === "click" && rendered.segments.length == 0) {
118
  onUserAction("nothing, to trigger a scene reload")
119
  return
120
  }
 
141
  } else {
142
  // only trigger hover events if there are segments,
143
  // otherwise it's best to stay silent
144
+ if (rendered.segments.length) {
145
  onUserHover(actionnable)
146
  }
147
  }
 
169
  if (isLoading) {
170
  timeoutRef.current = setInterval(updateProgressBar, 200)
171
  }
172
+ }, [isLoading, rendered.assetUrl, engine?.type])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
 
174
  return (
175
  <div className="w-full pt-2">
 
178
  "relative border-2 border-gray-50 rounded-xl overflow-hidden",
179
  engine.type === "cartesian_video"
180
  || engine.type === "cartesian_image"
181
+ ? "w-full h-screen" // w-[1024px] h-[512px]"
182
  : "w-full h-[800px]",
183
 
184
  isLoading
 
187
  ? "cursor-pointer"
188
  : ""
189
  ].join(" ")}>
190
+ {engine.type === "cartesian_video"
 
 
191
  ? <CartesianVideo
192
+ rendered={rendered}
193
+ ref={viewRef as any}
 
 
194
  onEvent={handleMouseEvent}
195
  />
196
  : engine.type === "spherical_image"
197
  ? <SphericalImage
198
+ rendered={rendered}
199
+ ref={viewRef as any}
200
  onEvent={handleMouseEvent}
201
  />
202
  : <CartesianImage
203
+ rendered={rendered}
204
+ ref={viewRef as any}
 
 
205
  onEvent={handleMouseEvent}
206
  />
207
  }
src/components/business/spherical-image.tsx CHANGED
@@ -2,13 +2,14 @@ import { ForwardedRef, forwardRef } from "react"
2
  import { ReactPhotoSphereViewer } from "react-photo-sphere-viewer"
3
 
4
  import { SceneEventHandler } from "./types"
 
5
 
6
  export const SphericalImage = forwardRef(({
7
- src,
8
  onEvent,
9
  className,
10
  }: {
11
- src: string
12
  onEvent: SceneEventHandler
13
  className?: string
14
  }, ref: ForwardedRef<HTMLImageElement>) => {
@@ -16,7 +17,7 @@ export const SphericalImage = forwardRef(({
16
 
17
  return (
18
  <ReactPhotoSphereViewer
19
- src={src}
20
  // ref={ref}
21
  container=""
22
  containerClass={className}
 
2
  import { ReactPhotoSphereViewer } from "react-photo-sphere-viewer"
3
 
4
  import { SceneEventHandler } from "./types"
5
+ import { RenderedScene } from "@/app/types"
6
 
7
  export const SphericalImage = forwardRef(({
8
+ rendered,
9
  onEvent,
10
  className,
11
  }: {
12
+ rendered: RenderedScene
13
  onEvent: SceneEventHandler
14
  className?: string
15
  }, ref: ForwardedRef<HTMLImageElement>) => {
 
17
 
18
  return (
19
  <ReactPhotoSphereViewer
20
+ src={rendered.assetUrl}
21
  // ref={ref}
22
  container=""
23
  containerClass={className}