Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 17 additions & 18 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,30 @@ name: Go

on:
push:
branches: [ main ]
branches: [main]
pull_request:
branches: [ main ]
branches: [main]

jobs:

build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v2

- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.22
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.24.0

- name: Build
run: go build -v ./...
- name: Build
run: go build -v ./...

- name: Test
run: go test -v ./...
- name: Test
run: go test -v ./...

- name: GoGitOps Step
id: gogitops
uses: beaujr/gogitops-action@v0.2
with:
github-actions-user: owulveryck
github-actions-token: ${{secrets.GITHUB_TOKEN}}
- name: GoGitOps Step
id: gogitops
uses: beaujr/gogitops-action@v0.2
with:
github-actions-user: owulveryck
github-actions-token: ${{secrets.GITHUB_TOKEN}}
2 changes: 1 addition & 1 deletion .github/workflows/goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.23
go-version: 1.24.0
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2
with:
Expand Down
148 changes: 126 additions & 22 deletions client/glCanvas.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
// WebGL initialization
//const gl = visibleCanvas.getContext('webgl');
//const gl = canvas.getContext('webgl', { antialias: true, preserveDrawingBuffer: true });
let laserX = 0; // Initialize with default values
let laserY = 0;
const gl = canvas.getContext('webgl', { antialias: true });
// Use -10,-10 as the default laser coordinate (off-screen) to hide the pointer initially
let laserX = -10;
let laserY = -10;
const gl = canvas.getContext('webgl', {
antialias: true,
preserveDrawingBuffer: true, // Important for proper rendering
alpha: true // Enable transparency
});


if (!gl) {
Expand All @@ -19,30 +22,64 @@ uniform float uScaleFactor;
varying highp vec2 vTextureCoord;

void main(void) {
gl_Position = uRotationMatrix * vec4(aVertexPosition.xy * uScaleFactor, aVertexPosition.zw);
vTextureCoord = aTextureCoord;
// Apply scaling and rotation transformations
gl_Position = uRotationMatrix * vec4(aVertexPosition.xy * uScaleFactor, aVertexPosition.zw);

// Pass texture coordinates to fragment shader
vTextureCoord = aTextureCoord;
}
`;

// Fragment shader program
const fsSource = `
precision mediump float;
precision highp float;

varying highp vec2 vTextureCoord;
uniform sampler2D uSampler;
uniform float uLaserX;
uniform float uLaserY;
uniform bool uDarkMode;

// Constants for laser pointer visualization
const float LASER_RADIUS = 6.0;
const float LASER_EDGE_SOFTNESS = 2.0;
const vec3 LASER_COLOR = vec3(1.0, 0.0, 0.0);

// Constants for image processing
const float CONTRAST = 1.15; // Slight contrast boost
const float BRIGHTNESS = 0.05; // Slight brightness boost
const float SHARPNESS = 0.5; // Sharpness level

// Get texture color without any sharpening - better for handwriting
vec4 getBaseTexture(sampler2D sampler, vec2 texCoord) {
return texture2D(sampler, texCoord);
}

void main(void) {
// Get base texture color directly - no sharpening for clearer handwriting
vec4 texColor = getBaseTexture(uSampler, vTextureCoord);

// Apply very mild contrast adjustments - avoid distortion
vec3 adjusted = (texColor.rgb - 0.5) * 1.05 + 0.5;
texColor.rgb = clamp(adjusted, 0.0, 1.0);

// Calculate laser pointer effect
float dx = gl_FragCoord.x - uLaserX;
float dy = gl_FragCoord.y - uLaserY;
float distance = sqrt(dx * dx + dy * dy);
float radius = 5.0; // Radius of the dot, adjust as needed

if(distance < radius) {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // Red color for the laser dot

if (uDarkMode) {
// Invert colors in dark mode, but preserve alpha
texColor.rgb = 1.0 - texColor.rgb;
}

// Simple laser pointer - more reliable rendering
if (distance < 8.0 && uLaserX > 0.0 && uLaserY > 0.0) {
// Create solid circle with slight fade at edge
float fade = 1.0 - smoothstep(6.0, 8.0, distance);
gl_FragColor = vec4(1.0, 0.0, 0.0, fade); // Red with fade at edge
} else {
gl_FragColor = texture2D(uSampler, vTextureCoord);
gl_FragColor = texColor;
}
}
`;
Expand Down Expand Up @@ -107,6 +144,7 @@ const programInfo = {
uSampler: gl.getUniformLocation(shaderProgram, 'uSampler'),
uLaserX: gl.getUniformLocation(shaderProgram, 'uLaserX'),
uLaserY: gl.getUniformLocation(shaderProgram, 'uLaserY'),
uDarkMode: gl.getUniformLocation(shaderProgram, 'uDarkMode'),
},
};

Expand Down Expand Up @@ -172,18 +210,33 @@ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
let imageData = new ImageData(screenWidth, screenHeight);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imageData);

// Variable to track dark mode state, default is false (light mode)
let isDarkMode = false;

// Draw the scene
function drawScene(gl, programInfo, positionBuffer, textureCoordBuffer, texture) {
// Handle canvas resize for proper rendering
if (resizeGLCanvas(gl.canvas)) {
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
}
gl.clearColor(0.5, 0.5, 0.5, 0.25); // Gray with 75% transparency
gl.clearDepth(1.0); // Clear everything
gl.enable(gl.DEPTH_TEST); // Enable depth testing
gl.depthFunc(gl.LEQUAL); // Near things obscure far things

// Adjust background color based on dark mode
const bgColor = isDarkMode
? [0.12, 0.12, 0.13, 0.25] // Darker, more neutral dark mode bg
: [0.98, 0.98, 0.98, 0.25]; // Nearly white light mode bg
gl.clearColor(bgColor[0], bgColor[1], bgColor[2], bgColor[3]);

// Enable alpha blending for transparency
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);

// Setup depth buffer
gl.clearDepth(1.0);
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);

// Clear the canvas before we start drawing on it.
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

// Tell WebGL to use our program when drawing
gl.useProgram(programInfo.program);
Expand All @@ -206,9 +259,12 @@ function drawScene(gl, programInfo, positionBuffer, textureCoordBuffer, texture)
// Tell the shader we bound the texture to texture unit 0
gl.uniform1i(programInfo.uniformLocations.uSampler, 0);

// Set the laser coordinates
// Set the laser coordinates
gl.uniform1f(programInfo.uniformLocations.uLaserX, laserX);
gl.uniform1f(programInfo.uniformLocations.uLaserY, laserY);

// Set the dark mode flag
gl.uniform1i(programInfo.uniformLocations.uDarkMode, isDarkMode ? 1 : 0);

gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
}
Expand Down Expand Up @@ -263,9 +319,57 @@ function resizeGLCanvas(canvas) {
return false; // indicates no change in size
}

// Direct laser pointer position - no animation for more reliability
function updateLaserPosition(x, y) {
laserX = x / screenWidth * gl.canvas.width;
laserY = gl.canvas.height - (y / screenHeight * gl.canvas.height);

// If x and y are valid positive values
if (x > 0 && y > 0) {
// Position is now directly proportional to canvas size
laserX = x * (gl.canvas.width / screenWidth);
laserY = gl.canvas.height - (y * (gl.canvas.height / screenHeight));
} else {
// Hide the pointer by moving it off-screen
laserX = -10;
laserY = -10;
}

// Redraw immediately
drawScene(gl, programInfo, positionBuffer, textureCoordBuffer, texture);
}

// Function to update dark mode state with transition effect
let darkModeTransition = 0; // 0 = light mode, 1 = dark mode
let transitionActive = false;

function setDarkMode(darkModeEnabled) {
isDarkMode = darkModeEnabled;

// If not already transitioning, start a smooth transition
if (!transitionActive) {
transitionActive = true;
const startTime = performance.now();
const duration = 300; // transition duration in ms

function animateDarkModeTransition(timestamp) {
const elapsed = timestamp - startTime;
const progress = Math.min(elapsed / duration, 1);

// Update transition value (0 to 1 for light to dark)
darkModeTransition = darkModeEnabled ? progress : 1 - progress;

// Render with current transition value
drawScene(gl, programInfo, positionBuffer, textureCoordBuffer, texture);

// Continue animation if not complete
if (progress < 1) {
requestAnimationFrame(animateDarkModeTransition);
} else {
transitionActive = false;
}
}

requestAnimationFrame(animateDarkModeTransition);
} else {
// Just update the scene if already transitioning
drawScene(gl, programInfo, positionBuffer, textureCoordBuffer, texture);
}
}
79 changes: 52 additions & 27 deletions client/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<title>goMarkableStream</title>
<link rel="icon" type="image/x-icon" href="favicon.ico">
<!-- Including the CSS stylesheet -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<script>
const screenWidth = {{ .ScreenWidth }};
Expand All @@ -16,39 +16,64 @@
</head>
<body>
<div id="menuContainer">

<div class="sidebar" id="sidebar">
<div class="sidebar-header">
<img src="favicon.png" alt="Logo" class="sidebar-logo">
<h3>reMarkable</h3>
</div>
<ul class="menu">
<li><button id="rotate" class="apple-button">Rotate</button></li>
<li><button id="colors" class="apple-button">Colors</button></li>
<!--
<li><button id="startStopButton" class="apple-button">
<div class="icon" id="icon"></div>
<span id="label">Record</span>
</button></li>
<li><button id="startStopButtonWithSound" class="apple-button">
<div class="icon" id="icon2"></div>
<span id="label2">Record with audio</span>
</button></li>
<li><button id="screenshotButton" class="apple-button">Screenshot</button><a id="screenshot"></a></li>
-->
<li><button id="pointerButton" class="apple-button">Pointer</button></a></li>
<li><button id="switchOrderButton" class="apple-button">Mask drawing</button><a id="switch"></a></li>
<li>
<button id="rotate" class="apple-button">
<svg class="button-icon" viewBox="0 0 24 24" width="20" height="20">
<path fill="currentColor" d="M7.11,8.53L5.7,7.11C4.8,8.27 4.24,9.61 4.07,11h2.02c0.14-0.87 0.49-1.72 1.02-2.47zM6.09,13H4.07c0.17,1.39 0.72,2.73 1.62,3.89l1.41-1.42c-0.52-0.75-0.87-1.59-1.01-2.47zm1.01,5.32c1.16,0.9 2.51,1.44 3.9,1.61V17.9c-0.87-0.15-1.71-0.49-2.46-1.03L7.1,18.32zM13,4.07V1L8.45,5.55L13,10V6.09c2.84,0.48 5,2.94 5,5.91s-2.16,5.43-5,5.91v2.02c3.95-0.49 7-3.85 7-7.93S16.95,4.56 13,4.07z"/>
</svg>
<span>Rotate</span>
<div class="button-tooltip">Toggle orientation</div>
</button>
</li>
<li>
<button id="colors" class="apple-button toggled">
<svg class="button-icon" viewBox="0 0 24 24" width="20" height="20">
<path fill="currentColor" d="M12,22C6.49,22 2,17.51 2,12S6.49,2 12,2s10,4.04 10,9c0,3.31-2.69,6-6,6h-1.77c-0.28,0-0.5,0.22-0.5,0.5 c0,0.12 0.05,0.23 0.13,0.33c0.41,0.47 0.64,1.06 0.64,1.67C14.5,20.88 13.38,22 12,22z M12,4c-4.41,0-8,3.59-8,8s3.59,8 8,8c0.28,0 0.5-0.22 0.5-0.5c0-0.16-0.08-0.28-0.14-0.35c-0.41-0.46-0.63-1.05-0.63-1.65c0-1.38 1.12-2.5 2.5-2.5H16 c2.21,0 4-1.79 4-4C20,7.14 16.41,4 12,4z M6.5,10c-0.83,0-1.5-0.67-1.5-1.5S5.67,7 6.5,7S8,7.67 8,8.5S7.33,10 6.5,10z M9.5,6C8.67,6 8,5.33 8,4.5S8.67,3 9.5,3S11,3.67 11,4.5S10.33,6 9.5,6z M14.5,6C13.67,6 13,5.33 13,4.5 S13.67,3 14.5,3S16,3.67 16,4.5S15.33,6 14.5,6z M17.5,10c-0.83,0-1.5-0.67-1.5-1.5S16.67,7 17.5,7S19,7.67 19,8.5 S18.33,10 17.5,10z"/>
</svg>
<span>Colors</span>
<div class="button-tooltip">Toggle color mode</div>
</button>
</li>
<li>
<button id="switchOrderButton" class="apple-button">
<svg class="button-icon" viewBox="0 0 24 24" width="20" height="20">
<path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"/>
</svg>
<span>Layers</span>
<div class="button-tooltip">Toggle drawing layers</div>
</button>
</li>
</ul>
<div class="theme-switch-wrapper">
<label class="theme-switch" for="checkbox">
<input type="checkbox" id="checkbox" />
<div class="slider"></div>
</label>
<span class="theme-switch-label">Dark Mode</span>
</div>
<div class="sidebar-footer">
<small>goMarkableStream</small>
</div>
</div>
</div>
<div id="container">
<canvas id="canvas"></canvas>
<div id="message" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: red;"> </div>
<iframe id="content" allow="camera *;" allowfullscreen="true" frameborder="0" width="100%" height="100%" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true">></iframe>
<div id="message"></div>
<iframe id="content" allow="camera *;" allowfullscreen="true" frameborder="0" width="100%" height="100%" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>
</div>

<script src="main.js"></script>
<script src="glCanvas.js"></script>
<script src="utilities.js"></script>
<script src="recording.js"></script>
<script src="canvasHandling.js"></script>
<script src="uiInteractions.js"></script>
<script src="workersHandling.js"></script>
</body>
<script src="main.js"></script> <!-- Include the JavaScript file -->
<script src="glCanvas.js"></script> <!-- Include the JavaScript file -->
<script src="utilities.js"></script> <!-- Include the JavaScript file -->
<script src="recording.js"></script> <!-- Include the JavaScript file -->
<script src="canvasHandling.js"></script> <!-- Include the JavaScript file -->
<script src="uiInteractions.js"></script> <!-- Include the JavaScript file -->
<script src="workersHandling.js"></script>
</html>
</html>
9 changes: 8 additions & 1 deletion client/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ function getBoolQueryParam(param, defaultValue = false) {
return value === 'true';
}

window.onload = function() {
window.onload = async function() {
// Function to get the value of a query parameter by name
// Get the 'present' parameter from the URL
const presentURL = getQueryParam('present');
Expand All @@ -63,6 +63,13 @@ window.onload = function() {
if (presentURL) {
document.getElementById('content').src = presentURL;
}

// Update version in the sidebar footer
const version = await fetchVersion();
const versionElement = document.querySelector('.sidebar-footer small');
if (versionElement) {
versionElement.textContent = `goMarkableStream ${version}`;
}
};

// Add an event listener for the 'beforeunload' event, which is triggered when the page is refreshed or closed
Expand Down
Loading