Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@lightningjs/renderer

Package Overview
Dependencies
Maintainers
0
Versions
58
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@lightningjs/renderer - npm Package Compare versions

Comparing version 0.9.2 to 0.9.3

dist/src/core/renderers/webgl/newShader/effectsMock.d.ts

40

dist/src/core/CoreNode.js

@@ -249,2 +249,6 @@ /*

});
// Trigger a local update if the texture is loaded and the resizeMode is 'contain'
if (this.props.textureOptions?.resizeMode?.type === 'contain') {
this.setUpdateType(UpdateType.Local);
}
};

@@ -308,2 +312,38 @@ onTextureFailed = (target, error) => {

.translate(-pivotTranslateX, -pivotTranslateY);
// Handle 'contain' resize mode
const { width, height } = this.props;
const texture = this.props.texture;
if (texture &&
texture.dimensions &&
this.props.textureOptions?.resizeMode?.type === 'contain') {
let resizeModeScaleX = 1;
let resizeModeScaleY = 1;
let extraX = 0;
let extraY = 0;
const { width: tw, height: th } = texture.dimensions;
const txAspectRatio = tw / th;
const nodeAspectRatio = width / height;
if (txAspectRatio > nodeAspectRatio) {
// Texture is wider than node
// Center the node vertically (shift down by extraY)
// Scale the node vertically to maintain original aspect ratio
const scaleX = width / tw;
const scaledTxHeight = th * scaleX;
extraY = (height - scaledTxHeight) / 2;
resizeModeScaleY = scaledTxHeight / height;
}
else {
// Texture is taller than node (or equal)
// Center the node horizontally (shift right by extraX)
// Scale the node horizontally to maintain original aspect ratio
const scaleY = height / th;
const scaledTxWidth = tw * scaleY;
extraX = (width - scaledTxWidth) / 2;
resizeModeScaleX = scaledTxWidth / width;
}
// Apply the extra translation and scale to the local transform
this.localTransform
.translate(extraX, extraY)
.scale(resizeModeScaleX, resizeModeScaleY);
}
this.setUpdateType(UpdateType.Global);

@@ -310,0 +350,0 @@ }

@@ -36,2 +36,29 @@ import { ImageWorkerManager } from './lib/ImageWorker.js';

}
export type ResizeModeOptions = {
/**
* Specifies that the image should be resized to cover the specified dimensions.
*/
type: 'cover';
/**
* The horizontal clipping position
* To clip the left, set clipX to 0. To clip the right, set clipX to 1.
* clipX 0.5 will clip a equal amount from left and right
*
* @defaultValue 0.5
*/
clipX?: number;
/**
* The vertical clipping position
* To clip the top, set clipY to 0. To clip the bottom, set clipY to 1.
* clipY 0.5 will clip a equal amount from top and bottom
*
* @defaultValue 0.5
*/
clipY?: number;
} | {
/**
* Specifies that the image should be resized to fit within the specified dimensions.
*/
type: 'contain';
};
/**

@@ -105,2 +132,10 @@ * Universal options for all texture types

flipY?: boolean;
/**
* You can use resizeMode to determine the clipping automatically from the width
* and height of the source texture. This can be convenient if you are unsure about
* the exact image sizes but want the image to cover a specific area.
*
* The resize modes cover and contain are supported
*/
resizeMode?: ResizeModeOptions;
}

@@ -107,0 +142,0 @@ export declare class CoreTextureManager {

1

dist/src/core/lib/ImageWorker.d.ts

@@ -13,5 +13,4 @@ import { type TextureData } from '../textures/Texture.js';

private getNextWorker;
private convertUrlToAbsolute;
getImage(src: string, premultiplyAlpha: boolean | null): Promise<TextureData>;
}
export {};

@@ -114,6 +114,2 @@ /*

}
convertUrlToAbsolute(url) {
const absoluteUrl = new URL(url, self.location.href);
return absoluteUrl.href;
}
getImage(src, premultiplyAlpha) {

@@ -123,3 +119,2 @@ return new Promise((resolve, reject) => {

if (this.workers) {
const absoluteSrcUrl = this.convertUrlToAbsolute(src);
const id = this.nextId++;

@@ -131,3 +126,3 @@ this.messageManager[id] = [resolve, reject];

id,
src: absoluteSrcUrl,
src: src,
premultiplyAlpha,

@@ -134,0 +129,0 @@ });

@@ -44,1 +44,2 @@ export type RGBA = [r: number, g: number, b: number, a: number];

export declare function isRectPositive(rect: Rect): boolean;
export declare function convertUrlToAbsolute(url: string): string;

@@ -178,2 +178,22 @@ /*

}
export function convertUrlToAbsolute(url) {
// handle local file imports
if (self.location.protocol === 'file:') {
const path = self.location.pathname.split('/');
path.pop();
const basePath = path.join('/');
const baseUrl = self.location.protocol + '//' + basePath;
// check if url has a leading dot
if (url.charAt(0) === '.') {
url = url.slice(1);
}
// check if url has a leading slash
if (url.charAt(0) === '/') {
url = url.slice(1);
}
return baseUrl + '/' + url;
}
const absoluteUrl = new URL(url, self.location.href);
return absoluteUrl.href;
}
//# sourceMappingURL=utils.js.map

@@ -50,3 +50,4 @@ /*

static onEffectMask = `
float mask = clamp(shaderMask + width, 0.0, 1.0) - clamp(shaderMask, 0.0, 1.0);
float intR = shaderMask + 1.0;
float mask = clamp(intR + width, 0.0, 1.0) - clamp(intR, 0.0, 1.0);
return mix(shaderColor, mix(shaderColor, maskColor, maskColor.a), mask);

@@ -53,0 +54,0 @@ `;

@@ -35,2 +35,3 @@ /*

import { WebGlCoreCtxRenderTexture } from './WebGlCoreCtxRenderTexture.js';
import { ImageTexture } from '../../textures/ImageTexture.js';
const WORDS_PER_QUAD = 24;

@@ -210,2 +211,26 @@ export class WebGlCoreRenderer extends CoreRenderer {

}
const resizeMode = textureOptions?.resizeMode ?? false;
if (texture instanceof ImageTexture) {
if (resizeMode && texture.dimensions) {
const { width: tw, height: th } = texture.dimensions;
if (resizeMode.type === 'cover') {
const scaleX = width / tw;
const scaleY = height / th;
const scale = Math.max(scaleX, scaleY);
const precision = 1 / scale;
// Determine based on width
if (scale && scaleX && scaleX < scale) {
const desiredSize = precision * width;
texCoordX1 = (1 - desiredSize / tw) * (resizeMode.clipX ?? 0.5);
texCoordX2 = texCoordX1 + desiredSize / tw;
}
// Determine based on height
if (scale && scaleY && scaleY < scale) {
const desiredSize = precision * height;
texCoordY1 = (1 - desiredSize / th) * (resizeMode.clipY ?? 0.5);
texCoordY2 = texCoordY1 + desiredSize / th;
}
}
}
}
// Flip texture coordinates if dictated by texture options

@@ -212,0 +237,0 @@ if (flipX) {

@@ -21,2 +21,3 @@ /*

import { isCompressedTextureContainer, loadCompressedTexture, } from '../lib/textureCompression.js';
import { convertUrlToAbsolute } from '../lib/utils.js';
/**

@@ -68,7 +69,9 @@ * Texture consisting of an image loaded from a URL

}
// Convert relative URL to absolute URL
const absoluteSrc = convertUrlToAbsolute(src);
if (this.txManager.imageWorkerManager) {
return await this.txManager.imageWorkerManager.getImage(src, premultiplyAlpha);
return await this.txManager.imageWorkerManager.getImage(absoluteSrc, premultiplyAlpha);
}
else if (this.txManager.hasCreateImageBitmap) {
const response = await fetch(src);
const response = await fetch(absoluteSrc);
const blob = await response.blob();

@@ -90,3 +93,3 @@ const hasAlphaChannel = premultiplyAlpha ?? this.hasAlphaChannel(blob.type);

}
img.src = src;
img.src = absoluteSrc;
await new Promise((resolve, reject) => {

@@ -117,3 +120,3 @@ img.onload = () => resolve();

premultiplyAlpha: props.premultiplyAlpha ?? true,
key: props.key ?? null
key: props.key ?? null,
};

@@ -120,0 +123,0 @@ }

import type { ShaderMap } from '../core/CoreShaderManager.js';
import type { ExtractProps, TextureTypeMap, TextureMap } from '../core/CoreTextureManager.js';
import type { INodeWritableProps, ITextNodeWritableProps } from './INode.js';
import { EventEmitter } from '../common/EventEmitter.js';
import { Stage } from '../core/Stage.js';
import { CoreNode } from '../core/CoreNode.js';
import { CoreTextNode } from '../core/CoreTextNode.js';
import { CoreNode, type CoreNodeWritableProps } from '../core/CoreNode.js';
import { CoreTextNode, type CoreTextNodeWritableProps } from '../core/CoreTextNode.js';
import type { TextureMemoryManagerSettings } from '../core/TextureMemoryManager.js';
/**

@@ -54,12 +54,5 @@ * An immutable reference to a specific Shader type

/**
* Texture Memory Byte Threshold
*
* @remarks
* When the amount of GPU VRAM used by textures exceeds this threshold,
* the Renderer will free up all the textures that are current not visible
* within the configured `boundsMargin`.
*
* When set to `0`, the threshold-based texture memory manager is disabled.
* Texture Memory Manager Settings
*/
txMemByteThreshold?: number;
textureMemory?: Partial<TextureMemoryManagerSettings>;
/**

@@ -180,2 +173,26 @@ * Bounds margin to extend the boundary in which a CoreNode is added as Quad.

* ```
*
* ## Events
* - `fpsUpdate`
* - Emitted every `fpsUpdateInterval` milliseconds with the current FPS
* - `frameTick`
* - Emitted every frame tick
* - `idle`
* - Emitted when the renderer is idle (no changes to the scene
* graph/animations running)
* - `criticalCleanup`
* - Emitted when the Texture Memory Manager Cleanup process is triggered
* - Payload: { memUsed: number, criticalThreshold: number }
* - `memUsed` - The amount of memory (in bytes) used by textures before the
* cleanup process
* - `criticalThreshold` - The critical threshold (in bytes)
* - `criticalCleanupFailed`
* - Emitted when the Texture Memory Manager Cleanup process is unable to free
* up enough texture memory to reach below the critical threshold.
* This can happen when there is not enough non-renderable textures to
* free up.
* - Payload (object with keys):
* - `memUsed` - The amount of memory (in bytes) used by textures after
* the cleanup process
* - `criticalThreshold` - The critical threshold (in bytes)
*/

@@ -206,3 +223,3 @@ export declare class RendererMain extends EventEmitter {

*
* See {@link INode} for more details.
* See {@link CoreNode} for more details.
*

@@ -212,3 +229,3 @@ * @param props

*/
createNode(props: Partial<INodeWritableProps>): CoreNode;
createNode(props: Partial<CoreNodeWritableProps>): CoreNode;
/**

@@ -228,3 +245,3 @@ * Create a new scene graph text node

*/
createTextNode(props: Partial<ITextNodeWritableProps>): CoreTextNode;
createTextNode(props: Partial<CoreTextNodeWritableProps>): CoreTextNode;
/**

@@ -241,3 +258,3 @@ * Resolves the default property values for a Node

*/
resolveNodeDefaults(props: Partial<INodeWritableProps>): INodeWritableProps;
resolveNodeDefaults(props: Partial<CoreNodeWritableProps>): CoreNodeWritableProps;
/**

@@ -244,0 +261,0 @@ * Destroy a node

@@ -26,3 +26,3 @@ /*

import { CoreNode } from '../core/CoreNode.js';
import { CoreTextNode } from '../core/CoreTextNode.js';
import { CoreTextNode, } from '../core/CoreTextNode.js';
/**

@@ -51,2 +51,26 @@ * The Renderer Main API

* ```
*
* ## Events
* - `fpsUpdate`
* - Emitted every `fpsUpdateInterval` milliseconds with the current FPS
* - `frameTick`
* - Emitted every frame tick
* - `idle`
* - Emitted when the renderer is idle (no changes to the scene
* graph/animations running)
* - `criticalCleanup`
* - Emitted when the Texture Memory Manager Cleanup process is triggered
* - Payload: { memUsed: number, criticalThreshold: number }
* - `memUsed` - The amount of memory (in bytes) used by textures before the
* cleanup process
* - `criticalThreshold` - The critical threshold (in bytes)
* - `criticalCleanupFailed`
* - Emitted when the Texture Memory Manager Cleanup process is unable to free
* up enough texture memory to reach below the critical threshold.
* This can happen when there is not enough non-renderable textures to
* free up.
* - Payload (object with keys):
* - `memUsed` - The amount of memory (in bytes) used by textures after
* the cleanup process
* - `criticalThreshold` - The critical threshold (in bytes)
*/

@@ -68,6 +92,12 @@ export class RendererMain extends EventEmitter {

super();
const resolvedTxSettings = {
criticalThreshold: settings.textureMemory?.criticalThreshold || 124e6,
targetThresholdLevel: settings.textureMemory?.targetThresholdLevel || 0.5,
cleanupInterval: settings.textureMemory?.cleanupInterval || 30000,
debugLogging: settings.textureMemory?.debugLogging || false,
};
const resolvedSettings = {
appWidth: settings.appWidth || 1920,
appHeight: settings.appHeight || 1080,
txMemByteThreshold: settings.txMemByteThreshold || 124e6,
textureMemory: resolvedTxSettings,
boundsMargin: settings.boundsMargin || 0,

@@ -95,3 +125,2 @@ deviceLogicalPixelRatio: settings.deviceLogicalPixelRatio || 1,

this.stage = new Stage({
rootId: getNewId(),
appWidth: this.settings.appWidth,

@@ -102,5 +131,2 @@ appHeight: this.settings.appHeight,

canvas: this.canvas,
debug: {
monitorTextureCache: false,
},
deviceLogicalPixelRatio: this.settings.deviceLogicalPixelRatio,

@@ -112,14 +138,5 @@ devicePhysicalPixelRatio: this.settings.devicePhysicalPixelRatio,

renderMode: this.settings.renderMode,
txMemByteThreshold: this.settings.txMemByteThreshold,
textureMemory: resolvedTxSettings,
eventBus: this,
});
// Forward fpsUpdate events from the stage to RendererMain
this.stage.on('fpsUpdate', ((stage, fpsData) => {
this.emit('fpsUpdate', fpsData);
}));
this.stage.on('frameTick', ((stage, frameTickData) => {
this.emit('frameTick', frameTickData);
}));
this.stage.on('idle', () => {
this.emit('idle');
});
// Extract the root node

@@ -154,3 +171,3 @@ this.root = this.stage.root;

*
* See {@link INode} for more details.
* See {@link CoreNode} for more details.
*

@@ -165,3 +182,2 @@ * @param props

...resolvedProps,
id: getNewId(),
shaderProps: null,

@@ -264,2 +280,3 @@ });

shader: props.shader ?? null,
shaderProps: props.shaderProps ?? null,
// Since setting the `src` will trigger a texture load, we need to set it after

@@ -266,0 +283,0 @@ // we set the texture. Otherwise, problems happen.

@@ -1,2 +0,2 @@

import type { CustomDataMap } from '../main-api/INode.js';
import type { CustomDataMap } from '../core/CoreNode.js';
export declare function santizeCustomDataMap(d: CustomDataMap): CustomDataMap;

@@ -42,3 +42,8 @@ import { CoreExtension } from '../../exports/core-api.js';

export function santizeCustomDataMap(d) {
const validTypes = { boolean: true, string: true, number: true, undefined: true };
const validTypes = {
boolean: true,
string: true,
number: true,
undefined: true,
};
const keys = Object.keys(d);

@@ -45,0 +50,0 @@ for (let i = 0; i < keys.length; i++) {

{
"name": "@lightningjs/renderer",
"version": "0.9.2",
"version": "0.9.3",
"description": "Lightning 3 Renderer",

@@ -5,0 +5,0 @@ "type": "module",

@@ -342,2 +342,3 @@ /*

this.autosizeNode(dimensions);
// Texture was loaded. In case the RAF loop has already stopped, we request

@@ -357,2 +358,7 @@ // a render to ensure the texture is rendered.

} satisfies NodeTextureLoadedPayload);
// Trigger a local update if the texture is loaded and the resizeMode is 'contain'
if (this.props.textureOptions?.resizeMode?.type === 'contain') {
this.setUpdateType(UpdateType.Local);
}
};

@@ -436,2 +442,41 @@

// Handle 'contain' resize mode
const { width, height } = this.props;
const texture = this.props.texture;
if (
texture &&
texture.dimensions &&
this.props.textureOptions?.resizeMode?.type === 'contain'
) {
let resizeModeScaleX = 1;
let resizeModeScaleY = 1;
let extraX = 0;
let extraY = 0;
const { width: tw, height: th } = texture.dimensions;
const txAspectRatio = tw / th;
const nodeAspectRatio = width / height;
if (txAspectRatio > nodeAspectRatio) {
// Texture is wider than node
// Center the node vertically (shift down by extraY)
// Scale the node vertically to maintain original aspect ratio
const scaleX = width / tw;
const scaledTxHeight = th * scaleX;
extraY = (height - scaledTxHeight) / 2;
resizeModeScaleY = scaledTxHeight / height;
} else {
// Texture is taller than node (or equal)
// Center the node horizontally (shift right by extraX)
// Scale the node horizontally to maintain original aspect ratio
const scaleY = height / th;
const scaledTxWidth = tw * scaleY;
extraX = (width - scaledTxWidth) / 2;
resizeModeScaleX = scaledTxWidth / width;
}
// Apply the extra translation and scale to the local transform
this.localTransform
.translate(extraX, extraY)
.scale(resizeModeScaleX, resizeModeScaleY);
}
this.setUpdateType(UpdateType.Global);

@@ -438,0 +483,0 @@ }

@@ -60,2 +60,32 @@ /*

export type ResizeModeOptions =
| {
/**
* Specifies that the image should be resized to cover the specified dimensions.
*/
type: 'cover';
/**
* The horizontal clipping position
* To clip the left, set clipX to 0. To clip the right, set clipX to 1.
* clipX 0.5 will clip a equal amount from left and right
*
* @defaultValue 0.5
*/
clipX?: number;
/**
* The vertical clipping position
* To clip the top, set clipY to 0. To clip the bottom, set clipY to 1.
* clipY 0.5 will clip a equal amount from top and bottom
*
* @defaultValue 0.5
*/
clipY?: number;
}
| {
/**
* Specifies that the image should be resized to fit within the specified dimensions.
*/
type: 'contain';
};
/**

@@ -133,2 +163,11 @@ * Universal options for all texture types

flipY?: boolean;
/**
* You can use resizeMode to determine the clipping automatically from the width
* and height of the source texture. This can be convenient if you are unsure about
* the exact image sizes but want the image to cover a specific area.
*
* The resize modes cover and contain are supported
*/
resizeMode?: ResizeModeOptions;
}

@@ -135,0 +174,0 @@

@@ -128,7 +128,2 @@ /*

private convertUrlToAbsolute(url: string): string {
const absoluteUrl = new URL(url, self.location.href);
return absoluteUrl.href;
}
getImage(

@@ -141,3 +136,2 @@ src: string,

if (this.workers) {
const absoluteSrcUrl = this.convertUrlToAbsolute(src);
const id = this.nextId++;

@@ -149,3 +143,3 @@ this.messageManager[id] = [resolve, reject];

id,
src: absoluteSrcUrl,
src: src,
premultiplyAlpha,

@@ -152,0 +146,0 @@ });

@@ -251,1 +251,26 @@ /*

}
export function convertUrlToAbsolute(url: string): string {
// handle local file imports
if (self.location.protocol === 'file:') {
const path = self.location.pathname.split('/');
path.pop();
const basePath = path.join('/');
const baseUrl = self.location.protocol + '//' + basePath;
// check if url has a leading dot
if (url.charAt(0) === '.') {
url = url.slice(1);
}
// check if url has a leading slash
if (url.charAt(0) === '/') {
url = url.slice(1);
}
return baseUrl + '/' + url;
}
const absoluteUrl = new URL(url, self.location.href);
return absoluteUrl.href;
}

@@ -79,3 +79,4 @@ /*

static override onEffectMask = `
float mask = clamp(shaderMask + width, 0.0, 1.0) - clamp(shaderMask, 0.0, 1.0);
float intR = shaderMask + 1.0;
float mask = clamp(intR + width, 0.0, 1.0) - clamp(intR, 0.0, 1.0);
return mix(shaderColor, mix(shaderColor, maskColor, maskColor.a), mask);

@@ -82,0 +83,0 @@ `;

@@ -53,2 +53,3 @@ /*

import { WebGlCoreCtxRenderTexture } from './WebGlCoreCtxRenderTexture.js';
import { ImageTexture } from '../../textures/ImageTexture.js';

@@ -302,2 +303,28 @@ const WORDS_PER_QUAD = 24;

const resizeMode = textureOptions?.resizeMode ?? false;
if (texture instanceof ImageTexture) {
if (resizeMode && texture.dimensions) {
const { width: tw, height: th } = texture.dimensions;
if (resizeMode.type === 'cover') {
const scaleX = width / tw;
const scaleY = height / th;
const scale = Math.max(scaleX, scaleY);
const precision = 1 / scale;
// Determine based on width
if (scale && scaleX && scaleX < scale) {
const desiredSize = precision * width;
texCoordX1 = (1 - desiredSize / tw) * (resizeMode.clipX ?? 0.5);
texCoordX2 = texCoordX1 + desiredSize / tw;
}
// Determine based on height
if (scale && scaleY && scaleY < scale) {
const desiredSize = precision * height;
texCoordY1 = (1 - desiredSize / th) * (resizeMode.clipY ?? 0.5);
texCoordY2 = texCoordY1 + desiredSize / th;
}
}
}
}
// Flip texture coordinates if dictated by texture options

@@ -304,0 +331,0 @@ if (flipX) {

@@ -26,2 +26,3 @@ /*

} from '../lib/textureCompression.js';
import { convertUrlToAbsolute } from '../lib/utils.js';

@@ -112,9 +113,12 @@ /**

// Convert relative URL to absolute URL
const absoluteSrc = convertUrlToAbsolute(src);
if (this.txManager.imageWorkerManager) {
return await this.txManager.imageWorkerManager.getImage(
src,
absoluteSrc,
premultiplyAlpha,
);
} else if (this.txManager.hasCreateImageBitmap) {
const response = await fetch(src);
const response = await fetch(absoluteSrc);
const blob = await response.blob();

@@ -136,3 +140,3 @@ const hasAlphaChannel =

}
img.src = src;
img.src = absoluteSrc;
await new Promise<void>((resolve, reject) => {

@@ -168,3 +172,3 @@ img.onload = () => resolve();

premultiplyAlpha: props.premultiplyAlpha ?? true, // null,
key: props.key ?? null
key: props.key ?? null,
};

@@ -171,0 +175,0 @@ }

@@ -61,3 +61,8 @@ import { CoreExtension } from '../../exports/core-api.js';

export function santizeCustomDataMap(d: CustomDataMap): CustomDataMap {
const validTypes = { boolean: true, string: true, number: true, undefined: true };
const validTypes = {
boolean: true,
string: true,
number: true,
undefined: true,
};

@@ -64,0 +69,0 @@ const keys = Object.keys(d);

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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