Skip to content

Commit 517a28c

Browse files
committed
Merge branch '0.1.1'
2 parents 0ac4fad + 31a536b commit 517a28c

File tree

3 files changed

+21
-11
lines changed

3 files changed

+21
-11
lines changed

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,9 @@ Obs.js exposes the following classes under the following conditions:
165165
| `.has-latency-low` | Low RTT | `rtt < 75ms` |
166166
| `.has-latency-medium` | Medium RTT | `75–275ms` |
167167
| `.has-latency-high` | High RTT | `> 275ms` |
168-
| `.has-bandwidth-low` | Low estimated bandwidth | `downlinkBucket ≤ 5` (1 Mbps buckets via `Math.ceil`) |
169-
| `.has-bandwidth-high` | High estimated bandwidth | `downlinkBucket ≥ 8` (6–7 is a dead zone → no class) |
168+
| `.has-bandwidth-low` | Low estimated bandwidth | `downlinkBucket ≤ 5` (1Mbps buckets via `Math.ceil`) |
169+
| `.has-bandwidth-medium` | Mid estimated bandwidth | `downlinkBucket 6–7` |
170+
| `.has-bandwidth-high` | High estimated bandwidth | `downlinkBucket ≥ 8` |
170171
| `.has-connection-capability-strong` | Transport looks strong | `latency = low` **and** `bandwidth = high` |
171172
| `.has-connection-capability-moderate` | Transport middling | Anything not strong/weak |
172173
| `.has-connection-capability-weak` | Transport looks weak | `latency = high` **or** `bandwidth = low` |
@@ -184,6 +185,7 @@ Obs.js also stores the following properties on the `window.obs` object:
184185
| `rttBucket` | number (ms) | RTT bucketed to **ceil** 25 ms (e.g. 101→125) | `navigator.connection.rtt` | Undefined if Connection API missing |
185186
| `rttCategory` | `'low' \| 'medium' \| 'high'` | CrUX tri-bin: <75, 75–275, >275 | Derived from `rtt` | Drives latency classes |
186187
| `downlinkBucket` | number (Mbps) | Downlink bucketed to **ceil** 1 Mbps | `navigator.connection.downlink` | Low/High thresholds: `≤5` / `≥8` |
188+
| `downlinkCategory` | `'low' \| 'medium' \| 'high'` | Bandwidth category | Derived from `downlinkBucket` (≤5→low, 6–7→medium, ≥8→high) | Mirrors `.has-bandwidth-*` classes |
187189
| `downlinkMax` | number (Mbps) | Max estimated downlink (if exposed) | `navigator.connection.downlinkMax` | Not used for Stances; informational only |
188190
| `connectionCapability` | `'strong' \| 'moderate' \| 'weak'` | Transport assessment | Derived from `rttCategory` and `downlinkBucket` | Strong = low RTT **and** high BW; Weak = high RTT **or** low BW |
189191
| `conservationPreference` | `'conserve' \| 'neutral'` | Frugality signal | `dataSaver === true` **or** `batteryLow === true``conserve` ||

demo/index.html

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
<script>
1414
/*! Obs.js | (c) Harry Roberts, csswizardry.com | MIT */
15-
;(()=>{const e=document.currentScript;if((!e||e.src||e.type&&"module"===e.type.toLowerCase())&&!1===/^(localhost|127\.0\.0\.1|::1)$/.test(location.hostname))return void console.warn("[Obs.js] Skipping: must be an inline, classic <script> in <head>.",e?e.src?"src="+e.src:"type="+e.type:"type=module");const t=document.documentElement,{connection:n}=navigator;window.obs=window.obs||{};const i=!0===(window.obs&&window.obs.config||{}).observeChanges,o=()=>{const e=window.obs||{},n="number"==typeof e.downlinkBucket?e.downlinkBucket:null;e.connectionCapability="low"===e.rttCategory&&null!=n&&n>=8?"strong":"high"===e.rttCategory||null!=n&&n<=5?"weak":"moderate";const i=!0===e.dataSaver||!0===e.batteryLow;e.conservationPreference=i?"conserve":"neutral",e.deliveryMode=i||"strong"!==e.connectionCapability?i||"weak"===e.connectionCapability?"lite":"cautious":"rich",e.canShowRichMedia="rich"===e.deliveryMode,e.shouldAvoidRichMedia="lite"===e.deliveryMode,["strong","moderate","weak"].forEach(e=>{t.classList.remove(`has-connection-capability-${e}`)}),t.classList.add(`has-connection-capability-${e.connectionCapability}`),["conserve","neutral"].forEach(e=>{t.classList.remove(`has-conservation-preference-${e}`)}),t.classList.add(`has-conservation-preference-${e.conservationPreference}`),["rich","cautious","lite"].forEach(e=>{t.classList.remove(`has-delivery-mode-${e}`)}),t.classList.add(`has-delivery-mode-${e.deliveryMode}`)},a=()=>{if(!n)return;const{saveData:e,rtt:i,downlink:a}=n;window.obs.dataSaver=!!e,t.classList.toggle("has-data-saver",!!e);const s=(e=>Number.isFinite(e)?25*Math.ceil(e/25):null)(i);null!=s&&(window.obs.rttBucket=s);const c=(e=>Number.isFinite(e)?e<75?"low":e<=275?"medium":"high":null)(i);c&&(window.obs.rttCategory=c,["low","medium","high"].forEach(e=>t.classList.remove(`has-latency-${e}`)),t.classList.add(`has-latency-${c}`));const r=(l=a,Number.isFinite(l)?Math.ceil(l):null);var l;if(null!=r){window.obs.downlinkBucket=r;const e=r>=8;t.classList.toggle("has-bandwidth-low",r<=5),t.classList.toggle("has-bandwidth-high",e)}"downlinkMax"in n&&(window.obs.downlinkMax=n.downlinkMax),o()};a(),i&&n&&"function"==typeof n.addEventListener&&n.addEventListener("change",a);const s=e=>{if(!e)return;const{level:n,charging:i}=e,a=Number.isFinite(n)?n<=.05:null;window.obs.batteryCritical=a;const s=Number.isFinite(n)?n<=.2:null;window.obs.batteryLow=s,["critical","low"].forEach(e=>t.classList.remove(`has-battery-${e}`)),s&&t.classList.add("has-battery-low"),a&&t.classList.add("has-battery-critical");const c=!!i;window.obs.batteryCharging=c,t.classList.toggle("has-battery-charging",c),o()};"getBattery"in navigator&&navigator.getBattery().then(e=>{s(e),i&&"function"==typeof e.addEventListener&&(e.addEventListener("levelchange",()=>s(e)),e.addEventListener("chargingchange",()=>s(e)))}).catch(()=>{})})();
15+
;(()=>{const e=document.currentScript;if((!e||e.src||e.type&&"module"===e.type.toLowerCase())&&!1===/^(localhost|127\.0\.0\.1|::1)$/.test(location.hostname))return void console.warn("[Obs.js] Skipping: must be an inline, classic <script> in <head>.",e?e.src?"src="+e.src:"type="+e.type:"type=module");const t=document.documentElement,{connection:n}=navigator;window.obs=window.obs||{};const i=!0===(window.obs&&window.obs.config||{}).observeChanges,o=()=>{const e=window.obs||{},n="number"==typeof e.downlinkBucket?e.downlinkBucket:null;e.connectionCapability="low"===e.rttCategory&&null!=n&&n>=8?"strong":"high"===e.rttCategory||null!=n&&n<=5?"weak":"moderate";const i=!0===e.dataSaver||!0===e.batteryLow;e.conservationPreference=i?"conserve":"neutral",e.deliveryMode=i||"strong"!==e.connectionCapability?i||"weak"===e.connectionCapability?"lite":"cautious":"rich",e.canShowRichMedia="rich"===e.deliveryMode,e.shouldAvoidRichMedia="lite"===e.deliveryMode,["strong","moderate","weak"].forEach(e=>{t.classList.remove(`has-connection-capability-${e}`)}),t.classList.add(`has-connection-capability-${e.connectionCapability}`),["conserve","neutral"].forEach(e=>{t.classList.remove(`has-conservation-preference-${e}`)}),t.classList.add(`has-conservation-preference-${e.conservationPreference}`),["rich","cautious","lite"].forEach(e=>{t.classList.remove(`has-delivery-mode-${e}`)}),t.classList.add(`has-delivery-mode-${e.deliveryMode}`)},a=()=>{if(!n)return;const{saveData:e,rtt:i,downlink:a}=n;window.obs.dataSaver=!!e,t.classList.toggle("has-data-saver",!!e);const s=(e=>Number.isFinite(e)?25*Math.ceil(e/25):null)(i);null!=s&&(window.obs.rttBucket=s);const c=(e=>Number.isFinite(e)?e<75?"low":e<=275?"medium":"high":null)(i);c&&(window.obs.rttCategory=c,["low","medium","high"].forEach(e=>t.classList.remove(`has-latency-${e}`)),t.classList.add(`has-latency-${c}`));const r=(l=a,Number.isFinite(l)?Math.ceil(l):null);var l;if(null!=r){window.obs.downlinkBucket=r;const e=r<=5?"low":r>=8?"high":"medium";window.obs.downlinkCategory=e,["low","medium","high"].forEach(e=>t.classList.remove(`has-bandwidth-${e}`)),t.classList.add(`has-bandwidth-${e}`)}"downlinkMax"in n&&(window.obs.downlinkMax=n.downlinkMax),o()};a(),i&&n&&"function"==typeof n.addEventListener&&n.addEventListener("change",a);const s=e=>{if(!e)return;const{level:n,charging:i}=e,a=Number.isFinite(n)?n<=.05:null;window.obs.batteryCritical=a;const s=Number.isFinite(n)?n<=.2:null;window.obs.batteryLow=s,["critical","low"].forEach(e=>t.classList.remove(`has-battery-${e}`)),s&&t.classList.add("has-battery-low"),a&&t.classList.add("has-battery-critical");const c=!!i;window.obs.batteryCharging=c,t.classList.toggle("has-battery-charging",c),o()};"getBattery"in navigator&&navigator.getBattery().then(e=>{s(e),i&&"function"==typeof e.addEventListener&&(e.addEventListener("levelchange",()=>s(e)),e.addEventListener("chargingchange",()=>s(e)))}).catch(()=>{})})();
1616
//# sourceURL=obs.inline.js
1717
</script>
1818

@@ -146,16 +146,18 @@ <h2><code>window.obs</code></h2>
146146
// Red (bad)
147147
if (
148148
/battery-critical/.test(name) ||
149+
/latency-high/.test(name) ||
150+
/bandwidth-low/.test(name) ||
149151
/connection-capability-weak/.test(name) ||
150152
/delivery-mode-lite/.test(name)
151153
) return 'c-pill u-bad';
152154

153-
// Amber (warn)
155+
// Yellow (warn)
154156
if (
155157
/battery-low/.test(name) ||
156158
/has-data-saver/.test(name) ||
157-
/bandwidth-low/.test(name) ||
158-
/latency-high/.test(name) ||
159+
/bandwidth-medium/.test(name) ||
160+
/latency-medium/.test(name) ||
159161
/conservation-preference-conserve/.test(name) ||
160162
/connection-capability-moderate/.test(name) ||
161163
/delivery-mode-cautious/.test(name)

obs.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -180,12 +180,18 @@
180180
if (downlinkBucket != null) {
181181
window.obs.downlinkBucket = downlinkBucket; // 1‑Mbps
182182

183-
// Add high or low bandwidth classes to the `<html>` element.
183+
// Add low, medium, or high bandwidth classes to the `<html>` element.
184+
// low = ≤5 Mbps, medium = 6–7 Mbps, high = ≥8 Mbps
184185
// E.g. `<html class="has-bandwidth-high">`
185-
const isLow = downlinkBucket <= 5;
186-
const isHigh = downlinkBucket >= 8;
187-
html.classList.toggle('has-bandwidth-low', isLow);
188-
html.classList.toggle('has-bandwidth-high', isHigh);
186+
const downlinkCategory =
187+
downlinkBucket <= 5 ? 'low' :
188+
downlinkBucket >= 8 ? 'high' : 'medium';
189+
190+
window.obs.downlinkCategory = downlinkCategory;
191+
192+
['low', 'medium', 'high']
193+
.forEach(b => html.classList.remove(`has-bandwidth-${b}`));
194+
html.classList.add(`has-bandwidth-${downlinkCategory}`);
189195
}
190196

191197
// Obs.js doesn’t currently do anything with it, but we capture the maximum

0 commit comments

Comments
 (0)