diff --git a/README.md b/README.md
index 7de63d4..8fd6879 100644
--- a/README.md
+++ b/README.md
@@ -154,19 +154,19 @@ function getPresetFeatures() {
switch (navigator.cpuPerformance) {
case 1:
return {
- videoQuality: "QVGA",
+ videoQuality: 'QVGA',
frameRate: 15,
effects: [],
};
case 2:
return {
- videoQuality: "VGA",
+ videoQuality: 'VGA',
frameRate: 15,
effects: ['voice-detection', 'animated-reactions'],
};
case 3:
return {
- videoQuality: "720p",
+ videoQuality: '720p',
frameRate: 30,
effects: ['voice-detection', 'animated-reactions',
'noise-reduction'],
@@ -175,7 +175,7 @@ function getPresetFeatures() {
case 0: // Assuming high performance settings for unknown devices
default: // and for performance tiers higher than 4.
return {
- videoQuality: "1080p",
+ videoQuality: '1080p',
frameRate: 30,
effects: ['voice-detection', 'animated-reactions',
'noise-reduction', 'virtual-background'],
@@ -188,6 +188,50 @@ The API's specification should determine the smallest and largest acceptable
bucket size, to prevent fingerprinting. This size should be in the order of a
few hundred different CPU models.
+As a second example, a web application may consider applying some effect
+that improves UX but requires excessive computation power. When it loads,
+it could use the CPU Performance API to determine **statically** if the
+user device is powerful enough to enable this effect. Afterwards, it could
+use the [Compute Pressure API](https://github.com/w3c/compute-pressure) to **dynamically** monitor device usage, and control this effect accordingly.
+An [interactive demo](static-dynamic-demo.html) illustrates this use case.
+
+```js
+const available = navigator.cpuPerformance >= 3;
+let enabled = available;
+
+console.log(`Static: effect starts as ${enabled ? 'enabled' : 'disabled'}`);
+
+function callback(entries) {
+ const state = entries[entries.length - 1].state;
+
+ if (enabled && (state === 'serious' || state === 'critical')) {
+ enabled = false;
+ console.log(`CPU load is ${state}, disabling effect to preserve UX.`);
+ } else if (!enabled && available && (state === 'nominal' || state === 'fair')) {
+ enabled = true;
+ console.log(`CPU load is ${state}, re-enabling effect to improve UX.`);
+ }
+}
+
+console.log(`Dynamic: monitoring begins`);
+
+const observer = new PressureObserver(callback);
+await observer.observe('cpu', { sampleInterval: 1000 }); // 1000ms
+```
+
+This example shows clearly how the two APIs complement each other, but also
+an important difference between the static information obtained by the CPU
+Performance API (the performance tier) and the dynamic information obtained
+by the Compute Pressure API (the pressure state). The former is **absolute**:
+it tells the web app how powerful the user device is, regardless of the
+current load or other conditions. The latter is **relative**: it tells the
+web app how well the user device is performing now, compared to what it would
+do in ideal conditions and with zero load. For the use case that is illustrated
+above, dynamic information alone is not sufficient to inform the web app
+whether the effect should be enabled. E.g., even if the pressure state is
+nominal, the user device may not be powerful enough to support it.
+
+
## Alternatives Considered
### Nature and Semantics of Performance Buckets
diff --git a/static-dynamic-demo.html b/static-dynamic-demo.html
new file mode 100644
index 0000000..314c87c
--- /dev/null
+++ b/static-dynamic-demo.html
@@ -0,0 +1,353 @@
+
+
+
+
+
+ CPU Performance API — Static/Dynamic Example
+
+
+
+
+
CPU Performance API — Static/Dynamic Example
+
+
A web application considers applying some effect that
+ improves UX but requires excessive computation power.
+
It uses the CPU
+ Performance API to determine statically
+ if the user device is powerful enough. The effect will be available only
+ if the device's tier is at least 3.
+
It also uses the Compute
+ Pressure API to dynamically monitor device usage.
+ The effect is enabled if usage state is nominal or fair, and disabled
+ if it is serious or critical.