adapter.limits is the best this adapter can do. To go beyond the defaults, for a 1 GiB storage buffer or 1024-thread workgroups, use requiredLimits, but never ask for more than the adapter reports: an unclamped request for 16 color attachments rejected the whole call with OperationError: Required limit (16) is greater than the supported limit (8). So clamp each wish:
<script type="module">
const want = { maxBufferSize: 1024 ** 3, maxStorageBufferBindingSize: 1024 ** 3,
maxComputeInvocationsPerWorkgroup: 1024, maxColorAttachments: 16 };
const adapter = await navigator.gpu.requestAdapter();
const requiredLimits = {};
for (const [name, value] of Object.entries(want)) {
requiredLimits[name] = Math.min(value, adapter.limits[name]); // never ask for more
}
const device = await adapter.requestDevice({ requiredLimits });
for (const n in want) console.log(`${n}: wanted ${want[n]}, got ${device.limits[n]}`);
</script>maxBufferSize: wanted 1073741824, got 1073741824 maxStorageBufferBindingSize: wanted 1073741824, got 1073741824 maxComputeInvocationsPerWorkgroup: wanted 1024, got 1024 maxColorAttachments: wanted 16, got 8
Then read device.limits and adapt, for example by splitting work into more dispatches. The two alignment limits (minUniformBufferOffsetAlignment, minStorageBufferOffsetAlignment) work the other way round (smaller is better), so clamp those with Math.max, as the helper in Feature Detection does.