diff --git a/handheld/lcd-shader.slangp b/handheld/lcd-shader.slangp
new file mode 100644
index 0000000..08581bd
--- /dev/null
+++ b/handheld/lcd-shader.slangp
@@ -0,0 +1,31 @@
+shaders = 4
+
+shader0 = shaders/lcd-shader/lcd-pass-0.slang
+alias0 = PASS1
+
+shader1 = shaders/lcd-shader/lcd-pass-1.slang
+
+shader2 = shaders/lcd-shader/lcd-pass-2.slang
+
+shader3 = shaders/lcd-shader/lcd-pass-3.slang
+
+scale_type0 = viewport
+scale0 = 1
+
+scale_type1 = source
+scale1 = 1
+
+scale_type2 = source
+scale2 = 1
+
+scale_type3 = source
+scale3 = 1
+
+filter_linear0 = false
+filter_linear1 = false
+filter_linear2 = false
+filter_linear3 = false
+
+textures = "BACKGROUND"
+BACKGROUND = shaders/lcd-shader/background.png
+BACKGROUND_linear = true
diff --git a/handheld/shaders/lcd-shader/background.png b/handheld/shaders/lcd-shader/background.png
new file mode 100644
index 0000000..dd6fd76
Binary files /dev/null and b/handheld/shaders/lcd-shader/background.png differ
diff --git a/handheld/shaders/lcd-shader/lcd-pass-0.slang b/handheld/shaders/lcd-shader/lcd-pass-0.slang
new file mode 100644
index 0000000..264cb92
--- /dev/null
+++ b/handheld/shaders/lcd-shader/lcd-pass-0.slang
@@ -0,0 +1,128 @@
+#version 450
+
+///////////////////////////////////////////////////////////////////////////
+// //
+// LCD Shader v0.0.1 //
+// //
+// Copyright (C) 2013 Harlequin : unknown92835@gmail.com //
+// //
+// This program is free software: you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation, either version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+// //
+///////////////////////////////////////////////////////////////////////////
+
+layout(push_constant) uniform Push
+{
+ vec4 SourceSize;
+ vec4 OriginalSize;
+ vec4 OutputSize;
+ uint FrameCount; float response_time;
+} params;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//config //
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// Simulate response time
+// Higher values result in longer color transition periods - [0, 1]
+#pragma parameter response_time "LCD Response Time" 0.333 0.0 0.777 0.111
+#define response_time params.response_time
+
+layout(std140, set = 0, binding = 0) uniform UBO
+{
+ mat4 MVP;
+} global;
+
+#pragma stage vertex
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//vertex definitions //
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#define video_scale floor(params.OutputSize.y * params.SourceSize.w) //largest integer scale of input video that will fit in the current output (y axis would typically be limiting on widescreens)
+#define scaled_video_out (params.SourceSize.xy * video_scale) //size of the scaled video
+#define half_pixel (0.5 * params.OutputSize.zw) //it's... half a pixel
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//vertex shader //
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+layout(location = 0) in vec4 Position;
+layout(location = 1) in vec2 TexCoord;
+layout(location = 0) out vec2 vTexCoord;
+layout(location = 1) out float cell_height;
+layout(location = 2) out float texel_height;
+
+void main()
+{
+ gl_Position = global.MVP * Position;
+ vTexCoord = TexCoord;
+ cell_height = params.SourceSize.w;
+ texel_height = 1.0 / (params.SourceSize.y * video_scale);
+}
+
+#pragma stage fragment
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//fragment definitions //
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#define curr_rgb texture(Source, vTexCoord).rgb
+#define prev0_rgb texture(OriginalHistory1, vTexCoord).rgb
+#define prev1_rgb texture(OriginalHistory2, vTexCoord).rgb
+#define prev2_rgb texture(OriginalHistory3, vTexCoord).rgb
+#define prev3_rgb texture(OriginalHistory4, vTexCoord).rgb
+#define prev4_rgb texture(OriginalHistory5, vTexCoord).rgb
+#define prev5_rgb texture(OriginalHistory6, vTexCoord).rgb
+#define prev6_rgb texture(OriginalHistory7, vTexCoord).rgb
+
+#define line_alpha 0.5 //arbitrary 0 texel_height);
+ FragColor = vec4( (out_color.rgb * float(is_on_line)), (out_color.a - (line_alpha * float(!is_on_line))) );
+}
diff --git a/handheld/shaders/lcd-shader/lcd-pass-1.slang b/handheld/shaders/lcd-shader/lcd-pass-1.slang
new file mode 100644
index 0000000..d067155
--- /dev/null
+++ b/handheld/shaders/lcd-shader/lcd-pass-1.slang
@@ -0,0 +1,138 @@
+#version 450
+
+///////////////////////////////////////////////////////////////////////////
+// //
+// LCD Shader v0.0.1 //
+// //
+// Copyright (C) 2013 Harlequin : unknown92835@gmail.com //
+// //
+// This program is free software: you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation, either version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+// //
+///////////////////////////////////////////////////////////////////////////
+
+layout(push_constant) uniform Push
+{
+ vec4 SourceSize;
+ vec4 OriginalSize;
+ vec4 OutputSize;
+ uint FrameCount;
+ float cell_scale, triad_color_0_r, triad_color_0_g, triad_color_0_b,
+ triad_color_1_r, triad_color_1_g, triad_color_1_b, triad_color_2_r,
+ triad_color_2_g, triad_color_2_b;
+} params;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//config //
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma parameter cell_scale "LCD Cell Scale" 1.0 1.0 5.0 1.0
+#pragma parameter triad_color_0_r "LCD Red Triad Color R" 1.0 0.0 1.0 0.1
+#pragma parameter triad_color_0_g "LCD Red Triad Color G" 0.0 0.0 1.0 0.1
+#pragma parameter triad_color_0_b "LCD Red Triad Color B" 1.0 0.0 1.0 0.1
+#pragma parameter triad_color_1_r "LCD Green Triad Color R" 1.0 0.0 1.0 0.1
+#pragma parameter triad_color_1_g "LCD Green Triad Color G" 1.0 0.0 1.0 0.1
+#pragma parameter triad_color_1_b "LCD Green Triad Color B" 0.0 0.0 1.0 0.1
+#pragma parameter triad_color_2_r "LCD Blue Triad Color R" 0.0 0.0 1.0 0.1
+#pragma parameter triad_color_2_g "LCD Blue Triad Color G" 1.0 0.0 1.0 0.1
+#pragma parameter triad_color_2_b "LCD Blue Triad Color B" 1.0 0.0 1.0 0.1
+
+#define cell_scale params.cell_scale
+#define triad_color_0_r params.triad_color_0_r
+#define triad_color_0_g params.triad_color_0_g
+#define triad_color_0_b params.triad_color_0_b
+#define triad_color_1_r params.triad_color_1_r
+#define triad_color_1_g params.triad_color_1_g
+#define triad_color_1_b params.triad_color_1_b
+#define triad_color_2_r params.triad_color_2_r
+#define triad_color_2_g params.triad_color_2_g
+#define triad_color_2_b params.triad_color_2_b
+
+layout(std140, set = 0, binding = 0) uniform UBO
+{
+ mat4 MVP;
+} global;
+
+#pragma stage vertex
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//vertex shader //
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+layout(location = 0) in vec4 Position;
+layout(location = 1) in vec2 TexCoord;
+layout(location = 0) out vec2 vTexCoord;
+layout(location = 1) out float dX;
+layout(location = 2) out float two_dX;
+layout(location = 3) out float three_dX;
+
+void main()
+{
+ gl_Position = global.MVP * Position;
+ vTexCoord = TexCoord;
+
+ float texel_width = params.SourceSize.z;
+ dX = texel_width;
+ two_dX = 2.0 * texel_width;
+ three_dX = 3.0 * texel_width;
+}
+
+#pragma stage fragment
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//fragment definitions //
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+#define triad_color_0 vec3(triad_color_0_r, triad_color_0_g, triad_color_0_b) //magenta
+#define triad_color_1 vec3(triad_color_1_r, triad_color_1_g, triad_color_1_b) //yellow
+#define triad_color_2 vec3(triad_color_2_r, triad_color_2_g, triad_color_2_b) //cyan
+
+//#define triad_color_0 vec3(0.0, 0.0, 1.0) //blue
+//#define triad_color_1 vec3(1.0, 0.0, 0.0) //red
+//#define triad_color_2 vec3(0.0, 1.0, 0.0) //green
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//fragment shader //
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+layout(location = 0) in vec2 vTexCoord;
+layout(location = 1) in float dX;
+layout(location = 2) in float two_dX;
+layout(location = 3) in float three_dX;
+layout(location = 0) out vec4 FragColor;
+layout(set = 0, binding = 2) uniform sampler2D Source;
+
+void main()
+{
+ //use modulo to deterimine the current subcell location and apply proper color
+
+ float modX = mod(vTexCoord.x, cell_scale * three_dX);
+
+ vec3 subpixel_color = (modX < cell_scale * dX) ? triad_color_0 :
+ (modX < cell_scale * two_dX) ? triad_color_1 : triad_color_2;
+
+
+ //use color darkening with input texture to determine the final color of the subpixel
+ //color darkening: the minimum value for each color component between the LCD cell and the input image is selected
+ //ex. LCD cell subpixel is magenta (1.0, 1.0, 0.0) and the current video texel is red (1.0, 0.0, 0.0)...
+ //...the result will be the minimum of each component: result.rgb = min(1.0, 1.0), min(1.0, 0.0), min(0.0, 0.0) = (1.0, 0.0, 0.0) = red
+
+ vec4 out_color = texture(Source, vTexCoord);
+
+ out_color.rgb = vec3( min(out_color.r, subpixel_color.r),
+ min(out_color.g, subpixel_color.g),
+ min(out_color.b, subpixel_color.b) );
+
+ FragColor = out_color;
+}
diff --git a/handheld/shaders/lcd-shader/lcd-pass-2.slang b/handheld/shaders/lcd-shader/lcd-pass-2.slang
new file mode 100644
index 0000000..191f038
--- /dev/null
+++ b/handheld/shaders/lcd-shader/lcd-pass-2.slang
@@ -0,0 +1,111 @@
+#version 450
+
+///////////////////////////////////////////////////////////////////////////
+// //
+// LCD Shader v0.0.1 //
+// //
+// Copyright (C) 2013 Harlequin : unknown92835@gmail.com //
+// //
+// This program is free software: you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation, either version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+// //
+///////////////////////////////////////////////////////////////////////////
+
+layout(push_constant) uniform Push
+{
+ vec4 SourceSize;
+ vec4 OriginalSize;
+ vec4 OutputSize;
+ uint FrameCount;
+ float LCD_to_input_ratio, bg_tint_r, bg_tint_g, bg_tint_b;
+} params;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//config //
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma parameter LCD_to_input_ratio "LCD to Input Ratio" 0.9 0.0 1.0 0.01
+//the ratio of blending between the LCD pixels and the input image, higher values result in stronger LCD magenta/yellow/cyan bands - [0, 1]
+#pragma parameter bg_tint_r "LCD Background Tint (Red)" 0.0 0.0 1.0 0.01
+#pragma parameter bg_tint_g "LCD Background Tint (Green)" 0.0 0.0 1.0 0.01
+#pragma parameter bg_tint_b "LCD Background Tint (Blue)" 0.0 0.0 1.0 0.01
+
+#define LCD_to_input_ratio params.LCD_to_input_ratio
+#define bg_tint_r params.bg_tint_r
+#define bg_tint_g params.bg_tint_g
+#define bg_tint_b params.bg_tint_b
+
+vec3 bg_tint = vec3(bg_tint_r, bg_tint_g, bg_tint_b); //color to tint the background image in RGB format - each color component ranges from 0.0 (none) to 1.0 (fully saturated)
+
+#define saturate(c) clamp(c, 0., 1.)
+
+layout(std140, set = 0, binding = 0) uniform UBO
+{
+ mat4 MVP;
+} global;
+
+#pragma stage vertex
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//vertex shader //
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+layout(location = 0) in vec4 Position;
+layout(location = 1) in vec2 TexCoord;
+layout(location = 0) out vec2 vTexCoord;
+
+void main()
+{
+ gl_Position = global.MVP * Position;
+ vTexCoord = TexCoord;
+}
+
+#pragma stage fragment
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//fragment definitions //
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#define is_border_texel bool(out_color.a == 0.0)
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//fragment shader //
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+layout(location = 0) in vec2 vTexCoord;
+layout(location = 0) out vec4 FragColor;
+layout(set = 0, binding = 2) uniform sampler2D Source;
+layout(set = 0, binding = 3) uniform sampler2D PASS1;
+layout(set = 0, binding = 4) uniform sampler2D BACKGROUND;
+
+void main()
+{
+ //sample all relevant textures
+
+ vec4 lcd_color = texture(Source, vTexCoord); //color darkened pixels from the previous pass
+ vec4 input_color = texture(PASS1, vTexCoord); //scaled input video with vertical lines from first pass
+ vec4 bg_color = texture(BACKGROUND, vTexCoord); //background image
+
+ //overlay the LCD image onto the input image to brighten the output and dampen the LCD cell colors
+
+ vec4 out_color = vec4( (lcd_color.rgb * LCD_to_input_ratio) + (input_color.rgb * (1.0 - LCD_to_input_ratio)), input_color.a);
+
+ //tint the background image and apply it to the output color if the current fragment is located in the border region
+
+ bg_color.rgb = saturate( vec3( //allows for highlights, bg_color = bg_tint when the background image color is 0.5 gray
+ bg_tint.r + mix(-1.0, 1.0, bg_color.r),
+ bg_tint.g + mix(-1.0, 1.0, bg_color.g),
+ bg_tint.b + mix(-1.0, 1.0, bg_color.b) ) );
+
+ out_color.rgb = (bg_color.rgb * float(is_border_texel)) + (out_color.rgb * float(!is_border_texel));
+ FragColor = out_color;
+}
diff --git a/handheld/shaders/lcd-shader/lcd-pass-3.slang b/handheld/shaders/lcd-shader/lcd-pass-3.slang
new file mode 100644
index 0000000..8866474
--- /dev/null
+++ b/handheld/shaders/lcd-shader/lcd-pass-3.slang
@@ -0,0 +1,155 @@
+#version 450
+
+///////////////////////////////////////////////////////////////////////////
+// //
+// LCD Shader v0.0.1 //
+// //
+// Copyright (C) 2013 Harlequin : unknown92835@gmail.com //
+// //
+// This program is free software: you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation, either version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+// //
+///////////////////////////////////////////////////////////////////////////
+
+layout(push_constant) uniform Push
+{
+ vec4 SourceSize;
+ vec4 OriginalSize;
+ vec4 OutputSize;
+ uint FrameCount;
+ float LCD_blending, original_blending;
+} params;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//config //
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+//values related to color blending on the darkened vertical lines of the output image
+
+//contribution of LCD colors to the blended output, higher values apply more color - [0.0, 0.5]
+#pragma parameter LCD_blending "LCD Blending" 0.2 0.0 0.5 0.01
+//contribution of the original input colors to the blended output, higher values apply more color - [0.0, 0.5]
+#pragma parameter original_blending "Original Blending" 0.2 0.0 0.5 0.01
+
+#define LCD_blending params.LCD_blending
+#define original_blending params.original_blending
+
+layout(std140, set = 0, binding = 0) uniform UBO
+{
+ mat4 MVP;
+} global;
+
+#pragma stage vertex
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//vertex shader //
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+layout(location = 0) in vec4 Position;
+layout(location = 1) in vec2 TexCoord;
+layout(location = 0) out vec2 vTexCoord;
+layout(location = 1) out vec2 tex_coord_1;
+layout(location = 2) out vec2 tex_coord_2;
+layout(location = 3) out vec2 lower_bound;
+layout(location = 4) out vec2 upper_bound;
+
+void main()
+{
+ gl_Position = global.MVP * Position;
+ vTexCoord = TexCoord;
+
+ vec2 texel = params.SourceSize.zw; //size of one texel
+
+ tex_coord_1 = vTexCoord + vec2(0.0, texel.y); //down
+ tex_coord_2 = vTexCoord + vec2(0.0, -texel.y); //up
+ lower_bound = vec2(0.0); //lower texture bounds
+ upper_bound = texel * (params.OutputSize.xy - 2.0); //upper texture bounds
+}
+
+#pragma stage fragment
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//fragment definitions //
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#define epsilon 0.1
+#define line_alpha 0.5 //arbitrary 0