Compare commits
42
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c56c8682f | ||
|
|
92a9d52a8c | ||
|
|
80f6d02fc7 | ||
|
|
da54495d1c | ||
|
|
f60ec850f0 | ||
|
|
bce8edc150 | ||
|
|
fadc8cc451 | ||
|
|
8cb8bdfc5e | ||
|
|
0f1ab017ed | ||
|
|
9384f8f23e | ||
|
|
443bfc128a | ||
|
|
a3630abf92 | ||
|
|
74d99aff6e | ||
|
|
76814efb18 | ||
|
|
571a35633b | ||
|
|
5fa34eda14 | ||
|
|
37ad826a80 | ||
|
|
3f8a580984 | ||
|
|
b5f4d91ff8 | ||
|
|
351cc06495 | ||
|
|
4ea5c25a47 | ||
|
|
766dc92931 | ||
|
|
f570b456ca | ||
|
|
8c7cc19991 | ||
|
|
df6d77b870 | ||
|
|
b2a3d4f701 | ||
|
|
6291989dd4 | ||
|
|
a6fcc28ced | ||
|
|
66b6cc61e9 | ||
|
|
90ed8a6211 | ||
|
|
ceab43e861 | ||
|
|
ffd9f0187d | ||
|
|
0305dbe9b7 | ||
|
|
db4aac845c | ||
|
|
bd6978d392 | ||
|
|
310b3e7b17 | ||
|
|
ca87817b33 | ||
|
|
6f7b1bdf03 | ||
|
|
17a1d23768 | ||
|
|
0915c0a8d8 | ||
|
|
7ae052ee8b | ||
|
|
d9d8a7a8f0 |
+24
-28
@@ -1,19 +1,16 @@
|
||||
name: release-tag
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [released]
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
tags:
|
||||
- "**"
|
||||
|
||||
jobs:
|
||||
release-image:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
DOCKER_ORG: legonzaur
|
||||
DOCKER_LATEST: nightly
|
||||
REPO_NAME: ${{ gitea.repository }}
|
||||
ENDPOINT: git.legonzaur.fr
|
||||
|
||||
steps:
|
||||
@@ -23,24 +20,10 @@ jobs:
|
||||
lfs: false
|
||||
persist-credentials: false
|
||||
|
||||
- name: Get Meta
|
||||
id: meta
|
||||
run: |
|
||||
echo REPO_NAME=$(echo ${GITHUB_REPOSITORY} | awk -F"/" '{print $2}') >> $GITHUB_OUTPUT
|
||||
echo REPO_VERSION=$(git describe --tags --always | sed 's/^v//') >> $GITHUB_OUTPUT
|
||||
|
||||
- name: setup private key
|
||||
- name: LFS Checkout
|
||||
shell: bash
|
||||
run: |
|
||||
echo "${{ secrets.RUNNER_SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
|
||||
chmod 400 ~/.ssh/id_ed25519
|
||||
echo "{{ secrets.INSTANCE_SSH_PUBLIC_KEY }} > ~/.ssh/known_hosts"
|
||||
|
||||
- name: git lfs pull
|
||||
shell: bash
|
||||
run: |
|
||||
ssh-keyscan ${{ env.ENDPOINT }} >> ~/.ssh/known_hosts
|
||||
git remote set-url origin git@${{ env.ENDPOINT }}:${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}.git
|
||||
git remote set-url origin https://${{ env.ENDPOINT }}/${{ env.REPO_NAME }}.git
|
||||
git lfs pull
|
||||
|
||||
- name: Login to DockerHub
|
||||
@@ -50,15 +33,28 @@ jobs:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.ENDPOINT }}/${{ env.REPO_NAME }}
|
||||
tags: |
|
||||
type=schedule
|
||||
type=ref,event=branch
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
type=sha
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
secrets: |
|
||||
"NUXT_PUBLIC_WEBSOCKET_ENDPOINT=${{ secrets.NUXT_PUBLIC_WEBSOCKET_ENDPOINT }}"
|
||||
"NUXT_PUBLIC_DISCORD_LOGIN_ENDPOINT=${{ secrets.NUXT_PUBLIC_DISCORD_LOGIN_ENDPOINT }}"
|
||||
build-args: |
|
||||
NUXT_PUBLIC_ENDPOINT=${{ vars.NUXT_PUBLIC_ENDPOINT }}
|
||||
NUXT_PUBLIC_DISCORD_LOGIN_ENDPOINT=${{ vars.NUXT_PUBLIC_DISCORD_LOGIN_ENDPOINT }}
|
||||
NUXT_PUBLIC_WELCOME_MESSAGE=${{ vars.NUXT_PUBLIC_WELCOME_MESSAGE }}
|
||||
push: true
|
||||
tags: | # replace it with your local IP and tags
|
||||
${{ env.ENDPOINT }}/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ steps.meta.outputs.REPO_VERSION }}
|
||||
${{ env.ENDPOINT }}/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ env.DOCKER_LATEST }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
@@ -15,7 +15,8 @@ uniform float u_time;
|
||||
|
||||
void main(){
|
||||
vec2 st=(gl_FragCoord.xy+u_offset)/u_resolution;
|
||||
|
||||
|
||||
|
||||
vec2 q=vec2(0.);
|
||||
q.x=fbm(st);
|
||||
q.y=fbm(st+vec2(1.));
|
||||
@@ -31,4 +32,5 @@ void main(){
|
||||
vec3 color=mix(u_color_start,u_color_end,f*.3);
|
||||
|
||||
gl_FragColor=vec4(color,1.);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
import noise from "~/assets/shaders/noise.frag?raw"
|
||||
|
||||
import resolveLygia from "~/assets/workers/resolve-lygia.esm"
|
||||
|
||||
let interval: number
|
||||
let timeout: number
|
||||
|
||||
const shaderOptions = { quality: 1, framerate: 1000 / 60 }
|
||||
const screen = { width: 0, height: 0, devicePixelRatio: 0 }
|
||||
|
||||
const _colorStart = [0, 0, 0]
|
||||
const _colorEnd = [0, 0, 0]
|
||||
|
||||
let fragmentShader = resolveLygia(noise);
|
||||
|
||||
let canvas: OffscreenCanvas
|
||||
|
||||
let render: (time: number) => void
|
||||
|
||||
let must_resize = false
|
||||
|
||||
async function main(canvas: OffscreenCanvas) {
|
||||
const gl = canvas.getContext("webgl");
|
||||
if (!gl) {
|
||||
return;
|
||||
}
|
||||
// setup GLSL program
|
||||
const program = gl.createProgram()
|
||||
if (!program) { return }
|
||||
|
||||
const fragment = gl.createShader(gl.FRAGMENT_SHADER);
|
||||
if (!fragment) { return }
|
||||
gl.shaderSource(fragment, fragmentShader)
|
||||
gl.compileShader(fragment);
|
||||
if (!gl.getShaderParameter(fragment, gl.COMPILE_STATUS)) {
|
||||
const lastError = gl.getShaderInfoLog(fragment);
|
||||
console.error(lastError)
|
||||
gl.deleteShader(fragment);
|
||||
return
|
||||
}
|
||||
|
||||
const vertex = gl.createShader(gl.VERTEX_SHADER);
|
||||
if (!vertex) { return }
|
||||
gl.shaderSource(vertex, `attribute vec4 a_position;void main() {gl_Position = a_position;}`)
|
||||
gl.compileShader(vertex);
|
||||
if (!gl.getShaderParameter(vertex, gl.COMPILE_STATUS)) {
|
||||
const lastError = gl.getShaderInfoLog(vertex);
|
||||
console.error(lastError)
|
||||
gl.deleteShader(vertex);
|
||||
return
|
||||
}
|
||||
|
||||
gl.attachShader(program, fragment)
|
||||
gl.attachShader(program, vertex)
|
||||
gl.linkProgram(program)
|
||||
const linked = gl.getProgramParameter(program, gl.LINK_STATUS);
|
||||
if (!linked) { return }
|
||||
// const program = webglUtils.createProgramFromSources(gl, [vs, fragmentShader2]);
|
||||
|
||||
// look up where the vertex data needs to go.
|
||||
const positionAttributeLocation = gl.getAttribLocation(program, "a_position");
|
||||
|
||||
// look up uniform locations
|
||||
const offset = gl.getUniformLocation(program, "u_offset");
|
||||
const resolutionLocation = gl.getUniformLocation(program, "u_resolution");
|
||||
const colorStart = gl.getUniformLocation(program, "u_color_start");
|
||||
const quality = gl.getUniformLocation(program, "u_quality");
|
||||
const colorEnd = gl.getUniformLocation(program, "u_color_end");
|
||||
const timeLocation = gl.getUniformLocation(program, "u_time");
|
||||
|
||||
// Create a buffer to put three 2d clip space points in
|
||||
const positionBuffer = gl.createBuffer();
|
||||
|
||||
// Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer)
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
||||
|
||||
// fill it with a 2 triangles that cover clipspace
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
|
||||
-1, -1, // first triangle
|
||||
1, -1,
|
||||
-1, 1,
|
||||
-1, 1, // second triangle
|
||||
1, -1,
|
||||
1, 1,
|
||||
]), gl.STATIC_DRAW);
|
||||
|
||||
|
||||
const gl2 = gl
|
||||
function render(time: number) {
|
||||
if (must_resize) {
|
||||
canvas.width = screen.width * shaderOptions.quality / 10
|
||||
canvas.height = screen.height * shaderOptions.quality / 10
|
||||
must_resize = false;
|
||||
}
|
||||
|
||||
time *= 0.001; // convert to seconds
|
||||
// Tell WebGL how to convert from clip space to pixels
|
||||
gl2.viewport(0, 0, gl2.canvas.width, gl2.canvas.height);
|
||||
|
||||
// Tell it to use our program (pair of shaders)
|
||||
gl2.useProgram(program);
|
||||
|
||||
// Turn on the attribute
|
||||
gl2.enableVertexAttribArray(positionAttributeLocation);
|
||||
|
||||
// Bind the position buffer.
|
||||
gl2.bindBuffer(gl2.ARRAY_BUFFER, positionBuffer);
|
||||
|
||||
// Tell the attribute how to get data out of positionBuffer (ARRAY_BUFFER)
|
||||
gl2.vertexAttribPointer(
|
||||
positionAttributeLocation,
|
||||
2, // 2 components per iteration
|
||||
gl2.FLOAT, // the data is 32bit floats
|
||||
false, // don't normalize the data
|
||||
0, // 0 = move forward size * sizeof(type) each iteration to get the next position
|
||||
0, // start at the beginning of the buffer
|
||||
);
|
||||
|
||||
const secondRatio = screen.width / screen.height
|
||||
|
||||
if (secondRatio < 1) {
|
||||
const half = canvas.height / 2
|
||||
gl2.uniform2f(resolutionLocation, canvas.width, canvas.height * secondRatio);
|
||||
gl2.uniform2f(offset, 0, -half + ((half) / (1 / secondRatio)));
|
||||
} else {
|
||||
const half = canvas.width / 2
|
||||
gl2.uniform2f(resolutionLocation, canvas.width / secondRatio, canvas.height);
|
||||
gl2.uniform2f(offset, -half + ((half) / secondRatio), 0);
|
||||
}
|
||||
gl2.uniform1i(quality, shaderOptions.quality)
|
||||
|
||||
gl2.uniform3f(colorStart, _colorStart[0], _colorStart[1], _colorStart[2]);
|
||||
gl2.uniform3f(colorEnd, _colorEnd[0], _colorEnd[1], _colorEnd[2]);
|
||||
gl2.uniform1f(timeLocation, time);
|
||||
gl2.drawArrays(
|
||||
gl2.TRIANGLES,
|
||||
0, // offset
|
||||
6, // num vertices to process
|
||||
);
|
||||
if (timeout) {
|
||||
self.clearTimeout(timeout)
|
||||
timeout = self.setTimeout(() => {
|
||||
requestAnimationFrame(render)
|
||||
}, 1000 / shaderOptions.framerate)
|
||||
}
|
||||
}
|
||||
|
||||
requestAnimationFrame(render)
|
||||
|
||||
// self.clearInterval(interval)
|
||||
// interval = self.setInterval(() => requestAnimationFrame(render), 1000 / shaderOptions.framerate)
|
||||
self.clearTimeout(timeout)
|
||||
if (shaderOptions.framerate == 0) {
|
||||
return render
|
||||
}
|
||||
timeout = self.setTimeout(() => {
|
||||
requestAnimationFrame(render)
|
||||
}, 1000 / shaderOptions.framerate)
|
||||
return render
|
||||
}
|
||||
|
||||
self.addEventListener("message", (e) => {
|
||||
const data = e.data
|
||||
if (data.command == "initShader") {
|
||||
canvas = data.canvas
|
||||
shaderOptions.quality = data.shaderOptions.quality
|
||||
shaderOptions.framerate = data.shaderOptions.framerate
|
||||
if (shaderOptions.framerate == 65) {
|
||||
shaderOptions.framerate == Infinity
|
||||
}
|
||||
screen.devicePixelRatio = data.screen.devicePixelRatio
|
||||
screen.width = data.screen.width
|
||||
screen.height = data.screen.height
|
||||
loadShader()
|
||||
} else if (data.command == "killShader") {
|
||||
console.log("killShader")
|
||||
self.clearInterval(interval)
|
||||
self.clearTimeout(timeout)
|
||||
}
|
||||
else if (data.command == "resumeShader") {
|
||||
self.clearInterval(interval)
|
||||
self.clearTimeout(timeout)
|
||||
shaderOptions.framerate = data.shaderOptions.framerate
|
||||
if (shaderOptions.framerate == 65) {
|
||||
shaderOptions.framerate == Infinity
|
||||
}
|
||||
timeout = self.setTimeout(() => {
|
||||
requestAnimationFrame(render)
|
||||
}, 1000 / shaderOptions.framerate)
|
||||
// interval = self.setInterval(() => requestAnimationFrame(render), 1000 / shaderOptions.framerate)
|
||||
} else if (data.command == "recolorShader") {
|
||||
_colorStart[0] = data.colorStart[0]
|
||||
_colorStart[1] = data.colorStart[1]
|
||||
_colorStart[2] = data.colorStart[2]
|
||||
_colorEnd[0] = data.colorEnd[0]
|
||||
_colorEnd[1] = data.colorEnd[1]
|
||||
_colorEnd[2] = data.colorEnd[2]
|
||||
} else if (data.command == "resizeShader") {
|
||||
shaderOptions.quality = data.shaderOptions.quality
|
||||
screen.devicePixelRatio = data.screen.devicePixelRatio
|
||||
screen.width = data.screen.width
|
||||
screen.height = data.screen.height
|
||||
must_resize = true
|
||||
}
|
||||
})
|
||||
|
||||
async function loadShader() {
|
||||
if (!canvas) { return }
|
||||
// let fragmentShader2 = fragmentShader.replace("#define FBM_OCTAVES 6", "#define FBM_OCTAVES " + shaderOptions.quality);
|
||||
const temp = await main(canvas);
|
||||
if (temp) {
|
||||
render = temp
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
function getFile(url) {
|
||||
let httpRequest = new XMLHttpRequest();
|
||||
httpRequest.open("GET", url, false);
|
||||
httpRequest.send();
|
||||
if (httpRequest.status == 200)
|
||||
return httpRequest.responseText;
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
function resolveLygia(lines) {
|
||||
if ( !Array.isArray(lines) ) {
|
||||
lines = lines.split(/\r?\n/);
|
||||
}
|
||||
|
||||
let src = "";
|
||||
lines.forEach( (line, i) => {
|
||||
const line_trim = line.trim();
|
||||
if (line_trim.startsWith('#include \"lygia') ) {
|
||||
let include_url = line_trim.substring(15);
|
||||
include_url = "https://lygia.xyz" + include_url.replace(/\"|\;|\s/g,'');
|
||||
src += getFile(include_url) + '\n';
|
||||
}
|
||||
else {
|
||||
src += line + '\n';
|
||||
}
|
||||
});
|
||||
|
||||
return src;
|
||||
}
|
||||
|
||||
async function resolveLygiaAsync(lines) {
|
||||
if (!Array.isArray(lines))
|
||||
lines = lines.split(/\r?\n/);
|
||||
|
||||
let src = "";
|
||||
const response = await Promise.all(
|
||||
lines.map(async (line, i) => {
|
||||
const line_trim = line.trim();
|
||||
if (line_trim.startsWith('#include "lygia')) {
|
||||
let include_url = line_trim.substring(15);
|
||||
include_url = "https://lygia.xyz" + include_url.replace(/\"|\;|\s/g, "");
|
||||
return fetch(include_url).then((res) => res.text());
|
||||
}
|
||||
else
|
||||
return line;
|
||||
})
|
||||
);
|
||||
|
||||
return response.join("\n");
|
||||
}
|
||||
export { resolveLygia as default };
|
||||
@@ -1,151 +1,121 @@
|
||||
<script setup lang="ts">
|
||||
import noise from "~/assets/shaders/noise.frag?raw"
|
||||
|
||||
const canvas = ref<HTMLCanvasElement | null>(null)
|
||||
|
||||
const settingsStore = useSettingsStore()
|
||||
|
||||
declare const webglUtils: {
|
||||
createProgramFromSources: (gl: WebGLRenderingContext, array: [string, string]) => WebGLProgram,
|
||||
resizeCanvasToDisplaySize: (e: HTMLCanvasElement | OffscreenCanvas) => any
|
||||
}
|
||||
declare const resolveLygiaAsync: (source: string) => Promise<string>
|
||||
import gsap from 'gsap';
|
||||
import ShaderWorker from '~/assets/workers/ShaderWorker?worker'
|
||||
import goStore from '~/netcode';
|
||||
const worker = new ShaderWorker()
|
||||
|
||||
const canvas = ref<HTMLCanvasElement | null>(null)
|
||||
const canvas_resize_temp = ref<HTMLCanvasElement | null>(null)
|
||||
|
||||
|
||||
export interface Props {
|
||||
colorStart?: [number, number, number]
|
||||
colorEnd?: [number, number, number]
|
||||
}
|
||||
|
||||
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
colorStart: () => [0, .3, 0],
|
||||
colorEnd: () => [0, 1, 0]
|
||||
})
|
||||
|
||||
const targetFramerate = 1000 / settingsStore.shaderFramerate
|
||||
const _colorStart = reactive(props.colorStart)
|
||||
const _colorEnd = reactive(props.colorEnd)
|
||||
|
||||
const interval = ref<ReturnType<typeof setInterval>>()
|
||||
|
||||
let fragmentShader = await resolveLygiaAsync(noise);
|
||||
|
||||
async function main(canvas: HTMLCanvasElement, fragmentShader2: string) {
|
||||
// Get A WebGL context
|
||||
/** @type {HTMLCanvasElement} */
|
||||
const gl = canvas.getContext("webgl");
|
||||
if (!gl) {
|
||||
return;
|
||||
function initShader() {
|
||||
if (!canvas.value) { return }
|
||||
const offscreen = canvas.value?.transferControlToOffscreen()
|
||||
worker.postMessage({
|
||||
command: "initShader",
|
||||
canvas: offscreen,
|
||||
screen: { height: window.innerHeight * devicePixelRatio, width: window.innerWidth * devicePixelRatio, devicePixelRatio },
|
||||
shaderOptions: { quality: settingsStore.shaderQuality, framerate: settingsStore.shaderFramerate },
|
||||
}, [offscreen])
|
||||
if (settingsStore.shaderFramerate == 0) {
|
||||
killShader()
|
||||
}
|
||||
|
||||
const vs = `attribute vec4 a_position;void main() {gl_Position = a_position;}`;
|
||||
|
||||
// setup GLSL program
|
||||
const program = webglUtils.createProgramFromSources(gl, [vs, fragmentShader2]);
|
||||
|
||||
// look up where the vertex data needs to go.
|
||||
const positionAttributeLocation = gl.getAttribLocation(program, "a_position");
|
||||
|
||||
// look up uniform locations
|
||||
const offset = gl.getUniformLocation(program, "u_offset");
|
||||
const resolutionLocation = gl.getUniformLocation(program, "u_resolution");
|
||||
const colorStart = gl.getUniformLocation(program, "u_color_start");
|
||||
const quality = gl.getUniformLocation(program, "u_quality");
|
||||
const colorEnd = gl.getUniformLocation(program, "u_color_end");
|
||||
const timeLocation = gl.getUniformLocation(program, "u_time");
|
||||
|
||||
// Create a buffer to put three 2d clip space points in
|
||||
const positionBuffer = gl.createBuffer();
|
||||
|
||||
// Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer)
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
||||
|
||||
// fill it with a 2 triangles that cover clipspace
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
|
||||
-1, -1, // first triangle
|
||||
1, -1,
|
||||
-1, 1,
|
||||
-1, 1, // second triangle
|
||||
1, -1,
|
||||
1, 1,
|
||||
]), gl.STATIC_DRAW);
|
||||
|
||||
|
||||
const gl2 = gl
|
||||
function render(time: number) {
|
||||
time *= 0.001; // convert to seconds
|
||||
webglUtils.resizeCanvasToDisplaySize(gl2.canvas);
|
||||
|
||||
// Tell WebGL how to convert from clip space to pixels
|
||||
gl2.viewport(0, 0, gl2.canvas.width, gl2.canvas.height);
|
||||
|
||||
// Tell it to use our program (pair of shaders)
|
||||
gl2.useProgram(program);
|
||||
|
||||
// Turn on the attribute
|
||||
gl2.enableVertexAttribArray(positionAttributeLocation);
|
||||
|
||||
// Bind the position buffer.
|
||||
gl2.bindBuffer(gl2.ARRAY_BUFFER, positionBuffer);
|
||||
|
||||
// Tell the attribute how to get data out of positionBuffer (ARRAY_BUFFER)
|
||||
gl2.vertexAttribPointer(
|
||||
positionAttributeLocation,
|
||||
2, // 2 components per iteration
|
||||
gl2.FLOAT, // the data is 32bit floats
|
||||
false, // don't normalize the data
|
||||
0, // 0 = move forward size * sizeof(type) each iteration to get the next position
|
||||
0, // start at the beginning of the buffer
|
||||
);
|
||||
|
||||
const bounds = canvas.getBoundingClientRect()
|
||||
const aspectRatio = Math.max(window.screen.width, window.screen.height) * devicePixelRatio
|
||||
|
||||
gl2.uniform2f(offset, bounds.left, -bounds.bottom);
|
||||
// console.log(canvas.getBoundingClientRect().left * window.devicePixelRatio)
|
||||
gl2.uniform1i(quality, settingsStore.shaderQuality)
|
||||
gl2.uniform2f(resolutionLocation, aspectRatio, aspectRatio);
|
||||
gl2.uniform3f(colorStart, props.colorStart[0], props.colorStart[1], props.colorStart[2]);
|
||||
gl2.uniform3f(colorEnd, props.colorEnd[0], props.colorEnd[1], props.colorEnd[2]);
|
||||
gl2.uniform1f(timeLocation, time);
|
||||
gl2.drawArrays(
|
||||
gl2.TRIANGLES,
|
||||
0, // offset
|
||||
6, // num vertices to process
|
||||
);
|
||||
}
|
||||
clearInterval(interval.value)
|
||||
interval.value = setInterval(() => requestAnimationFrame(render), targetFramerate)
|
||||
resizeShader()
|
||||
}
|
||||
|
||||
|
||||
async function reloadShader() {
|
||||
nextTick(() => {
|
||||
if (!canvas.value) { return }
|
||||
let fragmentShader2 = fragmentShader.replace("#define FBM_OCTAVES 6", "#define FBM_OCTAVES " + settingsStore.shaderQuality);
|
||||
clearInterval(interval.value)
|
||||
main(canvas.value, fragmentShader2);
|
||||
function recolorShader() {
|
||||
worker.postMessage({
|
||||
command: 'recolorShader',
|
||||
colorStart: [..._colorStart],
|
||||
colorEnd: [..._colorEnd]
|
||||
})
|
||||
|
||||
}
|
||||
watch(() => settingsStore.shaderQuality, (newValue, oldValue) => {
|
||||
reloadShader()
|
||||
|
||||
function resizeShader() {
|
||||
worker.postMessage({
|
||||
command: 'resizeShader',
|
||||
screen: { height: window.innerHeight * devicePixelRatio, width: window.innerWidth * devicePixelRatio, devicePixelRatio },
|
||||
shaderOptions: { quality: settingsStore.shaderQuality, framerate: settingsStore.shaderFramerate },
|
||||
})
|
||||
}
|
||||
|
||||
function killShader() {
|
||||
worker.postMessage({
|
||||
command: 'killShader'
|
||||
})
|
||||
}
|
||||
|
||||
function resumeShader() {
|
||||
worker.postMessage({
|
||||
command: 'resumeShader',
|
||||
shaderOptions: { quality: settingsStore.shaderQuality, framerate: settingsStore.shaderFramerate },
|
||||
})
|
||||
}
|
||||
|
||||
watch(() => [settingsStore.shaderFramerate], () => {
|
||||
if (settingsStore.shaderFramerate == 0) {
|
||||
killShader()
|
||||
return
|
||||
}
|
||||
resumeShader()
|
||||
|
||||
})
|
||||
|
||||
watch(() => settingsStore.shaderFramerate, (newValue, oldValue) => {
|
||||
reloadShader()
|
||||
watch(() => [settingsStore.shaderQuality], () => {
|
||||
resizeShader()
|
||||
})
|
||||
|
||||
watch(() => [goStore.current_game?.current_turn], () => {
|
||||
if (goStore.current_game?.current_turn != goStore.self?.team) {
|
||||
gsap.to(_colorStart, { duration: 0.5, 0: 0, 1: .2, 2: .3 })
|
||||
gsap.to(_colorEnd, { duration: 0.5, 0: 0, 1: 1, 2: 1 })
|
||||
} else {
|
||||
gsap.to(_colorStart, { duration: 0.5, 0: 0, 1: .3, 2: 0 })
|
||||
gsap.to(_colorEnd, { duration: 0.5, 0: 0, 1: 1, 2: 0 })
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
|
||||
watch([_colorEnd, _colorStart], () => {
|
||||
recolorShader()
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
reloadShader()
|
||||
nextTick(() => {
|
||||
recolorShader()
|
||||
initShader()
|
||||
window.addEventListener("resize", resizeShader, true)
|
||||
})
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
clearInterval(interval.value)
|
||||
window.removeEventListener("resize", resizeShader)
|
||||
killShader()
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<canvas v-if="settingsStore.shaderQuality != 0" ref="canvas" id="background">test</canvas>
|
||||
<canvas ref="canvas" id="background" :class="{ pixelated: settingsStore.shaderPixelated }" width="480"
|
||||
height="270">test</canvas>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@@ -154,5 +124,10 @@ onUnmounted(() => {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
image-rendering: smooth;
|
||||
}
|
||||
|
||||
#background.pixelated {
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
</style>
|
||||
+50
-15
@@ -11,7 +11,8 @@ export interface Props {
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
wrapped: () => false,
|
||||
tilted: () => true
|
||||
tilted: () => true,
|
||||
locked: () => true
|
||||
})
|
||||
|
||||
|
||||
@@ -21,6 +22,8 @@ const settingsStore = useSettingsStore()
|
||||
|
||||
const childCount = ref<number>(0)
|
||||
|
||||
const card = ref<HTMLElement>()
|
||||
|
||||
function cardClick() {
|
||||
if (!props.card_id) return
|
||||
emit("click")
|
||||
@@ -41,10 +44,15 @@ watch(
|
||||
props.wrapped ? rotation.value = (Math.random() * 4) - 2 : rotation.value = Math.random() > .5 ? 2 : -2
|
||||
},
|
||||
{ immediate: true })
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
card.value?.style.setProperty("--random-seed", -Math.random() * 10 + 's')
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="`card ${childCount > 0 ? 'active' : ''} ${wrapped ? 'wrapped' : ''} ${props.locked ? 'locked' : ''}`"
|
||||
<div ref="card" class="card" :class="{ active: childCount > 0, wrapped, unlocked: !props.locked }"
|
||||
@contextmenu.prevent="false" @click.left="cardClick" :style="tilted ? `rotate:${rotation}deg;` : ''"
|
||||
@mouseenter="mouseenter" @mouseleave="mouseleave">
|
||||
<div id="contextMenuButtons" :ref="(el) => { childCount = ((el as Element)?.childElementCount ?? 0) }">
|
||||
@@ -66,15 +74,17 @@ watch(
|
||||
|
||||
<style scoped>
|
||||
.card {
|
||||
transition: 0.025s rotate linear;
|
||||
--max-height: 250px;
|
||||
--margin-bottom: calc(var(--max-height) * 0.05);
|
||||
max-width: 256px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
margin-bottom: 0px;
|
||||
margin-top: 15px;
|
||||
transition: all .125s cubic-bezier(0.075, 0.82, 0.165, 1);
|
||||
margin-top: var(--margin-bottom);
|
||||
transition: filter .125s cubic-bezier(0.075, 0.82, 0.165, 1), rotate 0.075s cubic-bezier(1, 1.81, .59, 1.42);
|
||||
isolation: isolate;
|
||||
pointer-events: all;
|
||||
max-height: var(--max-height);
|
||||
}
|
||||
|
||||
.card.active {
|
||||
@@ -82,8 +92,7 @@ watch(
|
||||
}
|
||||
|
||||
.card_image {
|
||||
max-height: 250px;
|
||||
transition: all .125s cubic-bezier(0.075, 0.82, 0.165, 1);
|
||||
max-height: var(--max-height);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@@ -92,20 +101,46 @@ watch(
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
.card.locked {
|
||||
@keyframes unlocked-float {
|
||||
from {
|
||||
transform: none;
|
||||
filter: drop-shadow(calc(var(--margin-bottom)*.3) var(--margin-bottom) 1px rgba(0, 0, 0, .60));
|
||||
}
|
||||
|
||||
to {
|
||||
transform: translateY(calc(var(--margin-bottom)*-.25));
|
||||
filter: drop-shadow(calc(var(--margin-bottom)*.3) calc(var(--margin-bottom)*1.5) 1px rgba(0, 0, 0, .60));
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes unlocked-rotate {
|
||||
from {
|
||||
rotate: -2deg;
|
||||
}
|
||||
|
||||
to {
|
||||
rotate: 2deg;
|
||||
}
|
||||
}
|
||||
|
||||
.card.unlocked {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 15px;
|
||||
filter: drop-shadow(5px 15px 2px rgba(0, 0, 0, .60));
|
||||
margin-bottom: var(--margin-bottom);
|
||||
filter: drop-shadow(calc(var(--margin-bottom)*.3) var(--margin-bottom) 1px rgba(0, 0, 0, .60));
|
||||
animation: 2s infinite alternate ease-in-out unlocked-float, 3.1s infinite alternate ease-in-out unlocked-rotate;
|
||||
animation-delay: var(--random-seed);
|
||||
animation-play-state: running;
|
||||
}
|
||||
|
||||
.card:not(.unlocked):hover {
|
||||
animation-play-state: paused;
|
||||
rotate: none !important;
|
||||
}
|
||||
|
||||
.card.wrapped {
|
||||
max-width: 10px;
|
||||
}
|
||||
|
||||
.card_image {
|
||||
max-height: 250px;
|
||||
}
|
||||
|
||||
#contextMenuButtons {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
@@ -115,7 +150,7 @@ watch(
|
||||
bottom: 0;
|
||||
width: 99%;
|
||||
transform: translateY(-0px);
|
||||
transition: 0.1s transform cubic-bezier(0.075, 0.82, 0.165, 1);
|
||||
transition: 0.1s transform cubic-bezier(1, 1.81, .59, 1.42);
|
||||
}
|
||||
|
||||
.card.active:hover #contextMenuButtons {
|
||||
|
||||
+36
-20
@@ -59,18 +59,21 @@ function showWinnerScreen() {
|
||||
|
||||
<template>
|
||||
<div @contextmenu.prevent="false" id="game_board">
|
||||
<AnimatedBackground></AnimatedBackground>
|
||||
<div id="market">
|
||||
<MarketCards></MarketCards>
|
||||
</div>
|
||||
<div id="player_list">
|
||||
<AnimatedBackground />
|
||||
<PlayerListElement v-for="p in goStore.current_game?.players" :player="p">
|
||||
</PlayerListElement>
|
||||
<div id="player_list_container">
|
||||
<div id="player_list">
|
||||
<PlayerListElement v-for="p in goStore.current_game?.players" :player="p">
|
||||
</PlayerListElement>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="current_player">
|
||||
<template v-for="p in current_players">
|
||||
<AnimatedBackground :color-start="goStore.self == p ? [.0, .3, .3] : undefined"
|
||||
:color-end="goStore.self == p ? [.0, 1, 1] : undefined" />
|
||||
<!-- <AnimatedBackground :color-start="goStore.self == p ? [.0, .3, .3] : undefined"
|
||||
:color-end="goStore.self == p ? [.0, 1, 1] : undefined" /> -->
|
||||
<PlayerSlot :player="p"></PlayerSlot>
|
||||
</template>
|
||||
|
||||
@@ -86,7 +89,7 @@ function showWinnerScreen() {
|
||||
<style scoped>
|
||||
#game_board {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 400px;
|
||||
grid-template-columns: 1fr 450px;
|
||||
grid-template-rows: min-content 1fr;
|
||||
grid-template-areas:
|
||||
"market player_list"
|
||||
@@ -99,30 +102,43 @@ function showWinnerScreen() {
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
isolation: isolate;
|
||||
background: url('/images/bg-darkgrass.png');
|
||||
}
|
||||
|
||||
#market {
|
||||
grid-area: market;
|
||||
background-image: url("/images/bg-sand.png");
|
||||
border-bottom: 3px solid black;
|
||||
;
|
||||
/* background: url('/images/bg-darkgrass.png'); */
|
||||
}
|
||||
|
||||
#current_player {
|
||||
grid-area: current_player;
|
||||
}
|
||||
|
||||
#player_list {
|
||||
#market {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#player_list_container {
|
||||
grid-area: player_list;
|
||||
border-left: 5px solid black;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
background-image: url("/images/bg-darkgrass.png");
|
||||
justify-content: center;
|
||||
|
||||
/* background-image: url("/images/bg-darkgrass.png"); */
|
||||
}
|
||||
|
||||
#player_list {
|
||||
min-height: 90%;
|
||||
background: rgba(0, 0, 0, 0.35);
|
||||
border: 5px solid #000;
|
||||
border-radius: 10px;
|
||||
filter: drop-shadow(2.5px 7.5px 1px rgba(0, 0, 0, .60));
|
||||
margin: 10px;
|
||||
backdrop-filter: blur(10px) contrast(90%) brightness(165%);
|
||||
background: rgba(26, 70, 91, 0.7);
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
#player_list .card_image {
|
||||
max-width: 64px;
|
||||
#player_list .card {
|
||||
--max-height: 90px;
|
||||
}
|
||||
</style>
|
||||
@@ -7,7 +7,7 @@ const displayOptions = ref(false)
|
||||
|
||||
<template>
|
||||
<div :class="`card_overlay`" ref="card">
|
||||
<img class="settings_button" src="/settings.png" alt="settings" @click="displayOptions = true"/>
|
||||
<img class="settings_button" src="/images/settings.png" alt="settings" @click="displayOptions = true"/>
|
||||
</div>
|
||||
<OptionsDialog :isVisible="displayOptions" @close="displayOptions = false" />
|
||||
</template>
|
||||
|
||||
@@ -12,7 +12,6 @@ const buyableFiregem = computed(() => goStore?.current_game?.gem_stack.at(-1))
|
||||
|
||||
<template>
|
||||
<div id="market">
|
||||
<AnimatedBackground :color-end="[1, 1, 0]" :color-start="[.3, .3, 0]"></AnimatedBackground>
|
||||
<CardPreview :tilted="false" :card_id="undefined"></CardPreview>
|
||||
<div class="separator"></div>
|
||||
<CardPreview :tilted="false" :card_id="c?.card_id" v-for="c in goStore.current_game?.market"
|
||||
@@ -55,6 +54,7 @@ const buyableFiregem = computed(() => goStore?.current_game?.gem_stack.at(-1))
|
||||
|
||||
<style scoped>
|
||||
#market {
|
||||
width: min-content;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
@@ -62,8 +62,15 @@ const buyableFiregem = computed(() => goStore?.current_game?.gem_stack.at(-1))
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
gap: 2px;
|
||||
padding: 10px;
|
||||
;
|
||||
margin: 10px;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
padding-bottom: 10px;
|
||||
border-radius: 10px;
|
||||
filter: drop-shadow(2.5px 7.5px 1px rgba(0, 0, 0, .60));
|
||||
backdrop-filter: blur(5px) brightness(80%);
|
||||
background: rgba(155, 62, 62, 0.46);
|
||||
|
||||
}
|
||||
|
||||
.separator {
|
||||
|
||||
@@ -6,6 +6,9 @@ export interface Props {
|
||||
isVisible: boolean;
|
||||
}
|
||||
|
||||
const _devicePixelRatio = computed(() => devicePixelRatio)
|
||||
const _window = computed(() => window)
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
})
|
||||
|
||||
@@ -15,10 +18,6 @@ const close = () => {
|
||||
emit('close')
|
||||
}
|
||||
|
||||
watch(() => settingsStore.shaderQuality, async () => {
|
||||
console.log(settingsStore.shaderQuality)
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -40,27 +39,29 @@ watch(() => settingsStore.shaderQuality, async () => {
|
||||
<span>Shader Quality</span>
|
||||
</div>
|
||||
<div class="dialog-body">
|
||||
<input type="range" min="0" max="10" v-model="settingsStore.shaderQuality">
|
||||
<input type="range" min="1" max="10" v-model="settingsStore.shaderQuality"
|
||||
:disabled="settingsStore.shaderFramerate == 0">
|
||||
</div>
|
||||
<div class="dialog-footer">
|
||||
<span>
|
||||
<template v-if="settingsStore.shaderQuality == 0">
|
||||
Disabled
|
||||
</template>
|
||||
<template v-if="settingsStore.shaderQuality > 0">
|
||||
{{ settingsStore.shaderQuality }}
|
||||
</template>
|
||||
</span>
|
||||
<span>{{ Math.floor(_window.innerWidth * _devicePixelRatio * settingsStore.shaderQuality / 10) }}x{{
|
||||
Math.floor(_window.innerHeight *
|
||||
_devicePixelRatio * settingsStore.shaderQuality / 10) }}</span>
|
||||
</div>
|
||||
<div class="dialog-header">
|
||||
<span>Shader Framerate</span>
|
||||
</div>
|
||||
<div class="dialog-body">
|
||||
<input type="range" min="10" max="60" step="5" v-model="settingsStore.shaderFramerate"
|
||||
:disabled="settingsStore.shaderQuality == 0">
|
||||
<input type="range" min="0" max="65" step="5" v-model="settingsStore.shaderFramerate">
|
||||
</div>
|
||||
<div class="dialog-footer">
|
||||
<span>{{ settingsStore.shaderFramerate }} fps</span>
|
||||
<span v-if="settingsStore.shaderFramerate == 65">vsync</span>
|
||||
<span v-else>{{ settingsStore.shaderFramerate }} fps</span>
|
||||
</div>
|
||||
<div class="dialog-header">
|
||||
<span>Pixelated</span>
|
||||
</div>
|
||||
<div class="dialog-body">
|
||||
<input type="checkbox" v-model="settingsStore.shaderPixelated">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
import goStore from '@/netcode';
|
||||
import type { Player } from "~/netcode/Player";
|
||||
|
||||
const settingsStore = useSettingsStore()
|
||||
|
||||
const view = ref<"main" | "discard">("main")
|
||||
|
||||
function show(data: "main" | "discard") {
|
||||
@@ -18,11 +20,11 @@ const props = defineProps<Props>()
|
||||
|
||||
<template>
|
||||
<div :class="`player_list_element ${goStore.self === props.player ? 'self' : ''}`">
|
||||
<AnimatedBackground v-if="goStore.self === props.player" :color-start="[.0, .3, .3]" :color-end="[.0, 1, 1]" />
|
||||
<!-- <AnimatedBackground v-if="goStore.self === props.player" :color-start="[.0, .3, .3]" :color-end="[.0, 1, 1]" /> -->
|
||||
<div class="button" id="player_list_buttons">
|
||||
<div class="main_button" @click="show('main')">
|
||||
<div class="tooltip">Board</div>
|
||||
<img :src="`/cards/${player.board.at(-1)?.card_id.toString().padStart(3, '0') ?? 'background'}.png`"
|
||||
<img :src="`/cards/${settingsStore.cardStyle}/${player.board.at(-1)?.card_id.toString().padStart(3, '0') ?? 'background'}.png`"
|
||||
draggable="false" :class="view === 'main' && 'selected'">
|
||||
<span class="button_card_number">{{ player.board.length }}</span>
|
||||
|
||||
@@ -35,7 +37,7 @@ const props = defineProps<Props>()
|
||||
</div>
|
||||
<div class="discard_button" @click="show('discard')">
|
||||
<div class="tooltip">Discard</div>
|
||||
<img :src="`/cards/${player.discard_pile.at(-1)?.card_id.toString().padStart(3, '0') ?? 'background'}.png`"
|
||||
<img :src="`/cards/${settingsStore.cardStyle}/${player.discard_pile.at(-1)?.card_id.toString().padStart(3, '0') ?? 'background'}.png`"
|
||||
draggable="false" :class="view === 'discard' && 'selected'">
|
||||
<span class="button_card_number">{{ player.discard_pile.length }}</span>
|
||||
|
||||
@@ -62,14 +64,17 @@ const props = defineProps<Props>()
|
||||
|
||||
|
||||
.tooltip {
|
||||
visibility: visible;
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
transition: .1s transform;
|
||||
background: white;
|
||||
right: 0;
|
||||
right: -0px;
|
||||
border-top-right-radius: 1em;
|
||||
border-bottom-right-radius: 1em;
|
||||
padding-right: 1em;
|
||||
transition-property: visibility, transform;
|
||||
transition-duration: 0.5s, 0.1s;
|
||||
transition-timing-function: ease-in-out, ease-in-out;
|
||||
}
|
||||
|
||||
.button {
|
||||
@@ -96,8 +101,9 @@ const props = defineProps<Props>()
|
||||
|
||||
.button div:hover .tooltip {
|
||||
visibility: visible;
|
||||
|
||||
display: block;
|
||||
transform: translateX(100%);
|
||||
transition-duration: 0, 0.1s;
|
||||
}
|
||||
|
||||
.button_card_number {
|
||||
@@ -118,13 +124,13 @@ const props = defineProps<Props>()
|
||||
grid-template-columns: min-content 1fr;
|
||||
grid-template-areas:
|
||||
"button player";
|
||||
border-bottom: 5px solid black;
|
||||
border: 5px solid black;
|
||||
min-height: 200px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.player_list_element.self {
|
||||
background-image: url('/images/bg-grass.png');
|
||||
/* background-image: url('/images/bg-grass.png'); */
|
||||
}
|
||||
|
||||
.view {
|
||||
|
||||
@@ -60,7 +60,6 @@ function can_buy_fire_gem(): boolean {
|
||||
|
||||
function checkEndTurn() {
|
||||
// TODO: Add a confirmation dialog if resources are left
|
||||
console.log("Checking end turn")
|
||||
if (
|
||||
(!warning.value)
|
||||
&& has_actions_remaining()) {
|
||||
@@ -144,9 +143,8 @@ function check_for_guard(player: Player) {
|
||||
<PlayerStats :player="props.player">
|
||||
</PlayerStats>
|
||||
<template v-if="!hide_stack_and_discard">
|
||||
<button id="end_turn" v-if="isSelfTurn" class="end_turn_button turn_icon"
|
||||
@click="checkEndTurn">END
|
||||
TURN</button>
|
||||
<button id="end_turn" class="end_turn_button turn_icon" :class="{ hidden: !isSelfTurn }"
|
||||
@click="checkEndTurn">END TURN</button>
|
||||
|
||||
<div class="warning"
|
||||
:class="{ 'warning-fire-gem': warningText == 'P\'tite Fire gem?', 'visible': warning }">
|
||||
@@ -275,6 +273,10 @@ function check_for_guard(player: Player) {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#end_turn.hidden {
|
||||
visibility: hidden
|
||||
}
|
||||
|
||||
.stack,
|
||||
.discard,
|
||||
.cards_container {
|
||||
@@ -348,8 +350,8 @@ function check_for_guard(player: Player) {
|
||||
"stack player"
|
||||
"discard player";
|
||||
transition: all 1s;
|
||||
margin-bottom: -75px;
|
||||
padding-bottom: 75px;
|
||||
/* margin-bottom: -75px;
|
||||
padding-bottom: 75px; */
|
||||
}
|
||||
|
||||
.discard_overlay {
|
||||
@@ -476,10 +478,18 @@ function check_for_guard(player: Player) {
|
||||
#player_info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
#player_banner.big>#player_info {
|
||||
margin-left: 500px;
|
||||
#player_banner.big {
|
||||
padding: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
max-width: min-content;
|
||||
border: 5px solid black;
|
||||
border-radius: 10px;
|
||||
filter: drop-shadow(2.5px 7.5px 1px rgba(0, 0, 0, .60));
|
||||
backdrop-filter: blur(5px) brightness(80%) grayscale(80%);
|
||||
}
|
||||
|
||||
#player_stats {
|
||||
|
||||
@@ -45,7 +45,9 @@ const close = () => {
|
||||
Et n'oubliez pas, la prochaine fois, vous gagnerez! Vous verrez! Vous êtes un gagnant, vous êtes un champion!
|
||||
Vous êtes le meilleur! Vous êtes
|
||||
le roi du monde!
|
||||
<img src="/images/so_back.png" alt="Une image décrivant le meme 'We are so back'" />
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -243,6 +243,8 @@ const router = useRouter();
|
||||
</p>
|
||||
<p>Quand vous avez un effet "Sacrifice", vous pouvez fouiller votre défausse pour choisir la carte à
|
||||
sacrifier. Vous pouvez également sacrifier une carte de la main qui n'est pas encore locked!</p>
|
||||
<h2>Zoomer sur les cartes</h2>
|
||||
<p>Pour zoomer sur une carte, maintenez votre clic droit.</p>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -12,13 +12,4 @@ export default defineNuxtConfig({
|
||||
'@pinia/nuxt',
|
||||
'@pinia-plugin-persistedstate/nuxt',
|
||||
],
|
||||
app: {
|
||||
head: {
|
||||
script: [{
|
||||
src: "/webgl-utils.js"
|
||||
}, {
|
||||
src: "https://lygia.xyz/resolve.js"
|
||||
}]
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
Generated
+7
@@ -8,6 +8,7 @@
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@pinia/nuxt": "^0.5.1",
|
||||
"gsap": "^3.12.5",
|
||||
"nuxt": "^3.11.2",
|
||||
"pinia": "^2.1.7",
|
||||
"vue": "^3.4.21",
|
||||
@@ -5670,6 +5671,12 @@
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
|
||||
},
|
||||
"node_modules/gsap": {
|
||||
"version": "3.12.5",
|
||||
"resolved": "https://registry.npmjs.org/gsap/-/gsap-3.12.5.tgz",
|
||||
"integrity": "sha512-srBfnk4n+Oe/ZnMIOXt3gT605BX9x5+rh/prT2F1SsNJsU1XuMiP0E2aptW481OnonOGACZWBqseH5Z7csHxhQ==",
|
||||
"license": "Standard 'no charge' license: https://gsap.com/standard-license. Club GSAP members get more: https://gsap.com/licensing/. Why GreenSock doesn't employ an MIT license: https://gsap.com/why-license/"
|
||||
},
|
||||
"node_modules/gzip-size": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-7.0.0.tgz",
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@pinia/nuxt": "^0.5.1",
|
||||
"gsap": "^3.12.5",
|
||||
"nuxt": "^3.11.2",
|
||||
"pinia": "^2.1.7",
|
||||
"vue": "^3.4.21",
|
||||
|
||||
@@ -18,7 +18,6 @@ import goStore, { setReady } from "@/netcode";
|
||||
<LoginView v-if="goStore.context === 'login'"></LoginView>
|
||||
<GameBoard v-if="goStore.context != 'lobby' && goStore.context != 'login'"></GameBoard>
|
||||
<LobbyView v-if="goStore.context == 'lobby'"></LobbyView>
|
||||
<RulesDisplay v-if="goStore.context == 'rules'"></RulesDisplay>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -8,8 +8,9 @@ enum CardStyles {
|
||||
export const useSettingsStore = defineStore("settingstore", {
|
||||
state: () => ({
|
||||
cardStyle: CardStyles.HERON,
|
||||
shaderQuality: 0,
|
||||
shaderFramerate: 10,
|
||||
shaderQuality: 3,
|
||||
shaderFramerate: 0,
|
||||
shaderPixelated: true
|
||||
}),
|
||||
actions: {
|
||||
switchCardStyles() {
|
||||
|
||||
Reference in New Issue
Block a user