moire: make the starfield its own pattern, with depth and halos

c2e4eb1 · Gabriel Morell · 2026-09-29 21:33

13 files +29 -31
Message
{commit_body(@commit)}

Files changed

modified README.md
+4 −4
@@ -53,12 +53,12 @@ adds to its size.
53 53
54 54 `plasma-wallpaper-neiam-moire` is a Plasma wallpaper plugin ("neiam
55 55 moire" under *Wallpaper type*, for the desktop or the lock screen)
56 −that draws its patterns live: the moire, a halftone field, both, or
56 +that draws its patterns live: the moire, a halftone field, both,
57 57 bokeh (soft out-of-focus discs drifting upward and fading in and out
58 58 as they rise, 4 to 64 of them, each its own shade from the primary
59 −towards the accent and from muted to vivid). It can also fade back and
60 −forth between any two of those every few minutes. Effects, each a checkbox and usable with any pattern: twinkling stars
61 −behind it; a glint, a band of light sweeping across the rings and dots
59 +towards the accent and from muted to vivid), or a starfield (sparse
60 +stars, mostly faint and a few bright, each twinkling at its own rate). It can also fade back and
61 +forth between any two of those every few minutes. Effects, each a checkbox and usable with any pattern: a glint, a band of light sweeping across the rings and dots
62 62 every minute and a half; breathing, the pattern slowly swelling and
63 63 easing; a few large defocused discs drifting past in front now and
64 64 then, like a light close to the lens; film grain; and dither (on by
modified moire/shaders/field.frag
+16 −8
@@ -82,21 +82,29 @@ float hash12(vec2 p)
82 82 // Stars on a jittered grid, most faint and a few bright, each
83 83 // twinkling at a whole multiple of the twinkle phase so the wrap is
84 84 // seamless. A star sits well inside its cell, so only one cell needs
85 −// checking per pixel.
86 −float starLight(vec2 p, float px)
85 +// checking per pixel. The brightest carry a soft halo.
86 +float starLayer(vec2 p, float px, float spacing, float salt)
87 87 {
88 − const float spacing = 0.035;
89 − vec2 id = floor(p / spacing);
90 − if (hash12(id) > 0.4)
91 − return 0.0; // 40% of cells hold a star
92 − vec2 at = (id + 0.15 + 0.7 * vec2(hash12(id + 17.0), hash12(id + 31.0))) * spacing;
88 + vec2 id = floor(p / spacing) + salt;
89 + if (hash12(id) > 0.45)
90 + return 0.0; // 45% of cells hold a star
91 + vec2 at = (floor(p / spacing) + 0.15 + 0.7 * vec2(hash12(id + 17.0), hash12(id + 31.0))) * spacing;
93 92 float bright = hash12(id + 47.0);
94 93 bright *= bright;
95 94 float rate = 1.0 + floor(hash12(id + 59.0) * 4.0);
96 95 float shimmer = 0.55 + 0.45 * sin(6.2831853 * (rate * twinkle + hash12(id + 71.0)));
97 96 float r = px * (0.8 + 1.4 * bright);
98 97 float d = length(p - at);
99 − return exp(-d * d / (r * r)) * (0.25 + 0.75 * bright) * shimmer;
98 + float core = exp(-d * d / (r * r)) * (0.25 + 0.75 * bright);
99 + float halo = exp(-d / (7.0 * px)) * 0.18 * bright * bright * bright;
100 + return (core + halo) * shimmer;
101 +}
102 +
103 +// Two layers: the stars proper, and a denser scatter of fainter,
104 +// smaller ones behind them that gives the field depth.
105 +float starLight(vec2 p, float px)
106 +{
107 + return starLayer(p, px, 0.035, 0.0) + 0.4 * starLayer(p, px, 0.016, 113.0);
100 108 }
101 109
102 110 // A band of light sweeping diagonally across the screen during the
modified moire/theme/contents/config/main.xml
+2 −6
@@ -7,11 +7,11 @@
7 7
8 8 <group name="General">
9 9 <entry name="Pattern" type="String">
10 − <label>moire, halftone, both, bokeh, or alternate</label>
10 + <label>moire, halftone, both, bokeh, stars, or alternate</label>
11 11 <default>both</default>
12 12 </entry>
13 13 <entry name="FadeFrom" type="String">
14 − <label>With Pattern alternate, the pattern faded from: moire, halftone, both, or bokeh</label>
14 + <label>With Pattern alternate, the pattern faded from: moire, halftone, both, bokeh, or stars</label>
15 15 <default>moire</default>
16 16 </entry>
17 17 <entry name="FadeTo" type="String">
@@ -35,10 +35,6 @@
35 35 <label>Now and then, large defocused lights drifting past in front</label>
36 36 <default>false</default>
37 37 </entry>
38 − <entry name="Stars" type="Bool">
39 − <label>Twinkling stars behind the pattern</label>
40 − <default>false</default>
41 − </entry>
42 38 <entry name="Glints" type="Bool">
43 39 <label>A band of light sweeping across the rings and dots now and then</label>
44 40 <default>false</default>
modified moire/theme/contents/ui/Field.qml
+6 −6
@@ -10,16 +10,15 @@ import QtQuick 2.15
10 10 Item {
11 11 id: field
12 12
13 − // "moire", "halftone", "both" (moire over halftone), "bokeh", or
14 − // "alternate": fading between fadeFrom and fadeTo, which are any of
15 − // the others, every few minutes.
13 + // "moire", "halftone", "both" (moire over halftone), "bokeh",
14 + // "stars", or "alternate": fading between fadeFrom and fadeTo, which
15 + // are any of the others, every few minutes.
16 16 property string pattern: "both"
17 17 property string fadeFrom: "moire"
18 18 property string fadeTo: "halftone"
19 19 property int bokehLights: 14
20 20 // Now and then, a few large defocused discs drifting past in front.
21 21 property bool foreground: false
22 − property bool stars: false
23 22 property bool glints: false
24 23 property bool breathing: false
25 24 property bool grain: false
@@ -56,6 +55,7 @@ Item {
56 55 moire: name === "moire" || name === "both" ? 1 : 0,
57 56 halftone: name === "halftone" || name === "both" ? 1 : 0,
58 57 bokeh: name === "bokeh" ? 1 : 0,
58 + stars: name === "stars" ? 1 : 0,
59 59 }
60 60 }
61 61
@@ -108,23 +108,23 @@ Item {
108 108 property real moire: field.amount("moire")
109 109 property real halftone: field.amount("halftone")
110 110 property real bokeh: field.amount("bokeh")
111 + property real stars: field.amount("stars")
111 112 property real lights: field.bokehLights
112 113 property real flare: field.foreground ? 1 : 0
113 114 Behavior on flare { NumberAnimation { duration: 1500 } }
114 115
115 − property real stars: field.stars ? 1 : 0
116 116 property real twinkle: (field.clock / 12) % 1
117 117 property real glints: field.glints ? 1 : 0
118 118 property real glintPhase: (field.clock / 90) % 1
119 119 property real grain: field.grain ? 1 : 0
120 120 property real dither: field.dither ? 1 : 0
121 121 property real seed: (field.frame * 0.618034) % 1
122 − Behavior on stars { NumberAnimation { duration: 1500 } }
123 122 Behavior on glints { NumberAnimation { duration: 1500 } }
124 123 Behavior on grain { NumberAnimation { duration: 1500 } }
125 124 Behavior on moire { enabled: field.pattern !== "alternate"; NumberAnimation { duration: 1500 } }
126 125 Behavior on halftone { enabled: field.pattern !== "alternate"; NumberAnimation { duration: 1500 } }
127 126 Behavior on bokeh { enabled: field.pattern !== "alternate"; NumberAnimation { duration: 1500 } }
127 + Behavior on stars { enabled: field.pattern !== "alternate"; NumberAnimation { duration: 1500 } }
128 128
129 129 property color base: field.base
130 130 property color deep: field.deep
modified moire/theme/contents/ui/config.qml
+1 −6
@@ -19,7 +19,6 @@ Kirigami.FormLayout {
19 19 property int cfg_FrameRate
20 20 property bool cfg_Wordmark
21 21 property bool cfg_ForegroundBokeh
22 − property bool cfg_Stars
23 22 property bool cfg_Glints
24 23 property bool cfg_Breathing
25 24 property bool cfg_Grain
@@ -42,6 +41,7 @@ Kirigami.FormLayout {
42 41 { value: "moire", text: "Moire" },
43 42 { value: "halftone", text: "Halftone" },
44 43 { value: "bokeh", text: "Bokeh" },
44 + { value: "stars", text: "Starfield" },
45 45 ]
46 46 readonly property var patterns: layers.concat([{ value: "alternate", text: "Fade between two…" }])
47 47
@@ -135,11 +135,6 @@ Kirigami.FormLayout {
135 135
136 136 QQC2.CheckBox {
137 137 Kirigami.FormData.label: "Effects:"
138 − text: "Twinkling stars"
139 − checked: root.cfg_Stars
140 − onToggled: root.cfg_Stars = checked
141 − }
142 − QQC2.CheckBox {
143 138 text: "Light glinting across the pattern"
144 139 checked: root.cfg_Glints
145 140 onToggled: root.cfg_Glints = checked
modified ?
+0 −0

Binary file — not rendered.

modified moire/theme/contents/ui/main.qml
+0 −1
@@ -33,7 +33,6 @@ WallpaperItem {
33 33 fadeTo: root.cfg.FadeTo
34 34 bokehLights: root.cfg.BokehLights
35 35 foreground: root.cfg.ForegroundBokeh
36 − stars: root.cfg.Stars
37 36 glints: root.cfg.Glints
38 37 breathing: root.cfg.Breathing
39 38 grain: root.cfg.Grain

Parents: cced89e