Modules
StringProgress
Scroll progress engine that emits a normalized 0..1 timeline and writes progress CSS variables.
StringProgress
StringProgress turns an element's scroll travel into a stable 0..1 value. It uses shared geometry attributes such as entry, exit, and offsets, then exposes the result in two public places:
- a CSS variable
- a scoped event
Public API
Attributes
| Attribute | Type | Default | Real runtime effect |
|---|---|---|---|
string-key | string | --progress | Names the CSS variable written by the module. |
string-easing | easing string | cubic-bezier(0.25, 0.25, 0.25, 0.25) | Remaps raw linear progress before the event and CSS write happen. |
string-offset-top | dimension | 0% | Moves the effective end position of the timeline. |
string-offset-bottom | dimension | 0% | Moves the effective start position of the timeline. |
string-enter-el | string | top | Picks the element edge used to start the timeline. |
string-enter-vp | string | bottom | Picks the viewport edge paired with string-enter-el. |
string-exit-el | string | bottom | Picks the element edge used to finish the timeline. |
string-exit-vp | string | top | Picks the viewport edge paired with string-exit-el. |
CSS Variables and DOM Output
StringProgress writes one CSS variable to the source element:
- the variable named by
string-key
If you do not provide string-key, the module writes:
--progress
The written value is the eased progress, already clamped to 0..1.
The module does not apply any inline transform, does not toggle any classes, and does not expose raw progress as public CSS.
Events
| Channel | Payload | Fired when |
|---|---|---|
object:progress:<id> | number | The eased progress value changes |
TypeScript
stringTune.on('object:progress:page-progress', (progress) => {
console.log(progress);
});
Mirror Behavior
If another element uses string-copy-from="<source-id>", the progress output is mirrored there too.
- the same CSS variable name is written to the mirror
- the mirror can apply its own
string-easing, because mirror easing is resolved separately from the source element
Quick Example
HTML
<section class="hero">Scroll down</section>
<section string="progress" string-id="page-progress" class="progress-stage">
<div class="progress-demo">
<div class="progress-box"></div>
<div class="progress-label">Progress <span id="progress-value">0%</span></div>
</div>
</section>
<section class="hero">Scroll up</section>
CSS
.hero,
.progress-stage {
min-height: 100vh;
display: grid;
place-items: center;
}
.progress-demo {
display: grid;
gap: 20px;
justify-items: center;
}
.progress-box {
width: 160px;
height: 160px;
border: 2px solid black;
background: white;
transform: rotate(calc(var(--progress, 0) * 1turn));
}
Registration
TypeScript
import StringTune, { StringProgress } from '@fiddle-digital/string-tune';
const stringTune = StringTune.getInstance();
stringTune.use(StringProgress);
stringTune.start(60);
Detailed Behavior
- Progress is computed from shared timeline geometry inside
StringModule. - Raw progress stays internal. The public event and the public CSS variable both use the eased value.
- Values are clamped to
0..1, and tiny floating-point noise is ignored. - On disconnect, the module removes the written CSS variable from the source element and its mirrors.