docs: every shader type is free
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
41b7476e70
commit
cf42fc020d
@@ -14,6 +14,56 @@ were optional are now defaults, and blending keeps the base noise's own statisti
|
||||
so the first step away from strength 0 is only as large as the shader makes it.
|
||||
|
||||
### Added
|
||||
- **Every archetype the Shader Matrix documents is now a shader type**, eight of
|
||||
them new: `gaussian`, `fractal`, `perlin`, `heterogeneous_fbm`, `interference`,
|
||||
`projection_3d`, `cellular` and `waves`, beside the five that existed. They were
|
||||
marketed as supporter exclusives and never built; the README, the matrix modal and
|
||||
the Ko-fi cups stamped on nine of its thumbnails said otherwise, and that wording is
|
||||
gone. Each type is one module under `shaders/`, registered by import, selectable on
|
||||
every node, and pinned by a golden fixture for an image and a clip.
|
||||
|
||||
What they are, and what the four shared knobs do to each -- the `shader_type`
|
||||
tooltip carries the same, one sentence per type:
|
||||
- `gaussian`: white noise, the same thing the sampler already starts from, so it is
|
||||
the control. Strength moves toward another seed's neighbourhood without adding
|
||||
structure. No pattern knob reaches it; shape masks still apply; with temporal
|
||||
coherence a clip drifts from one white field to a second.
|
||||
- `fractal`: the reference FBM, plain layered simplex. `warp_strength` is the
|
||||
spacing between the layers (a lacunarity dial, 1.5x to 4x), `phase_shift` slides
|
||||
each layer to a different part of the field; neither does anything at octaves 1.
|
||||
- `perlin`: classic gradient noise, smoother and more lattice-like than simplex,
|
||||
zero on every lattice point. `warp_strength` swirls the detail layers while the
|
||||
base layer keeps its shape; `phase_shift` is contrast, as in `domain_warp`.
|
||||
- `heterogeneous_fbm`: an FBM whose persistence varies across the frame, so it has
|
||||
rough patches and smooth ones. `warp_strength` is how different they are (0 is
|
||||
plain FBM), `phase_shift` how much of the frame is rough. Needs octaves above 1.
|
||||
- `interference`: two FBMs cut into cos and sin fringes that cross, banded and
|
||||
moire-like. `warp_strength` is the fringe density, from soft folds to dense
|
||||
moire; `phase_shift` retunes the second field.
|
||||
- `projection_3d`: a plane through a 3D simplex FBM. `phase_shift` is the depth of
|
||||
the slice, so it is the "different facet of the same field" knob literally, and
|
||||
`time` slides the plane, so a clip is coherent by construction. `warp_strength`
|
||||
bends the plane.
|
||||
- `cellular`: Worley cells. `octaves` picks the pattern -- 1 nearest distance, 2
|
||||
second-nearest, 3 edges, 4 product, a fractional value blends two -- and
|
||||
`phase_shift` the cell shape, 0 diamond, 0.5 round, 2 square. `warp_strength`
|
||||
bends the lattice. On a clip the cells live in 3D and time moves through them.
|
||||
- `waves`: `octaves` seeded plane waves summed, straight at `warp_strength` 0 and
|
||||
bent above it; `phase_shift` rearranges the same waves into a different
|
||||
interference pattern; `time` drifts each wave at its own rate.
|
||||
|
||||
All of them fill every latent channel with a field of their own, keep channel 0 the
|
||||
same whether one channel or many were asked for, draw the channel axis in one
|
||||
batched call, and leave the global RNG alone. Like `spectral`, their strengths are
|
||||
**not** calibrated against real prompts the way the first four are.
|
||||
|
||||
Shared underneath: `shaders/fbm.py` (the draw-and-fill skeleton every scalar-field
|
||||
type uses, an FBM over the shared simplex, `simplex_warp`), `lattice_hash` and the
|
||||
four-corner `simplex_3d_full` in `shaders/simplex.py` (the latter moved verbatim
|
||||
from `temporal_coherent`, which now delegates; a new golden fixture pins it across
|
||||
the move), and `BaseNoiseGenerator.palette_channels`, one copy of the colour-scheme
|
||||
mapping `domain_warp` carries for itself.
|
||||
|
||||
- **`Shader Noise Source`, a node that outputs a `NOISE` object**, so shader noise can
|
||||
start a run driven by `SamplerCustomAdvanced` -- with the guider, sampler and sigma
|
||||
schedule chosen separately. It answers a standing request for a custom-sampling
|
||||
@@ -66,6 +116,13 @@ so the first step away from strength 0 is only as large as the shader makes it.
|
||||
Its strengths are **not** calibrated against real prompts the way the other four
|
||||
are. Treat the presets' numbers as not applying to it yet.
|
||||
|
||||
### Removed
|
||||
- **The "supporter exclusive" framing of the missing shader types.** Nine Ko-fi
|
||||
badges under the matrix gallery's cards, the "Unlock Exclusive Shader Noise
|
||||
Palettes" card, the Ko-fi cup the thumbnail renderer stamped onto those nine
|
||||
previews (and the SVG it loaded for it), and the README's "additional advanced noise
|
||||
types are available to supporters" sentence. The general support link stays.
|
||||
|
||||
### Fixed
|
||||
- **Legacy mode sampled `tensor_field` when asked for `temporal_coherent`.** The
|
||||
parameter whitelist was a hand-written set that never gained the name, and it
|
||||
|
||||
@@ -99,7 +99,7 @@ This README provides an overview, but the Shader Matrix is your ultimate guide f
|
||||
- **🔬 Multi-Stage Shader Application**:
|
||||
- **Sequential Stages**: Apply shader noise over segments of the diffusion process.
|
||||
- **Injection Stages**: Apply shader noise at specific, discrete steps.
|
||||
- **🎨 Three Shader Noise Archetypes**: `Domain Warp` for flowing distortions, `Tensor Field` for structured directional patterns, and `Curl Noise` for fluid motion. Each is a distinct lens on the latent neighbourhood, and each supports shape masks, colour schemes and transforms.
|
||||
- **🎨 Thirteen Shader Noise Types**: the twelve archetypes the Shader Matrix documents -- `domain_warp`, `tensor_field`, `curl_noise`, `spectral`, `gaussian`, `fractal`, `perlin`, `heterogeneous_fbm`, `interference`, `projection_3d`, `cellular` and `waves` -- plus `temporal_coherent`, built for video. Each is a distinct lens on the latent neighbourhood, and each supports shape masks, colour schemes and transforms.
|
||||
- **🎭 Sophisticated Blending & Transformations**:
|
||||
- **Blend Modes**: Combine shader noise with base noise using modes like Multiply, Add, Overlay, Screen, Soft Light, Hard Light, Difference.
|
||||
- **Noise Transformations**: Apply mathematical operations (Absolute, Sin, Square Root, etc.) to shader noise before blending.
|
||||
@@ -230,7 +230,7 @@ Restart ComfyUI after installation. No additional `pip install` steps are requir
|
||||
- **Stages**: Define `sequential_stages` and `injection_stages`.
|
||||
- **Global Controls**: Set `shader_strength` (0.0 to disable shaders), `blend_mode`, and `noise_transform`.
|
||||
- **Per-Stage Controls**: For each stage, configure:
|
||||
- `shader_noise_type` (e.g., perlin, cellular)
|
||||
- `shader_type` (e.g., `domain_warp`, `perlin`, `cellular`)
|
||||
- `noise_scale` (zoom control), `noise_octaves` (detail level), `noise_warp_strength` (non-linear navigation), `noise_phase_shift` (perspective shift)
|
||||
- `shape_mask_type` and `shape_mask_strength`
|
||||
- `color_scheme` and `color_intensity`
|
||||
@@ -318,7 +318,7 @@ The `ShaderNoiseKSampler` offers extensive control. Key parameters are listed be
|
||||
| **`noise_transform`** | Math operation on shader noise (e.g., `none`, `absolute`, `sin`). | `none` |
|
||||
| **`use_temporal_coherence`** | For consistent noise in animations or exploration. | `false` |
|
||||
| **`sampling_mode`** | `standard` samples one schedule split into stage segments, and honours `denoise` and `custom_sigmas`. `legacy` keeps the pre-2.0.0 pipeline and is selected automatically for older workflows, but no longer reproduces every earlier seed exactly (see Known Issues). | `standard` |
|
||||
| **`shader_noise_type (per stage)`** | The base pattern (e.g., `domain_warp`, `tensor_field`, `curl_noise`). | `domain_warp` |
|
||||
| **`shader_type`** | The base pattern: one of the thirteen types, `domain_warp` by default. The node's tooltip describes each one's character and what its knobs do. | `domain_warp` |
|
||||
| **`noise_scale (per stage)`** | The "Zoom Control" - determines how "zoomed in" or "zoomed out" you are in latent space. | `1.0` |
|
||||
| **`noise_octaves (per stage)`** | The "Detail Slider" - controls the level of detail and complexity in your noise pattern. | `1` |
|
||||
| **`noise_warp_strength (per stage)`** | The "Non-Linear Navigator" - creates non-linear paths through latent space. | `0.5` |
|
||||
@@ -369,7 +369,7 @@ nothing to paint, and the node then samples those models as a plain KSampler.
|
||||
|
||||
The true depth of `ShaderNoiseKSampler` lies in its components. The "Shader Matrix" covers these extensively.
|
||||
|
||||
- **Shader Noise Types**: Start your exploration with three powerful, freely available noise archetypes: `Domain Warp` for intricate, flowing distortions, `Tensor Field` for structured and directional patterns, and `Curl Noise` for smooth, fluid dynamics. Each offers a **unique visual lens** 🔭 for navigating latent space. ✨ **Additional advanced noise types** are available to supporters on [Ko-fi](https://ko-fi.com/aemotionstudio).
|
||||
- **Shader Noise Types**: Start with `Domain Warp` for intricate, flowing distortions, `Tensor Field` for structured and directional patterns, and `Curl Noise` for smooth, fluid dynamics. Each offers a **unique visual lens** 🔭 for navigating latent space. The other ten -- `spectral`, `gaussian`, `fractal`, `perlin`, `heterogeneous_fbm`, `interference`, `projection_3d`, `cellular`, `waves` and `temporal_coherent` -- are all included; the Shader Matrix documents every one of them, and the `shader_type` tooltip says what each knob does to each.
|
||||
|
||||
**Domain Warp**
|
||||
|
||||
@@ -419,7 +419,6 @@ The journey into guided latent space exploration is just beginning. Here's a gli
|
||||
| Area | Focus | Technologies Involved (Examples) |
|
||||
| :---------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------- |
|
||||
| **🌌 Advanced Latent Space Cartography** | Evolve current research into an intuitive "Visual Intent Engine". This system will allow users to express desired visual outcomes semantically (e.g., "enhance fabric texture," "shift lighting ambiance"). The engine will then intelligently translate these intents into optimal shader parameter configurations, fostering a more direct and expressive artistic workflow by deeply mapping the interplay between parameters and visual impact. | Semantic AI, Parameter Response Modeling, Machine Learning |
|
||||
| **🎨 Expanded Shader Noise Palettes** | Introduce a richer vocabulary of shader noise types, each with unique navigational properties and aesthetic fingerprints. Explore new dimensions of textural complexity, flow dynamics, and structural organization. | Advanced Noise Algorithms, GLSL concepts |
|
||||
| **🧭 Precision Navigation Tools** | Create more granular and predictable tools for manipulating latent pathways. Research direct correlations between mathematical noise constructs and emergent visual features for greater artistic intent. | Mathematical Modelling, Latent Space Analysis |
|
||||
| **🔮 Cross-Modal Exploration** | Investigate applying structured noise principles to modalities beyond 2D images, such as 3D and audio, opening new avenues for creative exploration. | Signal Processing, Generative Models for Audio/3D |
|
||||
|
||||
|
||||
+6
-5
@@ -1,11 +1,12 @@
|
||||
"""
|
||||
Shader noise generators for ComfyUI-ShaderNoiseKSampler.
|
||||
|
||||
This package provides various noise generation algorithms:
|
||||
- domain_warp: Domain warping noise
|
||||
- tensor_field: Tensor field noise
|
||||
- curl_noise: Curl/fluid noise
|
||||
- temporal_coherent: Temporally coherent noise for animations
|
||||
One module per shader type, each registered under its name by the
|
||||
@shader_generator decorator when the module is imported: domain_warp,
|
||||
tensor_field, curl_noise, temporal_coherent, spectral, gaussian, fractal,
|
||||
perlin, heterogeneous_fbm, interference, projection_3d, cellular and waves.
|
||||
simplex.py holds the hashes and simplex primitives they share, fbm.py the
|
||||
draw-and-fill skeleton of the scalar-field types.
|
||||
"""
|
||||
|
||||
from .base import BaseNoiseGenerator
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
<svg width="241" height="194" viewBox="0 0 241 194" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="mask0_1_219" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="-1" y="0" width="242" height="194">
|
||||
<path d="M240.469 0.958984H-0.00585938V193.918H240.469V0.958984Z" fill="white"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_1_219)">
|
||||
<path d="M96.1344 193.911C61.1312 193.911 32.6597 178.256 15.9721 149.829C1.19788 124.912 -0.00585938 97.9229 -0.00585938 67.7662C-0.00585938 49.8876 5.37293 34.3215 15.5413 22.7466C24.8861 12.1157 38.1271 5.22907 52.8317 3.35378C70.2858 1.14271 91.9848 0.958984 114.545 0.958984C151.259 0.958984 161.63 1.4088 176.075 2.85328C195.29 4.76026 211.458 11.932 222.824 23.5955C234.368 35.4428 240.469 51.2624 240.469 69.3627V72.9994C240.469 103.885 219.821 129.733 191.046 136.759C188.898 141.827 186.237 146.871 183.089 151.837L183.006 151.964C172.869 167.632 149.042 193.918 103.401 193.918H96.1281L96.1344 193.911Z" fill="white"/>
|
||||
<path d="M174.568 17.9772C160.927 16.6151 151.38 16.1589 114.552 16.1589C90.908 16.1589 70.9008 16.387 54.7644 18.4334C33.3949 21.164 15.2058 37.5285 15.2058 67.7674C15.2058 98.0066 16.796 121.422 29.0741 142.107C42.9425 165.751 66.1302 178.707 96.1412 178.707H103.414C140.242 178.707 160.25 159.156 170.253 143.698C174.574 136.874 177.754 130.058 179.801 123.234C205.947 120.96 225.27 99.3624 225.27 72.9941V69.3577C225.27 40.9432 206.631 21.164 174.574 17.9772H174.568Z" fill="white"/>
|
||||
<path d="M15.1975 67.7674C15.1975 37.5285 33.3866 21.164 54.7559 18.4334C70.8987 16.387 90.906 16.1589 114.544 16.1589C151.372 16.1589 160.919 16.6151 174.559 17.9772C206.617 21.1576 225.255 40.937 225.255 69.3577V72.9941C225.255 99.3687 205.932 120.966 179.786 123.234C177.74 130.058 174.559 136.874 170.238 143.698C160.235 159.156 140.228 178.707 103.4 178.707H96.1264C66.1155 178.707 42.9277 165.751 29.0595 142.107C16.7814 121.422 15.1912 98.4563 15.1912 67.7674" fill="#202020"/>
|
||||
<path d="M32.2469 67.9899C32.2469 97.3168 34.0654 116.184 43.6127 133.689C54.5225 153.924 74.3018 161.653 96.8117 161.653H103.857C133.411 161.653 147.736 147.329 155.693 134.829C159.558 128.462 162.966 121.417 164.784 112.547L166.147 106.864H174.332C192.521 106.864 208.208 92.09 208.208 73.2166V69.8082C208.208 48.6669 195.024 37.5228 172.058 34.7987C159.102 33.6646 151.372 33.2084 114.538 33.2084C89.7602 33.2084 72.0272 33.4364 58.6152 35.4828C39.7483 38.2134 32.2407 48.8951 32.2407 67.9899" fill="white"/>
|
||||
<path d="M166.158 83.6801C166.158 86.4107 168.204 88.4572 171.841 88.4572C183.435 88.4572 189.802 81.8619 189.802 70.9523C189.802 60.0427 183.435 53.2195 171.841 53.2195C168.204 53.2195 166.158 55.2657 166.158 57.9963V83.6866V83.6801Z" fill="#202020"/>
|
||||
<path d="M54.5321 82.3198C54.5321 95.732 62.0332 107.326 71.5807 116.424C77.9478 122.562 87.9515 128.93 94.7685 133.022C96.8147 134.157 98.8611 134.841 101.136 134.841C103.866 134.841 106.134 134.157 107.959 133.022C114.782 128.93 124.779 122.562 130.919 116.424C140.694 107.332 148.195 95.7383 148.195 82.3198C148.195 67.7673 137.286 54.8115 121.599 54.8115C112.28 54.8115 105.912 59.5882 101.136 66.1772C96.8147 59.582 90.2259 54.8115 80.9001 54.8115C64.9855 54.8115 54.5256 67.7673 54.5256 82.3198" fill="#FF5A16"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.2 KiB |
+1
-14
@@ -1335,7 +1335,6 @@ import { app } from "../../../scripts/app.js";
|
||||
<div class="noise-canvas" id="noise-canvas-cellular"></div>
|
||||
<div class="noise-name">Cellular</div>
|
||||
<div class="noise-description">Creates organic, cell-like structures through Voronoi diagrams, mimicking natural growth patterns.</div>
|
||||
<div style="margin-top: 5px; text-align: center;"><a href="https://ko-fi.com/aemotionstudio" target="_blank" rel="noopener noreferrer"><img src="https://ko-fi.com/img/githubbutton_sm.svg" alt="Support me on Ko-fi" style="height: 22px; border:0px;"/></a></div>
|
||||
</div>
|
||||
<div class="noise-item">
|
||||
<div class="noise-canvas" id="noise-canvas-domain_warp"></div>
|
||||
@@ -1346,49 +1345,41 @@ import { app } from "../../../scripts/app.js";
|
||||
<div class="noise-canvas" id="noise-canvas-fractal"></div>
|
||||
<div class="noise-name">Fractal</div>
|
||||
<div class="noise-description">Embodies self-similarity across scales, reflecting the infinite recursive patterns found throughout nature.</div>
|
||||
<div style="margin-top: 5px; text-align: center;"><a href="https://ko-fi.com/aemotionstudio" target="_blank" rel="noopener noreferrer"><img src="https://ko-fi.com/img/githubbutton_sm.svg" alt="Support me on Ko-fi" style="height: 22px; border:0px;"/></a></div>
|
||||
</div>
|
||||
<div class="noise-item">
|
||||
<div class="noise-canvas" id="noise-canvas-perlin"></div>
|
||||
<div class="noise-name">Perlin</div>
|
||||
<div class="noise-description">The classic gradient noise that creates smooth, natural-looking transitions and flowing textures.</div>
|
||||
<div style="margin-top: 5px; text-align: center;"><a href="https://ko-fi.com/aemotionstudio" target="_blank" rel="noopener noreferrer"><img src="https://ko-fi.com/img/githubbutton_sm.svg" alt="Support me on Ko-fi" style="height: 22px; border:0px;"/></a></div>
|
||||
</div>
|
||||
<div class="noise-item">
|
||||
<div class="noise-canvas" id="noise-canvas-waves"></div>
|
||||
<div class="noise-name">Waves</div>
|
||||
<div class="noise-description">Generates harmonic oscillations that combine to form complex interference patterns.</div>
|
||||
<div style="margin-top: 5px; text-align: center;"><a href="https://ko-fi.com/aemotionstudio" target="_blank" rel="noopener noreferrer"><img src="https://ko-fi.com/img/githubbutton_sm.svg" alt="Support me on Ko-fi" style="height: 22px; border:0px;"/></a></div>
|
||||
</div>
|
||||
<div class="noise-item">
|
||||
<div class="noise-canvas" id="noise-canvas-gaussian"></div>
|
||||
<div class="noise-name">Gaussian</div>
|
||||
<div class="noise-description">Pure probabilistic noise based on the normal distribution, the foundation of natural randomness.</div>
|
||||
<div style="margin-top: 5px; text-align: center;"><a href="https://ko-fi.com/aemotionstudio" target="_blank" rel="noopener noreferrer"><img src="https://ko-fi.com/img/githubbutton_sm.svg" alt="Support me on Ko-fi" style="height: 22px; border:0px;"/></a></div>
|
||||
</div>
|
||||
<div class="noise-item">
|
||||
<div class="noise-canvas" id="noise-canvas-heterogeneous_fbm"></div>
|
||||
<div class="noise-name">Heterogeneous FBM</div>
|
||||
<div class="noise-description">Varies the fractal dimension across space, creating regions of different turbulence and detail.</div>
|
||||
<div style="margin-top: 5px; text-align: center;"><a href="https://ko-fi.com/aemotionstudio" target="_blank" rel="noopener noreferrer"><img src="https://ko-fi.com/img/githubbutton_sm.svg" alt="Support me on Ko-fi" style="height: 22px; border:0px;"/></a></div>
|
||||
</div>
|
||||
<div class="noise-item">
|
||||
<div class="noise-canvas" id="noise-canvas-interference"></div>
|
||||
<div class="noise-name">Interference</div>
|
||||
<div class="noise-description">Simulates wave interaction patterns, creating complex nodal structures through phase relationships.</div>
|
||||
<div style="margin-top: 5px; text-align: center;"><a href="https://ko-fi.com/aemotionstudio" target="_blank" rel="noopener noreferrer"><img src="https://ko-fi.com/img/githubbutton_sm.svg" alt="Support me on Ko-fi" style="height: 22px; border:0px;"/></a></div>
|
||||
</div>
|
||||
<div class="noise-item">
|
||||
<div class="noise-canvas" id="noise-canvas-spectral"></div>
|
||||
<div class="noise-name">Spectral</div>
|
||||
<div class="noise-description">Controls the frequency spectrum directly, allowing precise frequency band manipulation.</div>
|
||||
<div style="margin-top: 5px; text-align: center;"><a href="https://ko-fi.com/aemotionstudio" target="_blank" rel="noopener noreferrer"><img src="https://ko-fi.com/img/githubbutton_sm.svg" alt="Support me on Ko-fi" style="height: 22px; border:0px;"/></a></div>
|
||||
</div>
|
||||
<div class="noise-item">
|
||||
<div class="noise-canvas" id="noise-canvas-projection_3d"></div>
|
||||
<div class="noise-name">3D Projection</div>
|
||||
<div class="noise-description">Projects three-dimensional noise onto a 2D plane, creating depth and volumetric effects.</div>
|
||||
<div style="margin-top: 5px; text-align: center;"><a href="https://ko-fi.com/aemotionstudio" target="_blank" rel="noopener noreferrer"><img src="https://ko-fi.com/img/githubbutton_sm.svg" alt="Support me on Ko-fi" style="height: 22px; border:0px;"/></a></div>
|
||||
</div>
|
||||
<div class="noise-item">
|
||||
<div class="noise-canvas" id="noise-canvas-curl_noise"></div>
|
||||
@@ -1398,10 +1389,6 @@ import { app } from "../../../scripts/app.js";
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="card" style="text-align: center; margin-top: calc(var(--section-padding) * 1.2); padding: calc(var(--section-padding) * 0.9); background: linear-gradient(145deg, rgba(var(--accent-color-rgb, 138, 43, 226), 0.1), rgba(var(--secondary-color-rgb, 52, 152, 219), 0.05)); border: 1px solid var(--accent-color); border-radius: 12px; box-shadow: 0 4px 20px rgba(var(--accent-color-rgb, 138, 43, 226), 0.2);">
|
||||
<h3 style="color: var(--accent-color); text-shadow: 0 0 8px rgba(var(--accent-color-rgb, 138, 43, 226), 0.5); margin-bottom: 0.7rem; font-size: 1.4rem;">🌟 Unlock Exclusive Shader Noise Palettes!</h3>
|
||||
<p style="font-size: 0.95rem; margin-bottom: 0rem; opacity: 0.9; line-height: 1.5;">Become a valued member to access an expanded library of unique shader noise archetypes, advanced shader features, and custom ComfyUI tools. Your support helps fuel further development!</p>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
@@ -1528,7 +1515,7 @@ import { app } from "../../../scripts/app.js";
|
||||
result = torch.zeros(batch_size, height, width, 1, device=device)
|
||||
|
||||
# Generate cellular pattern based on octaves mode
|
||||
pattern_type = int(octaves) % 4 # Use octaves to select pattern type
|
||||
pattern_type = (max(int(octaves), 1) - 1) % 4 # octaves 1 is F1, the node's default
|
||||
|
||||
# Calculate F1 and F2 distances (assuming compute_feature_distances exists)
|
||||
f1, f2 = compute_feature_distances(p * scale, seed)
|
||||
|
||||
@@ -6,73 +6,7 @@
|
||||
// ============================
|
||||
if (!window.NoiseVisualizer) {
|
||||
const NoiseVisualizer = {
|
||||
kofiCupImageBitmap: null,
|
||||
kofiImageLoaded: false,
|
||||
kofiImageLoadAttempted: false,
|
||||
_preloadKofiImage: async function () {
|
||||
if (this.kofiImageLoadAttempted)
|
||||
return;
|
||||
this.kofiImageLoadAttempted = true;
|
||||
const absolutePath = '/extensions/comfyui-shadernoiseksampler/images/kofi_symbol.svg';
|
||||
// Attempt 1: Direct Image load
|
||||
try {
|
||||
console.log('Attempting Ko-fi SVG load using new Image() with direct path (Primary Attempt)...');
|
||||
const img = new Image();
|
||||
await new Promise((resolve, reject) => {
|
||||
img.onload = () => {
|
||||
this.kofiCupImageBitmap = img;
|
||||
this.kofiImageLoaded = true;
|
||||
console.log('Ko-fi symbol SVG loaded via Image() successfully (Primary).');
|
||||
resolve();
|
||||
};
|
||||
img.onerror = (e) => {
|
||||
console.warn('Primary Ko-fi symbol SVG load via Image() failed. Proceeding to secondary attempt.', e);
|
||||
reject(e);
|
||||
};
|
||||
img.src = absolutePath;
|
||||
});
|
||||
return;
|
||||
}
|
||||
catch {
|
||||
this.kofiImageLoaded = false;
|
||||
this.kofiCupImageBitmap = null;
|
||||
}
|
||||
// Attempt 2: Fetch -> Blob -> Intermediate Image -> ImageBitmap
|
||||
let objectURL = null;
|
||||
try {
|
||||
console.log('Attempting Ko-fi SVG load via Blob -> Image -> ImageBitmap (Secondary Attempt)...');
|
||||
const response = await fetch(absolutePath);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status} for ${absolutePath}`);
|
||||
}
|
||||
const svgText = await response.text();
|
||||
const blob = new Blob([svgText], { type: 'image/svg+xml' });
|
||||
objectURL = URL.createObjectURL(blob);
|
||||
const intermediateImg = new Image();
|
||||
await new Promise((resolve, reject) => {
|
||||
intermediateImg.onload = () => resolve();
|
||||
intermediateImg.onerror = () => reject(new Error('Intermediate Image() load failed for SVG blob (Secondary).'));
|
||||
intermediateImg.src = objectURL;
|
||||
});
|
||||
this.kofiCupImageBitmap = await createImageBitmap(intermediateImg);
|
||||
this.kofiImageLoaded = true;
|
||||
console.log('Ko-fi symbol SVG processed to ImageBitmap successfully (Secondary).');
|
||||
}
|
||||
catch (error) {
|
||||
this.kofiImageLoaded = false;
|
||||
this.kofiCupImageBitmap = null;
|
||||
console.error('All Ko-fi SVG load attempts failed: ', error, '. Will use fallback drawing.');
|
||||
}
|
||||
finally {
|
||||
if (objectURL) {
|
||||
URL.revokeObjectURL(objectURL);
|
||||
}
|
||||
}
|
||||
},
|
||||
renderAllInModal: async function (modalContentElement) {
|
||||
if (!this.kofiImageLoadAttempted) {
|
||||
await this._preloadKofiImage();
|
||||
}
|
||||
const noiseCanvases = modalContentElement.querySelectorAll('.noise-canvas');
|
||||
noiseCanvases.forEach(canvasDiv => {
|
||||
const canvasId = canvasDiv.id;
|
||||
@@ -209,50 +143,6 @@ if (!window.NoiseVisualizer) {
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
return ctx;
|
||||
},
|
||||
_drawKofiIcon: function (ctx) {
|
||||
const iconSize = 18;
|
||||
const padding = 3;
|
||||
const x = ctx.canvas.width - iconSize - padding;
|
||||
const y = ctx.canvas.height - iconSize - padding;
|
||||
if (this.kofiImageLoaded && this.kofiCupImageBitmap) {
|
||||
try {
|
||||
ctx.drawImage(this.kofiCupImageBitmap, x, y, iconSize, iconSize);
|
||||
}
|
||||
catch (e) {
|
||||
console.error('Error drawing local Ko-fi SVG ImageBitmap, falling back to manual draw:', e);
|
||||
this._drawManualKofiCup(ctx, x, y, iconSize);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this._drawManualKofiCup(ctx, x, y, iconSize);
|
||||
}
|
||||
},
|
||||
_drawManualKofiCup: function (ctx, x, y, iconSize) {
|
||||
ctx.save();
|
||||
ctx.fillStyle = '#FFDD99';
|
||||
ctx.strokeStyle = '#D2B48C';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x, y + iconSize * 0.2);
|
||||
ctx.lineTo(x, y + iconSize * 0.9);
|
||||
ctx.quadraticCurveTo(x + iconSize * 0.5, y + iconSize * 1.1, x + iconSize, y + iconSize * 0.9);
|
||||
ctx.lineTo(x + iconSize, y + iconSize * 0.2);
|
||||
ctx.quadraticCurveTo(x + iconSize * 0.5, y, x, y + iconSize * 0.2);
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.beginPath();
|
||||
ctx.arc(x + iconSize * 0.9, y + iconSize * 0.5, iconSize * 0.25, -Math.PI / 2, Math.PI / 2);
|
||||
ctx.stroke();
|
||||
ctx.strokeStyle = '#FFFFFF';
|
||||
ctx.lineWidth = 0.5;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x + iconSize * 0.3, y + iconSize * 0.1);
|
||||
ctx.quadraticCurveTo(x + iconSize * 0.2, y - iconSize * 0.2, x + iconSize * 0.4, y - iconSize * 0.3);
|
||||
ctx.moveTo(x + iconSize * 0.6, y + iconSize * 0.05);
|
||||
ctx.quadraticCurveTo(x + iconSize * 0.5, y - iconSize * 0.3, x + iconSize * 0.7, y - iconSize * 0.4);
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
},
|
||||
renderPlaceholder: function (canvas, noiseName) {
|
||||
const ctx = this._clearCanvas(canvas, '#2c2c34');
|
||||
const nameToShow = noiseName.split(' ').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' ');
|
||||
@@ -306,7 +196,6 @@ if (!window.NoiseVisualizer) {
|
||||
ctx.fillRect(x, y, 4, 4);
|
||||
}
|
||||
}
|
||||
this._drawKofiIcon(ctx.canvas.getContext('2d'));
|
||||
},
|
||||
renderDomainWarp: function (canvas) {
|
||||
const ctx = this._clearCanvas(canvas);
|
||||
@@ -353,7 +242,6 @@ if (!window.NoiseVisualizer) {
|
||||
ctx.fillRect(x, y, 2, 2);
|
||||
}
|
||||
}
|
||||
this._drawKofiIcon(ctx.canvas.getContext('2d'));
|
||||
},
|
||||
renderPerlin: function (canvas) {
|
||||
const ctx = this._clearCanvas(canvas);
|
||||
@@ -365,7 +253,6 @@ if (!window.NoiseVisualizer) {
|
||||
ctx.fillRect(x, y, 3, 3);
|
||||
}
|
||||
}
|
||||
this._drawKofiIcon(ctx.canvas.getContext('2d'));
|
||||
},
|
||||
renderWaves: function (canvas) {
|
||||
const ctx = this._clearCanvas(canvas);
|
||||
@@ -381,7 +268,6 @@ if (!window.NoiseVisualizer) {
|
||||
}
|
||||
ctx.stroke();
|
||||
}
|
||||
this._drawKofiIcon(ctx.canvas.getContext('2d'));
|
||||
},
|
||||
renderGaussian: function (canvas) {
|
||||
const ctx = this._clearCanvas(canvas);
|
||||
@@ -392,7 +278,6 @@ if (!window.NoiseVisualizer) {
|
||||
ctx.fillStyle = `rgba(${intensity * 0.8}, ${intensity * 0.9}, ${intensity}, ${Math.random() * 0.5 + 0.1})`;
|
||||
ctx.fillRect(x - 1, y - 1, 2, 2);
|
||||
}
|
||||
this._drawKofiIcon(ctx.canvas.getContext('2d'));
|
||||
},
|
||||
renderHeterogeneousFBM: function (canvas) {
|
||||
const ctx = this._clearCanvas(canvas);
|
||||
@@ -409,7 +294,6 @@ if (!window.NoiseVisualizer) {
|
||||
}
|
||||
}
|
||||
}
|
||||
this._drawKofiIcon(ctx.canvas.getContext('2d'));
|
||||
},
|
||||
renderInterference: function (canvas) {
|
||||
const ctx = this._clearCanvas(canvas);
|
||||
@@ -430,7 +314,6 @@ if (!window.NoiseVisualizer) {
|
||||
ctx.fillRect(x, y, 3, 3);
|
||||
}
|
||||
}
|
||||
this._drawKofiIcon(ctx.canvas.getContext('2d'));
|
||||
},
|
||||
renderSpectral: function (canvas) {
|
||||
const ctx = this._clearCanvas(canvas);
|
||||
@@ -442,7 +325,6 @@ if (!window.NoiseVisualizer) {
|
||||
ctx.strokeStyle = 'rgba(0,0,0,0.2)';
|
||||
ctx.strokeRect(0, i, canvas.width, 4);
|
||||
}
|
||||
this._drawKofiIcon(ctx.canvas.getContext('2d'));
|
||||
},
|
||||
renderProjection3D: function (canvas) {
|
||||
const ctx = this._clearCanvas(canvas);
|
||||
@@ -457,7 +339,6 @@ if (!window.NoiseVisualizer) {
|
||||
ctx.arc(x, y, size, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
}
|
||||
this._drawKofiIcon(ctx.canvas.getContext('2d'));
|
||||
},
|
||||
renderCurlNoise: function (canvas) {
|
||||
const ctx = this._clearCanvas(canvas);
|
||||
@@ -937,15 +818,6 @@ if (!window.NoiseVisualizer) {
|
||||
}
|
||||
};
|
||||
window.NoiseVisualizer = NoiseVisualizer;
|
||||
// Use local reference for type safety
|
||||
if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
||||
(async () => { await NoiseVisualizer._preloadKofiImage(); })();
|
||||
}
|
||||
else {
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
await NoiseVisualizer._preloadKofiImage();
|
||||
});
|
||||
}
|
||||
}
|
||||
export {};
|
||||
//# sourceMappingURL=noise_visualizer.js.map
|
||||
@@ -1406,7 +1406,6 @@ interface ButtonWidget extends IWidget {
|
||||
<div class="noise-canvas" id="noise-canvas-cellular"></div>
|
||||
<div class="noise-name">Cellular</div>
|
||||
<div class="noise-description">Creates organic, cell-like structures through Voronoi diagrams, mimicking natural growth patterns.</div>
|
||||
<div style="margin-top: 5px; text-align: center;"><a href="https://ko-fi.com/aemotionstudio" target="_blank" rel="noopener noreferrer"><img src="https://ko-fi.com/img/githubbutton_sm.svg" alt="Support me on Ko-fi" style="height: 22px; border:0px;"/></a></div>
|
||||
</div>
|
||||
<div class="noise-item">
|
||||
<div class="noise-canvas" id="noise-canvas-domain_warp"></div>
|
||||
@@ -1417,49 +1416,41 @@ interface ButtonWidget extends IWidget {
|
||||
<div class="noise-canvas" id="noise-canvas-fractal"></div>
|
||||
<div class="noise-name">Fractal</div>
|
||||
<div class="noise-description">Embodies self-similarity across scales, reflecting the infinite recursive patterns found throughout nature.</div>
|
||||
<div style="margin-top: 5px; text-align: center;"><a href="https://ko-fi.com/aemotionstudio" target="_blank" rel="noopener noreferrer"><img src="https://ko-fi.com/img/githubbutton_sm.svg" alt="Support me on Ko-fi" style="height: 22px; border:0px;"/></a></div>
|
||||
</div>
|
||||
<div class="noise-item">
|
||||
<div class="noise-canvas" id="noise-canvas-perlin"></div>
|
||||
<div class="noise-name">Perlin</div>
|
||||
<div class="noise-description">The classic gradient noise that creates smooth, natural-looking transitions and flowing textures.</div>
|
||||
<div style="margin-top: 5px; text-align: center;"><a href="https://ko-fi.com/aemotionstudio" target="_blank" rel="noopener noreferrer"><img src="https://ko-fi.com/img/githubbutton_sm.svg" alt="Support me on Ko-fi" style="height: 22px; border:0px;"/></a></div>
|
||||
</div>
|
||||
<div class="noise-item">
|
||||
<div class="noise-canvas" id="noise-canvas-waves"></div>
|
||||
<div class="noise-name">Waves</div>
|
||||
<div class="noise-description">Generates harmonic oscillations that combine to form complex interference patterns.</div>
|
||||
<div style="margin-top: 5px; text-align: center;"><a href="https://ko-fi.com/aemotionstudio" target="_blank" rel="noopener noreferrer"><img src="https://ko-fi.com/img/githubbutton_sm.svg" alt="Support me on Ko-fi" style="height: 22px; border:0px;"/></a></div>
|
||||
</div>
|
||||
<div class="noise-item">
|
||||
<div class="noise-canvas" id="noise-canvas-gaussian"></div>
|
||||
<div class="noise-name">Gaussian</div>
|
||||
<div class="noise-description">Pure probabilistic noise based on the normal distribution, the foundation of natural randomness.</div>
|
||||
<div style="margin-top: 5px; text-align: center;"><a href="https://ko-fi.com/aemotionstudio" target="_blank" rel="noopener noreferrer"><img src="https://ko-fi.com/img/githubbutton_sm.svg" alt="Support me on Ko-fi" style="height: 22px; border:0px;"/></a></div>
|
||||
</div>
|
||||
<div class="noise-item">
|
||||
<div class="noise-canvas" id="noise-canvas-heterogeneous_fbm"></div>
|
||||
<div class="noise-name">Heterogeneous FBM</div>
|
||||
<div class="noise-description">Varies the fractal dimension across space, creating regions of different turbulence and detail.</div>
|
||||
<div style="margin-top: 5px; text-align: center;"><a href="https://ko-fi.com/aemotionstudio" target="_blank" rel="noopener noreferrer"><img src="https://ko-fi.com/img/githubbutton_sm.svg" alt="Support me on Ko-fi" style="height: 22px; border:0px;"/></a></div>
|
||||
</div>
|
||||
<div class="noise-item">
|
||||
<div class="noise-canvas" id="noise-canvas-interference"></div>
|
||||
<div class="noise-name">Interference</div>
|
||||
<div class="noise-description">Simulates wave interaction patterns, creating complex nodal structures through phase relationships.</div>
|
||||
<div style="margin-top: 5px; text-align: center;"><a href="https://ko-fi.com/aemotionstudio" target="_blank" rel="noopener noreferrer"><img src="https://ko-fi.com/img/githubbutton_sm.svg" alt="Support me on Ko-fi" style="height: 22px; border:0px;"/></a></div>
|
||||
</div>
|
||||
<div class="noise-item">
|
||||
<div class="noise-canvas" id="noise-canvas-spectral"></div>
|
||||
<div class="noise-name">Spectral</div>
|
||||
<div class="noise-description">Controls the frequency spectrum directly, allowing precise frequency band manipulation.</div>
|
||||
<div style="margin-top: 5px; text-align: center;"><a href="https://ko-fi.com/aemotionstudio" target="_blank" rel="noopener noreferrer"><img src="https://ko-fi.com/img/githubbutton_sm.svg" alt="Support me on Ko-fi" style="height: 22px; border:0px;"/></a></div>
|
||||
</div>
|
||||
<div class="noise-item">
|
||||
<div class="noise-canvas" id="noise-canvas-projection_3d"></div>
|
||||
<div class="noise-name">3D Projection</div>
|
||||
<div class="noise-description">Projects three-dimensional noise onto a 2D plane, creating depth and volumetric effects.</div>
|
||||
<div style="margin-top: 5px; text-align: center;"><a href="https://ko-fi.com/aemotionstudio" target="_blank" rel="noopener noreferrer"><img src="https://ko-fi.com/img/githubbutton_sm.svg" alt="Support me on Ko-fi" style="height: 22px; border:0px;"/></a></div>
|
||||
</div>
|
||||
<div class="noise-item">
|
||||
<div class="noise-canvas" id="noise-canvas-curl_noise"></div>
|
||||
@@ -1469,10 +1460,6 @@ interface ButtonWidget extends IWidget {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="card" style="text-align: center; margin-top: calc(var(--section-padding) * 1.2); padding: calc(var(--section-padding) * 0.9); background: linear-gradient(145deg, rgba(var(--accent-color-rgb, 138, 43, 226), 0.1), rgba(var(--secondary-color-rgb, 52, 152, 219), 0.05)); border: 1px solid var(--accent-color); border-radius: 12px; box-shadow: 0 4px 20px rgba(var(--accent-color-rgb, 138, 43, 226), 0.2);">
|
||||
<h3 style="color: var(--accent-color); text-shadow: 0 0 8px rgba(var(--accent-color-rgb, 138, 43, 226), 0.5); margin-bottom: 0.7rem; font-size: 1.4rem;">🌟 Unlock Exclusive Shader Noise Palettes!</h3>
|
||||
<p style="font-size: 0.95rem; margin-bottom: 0rem; opacity: 0.9; line-height: 1.5;">Become a valued member to access an expanded library of unique shader noise archetypes, advanced shader features, and custom ComfyUI tools. Your support helps fuel further development!</p>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
@@ -1599,7 +1586,7 @@ interface ButtonWidget extends IWidget {
|
||||
result = torch.zeros(batch_size, height, width, 1, device=device)
|
||||
|
||||
# Generate cellular pattern based on octaves mode
|
||||
pattern_type = int(octaves) % 4 # Use octaves to select pattern type
|
||||
pattern_type = (max(int(octaves), 1) - 1) % 4 # octaves 1 is F1, the node's default
|
||||
|
||||
# Calculate F1 and F2 distances (assuming compute_feature_distances exists)
|
||||
f1, f2 = compute_feature_distances(p * scale, seed)
|
||||
|
||||
@@ -39,14 +39,8 @@ interface BackgroundPattern {
|
||||
type PatternType = 'tensor_field' | 'cellular' | 'domain_warp' | 'perlin' | 'curl_noise' | 'waves_interference';
|
||||
|
||||
interface NoiseVisualizerInterface {
|
||||
kofiCupImageBitmap: HTMLImageElement | ImageBitmap | null;
|
||||
kofiImageLoaded: boolean;
|
||||
kofiImageLoadAttempted: boolean;
|
||||
_preloadKofiImage: () => Promise<void>;
|
||||
renderAllInModal: (modalContentElement: HTMLElement) => Promise<void>;
|
||||
_clearCanvas: (canvas: HTMLCanvasElement, backgroundColor?: string) => CanvasRenderingContext2D;
|
||||
_drawKofiIcon: (ctx: CanvasRenderingContext2D) => void;
|
||||
_drawManualKofiCup: (ctx: CanvasRenderingContext2D, x: number, y: number, iconSize: number) => void;
|
||||
renderPlaceholder: (canvas: HTMLCanvasElement, noiseName: string) => void;
|
||||
// Noise visualizations
|
||||
renderTensorField: (canvas: HTMLCanvasElement) => void;
|
||||
@@ -116,77 +110,7 @@ declare global {
|
||||
|
||||
if (!window.NoiseVisualizer) {
|
||||
const NoiseVisualizer: NoiseVisualizerInterface = {
|
||||
kofiCupImageBitmap: null,
|
||||
kofiImageLoaded: false,
|
||||
kofiImageLoadAttempted: false,
|
||||
|
||||
_preloadKofiImage: async function (): Promise<void> {
|
||||
if (this.kofiImageLoadAttempted) return;
|
||||
this.kofiImageLoadAttempted = true;
|
||||
|
||||
const absolutePath = '/extensions/comfyui-shadernoiseksampler/images/kofi_symbol.svg';
|
||||
|
||||
// Attempt 1: Direct Image load
|
||||
try {
|
||||
console.log('Attempting Ko-fi SVG load using new Image() with direct path (Primary Attempt)...');
|
||||
const img = new Image();
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
img.onload = (): void => {
|
||||
this.kofiCupImageBitmap = img;
|
||||
this.kofiImageLoaded = true;
|
||||
console.log('Ko-fi symbol SVG loaded via Image() successfully (Primary).');
|
||||
resolve();
|
||||
};
|
||||
img.onerror = (e): void => {
|
||||
console.warn('Primary Ko-fi symbol SVG load via Image() failed. Proceeding to secondary attempt.', e);
|
||||
reject(e);
|
||||
};
|
||||
img.src = absolutePath;
|
||||
});
|
||||
return;
|
||||
} catch {
|
||||
this.kofiImageLoaded = false;
|
||||
this.kofiCupImageBitmap = null;
|
||||
}
|
||||
|
||||
// Attempt 2: Fetch -> Blob -> Intermediate Image -> ImageBitmap
|
||||
let objectURL: string | null = null;
|
||||
try {
|
||||
console.log('Attempting Ko-fi SVG load via Blob -> Image -> ImageBitmap (Secondary Attempt)...');
|
||||
const response = await fetch(absolutePath);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status} for ${absolutePath}`);
|
||||
}
|
||||
const svgText = await response.text();
|
||||
const blob = new Blob([svgText], { type: 'image/svg+xml' });
|
||||
objectURL = URL.createObjectURL(blob);
|
||||
|
||||
const intermediateImg = new Image();
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
intermediateImg.onload = (): void => resolve();
|
||||
intermediateImg.onerror = (): void => reject(new Error('Intermediate Image() load failed for SVG blob (Secondary).'));
|
||||
intermediateImg.src = objectURL!;
|
||||
});
|
||||
|
||||
this.kofiCupImageBitmap = await createImageBitmap(intermediateImg);
|
||||
this.kofiImageLoaded = true;
|
||||
console.log('Ko-fi symbol SVG processed to ImageBitmap successfully (Secondary).');
|
||||
} catch (error) {
|
||||
this.kofiImageLoaded = false;
|
||||
this.kofiCupImageBitmap = null;
|
||||
console.error('All Ko-fi SVG load attempts failed: ', error, '. Will use fallback drawing.');
|
||||
} finally {
|
||||
if (objectURL) {
|
||||
URL.revokeObjectURL(objectURL);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
renderAllInModal: async function (modalContentElement: HTMLElement): Promise<void> {
|
||||
if (!this.kofiImageLoadAttempted) {
|
||||
await this._preloadKofiImage();
|
||||
}
|
||||
|
||||
const noiseCanvases = modalContentElement.querySelectorAll('.noise-canvas');
|
||||
noiseCanvases.forEach(canvasDiv => {
|
||||
const canvasId = canvasDiv.id;
|
||||
@@ -326,55 +250,6 @@ if (!window.NoiseVisualizer) {
|
||||
return ctx;
|
||||
},
|
||||
|
||||
_drawKofiIcon: function (ctx: CanvasRenderingContext2D): void {
|
||||
const iconSize = 18;
|
||||
const padding = 3;
|
||||
const x = ctx.canvas.width - iconSize - padding;
|
||||
const y = ctx.canvas.height - iconSize - padding;
|
||||
|
||||
if (this.kofiImageLoaded && this.kofiCupImageBitmap) {
|
||||
try {
|
||||
ctx.drawImage(this.kofiCupImageBitmap, x, y, iconSize, iconSize);
|
||||
} catch (e) {
|
||||
console.error('Error drawing local Ko-fi SVG ImageBitmap, falling back to manual draw:', e);
|
||||
this._drawManualKofiCup(ctx, x, y, iconSize);
|
||||
}
|
||||
} else {
|
||||
this._drawManualKofiCup(ctx, x, y, iconSize);
|
||||
}
|
||||
},
|
||||
|
||||
_drawManualKofiCup: function (ctx: CanvasRenderingContext2D, x: number, y: number, iconSize: number): void {
|
||||
ctx.save();
|
||||
ctx.fillStyle = '#FFDD99';
|
||||
ctx.strokeStyle = '#D2B48C';
|
||||
ctx.lineWidth = 1;
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x, y + iconSize * 0.2);
|
||||
ctx.lineTo(x, y + iconSize * 0.9);
|
||||
ctx.quadraticCurveTo(x + iconSize * 0.5, y + iconSize * 1.1, x + iconSize, y + iconSize * 0.9);
|
||||
ctx.lineTo(x + iconSize, y + iconSize * 0.2);
|
||||
ctx.quadraticCurveTo(x + iconSize * 0.5, y, x, y + iconSize * 0.2);
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(x + iconSize * 0.9, y + iconSize * 0.5, iconSize * 0.25, -Math.PI / 2, Math.PI / 2);
|
||||
ctx.stroke();
|
||||
|
||||
ctx.strokeStyle = '#FFFFFF';
|
||||
ctx.lineWidth = 0.5;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x + iconSize * 0.3, y + iconSize * 0.1);
|
||||
ctx.quadraticCurveTo(x + iconSize * 0.2, y - iconSize * 0.2, x + iconSize * 0.4, y - iconSize * 0.3);
|
||||
ctx.moveTo(x + iconSize * 0.6, y + iconSize * 0.05);
|
||||
ctx.quadraticCurveTo(x + iconSize * 0.5, y - iconSize * 0.3, x + iconSize * 0.7, y - iconSize * 0.4);
|
||||
ctx.stroke();
|
||||
|
||||
ctx.restore();
|
||||
},
|
||||
|
||||
renderPlaceholder: function (canvas: HTMLCanvasElement, noiseName: string): void {
|
||||
const ctx = this._clearCanvas(canvas, '#2c2c34');
|
||||
const nameToShow = noiseName.split(' ').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' ');
|
||||
@@ -431,7 +306,6 @@ if (!window.NoiseVisualizer) {
|
||||
ctx.fillRect(x, y, 4, 4);
|
||||
}
|
||||
}
|
||||
this._drawKofiIcon(ctx.canvas.getContext('2d')!);
|
||||
},
|
||||
|
||||
renderDomainWarp: function (canvas: HTMLCanvasElement): void {
|
||||
@@ -483,7 +357,6 @@ if (!window.NoiseVisualizer) {
|
||||
ctx.fillRect(x, y, 2, 2);
|
||||
}
|
||||
}
|
||||
this._drawKofiIcon(ctx.canvas.getContext('2d')!);
|
||||
},
|
||||
|
||||
renderPerlin: function (canvas: HTMLCanvasElement): void {
|
||||
@@ -496,7 +369,6 @@ if (!window.NoiseVisualizer) {
|
||||
ctx.fillRect(x, y, 3, 3);
|
||||
}
|
||||
}
|
||||
this._drawKofiIcon(ctx.canvas.getContext('2d')!);
|
||||
},
|
||||
|
||||
renderWaves: function (canvas: HTMLCanvasElement): void {
|
||||
@@ -513,7 +385,6 @@ if (!window.NoiseVisualizer) {
|
||||
}
|
||||
ctx.stroke();
|
||||
}
|
||||
this._drawKofiIcon(ctx.canvas.getContext('2d')!);
|
||||
},
|
||||
|
||||
renderGaussian: function (canvas: HTMLCanvasElement): void {
|
||||
@@ -525,7 +396,6 @@ if (!window.NoiseVisualizer) {
|
||||
ctx.fillStyle = `rgba(${intensity * 0.8}, ${intensity * 0.9}, ${intensity}, ${Math.random() * 0.5 + 0.1})`;
|
||||
ctx.fillRect(x - 1, y - 1, 2, 2);
|
||||
}
|
||||
this._drawKofiIcon(ctx.canvas.getContext('2d')!);
|
||||
},
|
||||
|
||||
renderHeterogeneousFBM: function (canvas: HTMLCanvasElement): void {
|
||||
@@ -543,7 +413,6 @@ if (!window.NoiseVisualizer) {
|
||||
}
|
||||
}
|
||||
}
|
||||
this._drawKofiIcon(ctx.canvas.getContext('2d')!);
|
||||
},
|
||||
|
||||
renderInterference: function (canvas: HTMLCanvasElement): void {
|
||||
@@ -565,7 +434,6 @@ if (!window.NoiseVisualizer) {
|
||||
ctx.fillRect(x, y, 3, 3);
|
||||
}
|
||||
}
|
||||
this._drawKofiIcon(ctx.canvas.getContext('2d')!);
|
||||
},
|
||||
|
||||
renderSpectral: function (canvas: HTMLCanvasElement): void {
|
||||
@@ -578,7 +446,6 @@ if (!window.NoiseVisualizer) {
|
||||
ctx.strokeStyle = 'rgba(0,0,0,0.2)';
|
||||
ctx.strokeRect(0, i, canvas.width, 4);
|
||||
}
|
||||
this._drawKofiIcon(ctx.canvas.getContext('2d')!);
|
||||
},
|
||||
|
||||
renderProjection3D: function (canvas: HTMLCanvasElement): void {
|
||||
@@ -594,7 +461,6 @@ if (!window.NoiseVisualizer) {
|
||||
ctx.arc(x, y, size, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
}
|
||||
this._drawKofiIcon(ctx.canvas.getContext('2d')!);
|
||||
},
|
||||
|
||||
renderCurlNoise: function (canvas: HTMLCanvasElement): void {
|
||||
@@ -1168,13 +1034,4 @@ if (!window.NoiseVisualizer) {
|
||||
};
|
||||
|
||||
window.NoiseVisualizer = NoiseVisualizer;
|
||||
|
||||
// Use local reference for type safety
|
||||
if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
||||
(async (): Promise<void> => { await NoiseVisualizer._preloadKofiImage(); })();
|
||||
} else {
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
await NoiseVisualizer._preloadKofiImage();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,10 +31,6 @@ describe('NoiseVisualizer', () => {
|
||||
expect(typeof window.NoiseVisualizer?.renderAllInModal).toBe('function');
|
||||
});
|
||||
|
||||
it('should have kofi image properties', () => {
|
||||
expect(window.NoiseVisualizer).toHaveProperty('kofiImageLoaded');
|
||||
expect(window.NoiseVisualizer).toHaveProperty('kofiImageLoadAttempted');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Canvas Rendering Methods', () => {
|
||||
@@ -132,26 +128,6 @@ describe('NoiseVisualizer', () => {
|
||||
const result = (window.NoiseVisualizer as any)?._clearCanvas(canvas);
|
||||
expect(result).toBeDefined();
|
||||
});
|
||||
|
||||
it('should have _drawKofiIcon method', () => {
|
||||
expect(typeof window.NoiseVisualizer?._drawKofiIcon).toBe('function');
|
||||
});
|
||||
|
||||
it('should draw Ko-fi icon without errors', () => {
|
||||
expect(() => {
|
||||
(window.NoiseVisualizer as any)?._drawKofiIcon(ctx);
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it('should have _drawManualKofiCup method', () => {
|
||||
expect(typeof window.NoiseVisualizer?._drawManualKofiCup).toBe('function');
|
||||
});
|
||||
|
||||
it('should draw manual Ko-fi cup without errors', () => {
|
||||
expect(() => {
|
||||
(window.NoiseVisualizer as any)?._drawManualKofiCup(ctx, 10, 10, 18);
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('renderAllInModal', () => {
|
||||
|
||||
Reference in New Issue
Block a user