Add Nebula Browser app, UI and assets

Add initial Nebula Browser project skeleton: CMakeLists to configure and link CEF (including post-build steps to copy runtime and UI files), a Windows CEF-based entry (app/main.cpp) that initializes CEF and loads the bundled UI, and a full ui/ and assets/ tree (HTML, CSS, JS, fonts, icons, and branding images). Update .gitignore to ignore build/out, thirdparty/cef, IDE and common OS artifacts.
This commit is contained in:
Andrew Zambazos
2026-05-13 22:17:58 +12:00
parent 79565f2ef3
commit 207a849f06
52 changed files with 13906 additions and 109 deletions
+231
View File
@@ -0,0 +1,231 @@
<!DOCTYPE html>
<html>
<head>
<title>GPU Diagnostics - Nebula Browser</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
background: #f5f5f5;
}
.container {
max-width: 800px;
margin: 0 auto;
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.status {
padding: 10px;
margin: 10px 0;
border-radius: 4px;
}
.status.good { background: #d4edda; color: #155724; }
.status.warning { background: #fff3cd; color: #856404; }
.status.error { background: #f8d7da; color: #721c24; }
button {
background: #007bff;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
margin: 5px;
}
button:hover { background: #0056b3; }
pre {
background: #f8f9fa;
padding: 10px;
border-radius: 4px;
overflow-x: auto;
font-size: 12px;
}
.canvas-test {
border: 1px solid #ccc;
margin: 10px 0;
}
</style>
</head>
<body>
<div class="container">
<h1>GPU Diagnostics</h1>
<div id="gpu-status" class="status">
<h3>GPU Status</h3>
<p>Loading GPU information...</p>
</div>
<div class="status">
<h3>WebGL Test</h3>
<canvas id="webgl-canvas" class="canvas-test" width="300" height="150"></canvas>
<p id="webgl-status">Testing WebGL...</p>
</div>
<div class="status">
<h3>Canvas 2D Acceleration Test</h3>
<canvas id="canvas2d" class="canvas-test" width="300" height="150"></canvas>
<p id="canvas2d-status">Testing Canvas 2D...</p>
</div>
<div>
<h3>Actions</h3>
<button onclick="refreshGPUInfo()">Refresh GPU Info</button>
<button onclick="forceGC()">Force Garbage Collection</button>
<button onclick="applyFallback(1)">Apply GPU Fallback Level 1</button>
<button onclick="applyFallback(2)">Apply GPU Fallback Level 2</button>
</div>
<div>
<h3>Detailed GPU Information</h3>
<pre id="gpu-details">Loading...</pre>
</div>
</div>
<script>
async function refreshGPUInfo() {
try {
if (!window.electronAPI?.invoke) {
const statusDiv = document.getElementById('gpu-status');
const detailsDiv = document.getElementById('gpu-details');
statusDiv.className = 'status warning';
statusDiv.innerHTML = '<h3>GPU Status</h3><p>Native GPU diagnostics are not exposed to this CEF page.</p>';
detailsDiv.textContent = navigator.userAgent;
return;
}
const gpuInfo = await window.electronAPI.invoke('get-gpu-info');
const statusDiv = document.getElementById('gpu-status');
const detailsDiv = document.getElementById('gpu-details');
if (gpuInfo.error) {
statusDiv.className = 'status error';
statusDiv.innerHTML = `<h3>GPU Status</h3><p>Error: ${gpuInfo.error}</p>`;
} else {
const isGPUWorking = checkGPUFeatures(gpuInfo.featureStatus);
statusDiv.className = `status ${isGPUWorking ? 'good' : 'warning'}`;
statusDiv.innerHTML = `
<h3>GPU Status</h3>
<p><strong>Hardware Acceleration:</strong> ${isGPUWorking ? 'Enabled' : 'Disabled/Limited'}</p>
<p><strong>Fallback Level:</strong> ${gpuInfo.fallbackStatus?.fallbackLevel || 0}</p>
<p><strong>GPU Enabled:</strong> ${gpuInfo.fallbackStatus?.gpuEnabled ? 'Yes' : 'No'}</p>
`;
}
detailsDiv.textContent = JSON.stringify(gpuInfo, null, 2);
} catch (err) {
console.error('Failed to get GPU info:', err);
document.getElementById('gpu-status').innerHTML = `<h3>GPU Status</h3><p>Error: ${err.message}</p>`;
}
}
function checkGPUFeatures(features) {
const criticalFeatures = ['gpu_compositing', 'webgl', 'webgl2'];
return criticalFeatures.some(feature =>
features[feature] && !features[feature].includes('disabled')
);
}
async function forceGC() {
try {
if (!window.electronAPI?.invoke) {
alert('Garbage collection is managed by CEF in this build.');
return;
}
await window.electronAPI.invoke('force-gc');
alert('Garbage collection completed');
} catch (err) {
alert('Failed to force GC: ' + err.message);
}
}
async function applyFallback(level) {
try {
if (!window.electronAPI?.invoke) {
alert('GPU fallback settings are managed by the native CEF app.');
return;
}
const result = await window.electronAPI.invoke('apply-gpu-fallback', level);
if (result.success) {
alert(`Applied GPU fallback level ${level}. App restart may be required.`);
} else {
alert('Failed to apply fallback: ' + result.error);
}
} catch (err) {
alert('Failed to apply fallback: ' + err.message);
}
}
// Test WebGL
function testWebGL() {
const canvas = document.getElementById('webgl-canvas');
const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
const status = document.getElementById('webgl-status');
if (gl) {
// Draw a simple triangle
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, `
attribute vec2 position;
void main() {
gl_Position = vec4(position, 0.0, 1.0);
}
`);
gl.compileShader(vertexShader);
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, `
precision mediump float;
void main() {
gl_Color = vec4(0.0, 1.0, 0.0, 1.0);
}
`);
gl.compileShader(fragmentShader);
status.textContent = 'WebGL: Available ✓';
status.parentElement.className = 'status good';
// Clear with green color to show it's working
gl.clearColor(0.0, 0.8, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
} else {
status.textContent = 'WebGL: Not Available ✗';
status.parentElement.className = 'status error';
}
}
// Test Canvas 2D
function testCanvas2D() {
const canvas = document.getElementById('canvas2d');
const ctx = canvas.getContext('2d');
const status = document.getElementById('canvas2d-status');
try {
// Draw some graphics to test acceleration
const gradient = ctx.createLinearGradient(0, 0, 300, 0);
gradient.addColorStop(0, '#ff0000');
gradient.addColorStop(1, '#0000ff');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, 300, 150);
ctx.fillStyle = 'white';
ctx.font = '20px Arial';
ctx.fillText('Canvas 2D Working!', 50, 80);
status.textContent = 'Canvas 2D: Working ✓';
status.parentElement.className = 'status good';
} catch (err) {
status.textContent = 'Canvas 2D: Error - ' + err.message;
status.parentElement.className = 'status error';
}
}
// Initialize tests
window.addEventListener('DOMContentLoaded', () => {
refreshGPUInfo();
testWebGL();
testCanvas2D();
});
</script>
</body>
</html>