Sample the springs over M3's web durations, and add the Standard scheme
bin/springs.mjs is the sampler behind motion.css: damping ratio and stiffness in, the 49-point linear() and the settle time out. Run with --settle it reproduces the six curves the file carried byte for byte, so only the window changed. Each spring is now sampled over the duration M3 publishes for the web (spatial 350/500/650 ms, effects 150/200/300 ms) instead of stopping at its own settle time, so the *-duration tokens read Google's numbers. Sampling stays in real time — point i is the spring at duration × i / 48 — so the bounce lands at the same millisecond as before; a longer duration just holds the tail flat at 1, and a shorter one pins the last point, at most 0.3% of the travel in one frame. Each token's comment records damping, stiffness, settle time and sampled duration. M3's second motion scheme is here too: [data-motion="standard"] swaps the three spatial springs (damping 0.9, 0.2% overshoot instead of 9%) and their durations; the effects springs sample identically in both schemes, so they are shared. The reduced-motion block names both selectors, so it still zeroes every duration. Plan: docs/plans/material-3-alignment.md step 5, findings core C8, C9. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
2feb623ec0
commit
5b0ca26857
@@ -113,13 +113,16 @@ it('reads every safe-area inset through a variable that can replace it', functio
|
||||
->and(File::get(packageCss('components/app-bar.css')))->toContain('padding-top: var(--material-safe-top, env(safe-area-inset-top));');
|
||||
});
|
||||
|
||||
it('makes every motion token instant under reduced motion', function () {
|
||||
it('makes every motion token instant under reduced motion, in both schemes', function () {
|
||||
$motion = File::get(packageCss('tokens/motion.css'));
|
||||
$reduced = Str::of($motion)->after('prefers-reduced-motion: reduce')->toString();
|
||||
|
||||
preg_match_all('/(--md-sys-motion-[\w-]*duration[\w-]*):/', Str::before($motion, '@media'), $durations);
|
||||
|
||||
expect($durations[1])->not->toBeEmpty();
|
||||
expect($durations[1])->not->toBeEmpty()
|
||||
// The Standard scheme sets the same variables on a selector of its own, so :root alone
|
||||
// would not reach it: the block has to name both.
|
||||
->and($reduced)->toMatch('/:root,\s*\[data-motion="standard"\] \{/');
|
||||
|
||||
foreach ($durations[1] as $duration) {
|
||||
expect($reduced)->toContain("{$duration}: 0ms;");
|
||||
@@ -164,3 +167,39 @@ it('gives every emphasized type style its own tracking, as Compose does', functi
|
||||
'--md-sys-typescale-emphasized-label-md-tracking' => '0.03125rem',
|
||||
]);
|
||||
});
|
||||
|
||||
it('reads every spring over the duration M3 publishes for the web', function () {
|
||||
$expressive = declarations(File::get(packageCss('tokens/motion.css')), ':root');
|
||||
|
||||
// docs/reference/m3/styles.md § Motion, "Web curve equivalents for springs".
|
||||
$durations = [
|
||||
'spatial-fast' => '350ms', 'spatial-default' => '500ms', 'spatial-slow' => '650ms',
|
||||
'effects-fast' => '150ms', 'effects-default' => '200ms', 'effects-slow' => '300ms',
|
||||
];
|
||||
|
||||
foreach ($durations as $spring => $duration) {
|
||||
expect($expressive["--md-sys-motion-{$spring}-duration"])->toBe($duration)
|
||||
// 49 sampled points, starting at rest and landing exactly on the target.
|
||||
->and($expressive["--md-sys-motion-{$spring}"])->toStartWith('linear(0, ')->toEndWith(', 1)')
|
||||
->and(explode(', ', $expressive["--md-sys-motion-{$spring}"]))->toHaveCount(49);
|
||||
}
|
||||
});
|
||||
|
||||
it('swaps only the spatial springs for the Standard motion scheme', function () {
|
||||
$motion = File::get(packageCss('tokens/motion.css'));
|
||||
$expressive = declarations($motion, ':root');
|
||||
$standard = declarations($motion, '[data-motion="standard"] {');
|
||||
|
||||
// Both schemes share the effects springs, so the block carries the three spatial pairs only.
|
||||
expect(array_keys($standard))->toBe([
|
||||
'--md-sys-motion-spatial-fast', '--md-sys-motion-spatial-fast-duration',
|
||||
'--md-sys-motion-spatial-default', '--md-sys-motion-spatial-default-duration',
|
||||
'--md-sys-motion-spatial-slow', '--md-sys-motion-spatial-slow-duration',
|
||||
]);
|
||||
|
||||
foreach (['fast' => '350ms', 'default' => '500ms', 'slow' => '750ms'] as $speed => $duration) {
|
||||
expect($standard["--md-sys-motion-spatial-{$speed}-duration"])->toBe($duration)
|
||||
->and($standard["--md-sys-motion-spatial-{$speed}"])->toStartWith('linear(0, ')
|
||||
->not->toBe($expressive["--md-sys-motion-spatial-{$speed}"]);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user