New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

fragment-shader

Package Overview
Dependencies
Maintainers
1
Versions
27
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fragment-shader - npm Package Compare versions

Comparing version 0.1.7 to 0.2.0

classes/CodeEditor.ts

297

classes/Editor.ts

@@ -1,283 +0,64 @@

import Shader from './Shader';
import { EditorView, basicSetup } from 'codemirror';
import { EditorViewConfig, ViewUpdate, keymap } from '@codemirror/view';
import { EditorState } from '@codemirror/state';
import { clike } from '@codemirror/legacy-modes/mode/clike';
import { defaultKeymap, indentWithTab } from '@codemirror/commands';
import { StreamLanguage } from '@codemirror/language';
import { createStyleSheet } from '../util/dom';
import { formatShadertoySource } from '../util/shadertoy';
import { oneDark } from '@codemirror/theme-one-dark';
import { BLOCKS, KEYWORDS, MATH, TYPES, RAW_UTILS } from '../constants/glsl';
import { DEFAULT_FRAGMENT_SHADER, DEFAULT_UNIFORMS } from '../constants/shader';
import { type UniformValue } from '../types/shader';
import { createShaderEditor } from '../util/editor';
import { type EditorConfig } from '../types/editor';
import Shader, { DEFAULT_SHADER_CONFIG } from './Shader';
import CodeEditor from './CodeEditor';
import '../css/editor.css';
import { UniformValue } from '../types/shader';
const buildAtoms = (uniforms: UniformValue[]) => ({
...uniforms.reduce((acc: any, uniform: any) => {
acc[uniform[0]] = true;
return acc;
}, {}),
...Object.keys(RAW_UTILS).reduce((acc: any, key: string) => {
acc[key] = true;
return acc;
}, {}),
});
const defineLanguageDetails = (uniforms: UniformValue[]) =>
clike({
name: 'FragmentShader',
types: TYPES,
atoms: buildAtoms(uniforms as any),
builtin: MATH,
keywords: KEYWORDS,
blockKeywords: BLOCKS,
});
const DEFAULT_CONFIG = {
target: document.body,
shader: DEFAULT_FRAGMENT_SHADER,
uniforms: DEFAULT_UNIFORMS,
showErrors: true,
onError: () => {},
onSuccess: () => {},
const DEFAULT_EDITOR_CONFIG: EditorConfig = {
...DEFAULT_SHADER_CONFIG,
debug: true,
onUpdate: () => {},
width: window.innerWidth,
height: window.innerHeight,
dpr: window.devicePixelRatio,
fillViewport: true,
showLineNumbers: true,
};
const errorStylesheet = createStyleSheet();
let errorStyleTimeout = 0;
function setErrorStyle({
message,
line,
}: {
message: string;
line: string;
}): void {
clearTimeout(errorStyleTimeout);
errorStyleTimeout = setTimeout(() => {
errorStylesheet.textContent = /*css*/ `
.cm-line:nth-child(${line}) {
position: relative;
outline: 1px solid var(--red);
}
.cm-gutterElement:nth-child(${line + 1}) {
background: var(--red);
transition: all var(--hover-duration) var(--easing);
outline: 1px solid var(--red);
}
.cm-line:nth-child(${line}):after {
transition: all var(--hover-duration) var(--easing);
content: "${message}";
position: absolute;
top: 0;
left: 100%;
background: var(--red);
color: var(--white);
z-index: 100;
padding: 0 .5rem;
outline: 1px solid var(--red);
}
`;
}, 500);
}
function hideError() {
clearTimeout(errorStyleTimeout);
errorStylesheet.textContent = '';
}
export default class Editor {
private editorView: EditorView | undefined;
private config: EditorConfig;
private editor: CodeEditor;
private shader: Shader;
private uniforms: UniformValue[];
private config: EditorConfig;
private _onUpdate: Function | undefined;
private container: HTMLElement;
constructor(
configOrShader: EditorConfig | string = DEFAULT_CONFIG,
config: EditorConfig = DEFAULT_CONFIG
) {
if (typeof configOrShader === 'string') {
this.config = {
...DEFAULT_CONFIG,
...config,
shader: configOrShader,
};
} else {
this.config = {
...DEFAULT_CONFIG,
...configOrShader,
};
}
constructor(config: EditorConfig = DEFAULT_EDITOR_CONFIG) {
this.config = {
...DEFAULT_EDITOR_CONFIG,
...config,
};
if (
this.config.width !== window.innerWidth ||
this.config.height !== window.innerHeight
) {
this.config.fillViewport = false;
}
const { target, shader, uniforms }: any = this.config;
if (!target || !shader || !uniforms)
throw new Error('Initialization error.');
this.container = document.createElement('section');
this.container.classList.add('editor');
if (!this.config.showLineNumbers)
this.container.classList.add('no-line-numbers');
this.sizeContainer();
target?.appendChild(this.container);
this.shader = new Shader({
target: this.container,
shader,
uniforms,
debug: this.config.showErrors,
onError: this.onError.bind(this),
onSuccess: this.onSuccess.bind(this),
width: this.config.width,
height: this.config.height,
dpr: this.config.dpr,
fillViewport: false,
this.onUpdate = this.onUpdate.bind(this);
this.onError = this.onError.bind(this);
this.editor = createShaderEditor({
...this.config,
onUpdate: this.onUpdate,
});
this._onUpdate = this.config.onUpdate;
this.uniforms = [...uniforms] as UniformValue[];
this.createEditorView();
this.onPaste = this.onPaste.bind(this);
this.sizeContainer = this.sizeContainer.bind(this);
window.addEventListener('paste', this.onPaste);
window.addEventListener('resize', this.sizeContainer);
this.shader = new Shader({ ...this.config, onError: this.onError });
}
sizeContainer() {
const width = this.config.fillViewport
? window.innerWidth
: this.config.width || window.innerWidth;
const height = this.config.fillViewport
? window.innerHeight
: this.config.height || window.innerHeight;
this.container.style.position = 'relative';
this.container.style.width = width + 'px';
this.container.style.height = height + 'px';
this.container.style.overflow = 'hidden';
if (!this.shader) return;
this.shader.size = {
width,
height,
dpr: window.devicePixelRatio,
};
onUpdate(val: string) {
this.editor.hideError();
this.config?.onUpdate?.(val);
this.shader.rebuild({ shader: val, uniforms: this.config.uniforms });
}
onError({ line, message }: any) {
this.config?.onError?.({ line, message });
setErrorStyle({ line, message });
onError({ line, message }: { line: number; message: string }) {
this.editor.showError({ line, message });
}
onSuccess() {
this.config?.onSuccess?.();
hideError();
}
onPaste({ clipboardData }: ClipboardEvent) {
const string = clipboardData?.getData?.('text') || '';
const isShaderToy = string.indexOf('mainImage') !== -1;
if (clipboardData === null || !isShaderToy) return;
this.config.shader = formatShadertoySource(string);
this.shader.rebuild({
shader: this.config.shader,
uniforms: this.uniforms,
});
this.editorView?.setState(
this.createState(this.config.shader, this.uniforms)
);
}
rebuild(sketch: { shader: string; uniforms?: UniformValue[] }) {
const { shader = '', uniforms = [] } = sketch;
this.config.shader = shader;
this.config.uniforms = uniforms;
this.shader.rebuild({
rebuild(config: { shader?: string; uniforms?: UniformValue[] } = {}) {
const {
shader,
uniforms,
});
}: {
shader?: string;
uniforms?: UniformValue[];
} = {
shader: '',
uniforms: [],
...config,
};
this.editorView?.setState(this.createState(shader, uniforms));
this.shader.rebuild({ shader, uniforms });
}
setUniform(key: string, value: any) {
this.shader.setUniform(key, value);
}
start() {
this.shader.start();
}
stop() {
this.shader.stop();
}
createState(
shader: string = DEFAULT_FRAGMENT_SHADER,
uniforms: UniformValue[] = DEFAULT_UNIFORMS
): EditorState {
return EditorState.create({
doc: shader.trim(),
extensions: [
basicSetup,
keymap.of([defaultKeymap as any, indentWithTab]),
oneDark,
StreamLanguage.define(defineLanguageDetails(uniforms)),
EditorView.updateListener.of(this.update.bind(this)),
],
});
}
createEditorView(): void {
this.editorView?.destroy?.();
this.editorView = new EditorView({
parent: this.container,
state: this.createState(this.config.shader, this.config.uniforms),
} as EditorViewConfig);
}
update(e: ViewUpdate) {
const { state, docChanged }: any = e;
if (!docChanged) return;
const shader = state.doc.toString();
this._onUpdate?.(shader);
hideError();
this.shader.rebuild({ shader, uniforms: this.uniforms });
}
destroy() {
window.removeEventListener('paste', this.onPaste);
this.editorView?.destroy();
this.shader?.destroy();
this.container.remove();
this.editor.destroy();
this.shader.destroy();
}
}

@@ -23,4 +23,4 @@ import Uniform from './Uniform';

const DEFAULT_CONFIG: ShaderConfig = {
target: document.body,
export const DEFAULT_SHADER_CONFIG: ShaderConfig = {
parent: document.body,
shader: DEFAULT_FRAGMENT_SHADER,

@@ -53,8 +53,8 @@ uniforms: DEFAULT_UNIFORMS,

constructor(
configOrShader: ShaderConfig | string = DEFAULT_CONFIG,
config: ShaderConfig = DEFAULT_CONFIG
configOrShader: ShaderConfig | string = DEFAULT_SHADER_CONFIG,
config: ShaderConfig = DEFAULT_SHADER_CONFIG
) {
if (typeof configOrShader === 'string') {
this.config = {
...DEFAULT_CONFIG,
...DEFAULT_SHADER_CONFIG,
...config,

@@ -65,3 +65,3 @@ shader: configOrShader,

this.config = {
...DEFAULT_CONFIG,
...DEFAULT_SHADER_CONFIG,
...configOrShader,

@@ -75,8 +75,9 @@ };

this.canvas = createCanvas(this.config.target);
this.canvas = createCanvas(this.config.parent);
if (this.config.fillViewport) {
this.canvas.style.position = 'fixed';
this.canvas.style.position = 'absolute';
this.canvas.style.top = '0';
this.canvas.style.left = '0';
this.canvas.style.zIndex = '0';
}

@@ -111,4 +112,5 @@

this.tick = this.tick.bind(this);
this.setUniform = this.setUniform.bind(this);
this.raf = raf(this.tick.bind(this));
this.raf = raf(this.tick);

@@ -193,3 +195,3 @@ if (this.config.animate) {

return uniforms.reduce((acc, uniform: any, i) => {
return uniforms.reduce((acc, uniform: any) => {
acc[uniform[0]] = new Uniform(

@@ -304,2 +306,4 @@ this.ctx,

this.start();
} else {
requestAnimationFrame(this.tick);
}

@@ -306,0 +310,0 @@ } catch (e) {

@@ -75,2 +75,4 @@ export const k_hue = /*glsl*/ `

export const RAW_UTIL_KEYS = Object.keys(RAW_UTILS);
export const GLSL_UTILS = Object.keys(RAW_UTILS).reduce(

@@ -84,14 +86,5 @@ (acc: string, key: string) => {

const toKeyObject = (arr: any) =>
arr.reduce((acc: any, key: any) => ({ ...acc, [key]: true }), {});
export const BLOCKS = ['if', 'for', 'else', 'switch', 'while'] as any;
export const BLOCKS = toKeyObject([
'if',
'for',
'else',
'switch',
'while',
]) as any;
export const MATH = toKeyObject([
export const MATH = [
'sin',

@@ -105,5 +98,5 @@ 'cos',

'exp',
]) as any;
] as any;
export const KEYWORDS = toKeyObject([
export const KEYWORDS = [
'main',

@@ -116,6 +109,5 @@ 'stream',

'gl_FragColor',
...Object.keys(GLSL_UTILS),
]) as any;
] as any;
export const TYPES = toKeyObject([
export const TYPES = [
'attribute',

@@ -224,2 +216,2 @@ 'bool',

'void',
]) as any;
] as any;
{
"name": "fragment-shader",
"version": "0.1.7",
"version": "0.2.0",
"description": "A lightweight, performant WebGL fragment shader renderer + editor. ",

@@ -27,2 +27,3 @@ "main": "index.js",

"dependencies": {
"@codemirror/autocomplete": "^6.7.1",
"@codemirror/commands": "^6.2.4",

@@ -29,0 +30,0 @@ "@codemirror/language": "^6.7.0",

@@ -1,16 +0,8 @@

import type { UniformValue } from './shader';
import { StreamParser } from '@codemirror/language';
import type { ShaderConfig } from './shader';
export interface EditorConfig {
target?: HTMLElement;
shader?: string;
uniforms?: UniformValue[];
showErrors?: boolean;
onError?: Function;
onSuccess?: Function;
export interface EditorConfig extends ShaderConfig {
onUpdate?: Function;
width?: number;
height?: number;
dpr?: number;
fillViewport?: boolean;
showLineNumbers?: boolean;
document?: string;
streamParser?: StreamParser<any>;
}
export interface ShaderConfig {
target?: HTMLElement;
parent?: HTMLElement;
shader?: string;

@@ -4,0 +4,0 @@ uniforms?: any[];

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc