Spaces:
Runtime error
Runtime error
canvas
Browse files- Makefile +2 -2
- frontend/package.json +5 -1
- frontend/src/app.d.ts +4 -0
- frontend/src/lib/App.svelte +107 -0
- frontend/src/lib/Canvas.svelte +40 -92
- frontend/src/lib/store.ts +8 -1
- frontend/src/routes/+page.svelte +24 -22
- frontend/vite.config.dev.ts +1 -0
Makefile
CHANGED
@@ -1,9 +1,9 @@
|
|
1 |
build-client:
|
2 |
cd frontend && npm install && PUBLIC_DEV_MODE=PROD npm run build && rm -rf ../static && cp -r build/ ../static/
|
3 |
build-dev:
|
4 |
-
cd frontend && npm install &&
|
5 |
run-front-dev:
|
6 |
-
cd frontend && npm install &&
|
7 |
run-dev:
|
8 |
rm -rf .data/ && FLASK_ENV=development python app.py
|
9 |
run-prod:
|
|
|
1 |
build-client:
|
2 |
cd frontend && npm install && PUBLIC_DEV_MODE=PROD npm run build && rm -rf ../static && cp -r build/ ../static/
|
3 |
build-dev:
|
4 |
+
cd frontend && npm install && npm run build-dev && rm -rf ../static && cp -r build/ ../static/
|
5 |
run-front-dev:
|
6 |
+
cd frontend && npm install && npm run dev
|
7 |
run-dev:
|
8 |
rm -rf .data/ && FLASK_ENV=development python app.py
|
9 |
run-prod:
|
frontend/package.json
CHANGED
@@ -17,6 +17,8 @@
|
|
17 |
"@tailwindcss/forms": "^0.5.3",
|
18 |
"@tailwindcss/line-clamp": "^0.4.2",
|
19 |
"@types/cookie": "^0.5.1",
|
|
|
|
|
20 |
"@typescript-eslint/eslint-plugin": "^5.27.0",
|
21 |
"@typescript-eslint/parser": "^5.27.0",
|
22 |
"autoprefixer": "^10.4.11",
|
@@ -37,6 +39,8 @@
|
|
37 |
"type": "module",
|
38 |
"dependencies": {
|
39 |
"@fontsource/fira-mono": "^4.5.0",
|
40 |
-
"@liveblocks/client": "^0.18.2"
|
|
|
|
|
41 |
}
|
42 |
}
|
|
|
17 |
"@tailwindcss/forms": "^0.5.3",
|
18 |
"@tailwindcss/line-clamp": "^0.4.2",
|
19 |
"@types/cookie": "^0.5.1",
|
20 |
+
"@types/d3-selection": "^3.0.3",
|
21 |
+
"@types/d3-zoom": "^3.0.1",
|
22 |
"@typescript-eslint/eslint-plugin": "^5.27.0",
|
23 |
"@typescript-eslint/parser": "^5.27.0",
|
24 |
"autoprefixer": "^10.4.11",
|
|
|
39 |
"type": "module",
|
40 |
"dependencies": {
|
41 |
"@fontsource/fira-mono": "^4.5.0",
|
42 |
+
"@liveblocks/client": "^0.18.2",
|
43 |
+
"d3-selection": "^3.0.0",
|
44 |
+
"d3-zoom": "^3.0.0"
|
45 |
}
|
46 |
}
|
frontend/src/app.d.ts
CHANGED
@@ -1,6 +1,7 @@
|
|
1 |
// See https://kit.svelte.dev/docs/types#app
|
2 |
// for information about these interfaces
|
3 |
// and what to do when importing types
|
|
|
4 |
|
5 |
declare global {
|
6 |
namespace App {
|
@@ -12,4 +13,7 @@ declare global {
|
|
12 |
parentIFrame: unknown;
|
13 |
}
|
14 |
}
|
|
|
|
|
|
|
15 |
}
|
|
|
1 |
// See https://kit.svelte.dev/docs/types#app
|
2 |
// for information about these interfaces
|
3 |
// and what to do when importing types
|
4 |
+
import type { ZoomTransform } from 'd3-zoom';
|
5 |
|
6 |
declare global {
|
7 |
namespace App {
|
|
|
13 |
parentIFrame: unknown;
|
14 |
}
|
15 |
}
|
16 |
+
interface Event {
|
17 |
+
transform: ZoomTransform;
|
18 |
+
}
|
19 |
}
|
frontend/src/lib/App.svelte
ADDED
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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.
|
9 |
+
*/
|
10 |
+
|
11 |
+
export let room: Room;
|
12 |
+
|
13 |
+
// Get initial values for presence and others
|
14 |
+
let myPresence = room.getPresence();
|
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(() => {
|
28 |
+
unsubscribeMyPresence();
|
29 |
+
unsubscribeOthers();
|
30 |
+
});
|
31 |
+
|
32 |
+
// Update cursor presence to current pointer location
|
33 |
+
function handlePointerMove(event: PointerEvent) {
|
34 |
+
event.preventDefault();
|
35 |
+
room.updatePresence({
|
36 |
+
cursor: {
|
37 |
+
x: Math.round(event.clientX),
|
38 |
+
y: Math.round(event.clientY)
|
39 |
+
}
|
40 |
+
});
|
41 |
+
}
|
42 |
+
|
43 |
+
// When the pointer leaves the page, set cursor presence to null
|
44 |
+
function handlePointerLeave() {
|
45 |
+
room.updatePresence({
|
46 |
+
cursor: null
|
47 |
+
});
|
48 |
+
}
|
49 |
+
|
50 |
+
const COLORS = [
|
51 |
+
'#E57373',
|
52 |
+
'#9575CD',
|
53 |
+
'#4FC3F7',
|
54 |
+
'#81C784',
|
55 |
+
'#FFF176',
|
56 |
+
'#FF8A65',
|
57 |
+
'#F06292',
|
58 |
+
'#7986CB'
|
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; */
|
90 |
+
/* position: absolute;
|
91 |
+
top: 0;
|
92 |
+
left: 0;
|
93 |
+
width: 100vw;
|
94 |
+
height: 100vh;
|
95 |
+
display: flex;
|
96 |
+
place-content: center;
|
97 |
+
place-items: center;
|
98 |
+
touch-action: none;
|
99 |
+
background-color: white; */
|
100 |
+
}
|
101 |
+
|
102 |
+
.text {
|
103 |
+
max-width: 380px;
|
104 |
+
margin: 0 16px;
|
105 |
+
text-align: center;
|
106 |
+
}
|
107 |
+
</style>
|
frontend/src/lib/Canvas.svelte
CHANGED
@@ -1,103 +1,51 @@
|
|
1 |
<script lang="ts">
|
2 |
-
import
|
3 |
-
import type
|
4 |
-
import {
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
|
|
|
|
|
|
29 |
});
|
30 |
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
x: Math.round(event.clientX),
|
37 |
-
y: Math.round(event.clientY)
|
38 |
-
}
|
39 |
});
|
40 |
}
|
41 |
-
|
42 |
-
// When the pointer leaves the page, set cursor presence to null
|
43 |
-
function handlePointerLeave() {
|
44 |
-
room.updatePresence({
|
45 |
-
cursor: null
|
46 |
-
});
|
47 |
-
}
|
48 |
-
|
49 |
-
const COLORS = [
|
50 |
-
'#E57373',
|
51 |
-
'#9575CD',
|
52 |
-
'#4FC3F7',
|
53 |
-
'#81C784',
|
54 |
-
'#FFF176',
|
55 |
-
'#FF8A65',
|
56 |
-
'#F06292',
|
57 |
-
'#7986CB'
|
58 |
-
];
|
59 |
</script>
|
60 |
|
61 |
-
<
|
62 |
-
|
63 |
-
|
64 |
-
{myPresence?.cursor
|
65 |
-
? `${myPresence.cursor.x} × ${myPresence.cursor.y}`
|
66 |
-
: 'Move your cursor to broadcast its position to other people in the room.'}
|
67 |
-
</div>
|
68 |
-
|
69 |
-
<!-- When others connected, iterate through others and show their cursors -->
|
70 |
-
{#if others}
|
71 |
-
{#each [...others] as { connectionId, presence } (connectionId)}
|
72 |
-
{#if presence?.cursor}
|
73 |
-
<Cursor
|
74 |
-
color={COLORS[connectionId % COLORS.length]}
|
75 |
-
x={presence.cursor.x}
|
76 |
-
y={presence.cursor.y}
|
77 |
-
/>
|
78 |
-
{/if}
|
79 |
-
{/each}
|
80 |
-
{/if}
|
81 |
-
</main>
|
82 |
|
83 |
<style lang="postcss" scoped>
|
84 |
-
|
85 |
-
|
86 |
-
/* position: absolute;
|
87 |
-
top: 0;
|
88 |
-
left: 0;
|
89 |
-
width: 100vw;
|
90 |
-
height: 100vh;
|
91 |
-
display: flex;
|
92 |
-
place-content: center;
|
93 |
-
place-items: center;
|
94 |
-
touch-action: none;
|
95 |
-
background-color: white; */
|
96 |
-
}
|
97 |
-
|
98 |
-
.text {
|
99 |
-
max-width: 380px;
|
100 |
-
margin: 0 16px;
|
101 |
-
text-align: center;
|
102 |
}
|
103 |
</style>
|
|
|
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 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>
|
48 |
+
canvas {
|
49 |
+
transform-origin: 0 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
}
|
51 |
</style>
|
frontend/src/lib/store.ts
CHANGED
@@ -5,7 +5,14 @@ import { browser } from '$app/environment';
|
|
5 |
export const loadingState = writable<string>('');
|
6 |
export const isLoading = writable<boolean>(false);
|
7 |
|
8 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
|
10 |
export const currentUser = writable<User>(
|
11 |
browser ? JSON.parse(localStorage['user'] || JSON.stringify(initialUser)) : initialUser
|
|
|
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
|
frontend/src/routes/+page.svelte
CHANGED
@@ -6,14 +6,14 @@
|
|
6 |
import { createClient } from '@liveblocks/client';
|
7 |
import { currentUser } from '$lib/store';
|
8 |
|
9 |
-
import
|
10 |
import type { Presence, Storage } from '$lib/types';
|
11 |
-
|
12 |
const apiUrl =
|
13 |
PUBLIC_DEV_MODE === 'DEV'
|
14 |
? 'http://localhost:7860'
|
15 |
: '/embed/huggingface-projects/color-palette-generator-sd';
|
16 |
-
|
17 |
let client: Client;
|
18 |
let room: Room;
|
19 |
let roomId = 'sveltekit-live-cursors';
|
@@ -42,27 +42,29 @@
|
|
42 |
});
|
43 |
</script>
|
44 |
|
45 |
-
<div class="max-w-screen-md mx-auto px-3 py-8 relative
|
46 |
-
<
|
47 |
-
|
48 |
-
|
49 |
-
<
|
50 |
-
<
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
|
|
|
|
62 |
</div>
|
63 |
-
<div class="relative">
|
64 |
{#if room}
|
65 |
-
<
|
66 |
{/if}
|
67 |
</div>
|
68 |
</div>
|
|
|
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';
|
11 |
+
console.log('PUBLIC_DEV_MODE', PUBLIC_DEV_MODE);
|
12 |
const apiUrl =
|
13 |
PUBLIC_DEV_MODE === 'DEV'
|
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';
|
|
|
42 |
});
|
43 |
</script>
|
44 |
|
45 |
+
<div class="max-w-screen-md mx-auto px-3 py-8 relative">
|
46 |
+
<div class="relative z-10">
|
47 |
+
<h1 class="text-3xl font-bold leading-normal">Stable Diffussion Outpainting Multiplayer</h1>
|
48 |
+
<p class="text-sm" />
|
49 |
+
<div class="relative bg-white dark:bg-black py-3">
|
50 |
+
<form class="grid grid-cols-6">
|
51 |
+
<input
|
52 |
+
class="input"
|
53 |
+
placeholder="A photo of a beautiful sunset in San Francisco"
|
54 |
+
title="Input prompt to generate image and obtain palette"
|
55 |
+
type="text"
|
56 |
+
name="prompt"
|
57 |
+
disabled={$isLoading}
|
58 |
+
/>
|
59 |
+
<button class="button" disabled={$isLoading} title="Generate Palette">
|
60 |
+
Create Palette
|
61 |
+
</button>
|
62 |
+
</form>
|
63 |
+
</div>
|
64 |
</div>
|
65 |
+
<div class="relative z-0">
|
66 |
{#if room}
|
67 |
+
<App {room} />
|
68 |
{/if}
|
69 |
</div>
|
70 |
</div>
|
frontend/vite.config.dev.ts
CHANGED
@@ -4,6 +4,7 @@ import type { UserConfig } from 'vite';
|
|
4 |
const config: UserConfig = {
|
5 |
plugins: [sveltekit()],
|
6 |
server: {
|
|
|
7 |
proxy: {
|
8 |
'/moon': {
|
9 |
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',
|