@srsdesigndev/pi-loader 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +107 -0
- package/dist/pi-loader.min.js +1 -0
- package/package.json +32 -0
- package/src/pi-loader.js +262 -0
package/README.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
ex# π Loader
|
|
2
|
+
|
|
3
|
+
A pi-driven generative art loader. No randomness library. No predefined colors. No loops. Just pure math.
|
|
4
|
+
|
|
5
|
+
Every bar height, every background color, and every opacity is determined by the next unused digit of π — computed live, used once, discarded forever.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## How It Works
|
|
10
|
+
|
|
11
|
+
Pi is infinite and non-repeating. This project uses that property as an infinite source of deterministic "randomness."
|
|
12
|
+
|
|
13
|
+
- **10 digits** → mapped to bar heights and opacities
|
|
14
|
+
- **6 digits** → combined into a hex color code for the background
|
|
15
|
+
- Digits 0, 1, 2 → low opacity bars (quiet)
|
|
16
|
+
- Digits 3–9 → full opacity bars (loud)
|
|
17
|
+
- Bar color flips black or white based on background luminance — always readable
|
|
18
|
+
- Every digit is used once and thrown away — never repeated, never stored
|
|
19
|
+
|
|
20
|
+
The algorithm used is the **Rabinowitz-Wagon spigot algorithm**, implemented in JavaScript using `BigInt` for arbitrary precision. It yields one digit of π at a time, forever.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Demo
|
|
25
|
+
|
|
26
|
+
Just open `pi-loader-color.html` in any modern browser. No dependencies. No build step. No install.
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
open pi-loader-color.html
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Files
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
pi-loader-color.html # Full standalone demo — bars + color bg
|
|
38
|
+
pi-loader.html # Minimal version — bars only, dark bg
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## The Algorithm
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
function* piSpigot() {
|
|
47
|
+
let q = 1n, r = 0n, t = 1n, k = 1n, n = 3n, l = 3n;
|
|
48
|
+
while (true) {
|
|
49
|
+
if (4n * q + r - t < n * t) {
|
|
50
|
+
yield Number(n);
|
|
51
|
+
const nr = 10n * (r - n * t);
|
|
52
|
+
n = 10n * (3n * q + r) / t - 10n * n;
|
|
53
|
+
q *= 10n;
|
|
54
|
+
r = nr;
|
|
55
|
+
} else {
|
|
56
|
+
const nr = (2n * q + r) * l;
|
|
57
|
+
const nn = (q * (7n * k) + 2n + r * l) / (t * l);
|
|
58
|
+
q *= k;
|
|
59
|
+
t *= l;
|
|
60
|
+
l += 2n;
|
|
61
|
+
k += 1n;
|
|
62
|
+
n = nn;
|
|
63
|
+
r = nr;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Reference: Rabinowitz, S. & Wagon, S. (1995). *A spigot algorithm for the digits of π.*
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Digit → Visual Mapping
|
|
74
|
+
|
|
75
|
+
| Digits consumed | Used for |
|
|
76
|
+
|---|---|
|
|
77
|
+
| 10 | Bar heights (`digit × 5.4 + 6` px) |
|
|
78
|
+
| 6 | Background hex color (`#d3a9f1` etc.) |
|
|
79
|
+
| **16 total** | Per frame |
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Why Pi?
|
|
84
|
+
|
|
85
|
+
Because it's free, infinite, and needs no seed. Most generative art uses `Math.random()` — which is pseudorandom, stateful, and resets. Pi never resets. Pi never repeats. Pi is already there, waiting.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Ideas / Roadmap
|
|
90
|
+
|
|
91
|
+
- [ ] Map digits to musical notes — a pi-driven melody
|
|
92
|
+
- [ ] Export frames as a GIF
|
|
93
|
+
- [ ] Web component `<pi-loader>`
|
|
94
|
+
- [ ] Configurable bar count, speed, color palette
|
|
95
|
+
- [ ] Visualize digit distribution over time
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## License
|
|
100
|
+
|
|
101
|
+
MIT — do whatever you want with it.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Author
|
|
106
|
+
|
|
107
|
+
Built with curiosity and π.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
!function(){"use strict";const t=function*(){let t=1n,e=0n,n=1n,s=1n,i=3n,r=3n;for(;;)if(4n*t+e-n<i*n){yield Number(i);const s=10n*(e-i*n);i=10n*(3n*t+e)/n-10n*i,t*=10n,e=s}else{const a=(2n*t+e)*r,o=(t*(7n*s)+2n+e*r)/(n*r);t*=s,n*=r,r+=2n,s+=1n,i=o,e=a}}();function e(e){const n=[];for(let s=0;s<e;s++)n.push(t.next().value);return n}const n=new Set;let s=null;function i(t){n.forEach(e=>{e._visible&&t-e._lastFrame>=e._interval&&(e._frame(),e._lastFrame=t)}),s=requestAnimationFrame(i)}function r(t,e,n,s,i){const r=t.getAttribute(e);if(null===r)return n;const a=parseFloat(r);return isNaN(a)?n:void 0!==s?function(t,e,n){return Math.min(Math.max(t,e),n)}(a,s,i):a}class a extends HTMLElement{constructor(){super(),this._shadow=this.attachShadow({mode:"open"}),this._bars=[],this._wrapper=null,this._visible=!1,this._lastFrame=0,this._interval=600,this._observer=null}static get observedAttributes(){return["bars","min-height","max-height","width","gap","speed","radius","color","bg","low-opacity","theme","align"]}get config(){return{bars:r(this,"bars",10,3,20),minH:r(this,"min-height",6,1,200),maxH:r(this,"max-height",60,10,400),width:r(this,"width",10,2,100),gap:r(this,"gap",6,0,100),speed:r(this,"speed",600,80,5e3),radius:r(this,"radius",999,0,999),color:this.getAttribute("color")||"auto",bg:this.getAttribute("bg")||"transparent",lowOpacity:r(this,"low-opacity",.2,0,1),theme:this.getAttribute("theme")||"dark",align:this.getAttribute("align")||"center"}}connectedCallback(){this._build(),this._setupObserver(),n.add(this),s||(s=requestAnimationFrame(i))}disconnectedCallback(){n.delete(this),0===n.size&&s&&(cancelAnimationFrame(s),s=null),this._observer&&this._observer.disconnect()}attributeChangedCallback(){this._wrapper&&this._build()}_build(){const t=this.config;this._interval=t.speed,this._shadow.innerHTML="",this._bars=[];const e=document.createElement("style");e.textContent=`\n :host {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n }\n .w {\n display: inline-flex;\n align-items: ${"bottom"===t.align?"flex-end":"center"};\n justify-content: center;\n gap: ${t.gap}px;\n height: ${t.maxH+10}px;\n background: transparent;\n transition: background 1000ms ease-in-out;\n }\n .b {\n width: ${t.width}px;\n height: ${t.minH}px;\n border-radius: ${t.radius}px;\n background: ${"auto"!==t.color?t.color:"light"===t.theme?"#111":"#fff"};\n transition:\n height ${t.speed}ms ease-in-out,\n opacity ${t.speed}ms ease-in-out,\n background 1000ms ease-in-out;\n flex-shrink: 0;\n }\n `;const n=document.createElement("div");n.className="w",this._wrapper=n;for(let e=0;e<t.bars;e++){const t=document.createElement("div");t.className="b",n.appendChild(t),this._bars.push(t)}this._shadow.appendChild(e),this._shadow.appendChild(n)}_setupObserver(){this._observer&&this._observer.disconnect(),this._observer=new IntersectionObserver(t=>{this._visible=t[0].isIntersecting},{threshold:.1}),this._observer.observe(this)}_frame(){const t=this.config,n=e(t.bars),s=t.maxH-t.minH;let i="auto"!==t.color?t.color:"light"===t.theme?"#111111":"#ffffff";if("pi"===t.bg){const n=function(t){return"#"+t.map(t=>t.toString(16)).join("")}(e(6));this._wrapper.style.background=n,this.style.setProperty("--pi-bg",n),"auto"===t.color&&(i=function(t){return parseInt(t.slice(1,3),16)/255*.299+parseInt(t.slice(3,5),16)/255*.587+parseInt(t.slice(5,7),16)/255*.114}(n)>.4?"#111111":"#ffffff")}else this._wrapper.style.background="transparent"===t.bg?"transparent":t.bg;n.forEach((e,n)=>{const r=this._bars[n];r&&(r.style.height=t.minH+e/9*s+"px",r.style.opacity=e<=2?t.lowOpacity:1,r.style.background=i)})}}customElements.get("pi-loader")||customElements.define("pi-loader",a)}();
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@srsdesigndev/pi-loader",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A pi-driven generative loader web component. No randomness. No dependencies. Just π.",
|
|
5
|
+
"main": "src/pi-loader.js",
|
|
6
|
+
"module": "src/pi-loader.js",
|
|
7
|
+
"files": [
|
|
8
|
+
"src/",
|
|
9
|
+
"dist/"
|
|
10
|
+
],
|
|
11
|
+
"keywords": [
|
|
12
|
+
"loader",
|
|
13
|
+
"loading",
|
|
14
|
+
"animation",
|
|
15
|
+
"pi",
|
|
16
|
+
"web-component",
|
|
17
|
+
"custom-element",
|
|
18
|
+
"generative",
|
|
19
|
+
"math",
|
|
20
|
+
"zero-dependency"
|
|
21
|
+
],
|
|
22
|
+
"author": "srsdesigndev",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "https://github.com/srsdesigndev/pi_loader.git"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://srsdesigndev.github.io/pi_loader",
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/srsdesigndev/pi_loader/issues"
|
|
31
|
+
}
|
|
32
|
+
}
|
package/src/pi-loader.js
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-loader.js
|
|
3
|
+
* A pi-driven generative loader web component.
|
|
4
|
+
* No dependencies. No randomness. Just π.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* <script src="pi-loader.js"></script>
|
|
8
|
+
* <pi-loader></pi-loader>
|
|
9
|
+
*
|
|
10
|
+
* Attributes:
|
|
11
|
+
* bars {number} Number of bars. Min: 3, Max: 20. Default: 10
|
|
12
|
+
* min-height {number} Min bar height in px. Default: 6
|
|
13
|
+
* max-height {number} Max bar height in px. Default: 60
|
|
14
|
+
* width {number} Bar width in px. Default: 10
|
|
15
|
+
* gap {number} Gap between bars in px. Default: 6
|
|
16
|
+
* speed {number} Frame interval in ms. Default: 600
|
|
17
|
+
* radius {number} Border radius px. 999 = pill, 0 = square. Default: 999
|
|
18
|
+
* color {string} Bar color. 'auto' = adapts to bg. Any CSS color. Default: 'auto'
|
|
19
|
+
* bg {string} 'pi' = pi-driven hex, 'transparent', any CSS color. Default: 'transparent'
|
|
20
|
+
* low-opacity {number} Opacity for digits 0–2. Default: 0.2
|
|
21
|
+
* theme {string} 'dark' or 'light'. Default: 'dark'
|
|
22
|
+
* align {string} 'center' or 'bottom'. Default: 'center'
|
|
23
|
+
*
|
|
24
|
+
* Performance:
|
|
25
|
+
* - One shared BigInt pi spigot across ALL instances
|
|
26
|
+
* - One single requestAnimationFrame loop for ALL instances
|
|
27
|
+
* - IntersectionObserver pauses off-screen loaders automatically
|
|
28
|
+
* - No setInterval, no polling, no per-instance timers
|
|
29
|
+
*
|
|
30
|
+
* @version 2.0.0
|
|
31
|
+
* @license MIT
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
(function () {
|
|
35
|
+
'use strict';
|
|
36
|
+
|
|
37
|
+
// ── Pi Spigot (Rabinowitz-Wagon) ─────────────────────────────────────────
|
|
38
|
+
// One generator shared globally. Every digit consumed is gone forever.
|
|
39
|
+
function* piSpigot() {
|
|
40
|
+
let q = 1n, r = 0n, t = 1n, k = 1n, n = 3n, l = 3n;
|
|
41
|
+
while (true) {
|
|
42
|
+
if (4n * q + r - t < n * t) {
|
|
43
|
+
yield Number(n);
|
|
44
|
+
const nr = 10n * (r - n * t);
|
|
45
|
+
n = 10n * (3n * q + r) / t - 10n * n;
|
|
46
|
+
q *= 10n;
|
|
47
|
+
r = nr;
|
|
48
|
+
} else {
|
|
49
|
+
const nr = (2n * q + r) * l;
|
|
50
|
+
const nn = (q * (7n * k) + 2n + r * l) / (t * l);
|
|
51
|
+
q *= k; t *= l; l += 2n; k += 1n;
|
|
52
|
+
n = nn; r = nr;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const GLOBAL_GEN = piSpigot();
|
|
58
|
+
|
|
59
|
+
function nextDigits(n) {
|
|
60
|
+
const out = [];
|
|
61
|
+
for (let i = 0; i < n; i++) out.push(GLOBAL_GEN.next().value);
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ── Global RAF scheduler ─────────────────────────────────────────────────
|
|
66
|
+
// All instances register here. One rAF loop drives everything.
|
|
67
|
+
const _instances = new Set();
|
|
68
|
+
let _rafId = null;
|
|
69
|
+
|
|
70
|
+
function _tick(now) {
|
|
71
|
+
_instances.forEach(inst => {
|
|
72
|
+
if (inst._visible && now - inst._lastFrame >= inst._interval) {
|
|
73
|
+
inst._frame();
|
|
74
|
+
inst._lastFrame = now;
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
_rafId = requestAnimationFrame(_tick);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function _startLoop() {
|
|
81
|
+
if (!_rafId) _rafId = requestAnimationFrame(_tick);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function _stopLoop() {
|
|
85
|
+
if (_instances.size === 0 && _rafId) {
|
|
86
|
+
cancelAnimationFrame(_rafId);
|
|
87
|
+
_rafId = null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ── Utilities ────────────────────────────────────────────────────────────
|
|
92
|
+
function clamp(val, min, max) {
|
|
93
|
+
return Math.min(Math.max(val, min), max);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function getLuminance(hex) {
|
|
97
|
+
const r = parseInt(hex.slice(1, 3), 16) / 255;
|
|
98
|
+
const g = parseInt(hex.slice(3, 5), 16) / 255;
|
|
99
|
+
const b = parseInt(hex.slice(5, 7), 16) / 255;
|
|
100
|
+
return 0.299 * r + 0.587 * g + 0.114 * b;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function digitsToHex(digits) {
|
|
104
|
+
return '#' + digits.map(d => d.toString(16)).join('');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function parseAttr(el, name, def, min, max) {
|
|
108
|
+
const raw = el.getAttribute(name);
|
|
109
|
+
if (raw === null) return def;
|
|
110
|
+
const num = parseFloat(raw);
|
|
111
|
+
if (isNaN(num)) return def;
|
|
112
|
+
return (min !== undefined) ? clamp(num, min, max) : num;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// ── Web Component ────────────────────────────────────────────────────────
|
|
116
|
+
class PiLoader extends HTMLElement {
|
|
117
|
+
|
|
118
|
+
constructor() {
|
|
119
|
+
super();
|
|
120
|
+
this._shadow = this.attachShadow({ mode: 'open' });
|
|
121
|
+
this._bars = [];
|
|
122
|
+
this._wrapper = null;
|
|
123
|
+
this._visible = false;
|
|
124
|
+
this._lastFrame = 0;
|
|
125
|
+
this._interval = 600;
|
|
126
|
+
this._observer = null;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
static get observedAttributes() {
|
|
130
|
+
return ['bars','min-height','max-height','width','gap',
|
|
131
|
+
'speed','radius','color','bg','low-opacity','theme','align'];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
get config() {
|
|
135
|
+
return {
|
|
136
|
+
bars: parseAttr(this, 'bars', 10, 3, 20),
|
|
137
|
+
minH: parseAttr(this, 'min-height', 6, 1, 200),
|
|
138
|
+
maxH: parseAttr(this, 'max-height', 60, 10, 400),
|
|
139
|
+
width: parseAttr(this, 'width', 10, 2, 100),
|
|
140
|
+
gap: parseAttr(this, 'gap', 6, 0, 100),
|
|
141
|
+
speed: parseAttr(this, 'speed', 600, 80, 5000),
|
|
142
|
+
radius: parseAttr(this, 'radius', 999, 0, 999),
|
|
143
|
+
color: this.getAttribute('color') || 'auto',
|
|
144
|
+
bg: this.getAttribute('bg') || 'transparent',
|
|
145
|
+
lowOpacity: parseAttr(this, 'low-opacity', 0.2, 0, 1),
|
|
146
|
+
theme: this.getAttribute('theme') || 'dark',
|
|
147
|
+
align: this.getAttribute('align') || 'center',
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
connectedCallback() {
|
|
152
|
+
this._build();
|
|
153
|
+
this._setupObserver();
|
|
154
|
+
_instances.add(this);
|
|
155
|
+
_startLoop();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
disconnectedCallback() {
|
|
159
|
+
_instances.delete(this);
|
|
160
|
+
_stopLoop();
|
|
161
|
+
if (this._observer) this._observer.disconnect();
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
attributeChangedCallback() {
|
|
165
|
+
if (this._wrapper) this._build();
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
_build() {
|
|
169
|
+
const cfg = this.config;
|
|
170
|
+
this._interval = cfg.speed;
|
|
171
|
+
this._shadow.innerHTML = '';
|
|
172
|
+
this._bars = [];
|
|
173
|
+
|
|
174
|
+
const style = document.createElement('style');
|
|
175
|
+
style.textContent = `
|
|
176
|
+
:host {
|
|
177
|
+
display: inline-flex;
|
|
178
|
+
align-items: center;
|
|
179
|
+
justify-content: center;
|
|
180
|
+
}
|
|
181
|
+
.w {
|
|
182
|
+
display: inline-flex;
|
|
183
|
+
align-items: ${cfg.align === 'bottom' ? 'flex-end' : 'center'};
|
|
184
|
+
justify-content: center;
|
|
185
|
+
gap: ${cfg.gap}px;
|
|
186
|
+
height: ${cfg.maxH + 10}px;
|
|
187
|
+
background: transparent;
|
|
188
|
+
transition: background 1000ms ease-in-out;
|
|
189
|
+
}
|
|
190
|
+
.b {
|
|
191
|
+
width: ${cfg.width}px;
|
|
192
|
+
height: ${cfg.minH}px;
|
|
193
|
+
border-radius: ${cfg.radius}px;
|
|
194
|
+
background: ${cfg.color !== 'auto' ? cfg.color : (cfg.theme === 'light' ? '#111' : '#fff')};
|
|
195
|
+
transition:
|
|
196
|
+
height ${cfg.speed}ms ease-in-out,
|
|
197
|
+
opacity ${cfg.speed}ms ease-in-out,
|
|
198
|
+
background 1000ms ease-in-out;
|
|
199
|
+
flex-shrink: 0;
|
|
200
|
+
}
|
|
201
|
+
`;
|
|
202
|
+
|
|
203
|
+
const wrapper = document.createElement('div');
|
|
204
|
+
wrapper.className = 'w';
|
|
205
|
+
this._wrapper = wrapper;
|
|
206
|
+
|
|
207
|
+
for (let i = 0; i < cfg.bars; i++) {
|
|
208
|
+
const bar = document.createElement('div');
|
|
209
|
+
bar.className = 'b';
|
|
210
|
+
wrapper.appendChild(bar);
|
|
211
|
+
this._bars.push(bar);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
this._shadow.appendChild(style);
|
|
215
|
+
this._shadow.appendChild(wrapper);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
_setupObserver() {
|
|
219
|
+
if (this._observer) this._observer.disconnect();
|
|
220
|
+
this._observer = new IntersectionObserver(entries => {
|
|
221
|
+
this._visible = entries[0].isIntersecting;
|
|
222
|
+
}, { threshold: 0.1 });
|
|
223
|
+
this._observer.observe(this);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
_frame() {
|
|
227
|
+
const cfg = this.config;
|
|
228
|
+
const digits = nextDigits(cfg.bars);
|
|
229
|
+
const range = cfg.maxH - cfg.minH;
|
|
230
|
+
|
|
231
|
+
let barColor = cfg.color !== 'auto'
|
|
232
|
+
? cfg.color
|
|
233
|
+
: (cfg.theme === 'light' ? '#111111' : '#ffffff');
|
|
234
|
+
|
|
235
|
+
if (cfg.bg === 'pi') {
|
|
236
|
+
const hex = digitsToHex(nextDigits(6));
|
|
237
|
+
this._wrapper.style.background = hex;
|
|
238
|
+
// also bubble bg up to host so parent containers can mirror it
|
|
239
|
+
this.style.setProperty('--pi-bg', hex);
|
|
240
|
+
if (cfg.color === 'auto') {
|
|
241
|
+
barColor = getLuminance(hex) > 0.4 ? '#111111' : '#ffffff';
|
|
242
|
+
}
|
|
243
|
+
} else {
|
|
244
|
+
this._wrapper.style.background =
|
|
245
|
+
cfg.bg === 'transparent' ? 'transparent' : cfg.bg;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
digits.forEach((d, i) => {
|
|
249
|
+
const bar = this._bars[i];
|
|
250
|
+
if (!bar) return;
|
|
251
|
+
bar.style.height = (cfg.minH + (d / 9) * range) + 'px';
|
|
252
|
+
bar.style.opacity = d <= 2 ? cfg.lowOpacity : 1;
|
|
253
|
+
bar.style.background = barColor;
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (!customElements.get('pi-loader')) {
|
|
259
|
+
customElements.define('pi-loader', PiLoader);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
})();
|