<postprocess>, fix tab open/close, fix some URL bugs
236
docs/docs/postprocess.md
Normal file
@@ -0,0 +1,236 @@
|
||||
---
|
||||
sidebar_position: 5
|
||||
---
|
||||
|
||||
# Postprocess
|
||||
|
||||
The `<postprocess>` tag in Gurted allows you to apply real-time visual effects to your entire webpage through GPU-accelerated shaders. These effects are rendered as an overlay on top of your content, not affecting the browser UI.
|
||||
|
||||
## Usage
|
||||
|
||||
The postprocess tag supports three ways to define shader effects:
|
||||
|
||||
```html
|
||||
<!-- Using built-in presets -->
|
||||
<postprocess preset="crt" />
|
||||
|
||||
<!-- Loading external shader files -->
|
||||
<postprocess src="custom-shader.gdshader" />
|
||||
|
||||
<!-- Inline shader code -->
|
||||
<postprocess>
|
||||
shader_type canvas_item;
|
||||
void fragment() {
|
||||
COLOR = texture(SCREEN_TEXTURE, SCREEN_UV);
|
||||
}
|
||||
</postprocess>
|
||||
```
|
||||
|
||||
## Shader Tutorial
|
||||
For documentation on how to write GDShader code, see the [Godot Shader Language documentation](https://docs.godotengine.org/en/stable/tutorials/shading/index.html).
|
||||
|
||||
### Parameters
|
||||
|
||||
HTML attributes are automatically converted to shader uniforms with the following supported types:
|
||||
|
||||
#### Numeric Types
|
||||
```html
|
||||
<!-- Float values -->
|
||||
<postprocess preset="vignette" vignette_strength="1.5"></postprocess>
|
||||
|
||||
<!-- Integer values -->
|
||||
<postprocess preset="snowfall" num_of_layers="25"></postprocess>
|
||||
|
||||
<!-- Boolean values -->
|
||||
<postprocess preset="custom" enable_effect="true"></postprocess>
|
||||
```
|
||||
|
||||
#### Vector Types
|
||||
```html
|
||||
<!-- Vector2 -->
|
||||
<postprocess preset="rblur" blur_center="Vector2(0.3, 0.7)"></postprocess>
|
||||
<postprocess preset="rblur" blur_center="vec2(0.3, 0.7)"></postprocess>
|
||||
|
||||
<!-- Vector3 -->
|
||||
<postprocess preset="lensflare" tint="Vector3(1.4, 1.2, 1.0)"></postprocess>
|
||||
<postprocess preset="lensflare" tint="vec3(1.4, 1.2, 1.0)"></postprocess>
|
||||
|
||||
<!-- Vector4 -->
|
||||
<postprocess preset="vignette" vignette_color="Vector4(0.0, 0.0, 0.0, 1.0)"></postprocess>
|
||||
<postprocess preset="vignette" vignette_color="vec4(0.0, 0.0, 0.0, 1.0)"></postprocess>
|
||||
```
|
||||
|
||||
#### Color Values
|
||||
```html
|
||||
<!-- Hex colors -->
|
||||
<postprocess preset="vignette" vignette_color="#ff0000"></postprocess>
|
||||
|
||||
<!-- Named colors work as strings -->
|
||||
<postprocess preset="snowfall" snow_color="white"></postprocess>
|
||||
```
|
||||
|
||||
## Built-in Preset Shaders
|
||||
|
||||
### CRT Monitor Effect
|
||||
Creates a retro CRT monitor appearance with scanlines, distortion, and screen curvature.
|
||||
|
||||
```html
|
||||
<postprocess preset="crt"></postprocess>
|
||||
```
|
||||
|
||||

|
||||
|
||||
**Available Properties:**
|
||||
- `curvature` (0.0-10.0, default: 2.0) - Screen curvature amount
|
||||
- `skip` (0.0-1.0, default: 1.0) - Vertical hold distortion intensity
|
||||
- `image_flicker` (0.0-1.0, default: 1.0) - Image flicker intensity
|
||||
- `vignette_flicker_speed` (0.0-2.0, default: 1.0) - Vignette animation speed
|
||||
- `vignette_strength` (0.0-2.0, default: 1.0) - Dark edge vignette intensity
|
||||
- `small_scanlines_speed` (0.0-10.0, default: 1.0) - Fine scanline animation speed
|
||||
- `small_scanlines_proximity` (0.01-2.0, default: 1.0) - Fine scanline density
|
||||
- `small_scanlines_opacity` (0.01-5.0, default: 1.0) - Fine scanline visibility
|
||||
- `scanlines_opacity` (0.0-2.0, default: 1.0) - Main scanline visibility
|
||||
- `scanlines_speed` (0.0-5.0, default: 1.0) - Main scanline animation speed
|
||||
- `scanline_thickness` (0.0-0.6, default: 0.5) - Scanline thickness
|
||||
- `scanlines_spacing` (0.3-3.0, default: 1.0) - Space between scanlines
|
||||
|
||||
### Film Grain Effect
|
||||
Adds vintage film grain noise to give content an analog film appearance.
|
||||
|
||||
```html
|
||||
<postprocess preset="film"></postprocess>
|
||||
```
|
||||
|
||||

|
||||
|
||||
**Available Properties:**
|
||||
- `grain_amount` (0.0-1.0, default: 0.05) - Amount of grain noise added
|
||||
- `grain_size` (0.1-10.0, default: 1.0) - Size/scale of individual grain particles
|
||||
|
||||
### Vignette Effect
|
||||
Creates a darkened border around the screen edges, focusing attention on the center.
|
||||
|
||||
```html
|
||||
<postprocess preset="vignette"></postprocess>
|
||||
```
|
||||

|
||||
|
||||
**Available Properties:**
|
||||
- `inner_radius` (0.0-1.0, default: 0.1) - Inner edge of the vignette effect
|
||||
- `outer_radius` (0.0-1.0, default: 1.0) - Outer edge where vignette is strongest
|
||||
- `vignette_strength` (0.0-2.0, default: 1.0) - Intensity of the darkening effect
|
||||
- `dither_strength` (0.0-1.0, default: 0.03) - Noise added to prevent banding
|
||||
- `vignette_color` (color, default: black) - Color of the vignette overlay
|
||||
|
||||
### Pencil Effect
|
||||
Converts the webpage into a pencil drawing style with adjustable thresholds for line detection.
|
||||
|
||||
```html
|
||||
<postprocess preset="pencil"></postprocess>
|
||||
```
|
||||
|
||||

|
||||
|
||||
**Available Properties:**
|
||||
- `u_bgColorFactor` (0.0-1.0, default: 0.4) - Blend amount of background color
|
||||
- `u_threshold1` (0.0-1.0, default: 0.75) - Brightest areas threshold
|
||||
- `u_threshold2` (0.0-1.0, default: 0.50) - Medium-bright areas threshold
|
||||
- `u_threshold3` (0.0-1.0, default: 0.25) - Medium-dark areas threshold
|
||||
- `u_threshold4` (0.0-1.0, default: 0.05) - Darkest areas threshold
|
||||
- `u_bgTiling` (Vector2, default: vec2(1.0, 1.0)) - Background texture tiling
|
||||
- `u_patternTiling` (Vector2, default: vec2(1.0, 1.0)) - Pattern texture tiling
|
||||
- `u_bgColor` (color, default: white) - Background paper color
|
||||
- `u_patternColor` (color, default: black) - Pencil line color
|
||||
|
||||
### Snowfall Effect
|
||||
Adds animated falling snow particles over the content with customizable layers and physics.
|
||||
|
||||
```html
|
||||
<postprocess preset="snowfall"></postprocess>
|
||||
```
|
||||
|
||||

|
||||
|
||||
**Available Properties:**
|
||||
- `spread` (0.0-1.5, default: 0.5) - Horizontal spread of snowflakes
|
||||
- `size` (0.01-5.0, default: 0.5) - Size of individual snowflakes
|
||||
- `snow_color` (color, default: white) - Color of the snow particles
|
||||
- `snow_transparency` (-0.5-1.0, default: 0.2) - Transparency of snow overlay
|
||||
- `speed` (0.0-10.0, default: 0.5) - Falling speed of snowflakes
|
||||
- `wind` (-2.0-2.0, default: 0.0) - Horizontal wind effect
|
||||
- `num_of_layers` (integer, default: 40) - Number of snow layers for depth
|
||||
|
||||
### Chromatic Aberration Effect
|
||||
Simulates lens distortion by separating RGB color channels, creating a retro video glitch effect.
|
||||
|
||||
```html
|
||||
<postprocess preset="chrome"></postprocess>
|
||||
```
|
||||
|
||||

|
||||
|
||||
**Available Properties:**
|
||||
- `levels` (integer, default: 3) - Number of color separation levels
|
||||
- `spread` (float, default: 0.01) - Amount of color channel separation
|
||||
|
||||
|
||||
### Radial Blur Effect
|
||||
Creates motion blur radiating from a center point, useful for speed effects or focus attention.
|
||||
|
||||
```html
|
||||
<postprocess preset="rblur"></postprocess>
|
||||
```
|
||||
|
||||

|
||||
|
||||
**Available Properties:**
|
||||
- `blur_center` (Vector2, default: vec2(0.5, 0.5)) - Center point of the blur effect
|
||||
- `blur_power` (0.0-1.0, default: 0.01) - Intensity of the blur effect
|
||||
- `sampling_count` (1-64, default: 2) - Quality of the blur (higher = smoother)
|
||||
|
||||
### Lens Flare Effect
|
||||
Adds realistic lens flare effects, simulating light hitting a camera lens.
|
||||
|
||||
```html
|
||||
<postprocess preset="lensflare"></postprocess>
|
||||
```
|
||||

|
||||
|
||||
**Available Properties:**
|
||||
- `sun_position` (Vector2, default: vec2(400.0, 0.0)) - Position of the light source
|
||||
- `tint` (Vector3, default: vec3(1.4, 1.2, 1.0)) - Color tint of the lens flare
|
||||
|
||||
### Foliage Sway Effect
|
||||
Creates animated wave distortion effects, mimicking vegetation movement or underwater effects.
|
||||
|
||||
```html
|
||||
<postprocess preset="foliage"></postprocess>
|
||||
```
|
||||
|
||||

|
||||
|
||||
**Available Properties:**
|
||||
- `x_intensity` (float, default: 3.0) - Horizontal sway intensity
|
||||
- `y_intensity` (float, default: 0.5) - Vertical sway intensity
|
||||
- `offset` (float, default: 0.0) - Animation offset for timing
|
||||
- `speed` (0-20, default: 2.0) - Animation speed
|
||||
- `wave_frequency` (0-100, default: 20) - Frequency of wave oscillations
|
||||
- `wave_length` (50-800, default: 200.0) - Length of wave patterns
|
||||
|
||||
### Dithering Effect
|
||||
Applies retro pixel art dithering with color palette reduction for a vintage gaming aesthetic.
|
||||
|
||||
```html
|
||||
<postprocess preset="dither"></postprocess>
|
||||
```
|
||||
|
||||

|
||||
|
||||
:::note
|
||||
Due to the limitations of GDShader, the dithering effect relies on a `GradientTexture` node internally. This means the colors are hardcoded to be a rusty tint - unchangeable via parameters. A similar effect can be achieved with a custom `<postprocess>` shader without external nodes - however, that's beyond the scope of this preset.
|
||||
:::
|
||||
|
||||
**Available Properties:**
|
||||
- `pixel` (float, default: 1.0) - Pixel size for the dithering pattern
|
||||
|
||||
All postprocess shaders are GPU-accelerated thanks to Godot's shader system.
|
||||
@@ -31,7 +31,6 @@ const sidebars: SidebarsConfig = {
|
||||
items: [
|
||||
'dns-system',
|
||||
'flumi-browser',
|
||||
'search-engine'
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -40,6 +39,7 @@ const sidebars: SidebarsConfig = {
|
||||
items: [
|
||||
'html',
|
||||
'css',
|
||||
'postprocess',
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
BIN
docs/static/img/docs/chrome.png
vendored
Normal file
|
After Width: | Height: | Size: 686 KiB |
BIN
docs/static/img/docs/crt.gif
vendored
Normal file
|
After Width: | Height: | Size: 38 MiB |
BIN
docs/static/img/docs/dither.png
vendored
Normal file
|
After Width: | Height: | Size: 426 KiB |
BIN
docs/static/img/docs/film.png
vendored
Normal file
|
After Width: | Height: | Size: 117 KiB |
BIN
docs/static/img/docs/foliage.gif
vendored
Normal file
|
After Width: | Height: | Size: 13 MiB |
BIN
docs/static/img/docs/lensflare.png
vendored
Normal file
|
After Width: | Height: | Size: 406 KiB |
BIN
docs/static/img/docs/pencil.png
vendored
Normal file
|
After Width: | Height: | Size: 2.1 MiB |
BIN
docs/static/img/docs/rblur.png
vendored
Normal file
|
After Width: | Height: | Size: 438 KiB |
BIN
docs/static/img/docs/snowfall.gif
vendored
Normal file
|
After Width: | Height: | Size: 16 MiB |
BIN
docs/static/img/docs/vignette.png
vendored
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
BIN
flumi/Assets/Textures/bayer8tile4.png
Normal file
|
After Width: | Height: | Size: 327 B |
34
flumi/Assets/Textures/bayer8tile4.png.import
Normal file
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://c8eervlu44g5e"
|
||||
path="res://.godot/imported/bayer8tile4.png-af05367272eb1e9c5c1494aea351d772.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Assets/Textures/bayer8tile4.png"
|
||||
dest_files=["res://.godot/imported/bayer8tile4.png-af05367272eb1e9c5c1494aea351d772.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=0
|
||||
BIN
flumi/Assets/Textures/blue_noise.png
Normal file
|
After Width: | Height: | Size: 323 KiB |
34
flumi/Assets/Textures/blue_noise.png.import
Normal file
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bh6ou8qfqhml3"
|
||||
path="res://.godot/imported/blue_noise.png-3429c5fff13cc3510f3a6adb3d9b290a.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Assets/Textures/blue_noise.png"
|
||||
dest_files=["res://.godot/imported/blue_noise.png-3429c5fff13cc3510f3a6adb3d9b290a.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
BIN
flumi/Assets/Textures/dither_matrix.png
Normal file
|
After Width: | Height: | Size: 616 B |
34
flumi/Assets/Textures/dither_matrix.png.import
Normal file
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://crdyaxcy0l5fe"
|
||||
path="res://.godot/imported/dither_matrix.png-e5f72ab3b733bd12bb9be69cb29c5303.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Assets/Textures/dither_matrix.png"
|
||||
dest_files=["res://.godot/imported/dither_matrix.png-e5f72ab3b733bd12bb9be69cb29c5303.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
BIN
flumi/Assets/Textures/parchment.jpg
Normal file
|
After Width: | Height: | Size: 709 KiB |
34
flumi/Assets/Textures/parchment.jpg.import
Normal file
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://b8x712hkjbsh"
|
||||
path="res://.godot/imported/parchment.jpg-ea29c24066df61d46bc7b0bcc25a86c1.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Assets/Textures/parchment.jpg"
|
||||
dest_files=["res://.godot/imported/parchment.jpg-ea29c24066df61d46bc7b0bcc25a86c1.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
BIN
flumi/Assets/Textures/pencil.jpg
Normal file
|
After Width: | Height: | Size: 363 KiB |
34
flumi/Assets/Textures/pencil.jpg.import
Normal file
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dnvdbk47n56ej"
|
||||
path="res://.godot/imported/pencil.jpg-3bb1b8082faf74808f54e9dd81d1b7d0.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Assets/Textures/pencil.jpg"
|
||||
dest_files=["res://.godot/imported/pencil.jpg-3bb1b8082faf74808f54e9dd81d1b7d0.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
6
flumi/Scenes/Tags/postprocess.tscn
Normal file
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://bpn7d4x5qr8vw"]
|
||||
|
||||
[ext_resource type="Script" path="res://Scripts/Tags/postprocess.gd" id="1_postprocess"]
|
||||
|
||||
[node name="postprocess" type="Control"]
|
||||
script = ExtResource("1_postprocess")
|
||||
@@ -430,6 +430,9 @@ func get_all_images() -> Array[String]:
|
||||
func get_all_scripts() -> Array[String]:
|
||||
return get_attribute_values("script", "src")
|
||||
|
||||
func get_all_postprocess() -> Array[String]:
|
||||
return get_attribute_values("postprocess", "src")
|
||||
|
||||
func process_scripts(lua_api: LuaAPI, _lua_vm) -> void:
|
||||
if not lua_api:
|
||||
print("Warning: Lua API not available for script processing")
|
||||
@@ -459,6 +462,14 @@ func process_external_scripts(lua_api: LuaAPI, _lua_vm, base_url: String = "") -
|
||||
if not script_content.is_empty():
|
||||
lua_api.execute_lua_script(script_content)
|
||||
|
||||
func process_postprocess() -> HTMLParser.HTMLElement:
|
||||
var postprocess_elements = find_all("postprocess")
|
||||
if postprocess_elements.is_empty():
|
||||
return null
|
||||
|
||||
# Return the last postprocess element (last defined wins)
|
||||
return postprocess_elements[-1]
|
||||
|
||||
func get_all_stylesheets() -> Array[String]:
|
||||
return get_attribute_values("style", "src")
|
||||
|
||||
|
||||
@@ -672,7 +672,7 @@ func _handle_dom_operation(operation: Dictionary):
|
||||
"get_text":
|
||||
_handle_text_getting(operation)
|
||||
"append_element":
|
||||
LuaDOMUtils.handle_element_append(operation, dom_parser, self)
|
||||
LuaDOMUtils.handle_element_append(operation, dom_parser)
|
||||
"add_class":
|
||||
LuaClassListUtils.handle_add_class(operation, dom_parser)
|
||||
"remove_class":
|
||||
@@ -682,7 +682,7 @@ func _handle_dom_operation(operation: Dictionary):
|
||||
"remove_element":
|
||||
LuaDOMUtils.handle_element_remove(operation, dom_parser)
|
||||
"insert_before":
|
||||
LuaDOMUtils.handle_insert_before(operation, dom_parser, self)
|
||||
LuaDOMUtils.handle_insert_before(operation, dom_parser)
|
||||
"insert_after":
|
||||
LuaDOMUtils.handle_insert_after(operation, dom_parser)
|
||||
"replace_child":
|
||||
|
||||
@@ -9,7 +9,9 @@ static func is_gurt_domain(url: String) -> bool:
|
||||
return true
|
||||
|
||||
if not url.contains("://"):
|
||||
var parts = url.split(".")
|
||||
# Extract just the domain part (before any path)
|
||||
var domain = url.split("/")[0]
|
||||
var parts = domain.split(".")
|
||||
return parts.size() == 2
|
||||
|
||||
return false
|
||||
|
||||
@@ -64,19 +64,33 @@ static func apply_element_styles(node: Control, element: HTMLParser.HTMLElement,
|
||||
|
||||
if (width != null or height != null) and not skip_sizing:
|
||||
if width != null:
|
||||
if width is String and width == "100%":
|
||||
node.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
node.custom_minimum_size.x = 0
|
||||
if width is String and width.ends_with("%"):
|
||||
if width == "100%":
|
||||
node.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
node.custom_minimum_size.x = 0
|
||||
else:
|
||||
# For other percentages, convert to viewport-relative size
|
||||
var percent = float(width.replace("%", "")) / 100.0
|
||||
var viewport_width = node.get_viewport().get_visible_rect().size.x if node.get_viewport() else 800
|
||||
node.custom_minimum_size.x = viewport_width * percent
|
||||
node.set_meta("size_flags_set_by_style_manager", true)
|
||||
node.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
|
||||
else:
|
||||
node.custom_minimum_size.x = width
|
||||
node.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
|
||||
|
||||
if height != null:
|
||||
if height is String and height == "100%":
|
||||
node.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
node.custom_minimum_size.y = 0
|
||||
if height is String and height.ends_with("%"):
|
||||
if height == "100%":
|
||||
node.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
node.custom_minimum_size.y = 0
|
||||
else:
|
||||
# For other percentages, convert to viewport-relative size
|
||||
var percent = float(height.replace("%", "")) / 100.0
|
||||
var viewport_height = node.get_viewport().get_visible_rect().size.y if node.get_viewport() else 600
|
||||
node.custom_minimum_size.y = viewport_height * percent
|
||||
node.set_meta("size_flags_set_by_style_manager", true)
|
||||
node.size_flags_vertical = Control.SIZE_SHRINK_BEGIN
|
||||
else:
|
||||
node.custom_minimum_size.y = height
|
||||
node.size_flags_vertical = Control.SIZE_SHRINK_BEGIN
|
||||
|
||||
@@ -210,7 +210,9 @@ func create_tab() -> void:
|
||||
var index = tabs.size();
|
||||
var tab = TAB.instantiate()
|
||||
tabs.append(tab)
|
||||
h_box_container.add_child(tab)
|
||||
tab.tab_pressed.connect(_tab_pressed.bind(index))
|
||||
tab.tab_closed.connect(_tab_closed.bind(index))
|
||||
var viewport_width = get_viewport().get_visible_rect().size.x
|
||||
var available_width = viewport_width - POPUP_BUTTON_WIDTH - NEW_TAB_BUTTON_WIDTH - OTHER_UI_PADDING
|
||||
var visible_count = calculate_visible_tab_count(available_width)
|
||||
|
||||
162
flumi/Scripts/Tags/postprocess.gd
Normal file
@@ -0,0 +1,162 @@
|
||||
class_name HTMLPostprocess
|
||||
extends Control
|
||||
|
||||
const Network = preload("res://Scripts/Network.gd")
|
||||
|
||||
var element: HTMLParser.HTMLElement
|
||||
var parser: HTMLParser
|
||||
var shader_material: ShaderMaterial
|
||||
var built_in_shaders = {
|
||||
"crt": "res://Shaders/crt.gdshader",
|
||||
"film": "res://Shaders/film.gdshader",
|
||||
"vignette": "res://Shaders/vignette.gdshader",
|
||||
"pencil": "res://Shaders/pencil.gdshader",
|
||||
"snowfall": "res://Shaders/snowfall.gdshader",
|
||||
"chrome": "res://Shaders/chrome.gdshader",
|
||||
"rblur": "res://Shaders/rblur.gdshader",
|
||||
"lensflare": "res://Shaders/lensflare.gdshader",
|
||||
"foliage": "res://Shaders/foliage.gdshader",
|
||||
"dither": "res://Shaders/dither.gdshader"
|
||||
}
|
||||
|
||||
func init(element_: HTMLParser.HTMLElement, parser_: HTMLParser):
|
||||
element = element_
|
||||
parser = parser_
|
||||
|
||||
var preset = element.get_attribute("preset")
|
||||
if preset and built_in_shaders.has(preset):
|
||||
await apply_preset_shader(preset)
|
||||
|
||||
elif element.has_attribute("src"):
|
||||
await load_external_shader()
|
||||
|
||||
elif not element.text_content.is_empty():
|
||||
apply_inline_shader()
|
||||
|
||||
func apply_preset_shader(preset_name: String):
|
||||
var shader_resource = built_in_shaders[preset_name]
|
||||
var shader = load(shader_resource)
|
||||
|
||||
shader_material = ShaderMaterial.new()
|
||||
shader_material.shader = shader
|
||||
|
||||
shader_material.set_shader_parameter("u_bgTexture", load("res://Assets/Textures/parchment.jpg"))
|
||||
shader_material.set_shader_parameter("u_patternTexture", load("res://Assets/Textures/pencil.jpg"))
|
||||
|
||||
var BLUE_NOISE = load("res://Assets/Textures/blue_noise.png")
|
||||
shader_material.set_shader_parameter("uTexBlueNoise", BLUE_NOISE)
|
||||
var gradient_texture = GradientTexture2D.new()
|
||||
var gradient = Gradient.new()
|
||||
gradient.colors = [Color("#8B4513"), Color("#CD853F"), Color("#D2691E"), Color("#B22222"), Color("#A0522D")]
|
||||
gradient_texture.gradient = gradient
|
||||
shader_material.set_shader_parameter("pallete", gradient_texture)
|
||||
|
||||
apply_shader_uniforms()
|
||||
apply_postprocessing_to_viewport()
|
||||
|
||||
func load_external_shader():
|
||||
var src = element.get_attribute("src")
|
||||
|
||||
var main = Engine.get_main_loop().current_scene
|
||||
var resolved_url = URLUtils.resolve_url(main.current_domain, src)
|
||||
|
||||
var network = Network.new()
|
||||
var response = await network.fetch_content(resolved_url)
|
||||
|
||||
if response.success:
|
||||
var shader_code = response.content.get_string_from_utf8()
|
||||
var shader = Shader.new()
|
||||
shader.code = shader_code
|
||||
|
||||
shader_material = ShaderMaterial.new()
|
||||
shader_material.shader = shader
|
||||
|
||||
apply_shader_uniforms()
|
||||
apply_postprocessing_to_viewport()
|
||||
else:
|
||||
print("Failed to load shader from: ", resolved_url)
|
||||
|
||||
func apply_inline_shader():
|
||||
var shader_code = element.text_content.strip_edges()
|
||||
if shader_code.is_empty():
|
||||
return
|
||||
|
||||
var shader = Shader.new()
|
||||
shader.code = shader_code
|
||||
|
||||
shader_material = ShaderMaterial.new()
|
||||
shader_material.shader = shader
|
||||
|
||||
apply_shader_uniforms()
|
||||
apply_postprocessing_to_viewport()
|
||||
|
||||
func apply_shader_uniforms():
|
||||
if not shader_material or not shader_material.shader:
|
||||
return
|
||||
|
||||
for attr_name in element.attributes:
|
||||
if attr_name in ["src", "preset"]:
|
||||
continue
|
||||
|
||||
var attr_value = element.get_attribute(attr_name)
|
||||
var uniform_value = parse_uniform_value(attr_value)
|
||||
|
||||
if uniform_value != null:
|
||||
shader_material.set_shader_parameter(attr_name, uniform_value)
|
||||
|
||||
func parse_uniform_value(value_string: String):
|
||||
if value_string.is_valid_float():
|
||||
return value_string.to_float()
|
||||
|
||||
if value_string.is_valid_int():
|
||||
return value_string.to_int()
|
||||
|
||||
if value_string.to_lower() == "true":
|
||||
return true
|
||||
elif value_string.to_lower() == "false":
|
||||
return false
|
||||
|
||||
if value_string.begins_with("Vector2(") or value_string.begins_with("vec2("):
|
||||
var vec_str = value_string.replace("Vector2(", "").replace("vec2(", "").replace(")", "")
|
||||
var components = vec_str.split(",")
|
||||
if components.size() == 2:
|
||||
return Vector2(components[0].strip_edges().to_float(), components[1].strip_edges().to_float())
|
||||
|
||||
if value_string.begins_with("Vector3(") or value_string.begins_with("vec3("):
|
||||
var vec_str = value_string.replace("Vector3(", "").replace("vec3(", "").replace(")", "")
|
||||
var components = vec_str.split(",")
|
||||
if components.size() == 3:
|
||||
return Vector3(components[0].strip_edges().to_float(), components[1].strip_edges().to_float(), components[2].strip_edges().to_float())
|
||||
|
||||
if value_string.begins_with("Vector4(") or value_string.begins_with("vec4("):
|
||||
var vec_str = value_string.replace("Vector4(", "").replace("vec4(", "").replace(")", "")
|
||||
var components = vec_str.split(",")
|
||||
if components.size() == 4:
|
||||
return Vector4(components[0].strip_edges().to_float(), components[1].strip_edges().to_float(), components[2].strip_edges().to_float(), components[3].strip_edges().to_float())
|
||||
|
||||
if value_string.begins_with("#"):
|
||||
return Color(value_string)
|
||||
|
||||
return value_string
|
||||
|
||||
func apply_postprocessing_to_viewport():
|
||||
if not shader_material:
|
||||
return
|
||||
|
||||
var main_scene = Engine.get_main_loop().current_scene
|
||||
var active_tab = main_scene.get_active_tab()
|
||||
var panel_container = active_tab.background_panel
|
||||
|
||||
var existing_overlay = panel_container.get_node_or_null("PostprocessOverlay")
|
||||
if existing_overlay:
|
||||
existing_overlay.queue_free()
|
||||
|
||||
var overlay_rect = ColorRect.new()
|
||||
overlay_rect.name = "PostprocessOverlay"
|
||||
overlay_rect.material = shader_material
|
||||
overlay_rect.color = Color.WHITE
|
||||
overlay_rect.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
overlay_rect.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
||||
overlay_rect.z_index = 100
|
||||
|
||||
panel_container.add_child(overlay_rect)
|
||||
1
flumi/Scripts/Tags/postprocess.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://btm4uqcfr43cm
|
||||
@@ -95,7 +95,7 @@ static func get_element_last_child_handler(vm: LuauVM, dom_parser: HTMLParser, l
|
||||
|
||||
# DOM Manipulation Methods
|
||||
|
||||
static func handle_element_append(operation: Dictionary, dom_parser: HTMLParser, lua_api) -> void:
|
||||
static func handle_element_append(operation: Dictionary, dom_parser: HTMLParser) -> void:
|
||||
var parent_id: String = operation.parent_id
|
||||
var child_id: String = operation.child_id
|
||||
|
||||
@@ -153,7 +153,7 @@ static func handle_element_remove(operation: Dictionary, dom_parser: HTMLParser)
|
||||
if all_elements_index >= 0:
|
||||
dom_parser.parse_result.all_elements.remove_at(all_elements_index)
|
||||
|
||||
static func handle_insert_before(operation: Dictionary, dom_parser: HTMLParser, lua_api) -> void:
|
||||
static func handle_insert_before(operation: Dictionary, dom_parser: HTMLParser) -> void:
|
||||
var parent_id: String = operation.parent_id
|
||||
var new_child_id: String = operation.new_child_id
|
||||
var reference_child_id: String = operation.reference_child_id
|
||||
|
||||
@@ -472,7 +472,9 @@ func _set_interval_handler(vm: LuauVM) -> int:
|
||||
func get_current_href() -> String:
|
||||
var main_node = Engine.get_main_loop().current_scene
|
||||
|
||||
return main_node.current_domain
|
||||
if main_node:
|
||||
return main_node.current_domain
|
||||
return ""
|
||||
|
||||
func _gurt_select_handler(vm: LuauVM) -> int:
|
||||
var selector: String = vm.luaL_checkstring(1)
|
||||
|
||||
@@ -29,15 +29,15 @@ const SELECT = preload("res://Scenes/Tags/select.tscn")
|
||||
const TEXTAREA = preload("res://Scenes/Tags/textarea.tscn")
|
||||
const DIV = preload("res://Scenes/Tags/div.tscn")
|
||||
const AUDIO = preload("res://Scenes/Tags/audio.tscn")
|
||||
const POSTPROCESS = preload("res://Scenes/Tags/postprocess.tscn")
|
||||
|
||||
const MIN_SIZE = Vector2i(750, 200)
|
||||
|
||||
var font_dependent_elements: Array = []
|
||||
var current_domain = ""
|
||||
|
||||
func should_group_as_inline(element: HTMLParser.HTMLElement) -> bool:
|
||||
# Don't group inputs unless they're inside a form
|
||||
if element.tag_name == "input":
|
||||
# Check if this element has a form ancestor
|
||||
var parent = element.parent
|
||||
while parent:
|
||||
if parent.tag_name == "form":
|
||||
@@ -60,8 +60,6 @@ func _ready():
|
||||
|
||||
call_deferred("render")
|
||||
|
||||
var current_domain = "" # Store current domain for display
|
||||
|
||||
func resolve_url(href: String) -> String:
|
||||
return URLUtils.resolve_url(current_domain, href)
|
||||
|
||||
@@ -193,6 +191,20 @@ func render_content(html_bytes: PackedByteArray) -> void:
|
||||
remove_child(lua_api)
|
||||
lua_api.queue_free()
|
||||
active_tab.lua_apis.clear()
|
||||
|
||||
var existing_postprocess = []
|
||||
for child in get_children():
|
||||
if child is HTMLPostprocess:
|
||||
existing_postprocess.append(child)
|
||||
|
||||
for postprocess in existing_postprocess:
|
||||
remove_child(postprocess)
|
||||
postprocess.queue_free()
|
||||
|
||||
if active_tab.background_panel:
|
||||
var existing_overlay = active_tab.background_panel.get_node_or_null("PostprocessOverlay")
|
||||
if existing_overlay:
|
||||
existing_overlay.queue_free()
|
||||
else:
|
||||
var existing_lua_apis = []
|
||||
for child in get_children():
|
||||
@@ -204,6 +216,20 @@ func render_content(html_bytes: PackedByteArray) -> void:
|
||||
remove_child(lua_api)
|
||||
lua_api.queue_free()
|
||||
|
||||
var postprocess_nodes: Array[Node] = []
|
||||
for child in get_children():
|
||||
if child is HTMLPostprocess:
|
||||
postprocess_nodes.append(child)
|
||||
for node in postprocess_nodes:
|
||||
remove_child(node)
|
||||
node.queue_free()
|
||||
|
||||
var default_panel = website_container.get_parent()
|
||||
if default_panel and default_panel.has_method("get_node_or_null"):
|
||||
var existing_overlay = default_panel.get_node_or_null("PostprocessOverlay")
|
||||
if existing_overlay:
|
||||
existing_overlay.queue_free()
|
||||
|
||||
if target_container.get_parent() and target_container.get_parent().name == "BodyMarginContainer":
|
||||
var body_margin_container = target_container.get_parent()
|
||||
var scroll_container = body_margin_container.get_parent()
|
||||
@@ -320,6 +346,12 @@ func render_content(html_bytes: PackedByteArray) -> void:
|
||||
if parse_result.external_scripts and not parse_result.external_scripts.is_empty():
|
||||
await parser.process_external_scripts(lua_api, null, current_domain)
|
||||
|
||||
var postprocess_element = parser.process_postprocess()
|
||||
if postprocess_element:
|
||||
var postprocess_node = POSTPROCESS.instantiate()
|
||||
add_child(postprocess_node)
|
||||
await postprocess_node.init(postprocess_element, parser)
|
||||
|
||||
active_tab.current_url = current_domain
|
||||
active_tab.has_content = true
|
||||
|
||||
|
||||
29
flumi/Shaders/chrome.gdshader
Normal file
@@ -0,0 +1,29 @@
|
||||
// Chromatic Aberration Shader by https://godotshaders.com/shader/chromatic-abberation/
|
||||
// All credits to the original author!!!
|
||||
|
||||
shader_type canvas_item;
|
||||
|
||||
uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap;
|
||||
|
||||
uniform int levels = 3;
|
||||
uniform float spread = 0.01;
|
||||
|
||||
vec3 chromatic_slice(float t){
|
||||
vec3 res = vec3(1.0-t, 1.0 - abs(t - 1.0), t - 1.0);
|
||||
return max(res, 0.0);
|
||||
}
|
||||
|
||||
void fragment(){
|
||||
vec3 sum;
|
||||
COLOR.rgb = vec3(0);
|
||||
vec2 offset = (UV - vec2(0.5))*vec2(1,-1);
|
||||
for(int i = 0; i < levels; i++){
|
||||
float t = 2.0*float(i)/float(levels-1); // range 0.0->2.0
|
||||
vec3 slice = vec3(1.0-t, 1.0 - abs(t - 1.0), t - 1.0);
|
||||
slice = max(slice, 0.0);
|
||||
sum += slice;
|
||||
vec2 slice_offset = (t-1.0)*spread*offset;
|
||||
COLOR.rgb += slice * texture(SCREEN_TEXTURE, SCREEN_UV + slice_offset).rgb;
|
||||
}
|
||||
COLOR.rgb /= sum;
|
||||
}
|
||||
1
flumi/Shaders/chrome.gdshader.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dbkni4dqt0ral
|
||||
90
flumi/Shaders/crt.gdshader
Normal file
@@ -0,0 +1,90 @@
|
||||
/* License CC BY-NC-SA 4.0 Deed */
|
||||
/* https://creativecommons.org/licenses/by-nc-sa/4.0/ */
|
||||
/* Fork of Ryk's VCR distortion shader */
|
||||
/* https://www.shadertoy.com/view/ldjGzV */
|
||||
|
||||
shader_type canvas_item;
|
||||
|
||||
uniform sampler2D screen_texture: hint_screen_texture, filter_linear_mipmap, repeat_disable;
|
||||
|
||||
group_uniforms Image;
|
||||
uniform float curvature: hint_range(0., 10., .01) = 2.;
|
||||
uniform float skip: hint_range(0., 1., .01) = 1.;
|
||||
uniform float image_flicker: hint_range(0., 1., .01) = 1.;
|
||||
|
||||
group_uniforms Vignette;
|
||||
uniform float vignette_flicker_speed: hint_range(0., 2., .01) = 1.;
|
||||
uniform float vignette_strength: hint_range(0., 2., 0.01) = 1.;
|
||||
|
||||
group_uniforms Scanlines;
|
||||
uniform float small_scanlines_speed: hint_range(0., 10., .01) = 1.;
|
||||
uniform float small_scanlines_proximity: hint_range(.01, 2., .01) = 1.;
|
||||
uniform float small_scanlines_opacity: hint_range(0.01, 5., .01) = 1.;
|
||||
uniform float scanlines_opacity: hint_range(0., 2., .01) = 1.;
|
||||
uniform float scanlines_speed: hint_range(0., 5., .01) = 1.;
|
||||
uniform float scanline_thickness: hint_range(0., .6, .01) = 0.5;
|
||||
uniform float scanlines_spacing: hint_range(0.3, 3., .01) = 1.;
|
||||
|
||||
group_uniforms Noise;
|
||||
uniform sampler2D noise_texture: filter_linear_mipmap, repeat_enable;
|
||||
|
||||
float noise(vec2 p, vec2 uv)
|
||||
{
|
||||
float s = texture(noise_texture,vec2(1.*TIME,2.*TIME)*8. + p*1.).x;
|
||||
s *= s;
|
||||
return s;
|
||||
}
|
||||
|
||||
float onOff(float a, float b, float c)
|
||||
{
|
||||
return step(c, sin(TIME + a*cos(TIME*b)));
|
||||
}
|
||||
|
||||
float ramp(float y, float start, float end)
|
||||
{
|
||||
float inside = step(start,y) - step(end,y);
|
||||
float fact = (y-start)/(end-start)*inside;
|
||||
return (1.-fact) * inside;
|
||||
}
|
||||
|
||||
float stripes(vec2 uv)
|
||||
{
|
||||
float noi = noise(uv*vec2(0.5,1.) + vec2(1.,3.), uv)*scanlines_opacity;
|
||||
return ramp(mod(uv.y*4.*scanlines_spacing + TIME*scanlines_speed/(2.*scanlines_spacing)+sin(TIME*scanlines_speed + sin(TIME*scanlines_speed*0.63*scanlines_spacing)),1.),scanline_thickness,.6)*noi;
|
||||
}
|
||||
|
||||
vec3 getVideo(vec2 uv)
|
||||
{
|
||||
vec2 look = uv;
|
||||
float window = 1./(1.+20.*(look.y-mod(TIME/4.,1.))*(look.y-mod(TIME/4.,1.)))*image_flicker;
|
||||
look.x = look.x + sin(look.y*10. + TIME)/50.*onOff(4.,4.,.3)*(1.+cos(TIME*80.))*window;
|
||||
float vShift = 0.4*onOff(2.,3.,.9)*(sin(TIME)*sin(TIME*20.)+(0.5 + 0.1*sin(TIME*200.)*cos(TIME)))*skip;
|
||||
look.y = mod(look.y + vShift, 1.);
|
||||
vec3 video = texture(screen_texture,look).xyz;
|
||||
return video;
|
||||
}
|
||||
|
||||
vec2 screenDistort(vec2 uv)
|
||||
{
|
||||
uv -= vec2(.5,.5);
|
||||
uv = uv*1.2*(1./1.2+curvature*uv.x*uv.x*uv.y*uv.y);
|
||||
uv += vec2(.5,.5);
|
||||
return uv;
|
||||
}
|
||||
|
||||
void fragment()
|
||||
{
|
||||
vec2 uv = FRAGCOORD.xy / (1.0 / SCREEN_PIXEL_SIZE).xy;
|
||||
uv = screenDistort(uv);
|
||||
vec3 video = getVideo(uv);
|
||||
float vigAmt = 3.+.3*sin(TIME*vignette_flicker_speed+1. + 5.*cos(TIME*5.*vignette_flicker_speed+1.));
|
||||
vigAmt *= vignette_strength;
|
||||
float vignette = (1.-vigAmt*(uv.y-.5)*(uv.y-.5))*(1.-vigAmt*(uv.x-.5)*(uv.x-.5));
|
||||
|
||||
video += stripes(uv);
|
||||
video += noise(uv*2., uv)/2.;
|
||||
video *= vignette;
|
||||
video *= (12./small_scanlines_opacity+mod(uv.y*30.*small_scanlines_proximity+TIME*small_scanlines_speed,1.))/13.*small_scanlines_opacity;
|
||||
|
||||
COLOR = vec4(video,1.0);
|
||||
}
|
||||
1
flumi/Shaders/crt.gdshader.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://db3f2xubcujnq
|
||||
45
flumi/Shaders/dither.gdshader
Normal file
@@ -0,0 +1,45 @@
|
||||
//GODOT 4
|
||||
|
||||
shader_type canvas_item;
|
||||
|
||||
uniform float pixel = 1.0;
|
||||
uniform sampler2D pallete;
|
||||
|
||||
uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap;
|
||||
|
||||
const float bit = 6.0;
|
||||
const mat4 bayer = mat4(
|
||||
vec4(1.0, 9.0, 3.0, 11.0),
|
||||
vec4(13.0, 5.0, 15.0, 7.0),
|
||||
vec4(4.0, 12.0, 2.0, 10.0),
|
||||
vec4(16.0, 8.0, 14.0, 6.0));
|
||||
|
||||
|
||||
float getbayer(int x, int y)
|
||||
{
|
||||
return bayer[x][y];
|
||||
}
|
||||
|
||||
void fragment() {
|
||||
vec4 original = texture(TEXTURE, UV);
|
||||
|
||||
vec2 FUV = floor(FRAGCOORD.xy / pixel) / floor((1.0 / SCREEN_PIXEL_SIZE) / pixel);
|
||||
|
||||
vec4 _color = texture(SCREEN_TEXTURE, SCREEN_UV);
|
||||
vec4 color = _color * texture(pallete, vec2(_color.r, 1.0));
|
||||
|
||||
|
||||
float b = getbayer(int(FRAGCOORD.x) % 4, int(FRAGCOORD.y) % 4);// * 1.0) / 1.0;
|
||||
vec2 uv = FRAGCOORD.xy / SCREEN_PIXEL_SIZE;
|
||||
vec4 col_noise = color;
|
||||
vec3 noise = vec3(fract(sin(dot(FUV, vec2(12.9898, 78.233))) * 43758.5453));
|
||||
noise *= 0.1;
|
||||
noise.xy *= (b / 16.0) * 1.5;
|
||||
col_noise.rgb += noise; //noise effect
|
||||
|
||||
vec4 post = col_noise * floor(col_noise * 4.0) / 4.0; //noise + post-effect
|
||||
|
||||
COLOR *= post;
|
||||
|
||||
|
||||
}
|
||||
1
flumi/Shaders/dither.gdshader.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bggtn4uh67v0u
|
||||
20
flumi/Shaders/film.gdshader
Normal file
@@ -0,0 +1,20 @@
|
||||
shader_type canvas_item;
|
||||
|
||||
// Uniforms
|
||||
uniform sampler2D screen_texture : hint_screen_texture;
|
||||
uniform float grain_amount : hint_range(0.0, 1.0) = 0.05; // Adjust the amount of grain
|
||||
uniform float grain_size : hint_range(0.1, 10.0) = 1.0; // Adjust the size of the grain
|
||||
|
||||
void fragment() {
|
||||
// Sample the original screen texture
|
||||
vec4 original_color = texture(screen_texture, SCREEN_UV);
|
||||
|
||||
// Generate random noise
|
||||
float noise = (fract(sin(dot(UV, vec2(12.9898, 78.233))) * 43758.5453) - 0.5) * 2.0;
|
||||
|
||||
// Add noise to the original color
|
||||
original_color.rgb += noise * grain_amount * grain_size;
|
||||
|
||||
// Clamp the final color to make sure it stays in the valid range
|
||||
COLOR = clamp(original_color, 0.0, 1.0);
|
||||
}
|
||||
1
flumi/Shaders/film.gdshader.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bss3x1xthtaef
|
||||
32
flumi/Shaders/foliage.gdshader
Normal file
@@ -0,0 +1,32 @@
|
||||
shader_type canvas_item;
|
||||
|
||||
uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap;
|
||||
|
||||
uniform float x_intensity = 3.0;
|
||||
uniform float y_intensity = 0.5;
|
||||
uniform float offset = 0.0;
|
||||
uniform float speed : hint_range(0, 20) = 2.0;
|
||||
uniform float wave_frequency : hint_range(0, 100) = 20;
|
||||
uniform float wave_length : hint_range(50, 800) = 200.0;
|
||||
|
||||
void fragment() {
|
||||
vec2 real_uv = UV;
|
||||
|
||||
vec2 vecToBottom = vec2(1, 1) - UV.y;
|
||||
float distToBottom = length(vecToBottom);
|
||||
|
||||
float final_speed = TIME * (speed / 4.0) + offset;
|
||||
|
||||
float time_var = (cos(final_speed) * cos(final_speed * 4.0) * cos(final_speed * 2.0))/(200.0);
|
||||
float time_var2 = (cos(final_speed) * cos(final_speed * 6.0) * cos(final_speed * 2.0))/(200.0);
|
||||
|
||||
float wave_from_x = (cos(real_uv.x * 100.0)/1000.0);
|
||||
float wave_large_from_x = cos(TIME + (real_uv.x * wave_frequency))/wave_length;
|
||||
|
||||
float offset_x = time_var * (distToBottom * x_intensity) + wave_from_x + (wave_large_from_x);
|
||||
float offset_y = time_var2 * (distToBottom * y_intensity);
|
||||
|
||||
vec2 distortion_offset = vec2(offset_x, offset_y);
|
||||
|
||||
COLOR = texture(SCREEN_TEXTURE, SCREEN_UV + distortion_offset);
|
||||
}
|
||||
1
flumi/Shaders/foliage.gdshader.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://12ar0h66dukp
|
||||
1
flumi/Shaders/future.gdshader.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c8nv7tds2neww
|
||||
95
flumi/Shaders/lensflare.gdshader
Normal file
@@ -0,0 +1,95 @@
|
||||
// TRANSLATED & MODIFIED FROM: https://www.shadertoy.com/view/4sX3Rs
|
||||
|
||||
shader_type canvas_item;
|
||||
render_mode blend_mix;
|
||||
|
||||
uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap;
|
||||
|
||||
uniform vec2 sun_position = vec2(400.0, 0.0);
|
||||
uniform vec3 tint = vec3(1.4,1.2,1.0);
|
||||
uniform sampler2D noise_texture;
|
||||
|
||||
float noise_float(float t, vec2 texResolution)
|
||||
{
|
||||
return texture(noise_texture,vec2(t,0.0)/texResolution).x;
|
||||
}
|
||||
float noise_vec2(vec2 t, vec2 texResolution)
|
||||
{
|
||||
return texture(noise_texture,t/texResolution).x;
|
||||
}
|
||||
|
||||
vec3 lensflare(vec2 uv,vec2 pos, vec2 texResolution)
|
||||
{
|
||||
vec2 main = uv-pos;
|
||||
vec2 uvd = uv*(length(uv));
|
||||
|
||||
float ang = atan(main.x,main.y);
|
||||
float dist = length(main);
|
||||
dist = pow(dist,0.1);
|
||||
|
||||
float n = noise_vec2(vec2(ang*16.0,dist*32.0), texResolution);
|
||||
|
||||
// Do not need an artificial sun
|
||||
//float f0 = 1.0/(length(uv-pos)*16.0+1.0);
|
||||
//f0 = f0 + f0*(sin(noise_float(sin(ang*2.+pos.x)*4.0 - cos(ang*3.+pos.y), texResolution)*16.)*.1 + dist*.1 + .8);
|
||||
|
||||
float f1 = max(0.01-pow(length(uv+1.2*pos),1.9),.0)*7.0;
|
||||
|
||||
float f2 = max(1.0/(1.0+32.0*pow(length(uvd+0.8*pos),2.0)),.0)*00.25;
|
||||
float f22 = max(1.0/(1.0+32.0*pow(length(uvd+0.85*pos),2.0)),.0)*00.23;
|
||||
float f23 = max(1.0/(1.0+32.0*pow(length(uvd+0.9*pos),2.0)),.0)*00.21;
|
||||
|
||||
vec2 uvx = mix(uv,uvd,-0.5);
|
||||
|
||||
float f4 = max(0.01-pow(length(uvx+0.4*pos),2.4),.0)*6.0;
|
||||
float f42 = max(0.01-pow(length(uvx+0.45*pos),2.4),.0)*5.0;
|
||||
float f43 = max(0.01-pow(length(uvx+0.5*pos),2.4),.0)*3.0;
|
||||
|
||||
uvx = mix(uv,uvd,-.4);
|
||||
|
||||
float f5 = max(0.01-pow(length(uvx+0.2*pos),5.5),.0)*2.0;
|
||||
float f52 = max(0.01-pow(length(uvx+0.4*pos),5.5),.0)*2.0;
|
||||
float f53 = max(0.01-pow(length(uvx+0.6*pos),5.5),.0)*2.0;
|
||||
|
||||
uvx = mix(uv,uvd,-0.5);
|
||||
|
||||
float f6 = max(0.01-pow(length(uvx-0.3*pos),1.6),.0)*6.0;
|
||||
float f62 = max(0.01-pow(length(uvx-0.325*pos),1.6),.0)*3.0;
|
||||
float f63 = max(0.01-pow(length(uvx-0.35*pos),1.6),.0)*5.0;
|
||||
|
||||
vec3 c = vec3(.0);
|
||||
|
||||
c.r+=f2+f4+f5+f6; c.g+=f22+f42+f52+f62; c.b+=f23+f43+f53+f63;
|
||||
c = c*1.3 - vec3(length(uvd)*.05);
|
||||
|
||||
// Do not need an artificial sun
|
||||
//c+=vec3(f0);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
vec3 cc(vec3 color, float factor,float factor2) // color modifier
|
||||
{
|
||||
float w = color.x+color.y+color.z;
|
||||
return mix(color,vec3(w)*factor,w*factor2);
|
||||
}
|
||||
|
||||
void fragment()
|
||||
{
|
||||
vec2 texResolution = 1.0 / TEXTURE_PIXEL_SIZE;
|
||||
vec2 resolution = 1.0 / SCREEN_PIXEL_SIZE;
|
||||
|
||||
vec2 uv = FRAGCOORD.xy / resolution.xy - 0.5;
|
||||
uv.x *= resolution.x/resolution.y; //fix aspect ratio
|
||||
vec2 mouse = (sun_position.xy / resolution.xy) - vec2(0.5, 0.5);
|
||||
mouse.x *= resolution.x / resolution.y; //fix aspect ratio
|
||||
|
||||
vec4 previousColor = texture(SCREEN_TEXTURE, SCREEN_UV);
|
||||
|
||||
vec3 color = previousColor.rgb;
|
||||
|
||||
color += tint * lensflare(uv, mouse.xy, texResolution);
|
||||
color -= noise_vec2(FRAGCOORD.xy, texResolution)*.015;
|
||||
color = cc(color,.5,.1);
|
||||
COLOR = vec4(color,1.0);
|
||||
}
|
||||
1
flumi/Shaders/lensflare.gdshader.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c6auxoe0vpq46
|
||||
58
flumi/Shaders/pencil.gdshader
Normal file
@@ -0,0 +1,58 @@
|
||||
shader_type canvas_item;
|
||||
|
||||
uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap;
|
||||
uniform vec4 u_bgColor: source_color = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
uniform float u_bgColorFactor: hint_range(0.0, 1.0) = 0.4;
|
||||
uniform vec4 u_patternColor: source_color = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
|
||||
uniform float u_threshold1: hint_range(0.0, 1.0) = 0.75;
|
||||
uniform float u_threshold2: hint_range(0.0, 1.0) = 0.50;
|
||||
uniform float u_threshold3: hint_range(0.0, 1.0) = 0.25;
|
||||
uniform float u_threshold4: hint_range(0.0, 1.0) = 0.05;
|
||||
|
||||
uniform vec2 u_bgTiling = vec2(1.0, 1.0);
|
||||
uniform vec2 u_patternTiling = vec2(1.0, 1.0);
|
||||
|
||||
uniform sampler2D u_bgTexture;
|
||||
uniform sampler2D u_patternTexture;
|
||||
|
||||
const float C2_SQRT2 = 0.707106781;
|
||||
const mat2 ROT_45 = mat2(vec2(C2_SQRT2, -C2_SQRT2), vec2(C2_SQRT2, C2_SQRT2));
|
||||
const vec4 COLOR_WHITE = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
|
||||
float getIntensity(vec3 color)
|
||||
{
|
||||
return 0.299*color.r + 0.587*color.g + 0.114*color.b;
|
||||
}
|
||||
|
||||
vec4 getPatternColor(vec2 uv, float intensity)
|
||||
{
|
||||
vec2 patternUV1 = vec2(-uv.x, uv.y) * u_patternTiling;
|
||||
vec2 patternUV2 = uv * u_patternTiling;
|
||||
vec2 patternUV3 = ROT_45*(uv + vec2(0.2358, 0.9123)) * u_patternTiling;
|
||||
vec2 patternUV4 = (vec2(uv.x, -uv.y) + vec2(0.4123, 0.7218)) * u_patternTiling;
|
||||
vec4 pCol1 = texture(u_patternTexture, patternUV1);
|
||||
vec4 pCol2 = texture(u_patternTexture, patternUV2);
|
||||
vec4 pCol3 = texture(u_patternTexture, patternUV3);
|
||||
vec4 pCol4 = texture(u_patternTexture, patternUV4);
|
||||
|
||||
if(intensity > u_threshold1)
|
||||
return vec4(1.0, 1.0, 1.0, 1.0);
|
||||
if(intensity > u_threshold2)
|
||||
return mix(pCol1, COLOR_WHITE, 0.5);
|
||||
if(intensity > u_threshold3)
|
||||
return mix(pCol1*pCol2, COLOR_WHITE, 0.3);
|
||||
if(intensity > u_threshold4)
|
||||
return mix(pCol1*pCol2*pCol3, COLOR_WHITE, 0.1);
|
||||
return pCol1*pCol2*pCol3*pCol4*0.8;
|
||||
}
|
||||
|
||||
void fragment()
|
||||
{
|
||||
vec4 origColor = texture(SCREEN_TEXTURE, SCREEN_UV);
|
||||
float intensity = getIntensity(origColor.rgb);
|
||||
vec4 bgColor = mix(texture(u_bgTexture, UV*u_bgTiling), u_bgColor, u_bgColorFactor);
|
||||
vec4 patternColor = getPatternColor(UV, intensity);
|
||||
vec4 color = mix(u_patternColor, bgColor, getIntensity(patternColor.rgb));
|
||||
COLOR = color;
|
||||
}
|
||||
1
flumi/Shaders/pencil.gdshader.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c54knriu0lot8
|
||||
1
flumi/Shaders/pixelate.gdshader.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://b4qebk1wtx6pj
|
||||
27
flumi/Shaders/rblur.gdshader
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
放射状ブラーエフェクト by あるる(きのもと 結衣) @arlez80
|
||||
Radial Blur Effect by Yui Kinomoto
|
||||
|
||||
MIT License
|
||||
*/
|
||||
|
||||
shader_type canvas_item;
|
||||
uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap;
|
||||
|
||||
// 発射中央部
|
||||
uniform vec2 blur_center = vec2( 0.5, 0.5 );
|
||||
// ブラー強度
|
||||
uniform float blur_power : hint_range( 0.0, 1.0 ) = 0.01;
|
||||
// サンプリング回数
|
||||
uniform int sampling_count : hint_range( 1, 64 ) = 2;
|
||||
|
||||
void fragment( )
|
||||
{
|
||||
vec2 direction = SCREEN_UV - blur_center;
|
||||
vec3 c = vec3( 0.0, 0.0, 0.0 );
|
||||
float f = 1.0 / float( sampling_count );
|
||||
for( int i=0; i < sampling_count; i++ ) {
|
||||
c += texture( SCREEN_TEXTURE, SCREEN_UV - blur_power * direction * float(i) ).rgb * f;
|
||||
}
|
||||
COLOR.rgb = c;
|
||||
}
|
||||
1
flumi/Shaders/rblur.gdshader.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bcwhtc0sjmwr3
|
||||
1
flumi/Shaders/retro.gdshader.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c366ik3prmltu
|
||||
59
flumi/Shaders/snowfall.gdshader
Normal file
@@ -0,0 +1,59 @@
|
||||
// Modified version of https://godotshaders.com/shader/multilayer-snowfall-shader/
|
||||
// All credits to the original author!!!
|
||||
|
||||
shader_type canvas_item;
|
||||
|
||||
uniform float spread : hint_range(0.0, 1.5) = 0.5;
|
||||
uniform float size : hint_range(0.01, 5.0) = 0.5;
|
||||
uniform vec4 snow_color : source_color = vec4(1.0);
|
||||
uniform float snow_transparency: hint_range(-0.5, 1.0) = 0.2;
|
||||
|
||||
uniform float speed : hint_range(0.0, 10.0) = 0.5;
|
||||
uniform float wind : hint_range(-2.0, 2.0) = 0.0;
|
||||
uniform int num_of_layers = 40;
|
||||
|
||||
const mat3 NOISE_MATRIX = mat3(
|
||||
vec3(13.323122, 23.5112, 21.71123),
|
||||
vec3(21.1212, 28.7312, 11.9312),
|
||||
vec3(21.8112, 14.7212, 61.3934)
|
||||
);
|
||||
|
||||
vec3 generate_snowflake(vec2 coord, float layer_index, float time, float wind_strength) {
|
||||
float layer_scale = 1.0 + layer_index * 0.5 / (max(size, 0.01) * 2.0);
|
||||
vec2 scaled_coord = coord * layer_scale;
|
||||
|
||||
vec2 movement = vec2(
|
||||
scaled_coord.y * (spread * mod(layer_index * 7.238917, 1.0) - spread * 0.5) +
|
||||
(-wind_strength) * speed * time * 0.5,
|
||||
-speed * time / (1.0 + layer_index * 0.5 * 0.03)
|
||||
);
|
||||
vec2 final_coord = scaled_coord + movement;
|
||||
|
||||
vec3 noise_input = vec3(floor(final_coord), 31.189 + layer_index);
|
||||
vec3 noise_val = floor(noise_input) * 0.00001 + fract(noise_input);
|
||||
vec3 random = fract((31415.9 + noise_val) / fract(NOISE_MATRIX * noise_val));
|
||||
|
||||
vec2 shape = abs(mod(final_coord, 1.0) - 0.5 + 0.9 * random.xy - 0.45);
|
||||
shape += 0.01 * abs(2.0 * fract(10.0 * final_coord.yx) - 1.0);
|
||||
|
||||
float depth_offset = 5.0 * sin(time * 0.1);
|
||||
float edge_softness = 0.005 + 0.05 * min(0.5 * abs(layer_index - 5.0 - depth_offset), 1.0);
|
||||
|
||||
float shape_value = 0.6 * max(shape.x - shape.y, shape.x + shape.y) + max(shape.x, shape.y) - 0.01;
|
||||
|
||||
return vec3(smoothstep(edge_softness, -edge_softness, shape_value) *
|
||||
(random.x / (1.0 + 0.02 * layer_index * 0.5)));
|
||||
}
|
||||
|
||||
void fragment() {
|
||||
vec3 snow_accumulation = vec3(0.0);
|
||||
|
||||
for (int i = 0; i < num_of_layers; i++) {
|
||||
snow_accumulation += generate_snowflake(UV, float(i), TIME, wind);
|
||||
}
|
||||
|
||||
float snow_intensity = clamp(length(snow_accumulation), 0.0, 1.0);
|
||||
vec4 transparency_color = vec4(snow_color.rgb * (1.0 + snow_transparency), snow_intensity);
|
||||
|
||||
COLOR = transparency_color;
|
||||
}
|
||||
1
flumi/Shaders/snowfall.gdshader.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://deof0r34dt78d
|
||||
17
flumi/Shaders/vignette.gdshader
Normal file
@@ -0,0 +1,17 @@
|
||||
shader_type canvas_item;
|
||||
|
||||
uniform float inner_radius = 0.1;
|
||||
uniform float outer_radius = 1;
|
||||
uniform float vignette_strength = 1.0;
|
||||
uniform float dither_strength = 0.03;
|
||||
uniform vec4 vignette_color: source_color;
|
||||
|
||||
|
||||
void fragment() {
|
||||
float dist = distance(UV, vec2(0.5));
|
||||
|
||||
float vignette = smoothstep(inner_radius, outer_radius, dist) * vignette_strength;
|
||||
float dither = fract(sin(dot(UV, vec2(12.9898, 78.233))) * 43758.5453123) * dither_strength;
|
||||
|
||||
COLOR = vec4(vignette_color.rgb, vignette + dither);
|
||||
}
|
||||
1
flumi/Shaders/vignette.gdshader.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://boba7hm3vito8
|
||||
1
flumi/Shaders/wobbly.gdshader.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://186q3n8sc7qw
|
||||
@@ -14,6 +14,8 @@
|
||||
.copy-url-btn { bg-[#8b5cf6] text-white hover:bg-[#7c3aed] }
|
||||
</style>
|
||||
|
||||
<postprocess preset="chrome" />
|
||||
|
||||
<script>
|
||||
gurt.log('Script started!')
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<meta name="description" content="A stylish no-script dashboard">
|
||||
|
||||
<font name="roboto" src="https://fonts.gstatic.com/s/roboto/v48/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3KUBGEe.woff2" />
|
||||
<postprocess preset="rblur" />
|
||||
|
||||
<style>
|
||||
h1 { text-[#ffffff] text-3xl font-bold }
|
||||
|
||||