summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/shader_editor/index.html90
1 files changed, 86 insertions, 4 deletions
diff --git a/tools/shader_editor/index.html b/tools/shader_editor/index.html
index 122c15e..5db06de 100644
--- a/tools/shader_editor/index.html
+++ b/tools/shader_editor/index.html
@@ -166,11 +166,21 @@ body {
background: #1177bb;
}
-#code-editor {
+.editor-container {
flex: 1;
+ position: relative;
+ overflow: hidden;
+}
+
+#code-editor {
+ position: absolute;
+ top: 0;
+ left: 0;
width: 100%;
- background: #1e1e1e;
- color: #d4d4d4;
+ height: 100%;
+ background: transparent;
+ color: transparent;
+ caret-color: #d4d4d4;
border: none;
padding: 15px;
font-family: 'Courier New', monospace;
@@ -178,8 +188,36 @@ body {
line-height: 1.5;
resize: none;
outline: none;
+ z-index: 2;
}
+#syntax-highlight {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: #1e1e1e;
+ color: #d4d4d4;
+ padding: 15px;
+ font-family: 'Courier New', monospace;
+ font-size: 13px;
+ line-height: 1.5;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+ overflow: auto;
+ pointer-events: none;
+ z-index: 1;
+}
+
+.hl-keyword { color: #569cd6; }
+.hl-type { color: #4ec9b0; }
+.hl-attribute { color: #9cdcfe; }
+.hl-function { color: #dcdcaa; }
+.hl-number { color: #b5cea8; }
+.hl-comment { color: #6a9955; }
+.hl-string { color: #ce9178; }
+
.snippets-panel {
background: #252526;
border-top: 1px solid #3e3e42;
@@ -256,7 +294,10 @@ body {
<button id="snippets-btn">📚 Snippets</button>
</div>
- <textarea id="code-editor" spellcheck="false"></textarea>
+ <div class="editor-container">
+ <div id="syntax-highlight"></div>
+ <textarea id="code-editor" spellcheck="false"></textarea>
+ </div>
<div id="snippets-panel" class="snippets-panel hidden">
<h3>Available Snippets</h3>
@@ -636,9 +677,42 @@ const loopTimeValue = document.getElementById('loop-time-value');
const loopTimeBar = document.getElementById('loop-time-bar');
const snippetsPanel = document.getElementById('snippets-panel');
const snippetsList = document.getElementById('snippets-list');
+const syntaxHighlight = document.getElementById('syntax-highlight');
let composeTimeout = null;
+function highlightWGSL(code) {
+ const keywords = /\b(fn|var|let|const|struct|if|else|for|while|return|break|continue|switch|case|default|loop|continuing)\b/g;
+ const types = /\b(f32|i32|u32|bool|vec2|vec3|vec4|mat2x2|mat3x3|mat4x4|sampler|texture_2d|array)\b/g;
+ const attributes = /(@\w+)/g;
+ const functions = /\b([a-z_]\w*)\s*(?=\()/g;
+ const numbers = /\b(\d+\.?\d*)\b/g;
+ const comments = /(\/\/.*$)/gm;
+ const strings = /"([^"\\]|\\.)*"/g;
+
+ let highlighted = code
+ .replace(/&/g, '&amp;')
+ .replace(/</g, '&lt;')
+ .replace(/>/g, '&gt;');
+
+ highlighted = highlighted
+ .replace(comments, '<span class="hl-comment">$1</span>')
+ .replace(strings, '<span class="hl-string">$&</span>')
+ .replace(attributes, '<span class="hl-attribute">$1</span>')
+ .replace(keywords, '<span class="hl-keyword">$1</span>')
+ .replace(types, '<span class="hl-type">$1</span>')
+ .replace(functions, '<span class="hl-function">$1</span>')
+ .replace(numbers, '<span class="hl-number">$1</span>');
+
+ return highlighted;
+}
+
+function updateHighlight() {
+ syntaxHighlight.innerHTML = highlightWGSL(editor.value);
+ syntaxHighlight.scrollTop = editor.scrollTop;
+ syntaxHighlight.scrollLeft = editor.scrollLeft;
+}
+
async function init() {
try {
await preview.init();
@@ -654,6 +728,7 @@ async function init() {
updateResolution();
editor.value = preview.getDefaultShader();
+ updateHighlight();
preview.play();
playPauseBtn.textContent = '⏸ Pause';
renderLoop();
@@ -698,10 +773,16 @@ function updateResolution() {
}
editor.addEventListener('input', () => {
+ updateHighlight();
clearTimeout(composeTimeout);
composeTimeout = setTimeout(composeAndLoad, 300);
});
+editor.addEventListener('scroll', () => {
+ syntaxHighlight.scrollTop = editor.scrollTop;
+ syntaxHighlight.scrollLeft = editor.scrollLeft;
+});
+
editor.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
e.preventDefault();
@@ -731,6 +812,7 @@ fileInput.addEventListener('change', (e) => {
const reader = new FileReader();
reader.onload = (event) => {
editor.value = event.target.result;
+ updateHighlight();
composeAndLoad();
};
reader.readAsText(file);