radames commited on
Commit
66ed450
1 Parent(s): 6e6af53
frontend/src/app.html CHANGED
@@ -7,7 +7,8 @@
7
  <script src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.3.1/iframeResizer.contentWindow.min.js"></script>
8
  %sveltekit.head%
9
  </head>
10
- <body class="dark:bg-[rgb(11,15,25)] bg-white dark:text-white text-black">
 
11
  <div>%sveltekit.body%</div>
12
  </body>
13
  </html>
 
7
  <script src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.3.1/iframeResizer.contentWindow.min.js"></script>
8
  %sveltekit.head%
9
  </head>
10
+ <!-- <body class="dark:bg-[rgb(11,15,25)] bg-white dark:text-white text-black"> -->
11
+ <body>
12
  <div>%sveltekit.body%</div>
13
  </body>
14
  </html>
frontend/src/lib/App.svelte CHANGED
@@ -1,8 +1,12 @@
1
  <script lang="ts">
2
  import Cursor from '$lib/Cursor.svelte';
 
3
  import Canvas from '$lib/Canvas.svelte';
 
4
  import type { Room } from '@liveblocks/client';
5
  import { onDestroy } from 'svelte';
 
 
6
  /**
7
  * The main Liveblocks code for the example.
8
  * Check in src/routes/index.svelte to see the setup code.
@@ -15,13 +19,13 @@
15
  let others = room.getOthers();
16
 
17
  // Subscribe to further changes
18
- // const unsubscribeMyPresence = room.subscribe('my-presence', (presence) => {
19
- // myPresence = presence;
20
- // });
21
 
22
- // const unsubscribeOthers = room.subscribe('others', (otherUsers) => {
23
- // others = otherUsers;
24
- // });
25
 
26
  // Unsubscribe when unmounting
27
  onDestroy(() => {
@@ -34,8 +38,8 @@
34
  event.preventDefault();
35
  room.updatePresence({
36
  cursor: {
37
- x: Math.round(event.clientX),
38
- y: Math.round(event.clientY)
39
  }
40
  });
41
  }
@@ -59,31 +63,41 @@
59
  ];
60
  </script>
61
 
62
- <main on:pointerleave={handlePointerLeave} on:pointermove={handlePointerMove}>
63
- <!-- Show the current user's cursor location -->
64
- <div class="text">
65
- {myPresence?.cursor
66
- ? `${myPresence.cursor.x} × ${myPresence.cursor.y}`
67
- : 'Move your cursor to broadcast its position to other people in the room.'}
68
  </div>
 
 
 
 
 
 
 
 
 
 
69
 
70
- <!-- When others connected, iterate through others and show their cursors -->
71
- {#if others}
72
- {#each [...others] as { connectionId, presence } (connectionId)}
73
- {#if presence?.cursor}
74
- <Cursor
75
- color={COLORS[connectionId % COLORS.length]}
76
- x={presence.cursor.x}
77
- y={presence.cursor.y}
78
- />
79
- {/if}
80
- {/each}
81
- {/if}
82
-
83
- </main>
 
 
 
 
 
84
 
85
- <Canvas />
86
- <h3 class="text-xl">TESTS</h3>
87
  <style lang="postcss" scoped>
88
  main {
89
  /* @apply fixed top-0 left-0 w-screen h-screen flex flex-col items-center justify-center touch-none bg-white; */
 
1
  <script lang="ts">
2
  import Cursor from '$lib/Cursor.svelte';
3
+ import Frame from '$lib/Frame.svelte';
4
  import Canvas from '$lib/Canvas.svelte';
5
+ import Menu from '$lib/Menu.svelte';
6
  import type { Room } from '@liveblocks/client';
7
  import { onDestroy } from 'svelte';
8
+ import { currZoomTransform } from '$lib/store';
9
+
10
  /**
11
  * The main Liveblocks code for the example.
12
  * Check in src/routes/index.svelte to see the setup code.
 
19
  let others = room.getOthers();
20
 
21
  // Subscribe to further changes
22
+ const unsubscribeMyPresence = room.subscribe('my-presence', (presence) => {
23
+ myPresence = presence;
24
+ });
25
 
26
+ const unsubscribeOthers = room.subscribe('others', (otherUsers) => {
27
+ others = otherUsers;
28
+ });
29
 
30
  // Unsubscribe when unmounting
31
  onDestroy(() => {
 
38
  event.preventDefault();
39
  room.updatePresence({
40
  cursor: {
41
+ x: Math.round(event.layerX),
42
+ y: Math.round(event.layerY)
43
  }
44
  });
45
  }
 
63
  ];
64
  </script>
65
 
66
+ <div class="relative">
67
+ <div class="z-0">
68
+ <h3 class="text-xl">TESTS</h3>
 
 
 
69
  </div>
70
+ <main class="z-10 relative">
71
+ <!-- Show the current user's cursor location -->
72
+ <div class="text">
73
+ {myPresence?.cursor
74
+ ? `${myPresence.cursor.x} × ${myPresence.cursor.y}`
75
+ : 'Move your cursor to broadcast its position to other people in the room.'}
76
+ </div>
77
+ {#if myPresence?.cursor}
78
+ <Frame x={myPresence.cursor.x} y={myPresence.cursor.y} transform={$currZoomTransform} />
79
+ {/if}
80
 
81
+ <!-- When others connected, iterate through others and show their cursors -->
82
+ {#if others}
83
+ {#each [...others] as { connectionId, presence } (connectionId)}
84
+ {#if presence?.cursor}
85
+ <Cursor
86
+ color={COLORS[connectionId % COLORS.length]}
87
+ x={presence.cursor.x}
88
+ y={presence.cursor.y}
89
+ />
90
+ <Frame x={presence.cursor.x} y={presence.cursor.y} transform={$currZoomTransform} />
91
+ {/if}
92
+ {/each}
93
+ {/if}
94
+ <Canvas />
95
+ </main>
96
+ </div>
97
+ <div class="fixed bottom-0 left-0 right-0 z-50">
98
+ <Menu />
99
+ </div>
100
 
 
 
101
  <style lang="postcss" scoped>
102
  main {
103
  /* @apply fixed top-0 left-0 w-screen h-screen flex flex-col items-center justify-center touch-none bg-white; */
frontend/src/lib/Canvas.svelte CHANGED
@@ -1,47 +1,68 @@
1
  <script lang="ts">
2
- import { zoom, zoomIdentity } from 'd3-zoom';
3
- import { select, type Selection } from 'd3-selection';
4
- import { onMount, tick } from 'svelte';
5
-
6
- const width = 512 * 2;
7
- const height = 512 * 2;
8
 
9
  let canvasEl: HTMLCanvasElement;
 
10
  let canvasCtx: CanvasRenderingContext2D;
11
 
12
- const margin = { top: 50, right: 50, bottom: 50, left: 50 };
 
 
 
13
  const extent = [
14
- [margin.left, margin.top],
15
- [width - margin.right, height - margin.top]
16
  ] as [[number, number], [number, number]];
17
-
18
- const zoomHandler = zoom()
19
- .scaleExtent([0.5, 2])
20
- // .translateExtent(extent)
21
- .extent(extent)
22
- .on('zoom', zoomed);
23
-
24
  onMount(() => {
 
 
 
 
 
 
 
 
 
 
 
25
  select(canvasEl.parentElement)
26
  .call(zoomHandler as any)
27
- .call(zoomHandler.transform as any, zoomIdentity);
 
 
 
28
  canvasCtx = canvasEl.getContext('2d') as CanvasRenderingContext2D;
29
  canvasCtx.fillStyle = 'red';
30
- canvasCtx.rect(100, 100, 500, 500);
31
  canvasCtx.fill();
 
 
 
32
  });
33
 
34
  function zoomed(e: Event) {
35
- const transform = e.transform;
36
  console.log(canvasEl.style.transform, transform);
37
- tick().then(() => {
38
- canvasEl.style.transform = `translate(${transform.x}px, ${transform.y}px) scale(${transform.k})`;
39
- });
 
 
 
 
40
  }
41
  </script>
42
 
43
- <div class="fixed w-screen h-screen max-h-[1024px] top-0 left-0 overflow-hidden border-4 border-black">
44
- <canvas bind:this={canvasEl} {width} {height} />
 
 
 
45
  </div>
46
 
47
  <style lang="postcss" scoped>
 
1
  <script lang="ts">
2
+ import { zoom, type ZoomTransform, zoomIdentity } from 'd3-zoom';
3
+ import { select } from 'd3-selection';
4
+ import { onMount } from 'svelte';
5
+ import { currZoomTransform } from '$lib/store';
6
+ const height = 512 * 5;
7
+ const width = 512 * 5;
8
 
9
  let canvasEl: HTMLCanvasElement;
10
+ let containerEl: HTMLDivElement;
11
  let canvasCtx: CanvasRenderingContext2D;
12
 
13
+ $:{
14
+ console.log($currZoomTransform)
15
+ }
16
+ const margin = { top: 100, right: 100, bottom: 100, left: 100 };
17
  const extent = [
18
+ [-margin.left, -margin.top],
19
+ [width + margin.right, height + margin.bottom]
20
  ] as [[number, number], [number, number]];
 
 
 
 
 
 
 
21
  onMount(() => {
22
+ const scale = width / containerEl.clientWidth;
23
+ const zoomHandler = zoom()
24
+ .scaleExtent([1 / scale / 2, 2])
25
+ .translateExtent([
26
+ [0, 0],
27
+ [width, height]
28
+ ])
29
+ // .translateExtent(extent)
30
+ .clickDistance(2)
31
+ .on('zoom', zoomed);
32
+
33
  select(canvasEl.parentElement)
34
  .call(zoomHandler as any)
35
+ .call(zoomHandler.scaleTo as any, 1 / scale)
36
+ .on('pointermove', handlePointerMove)
37
+ .on('pointerleave', handlePointerLeave);
38
+
39
  canvasCtx = canvasEl.getContext('2d') as CanvasRenderingContext2D;
40
  canvasCtx.fillStyle = 'red';
41
+ canvasCtx.rect(10, 10, 160, 90);
42
  canvasCtx.fill();
43
+ canvasCtx.strokeStyle = 'blue';
44
+ canvasCtx.lineWidth = 5;
45
+ canvasCtx.strokeRect(0, 0, width, height);
46
  });
47
 
48
  function zoomed(e: Event) {
49
+ const transform = ($currZoomTransform = e.transform);
50
  console.log(canvasEl.style.transform, transform);
51
+ canvasEl.style.transform = `translate(${transform.x}px, ${transform.y}px) scale(${transform.k})`;
52
+ }
53
+ function handlePointerMove(e: PointerEvent) {
54
+ // console.log(e);
55
+ }
56
+ function handlePointerLeave(e: PointerEvent) {
57
+ // console.log(e);
58
  }
59
  </script>
60
 
61
+ <div
62
+ bind:this={containerEl}
63
+ class="fixed w-screen h-screen top-0 left-0 overflow-hidden border-4 border-black"
64
+ >
65
+ <canvas bind:this={canvasEl} {width} {height} class="absolute top-0 left-0" />
66
  </div>
67
 
68
  <style lang="postcss" scoped>
frontend/src/lib/Frame.svelte ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { spring } from 'svelte/motion';
3
+ import type { ZoomTransform } from 'd3-zoom';
4
+
5
+ export let transform: ZoomTransform;
6
+ export let color = '';
7
+ export let x = 0;
8
+ export let y = 0;
9
+
10
+ // Spring animation for cursor
11
+ const coords = spring(
12
+ { x, y },
13
+ {
14
+ stiffness: 0.07,
15
+ damping: 0.35
16
+ }
17
+ );
18
+ // Update spring when x and y change
19
+ $: coords.set({ x, y });
20
+ </script>
21
+
22
+ <div
23
+ class="frame"
24
+ style={`transform: translateX(${$coords.x}px) translateY(${$coords.y}px) scale(${transform.k})`}
25
+ />
26
+
27
+ <style lang="postcss" scoped>
28
+ .frame {
29
+ @apply absolute top-0 left-0 border-2 border-sky-500 bg-gradient-to-b from-sky-200 w-[512px] h-[512px];
30
+ transform-origin: 0 0;
31
+ }
32
+ </style>
frontend/src/lib/Menu.svelte ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { currZoomTransform } from '$lib/store';
3
+ </script>
4
+
5
+ <div class="grid grid-cols-3 gap-3 text-sm w-max mx-auto">
6
+ <div class="flex items-center">
7
+ <input
8
+ id="showframes"
9
+ type="checkbox"
10
+ class="w-4 h-4 text-blue-600 bg-gray-100 rounded border-gray-300 focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600 cursor-pointer"
11
+ />
12
+ <label for="showframes" class="text-black dark:text-white cursor-pointer ml-2"
13
+ >Show Frames</label
14
+ >
15
+ </div>
16
+ <button class="button" title="Add Prompt"> Add Prompt </button>
17
+ <button class="button-paint bg-violet-100 text-violet-900" title="New Paint Frame">
18
+ <span
19
+ class="rounded-sm h-5 w-5 m-1 flex justify-center items-center border-2 border-dashed border-violet-700 mr-2"
20
+ >+</span
21
+ >
22
+ Paint
23
+ </button>
24
+ </div>
25
+
26
+ <style lang="postcss" scoped>
27
+ .link {
28
+ @apply text-xs underline font-bold hover:no-underline hover:text-gray-500 visited:text-gray-500;
29
+ }
30
+ .input {
31
+ @apply disabled:opacity-50 italic dark:placeholder:text-black placeholder:text-white text-white dark:text-black placeholder:text-opacity-30 dark:placeholder:text-opacity-10 dark:bg-white bg-slate-900 border-2 border-black rounded-2xl px-2 shadow-sm focus:outline-none focus:border-gray-400 focus:ring-1;
32
+ }
33
+ .button {
34
+ @apply disabled:opacity-50 dark:bg-white dark:text-black bg-black text-white rounded-2xl text-xs shadow-sm focus:outline-none focus:border-gray-400;
35
+ }
36
+ .button-paint {
37
+ @apply flex justify-center items-center disabled:opacity-50 dark:bg-white dark:text-black rounded-2xl shadow-sm focus:outline-none focus:border-gray-400;
38
+ }
39
+ </style>
frontend/src/lib/store.ts CHANGED
@@ -1,24 +1,7 @@
1
  import { writable } from 'svelte/store';
2
- import type { User } from '$lib/types';
3
- import { browser } from '$app/environment';
4
 
5
  export const loadingState = writable<string>('');
6
  export const isLoading = writable<boolean>(false);
7
 
8
- let initialUser: User;
9
- if (typeof crypto['randomUUID'] === 'undefined') {
10
- initialUser = (1e7 + '').replace(/\d/g, (c) =>
11
- (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16)
12
- );
13
- } else {
14
- initialUser = crypto.randomUUID();
15
- }
16
-
17
- export const currentUser = writable<User>(
18
- browser ? JSON.parse(localStorage['user'] || JSON.stringify(initialUser)) : initialUser
19
- );
20
- currentUser.subscribe((value) => {
21
- if (browser) {
22
- return (localStorage['user'] = JSON.stringify(value));
23
- }
24
- });
 
1
  import { writable } from 'svelte/store';
2
+ import { type ZoomTransform, zoomIdentity } from 'd3-zoom';
 
3
 
4
  export const loadingState = writable<string>('');
5
  export const isLoading = writable<boolean>(false);
6
 
7
+ export const currZoomTransform = writable<ZoomTransform>(zoomIdentity);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
frontend/src/routes/+page.svelte CHANGED
@@ -4,7 +4,6 @@
4
  import { PUBLIC_WS_ENDPOINT, PUBLIC_DEV_MODE } from '$env/static/public';
5
  import type { Client, Room } from '@liveblocks/client';
6
  import { createClient } from '@liveblocks/client';
7
- import { currentUser } from '$lib/store';
8
 
9
  import App from '$lib/App.svelte';
10
  import type { Presence, Storage } from '$lib/types';
@@ -14,17 +13,14 @@
14
  ? 'http://localhost:7860'
15
  : '/embed/huggingface-projects/color-palette-generator-sd';
16
  console.log(apiUrl);
 
17
  let client: Client;
18
  let room: Room;
19
  let roomId = 'sveltekit-live-cursors';
20
 
21
- $: {
22
- console.log('whoami', $currentUser);
23
- }
24
-
25
  onMount(() => {
26
  client = createClient({
27
- publicApiKey: 'pk_live_6o9jIg1m7lFJp5kc7HgYgE3S'
28
  });
29
 
30
  room = client.enter<Presence, Storage /* UserMeta, RoomEvent */>(roomId, {
@@ -33,7 +29,6 @@
33
  },
34
  initialStorage: {}
35
  });
36
- console.log('room', room);
37
  return () => {
38
  if (client && room) {
39
  client.leave(roomId);
 
4
  import { PUBLIC_WS_ENDPOINT, PUBLIC_DEV_MODE } from '$env/static/public';
5
  import type { Client, Room } from '@liveblocks/client';
6
  import { createClient } from '@liveblocks/client';
 
7
 
8
  import App from '$lib/App.svelte';
9
  import type { Presence, Storage } from '$lib/types';
 
13
  ? 'http://localhost:7860'
14
  : '/embed/huggingface-projects/color-palette-generator-sd';
15
  console.log(apiUrl);
16
+
17
  let client: Client;
18
  let room: Room;
19
  let roomId = 'sveltekit-live-cursors';
20
 
 
 
 
 
21
  onMount(() => {
22
  client = createClient({
23
+ publicApiKey: 'pk_test_JlUZGH3kQmhmZQiqU2l8eIi5'
24
  });
25
 
26
  room = client.enter<Presence, Storage /* UserMeta, RoomEvent */>(roomId, {
 
29
  },
30
  initialStorage: {}
31
  });
 
32
  return () => {
33
  if (client && room) {
34
  client.leave(roomId);
frontend/vite.config.dev.ts CHANGED
@@ -4,7 +4,7 @@ import type { UserConfig } from 'vite';
4
  const config: UserConfig = {
5
  plugins: [sveltekit()],
6
  server: {
7
- host: "0.0.0.0",
8
  proxy: {
9
  '/moon': {
10
  target: 'https://huggingface.co',
 
4
  const config: UserConfig = {
5
  plugins: [sveltekit()],
6
  server: {
7
+ // host: "0.0.0.0",
8
  proxy: {
9
  '/moon': {
10
  target: 'https://huggingface.co',
package.json CHANGED
@@ -1,5 +1,8 @@
1
  {
2
  "devDependencies": {
3
  "@types/smoothscroll-polyfill": "^0.3.1"
 
 
 
4
  }
5
  }
 
1
  {
2
  "devDependencies": {
3
  "@types/smoothscroll-polyfill": "^0.3.1"
4
+ },
5
+ "dependencies": {
6
+ "d3-scale": "^4.0.2"
7
  }
8
  }