ExklusivBeta
Foresee <mv-foresee>
Sagt anhand der Zeigerbahn voraus, welches Bedienelement der Nutzer gleich anklicken wird, noch vor dem Klick, und führt Buch über die eigene Treffsicherheit. Umschließt einen beliebigen Bereich mit Links und Buttons und verfolgt die Annäherung bis zu 240px außerhalb davon; Richtung (kreuzt der Bewegungsstrahl das Ziel?), Entfernung und Abbremsen (Menschen werden langsamer, wenn sie ihr Ziel erreichen: Der Haltepunkt wird aus Geschwindigkeit und Verzögerung geschätzt) werden pro Kandidat bewertet, und sobald der beste über der Schwelle bleibt, bekommt er data-foresee="foreseen", eine Variable --mv-foresee-confidence und einen zarten Ring, der mit der Zuversicht fester wird. mv-foresee (abbrechbar) lässt die App alles vorab aufwärmen (Daten abrufen, den Code eines Dialogs laden), und das Attribut prefetch fügt pro Link gleicher Herkunft ein <link rel="prefetch"> ein. Jeder Klick wird dann an der bestehenden Vorhersage gemessen (mv-verdict: hit oder dissent, Vorsprung in ms), und stats fasst Genauigkeit und durchschnittlichen Vorsprung zusammen. Tastaturfokus und Touch-Berührungen zählen als sichere Vorhersagen, sodass jede Eingabemethode den Vorsprung bekommt; show-indicator="false" lässt die Komponente unsichtbar als reine Prefetch-Intelligenz laufen.
| Kategorie | Cursor |
|---|---|
| Typ | Web Component (<mv-foresee>) |
| Status | Beta |
| Keywords | exclusive, culture, cursor, prediction, prefetch, preload, intent, trajectory, pointer, performance, navigation, speculation, analytics, anticipation |
When to use
- A navigation grid or dashboard should start loading the next page or its data before the user actually clicks
- A heavy dialog, editor or route chunk should be warmed up only when the user is clearly heading for its trigger
- A team wants to measure how predictable its navigation is (accuracy and head start per click) before investing in prefetching
- Hover-based prefetching fires too late or too often and a trajectory-based signal is needed
Avoid when
- The targets are few, far apart and cheap to load: plain links already feel instant
- The goal is a decorative effect that follows the cursor → use Cursor Follower instead
- Prefetching has side effects (GET links that mutate state, metered data): only use the event, never the prefetch attribute
Installation
node scripts/add.mjs foresee --out ./src/marvelousKI-Agent mit dem MCP-Server von Marvelous UI: install_components({ slugs: ["foresee"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).
Kopierte Dateien (inklusive Abhängigkeiten): tokens/tokens.css, core/base.css, core/dom.js, core/element.js, core/motion.js, core/observe.js, components/foresee/foresee.js, components/foresee/foresee.css.
Verwendung
Referenz-Markup zum Starten und Anpassen mit Attributen, data-* und CSS-Variablen:
<div id="pc-demo" style="width:min(100%,64rem);margin-inline:auto">
<style>
#pc-demo { --pc-gap: .875rem }
#pc-demo .pc-layout { display:grid; grid-template-columns:minmax(0,1fr) 17rem; gap:1.25rem; align-items:start }
#pc-demo .pc-top { display:flex; align-items:center; justify-content:space-between; gap:.75rem 1rem; flex-wrap:wrap; margin:0 0 1rem }
#pc-demo .pc-top h3 { margin:0; font-size:1.125rem; letter-spacing:-.01em }
#pc-demo .pc-top p { margin:.125rem 0 0; color:var(--mv-fg-muted); font-size:.8125rem }
#pc-demo .pc-actions { display:flex; gap:.5rem; flex-wrap:wrap }
#pc-demo .pc-grid { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:var(--pc-gap) }
#pc-demo .pc-card { display:grid; grid-template-columns:auto minmax(0,1fr); gap:.25rem .75rem; align-items:start; padding:1rem; border:1px solid var(--mv-border); border-radius:var(--mv-radius-xl); background:var(--mv-surface); color:inherit; text-decoration:none; transition:border-color var(--mv-duration-fast), background-color var(--mv-duration-fast) }
#pc-demo .pc-card:hover { border-color:var(--mv-border-strong) }
#pc-demo .pc-card:focus-visible { outline:none; box-shadow:var(--mv-focus-ring) }
#pc-demo .pc-card[data-foresee="foreseen"] { background:color-mix(in oklab, var(--mv-accent) calc(3% * var(--mv-foresee-confidence, 0) + 1%), var(--mv-surface)) }
#pc-demo .pc-ico { grid-row:span 2; display:grid; place-items:center; width:2.25rem; height:2.25rem; border-radius:var(--mv-radius-lg); background:var(--mv-bg-muted); color:var(--mv-fg-muted) }
#pc-demo .pc-ico svg { width:1.125rem; height:1.125rem }
#pc-demo .pc-card b { font-size:.875rem; font-weight:600 }
#pc-demo .pc-card span.pc-d { color:var(--mv-fg-muted); font-size:.75rem; line-height:1.4 }
#pc-demo .pc-hud { position:sticky; top:1rem; display:grid; gap:1rem; padding:1.125rem; border:1px solid var(--mv-border); border-radius:var(--mv-radius-xl); background:var(--mv-surface-raised); box-shadow:var(--mv-shadow-sm); font-size:.8125rem }
#pc-demo .pc-hud h4 { display:flex; align-items:center; justify-content:space-between; margin:0; font-size:.8125rem; font-weight:600 }
#pc-demo .pc-k { color:var(--mv-fg-muted); font-size:.6875rem; letter-spacing:.04em; text-transform:uppercase; font-weight:600 }
#pc-demo .pc-now { display:grid; gap:.375rem }
#pc-demo .pc-target { font-size:1rem; font-weight:600; letter-spacing:-.01em; min-height:1.5rem; overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
#pc-demo .pc-target[data-empty] { color:var(--mv-fg-subtle); font-weight:500; font-size:.875rem }
#pc-demo .pc-bar { position:relative; height:6px; border-radius:3px; background:var(--mv-bg-muted); overflow:hidden }
#pc-demo .pc-bar i { position:absolute; inset:0; border-radius:inherit; background:var(--mv-accent); transform-origin:left; scale:var(--v,0) 1; transition:scale 120ms linear }
#pc-demo .pc-bar-row { display:flex; justify-content:space-between; color:var(--mv-fg-muted); font-size:.75rem; font-variant-numeric:tabular-nums }
#pc-demo .pc-stats { display:grid; grid-template-columns:1fr 1fr; gap:.75rem; margin:0 }
#pc-demo .pc-stats div { display:grid; gap:.125rem; padding:.625rem .75rem; border-radius:var(--mv-radius-lg); background:var(--mv-bg-subtle) }
#pc-demo .pc-stats dt { color:var(--mv-fg-muted); font-size:.6875rem }
#pc-demo .pc-stats dd { margin:0; font-size:1.25rem; font-weight:650; letter-spacing:-.02em; font-variant-numeric:tabular-nums }
#pc-demo .pc-stats dd small { font-size:.6875rem; font-weight:500; color:var(--mv-fg-muted); letter-spacing:0 }
#pc-demo .pc-log { list-style:none; margin:0; padding:0; display:grid; gap:.375rem }
#pc-demo .pc-log li { display:flex; justify-content:space-between; gap:.5rem; font-size:.75rem; color:var(--mv-fg-muted) }
#pc-demo .pc-log li b { color:var(--mv-fg); font-weight:500; overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
#pc-demo .pc-log li[data-hit="false"] b::after { content:" · dissent"; color:var(--mv-fg-subtle); font-weight:400 }
#pc-demo .pc-log li span { font-variant-numeric:tabular-nums; white-space:nowrap }
#pc-demo .pc-log .pc-empty { color:var(--mv-fg-subtle) }
#pc-demo .pc-sep { height:1px; background:var(--mv-border) }
#pc-demo .pc-hint { margin:.875rem 0 0; color:var(--mv-fg-muted); font-size:.75rem; text-align:center }
@media (max-width:52rem) {
#pc-demo .pc-layout { grid-template-columns:minmax(0,1fr) }
#pc-demo .pc-hud { position:static }
}
@media (max-width:36rem) { #pc-demo .pc-grid { grid-template-columns:minmax(0,1fr) } }
</style>
<div class="pc-layout">
<mv-foresee id="pc-region" prefetch>
<div class="pc-top">
<div>
<h3>Workspace</h3>
<p>Northwind Labs · 14 members</p>
</div>
<div class="pc-actions">
<button class="mv-button" data-variant="outline" data-size="sm" type="button">Invite</button>
<button class="mv-button" data-variant="outline" data-size="sm" type="button">Export</button>
<button class="mv-button" data-size="sm" type="button">New project</button>
</div>
</div>
<nav class="pc-grid" aria-label="Workspace sections">
<a class="pc-card" href="#overview"><span class="pc-ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="3" width="7" height="9" rx="1.5"/><rect x="14" y="3" width="7" height="5" rx="1.5"/><rect x="14" y="12" width="7" height="9" rx="1.5"/><rect x="3" y="16" width="7" height="5" rx="1.5"/></svg></span><b>Overview</b><span class="pc-d">Key metrics and recent activity</span></a>
<a class="pc-card" href="#projects"><span class="pc-ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg></span><b>Projects</b><span class="pc-d">12 active · 3 due this week</span></a>
<a class="pc-card" href="#analytics"><span class="pc-ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 20V10"/><path d="M10 20V4"/><path d="M16 20v-7"/><path d="M22 20H2"/></svg></span><b>Analytics</b><span class="pc-d">Traffic, funnels and retention</span></a>
<a class="pc-card" href="#docs"><span class="pc-ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z"/><path d="M14 3v5h5"/><path d="M9 13h6M9 17h4"/></svg></span><b>Documentation</b><span class="pc-d">Guides, API reference, changelog</span></a>
<a class="pc-card" href="#billing"><span class="pc-ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2.5" y="5" width="19" height="14" rx="2"/><path d="M2.5 10h19"/><path d="M6.5 15h3"/></svg></span><b>Billing</b><span class="pc-d">Pro plan · $240 / month</span></a>
<a class="pc-card" href="#team"><span class="pc-ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="9" cy="8" r="3.5"/><path d="M2.5 20a6.5 6.5 0 0 1 13 0"/><path d="M16 4.5a3.5 3.5 0 0 1 0 7"/><path d="M18.5 14.5a6.5 6.5 0 0 1 3 5.5"/></svg></span><b>Team</b><span class="pc-d">Roles, invitations and access</span></a>
<a class="pc-card" href="#integrations"><span class="pc-ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 2v6M15 2v6"/><path d="M6 8h12v4a6 6 0 0 1-12 0z"/><path d="M12 18v4"/></svg></span><b>Integrations</b><span class="pc-d">Slack, GitHub and 20 more</span></a>
<a class="pc-card" href="#security"><span class="pc-ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 2.5 4 5.5v6c0 4.8 3.4 8.7 8 10 4.6-1.3 8-5.2 8-10v-6z"/><path d="m8.8 12 2.2 2.2 4.2-4.4"/></svg></span><b>Security</b><span class="pc-d">SSO, audit log, API keys</span></a>
<a class="pc-card" href="#settings"><span class="pc-ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.7 1.7 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1a1.7 1.7 0 0 0-1.1-1.5 1.7 1.7 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1a1.7 1.7 0 0 0 1.5-1.1 1.7 1.7 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.8.3H9a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.8V9a1.7 1.7 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1z"/></svg></span><b>Settings</b><span class="pc-d">Workspace name, region, defaults</span></a>
</nav>
</mv-foresee>
<aside class="pc-hud" aria-label="Foresight monitor">
<h4>Foresight <span class="mv-badge" data-variant="secondary" data-shape="pill" id="pc-source">idle</span></h4>
<div class="pc-now">
<span class="pc-k">Foreseen</span>
<span class="pc-target" id="pc-target" data-empty>Move toward a card…</span>
<div class="pc-bar" aria-hidden="true"><i id="pc-bar"></i></div>
<div class="pc-bar-row"><span>Confidence</span><span id="pc-conf">-</span></div>
</div>
<dl class="pc-stats">
<div><dt>Accuracy</dt><dd id="pc-acc">-</dd></div>
<div><dt>Last head start</dt><dd id="pc-lead">-</dd></div>
<div><dt>Hits</dt><dd id="pc-hits">0 <small>of 0</small></dd></div>
<div><dt>Avg head start</dt><dd id="pc-avg">-</dd></div>
</dl>
<div class="pc-sep"></div>
<div class="pc-now">
<span class="pc-k">Warmed up before the click</span>
<ol class="pc-log" id="pc-log"><li class="pc-empty">Nothing yet: click any card</li></ol>
</div>
<label class="mv-choice" data-control="end">
<input type="checkbox" role="switch" class="mv-switch" id="pc-ring" checked>
<span class="mv-choice-text"><span class="mv-choice-title">Show foresight ring</span></span>
</label>
<span class="mv-sr-only" role="status" id="pc-status"></span>
</aside>
</div>
<p class="pc-hint">Head for a card and slow down as you approach: it is foreseen before you click · Tab through the cards for keyboard foresight</p>
<script type="module">
const pc = document.getElementById("pc-region");
await customElements.whenDefined("mv-foresee");
const $ = (id) => document.getElementById(id);
const target = $("pc-target"), bar = $("pc-bar"), conf = $("pc-conf"), source = $("pc-source");
const log = $("pc-log");
let raf = 0;
const labels = { pointer: "trajectory", keyboard: "keyboard", press: "press", touch: "touch", api: "app" };
const paint = () => {
raf = 0;
if (!pc.isConnected) return;
const f = pc.foreseen;
if (!f) return;
bar.style.setProperty("--v", f.confidence.toFixed(2));
conf.textContent = `${Math.round(f.confidence * 100)}%`;
raf = requestAnimationFrame(paint);
};
pc.addEventListener("mv-foresee", (e) => {
const { label, source: src } = e.detail;
target.textContent = e.detail.target.querySelector("b")?.textContent ?? label;
target.removeAttribute("data-empty");
source.textContent = labels[src] ?? src;
source.dataset.variant = src === "pointer" ? "info" : "secondary";
// Here the app would warm up whatever the section needs (data, code, a dialog…).
if (!raf) raf = requestAnimationFrame(paint);
});
pc.addEventListener("mv-foresee-end", () => {
cancelAnimationFrame(raf); raf = 0;
target.textContent = "Move toward a card…";
target.setAttribute("data-empty", "");
source.textContent = "idle"; source.dataset.variant = "secondary";
bar.style.setProperty("--v", 0);
conf.textContent = "-";
});
pc.addEventListener("click", (e) => { if (e.target.closest("a[href^='#']")) e.preventDefault(); });
const ms = (v) => (v == null ? "-" : `${v} ms`);
pc.addEventListener("mv-verdict", (e) => {
const { hit, actual, predicted, leadTime, source: src } = e.detail;
const s = pc.stats;
$("pc-acc").textContent = s.accuracy == null ? "-" : `${Math.round(s.accuracy * 100)}%`;
$("pc-hits").replaceChildren(`${s.hits} `, Object.assign(document.createElement("small"), { textContent: `of ${s.predictions}` }));
$("pc-avg").textContent = ms(s.avgLeadTime);
if (hit) $("pc-lead").textContent = ms(leadTime);
const name = (el) => el?.querySelector("b")?.textContent ?? el?.textContent.trim() ?? "";
const li = document.createElement("li");
li.dataset.hit = String(hit);
const b = document.createElement("b");
b.textContent = name(actual);
const t = document.createElement("span");
t.textContent = hit ? `${leadTime} ms early` : predicted ? `foresaw ${name(predicted)}` : "not foreseen";
li.append(b, t);
log.querySelector(".pc-empty")?.remove();
log.prepend(li);
while (log.children.length > 4) log.lastElementChild.remove();
$("pc-status").textContent = hit ? `${name(actual)} was foreseen ${leadTime} milliseconds early (${src}).` : `${name(actual)} was not foreseen.`;
});
$("pc-ring").addEventListener("change", (e) => { pc.showIndicator = e.target.checked; });
</script>
</div>Kulturelle Referenz
Minority Report, Steven Spielberg (nach der Kurzgeschichte von Philip K. Dick aus dem Jahr 1956) (2002, Film). Hellseher sehen eine Tat voraus, bevor sie geschieht, und eine abweichende Vision wird als Minderheitenbericht abgelegt. Übertragen auf die UI: Die Zeigerbahn sagt den Klick voraus, bevor er geschieht, die App handelt vorab, und jede falsche Vorhersage wird als Abweichung in der eigenen Bilanz der Komponente verbucht.
API
Attributes
| Name | Typ | Default | Description |
|---|---|---|---|
threshold | number (0..1) | 0.55 | Confidence above which the best candidate is foreseen (it must also stay there for dwell ms). Lower = earlier but more dissents; the foresight is dropped when its confidence falls below 60% of the threshold for 200 ms or another target wins. |
targets | CSS selector | a[href], button, [role='button'], [data-foresee] | Candidates inside the region. Disabled ones (:disabled, aria-disabled="true", inside [inert]) and invisible ones are skipped. Rects are cached and refreshed only on scroll, resize or DOM changes. |
prefetch | boolean | false | When a same-origin http(s) link is foreseen and mv-foresee is not canceled, inserts <link rel="prefetch"> once per URL (deduplicated across the document). Skipped for in-page anchors, download links, data-foresee-prefetch="false" and when the browser asks to save data. |
show-indicator | "true" | "false" | true | "false" hides the ring: the component still foresees, emits events and prefetches, invisibly. |
dwell | number (ms) | 40 | How long the best candidate must stay above the threshold before it is foreseen (filters out fly-overs). |
data-foresee | "foreseen" | any | On a candidate: set to "foreseen" by the component while it is foreseen (its previous value is restored afterwards). Any element carrying the attribute is also a candidate by default. | |
data-foresee-label | string | On a candidate: name reported in events and the foreseen property (default: aria-label, aria-labelledby, then text). | |
data-foresee-prefetch | "false" | On a link: never prefetched, even when foreseen. |
Properties
| Name | Typ | Description |
|---|---|---|
foreseen | { target, confidence, source, since, label } | null | Current foresight (read-only). source: "pointer" (trajectory), "keyboard" (focus), "press" (mouse/pen down), "touch" or "api". confidence is updated every frame while the pointer moves. |
stats | { predictions, hits, misses, accuracy, avgLeadTime } | Score of the pointer foresight (read-only). predictions = pointer clicks judged, hits = clicks on the foreseen target, accuracy = hits / predictions (null before the first click), avgLeadTime = mean head start of hits in ms. Keyboard and touch foresights are certain by construction and are not counted. |
threshold / targets / prefetch / showIndicator / dwell | reflected | Mirror the attributes. |
Methods
| Name | Description |
|---|---|
foresee(target, { confidence? }) | Forces a foresight on a candidate (element or selector) from app logic, e.g. the next step of a wizard. Emits mv-foresee like any other foresight. Returns false if the element is not a candidate. |
resetStats() | Clears the score. |
Events
| Name | Description |
|---|---|
mv-foresee | A target is foreseen. detail: { target, confidence, leadTime (estimated ms until the click, null when unknown), distance (px left to travel, 0 once on the target), source, label }. Cancelable: preventDefault() skips the built-in prefetch; warm up anything else here. |
mv-foresee-end | The foresight ended. detail: { target, reason: "lost" | "replaced" | "leave" | "click" | "blur" | "disconnect" }. |
mv-verdict | A candidate was clicked (or activated with the keyboard). detail: { hit, predicted (element or null), actual, leadTime (ms between foresight and click, hits only), confidence, source, stats }. A miss is a dissent: the prediction standing at pointerdown is the one judged. |
Content structure
| Name | Description |
|---|---|
(content) | Any region containing links and buttons. The ring is drawn in an overlay layer appended to the element; the app's DOM is only touched through data-foresee and --mv-foresee-confidence on the foreseen target. |
CSS classes
| Name | Description |
|---|---|
mv-foresee-layer | Overlay (aria-hidden, pointer-events: none) holding the indicator; hidden when show-indicator="false". |
mv-foresee-indicator / -ring | The foresight ring. data-active while visible, data-source, data-verdict="hit | miss" for half a second after a click, --_c = confidence. |
CSS variables
| Name | Default | Description |
|---|---|---|
--mv-foresee-confidence | 0..1 | Set on the foreseen target: style it by confidence (subtle tint, raised shadow…). |
--mv-foresee-color | var(--mv-accent) | Ring tint. |
--mv-foresee-offset | 3px | Gap between the target and the ring (the ring's corner radius follows the target's plus this gap). |
Accessibility
Purely additive: nothing is announced and focus is never moved, the ring is aria-hidden with pointer-events: none, and the foreseen target keeps its role, name and behavior (only data-foresee and a CSS variable are added, then restored). Keyboard users get the same benefit as pointer users: moving focus to a candidate is a foresight with confidence 1 (mv-foresee fires, links are prefetched), while the visible focus ring stays the only indicator so the two never compete. Touch has no hover, so a press foresees immediately and gives ~100 ms of head start before the click. The verdict is observed in the capture phase without calling preventDefault, so links and buttons work exactly as before. Reduced motion (prefers-reduced-motion or data-motion="reduce"): the ring jumps between targets with no glide and no pulse; confidence is still shown as a static change of intensity. Forced colors: the ring uses the Highlight system color. Performance: pointer events only store coordinates; scoring runs in a frameLoop that sleeps when the pointer is still, candidate rects are read once per invalidation (scroll, resize, DOM changes) and never inside the loop's write phase; everything stops when the element is removed.