← Cycles
Design · c91

DataMachine

archivedcreated 2026-09-17· last activity 2026-09-18· mode: assemblage — every piece is composed from existing primitives (`DataMetricValue`, `DataMetricTrend`, `DataMetricSpark`, `DataDonutChart`); the work is composition, not invention

Build the `DataMachine` composition component and document the base-component + curated-preset pattern it embodies

New in this cycle: DataMachine — the base-component + curated-preset pattern qmap arrived at, now a named layer idea

Why

Looking at the emerging DataMachine design (split out of c90's qcontrol page-chrome work), the same shape qmap and qflow arrived at independently became visible: a base component made maximally expressive — many props, deep visual range — specifically so the library maintainers, not end consumers, can curate a handful of copyable, pre-configured examples for real use cases. qmap's realization is explicit and documented: QMap (42 props) + preset wrapper components QMapDataflow/QMapPolicyViolation, with the workflow spelled out in qmap's own CLAUDE.md glossary ("Config Lab → tune → export → paste into a wrapper"). qflow hasn't grown this yet — TrafficViz is still simple (5 props) — but the same instinct is visible in its clientConfig/mode props.

This is a scope departure from c90 (qcontrol page-chrome assembly), so it becomes its own cycle rather than a thread inside c90.

Objective

Ship DataMachine as a new q-nuxt-layer composition component, document it on the design site with the two reference mockups as copyable presets, and write the base+preset pattern into component_philosophy.md and design_methodology.md as a named, reusable idea.

Scope

  1. q-nuxt-layer/components/data/machine/index.vue — new composition component. Composes DataMetricValue, DataMetricTrend, and DataMetricSpark as-is; adds new inline markup (title, full-width hairline, description, provenance row) that has no reuse case outside DataMachine, so it stays flat (index.vue + no sub-files) rather than following the _/ primitive-vs-layout split used by components/data/metric/ and components/data/history-graph/. #left/#right slots for consumer-composed content (icon grids, DataDonutChart) — no new primitives built for these.
  2. Design-site documentation — registry entry (new group, since DataMachine composes data-metric primitives rather than being one), _demos/DataMachine.vue with the two reference mockups ("User Coverage", "Devices Sensored") as primary copyable presets plus empty/minimal/typical/overflow/error scenario coverage, visual index placement.
  3. Philosophy docs — extend Principle 4 (Progressive enhancement) and its Design Lineage paragraph in component_philosophy.md; extend "Decomposition and Modularity" in design_methodology.md. Both cite qmap → DataMachine as the cross-project instance of the pattern.

Preset scope: design-site demo presets only for now, not named layer-level wrapper components like QMapDataflow. The two reference images become copyable example configs in DataMachine's own demo file — proving the pattern without committing to named wrapper components before real qcontrol usage validates which configs are worth freezing.

Explicitly out of scope: refactoring the existing _/ convention in components/data/metric/ or components/data/history-graph/ — those families have primitives genuinely reused outside their own layouts and keep their existing structure.

Key Changes

  • 2026-09-17 — Built q-nuxt-layer/components/data/machine/index.vue (DataMachine): title, full-width hairline, optional description, and provenance row wrapped around DataMetricValue/DataMetricTrend/DataMetricSpark, with #left/#right slots for consumer-composed content. No changes needed to the reused primitives — DataMetricValue's existing unit handling already covers bytes/duration/ms/%/custom passthrough cleanly.
  • 2026-09-17 — Documented on the design site: new data-machine registry group + DataMachine entry, _demos/DataMachine.vue with the two reference presets ("User Coverage", "Devices Sensored") plus empty/minimal/typical/overflow/error scenarios and a unit-passthrough spot-check, visual-index placement on /components. Also fixed a stale leftover from the c28 data-metric rename: the data-metric group's registry label and /components section header both still read "Data Machine" — renamed to "Data Metric" so the new real DataMachine component doesn't collide with it.
  • 2026-09-17 — Wrote the base + curated-presets pattern into component_philosophy.md (Principle 4 + Design Lineage) and design_methodology.md (Decomposition and Modularity), citing qmap's QMap/QMapDataflow/QMapPolicyViolation as the precedent and DataMachine as the new cross-project instance.
  • 2026-09-17 — Swapped the demo's hand-rolled, too-smooth sparkline arrays for the existing app/data/sparklines.ts fixtures (sparkNoise for generic examples, sparkUp for the positive-delta "Devices Sensored" preset) — real telemetry is jagged, not a clean ramp.
  • 2026-09-17 — Added a UxCopyBtn (icon-only, top-right corner) to each preset card in the demo, copying a self-contained Vue template snippet of that exact preset — makes the "copy this, don't hand-assemble" pattern literal instead of just stated.
  • 2026-09-17 — Fixed a real bug in DataMetricSpark surfaced by using it unfilled: svgMachine.sparkChart always injected baseline anchor points ((0,-10) / (width+10,-1)) meant to close a filled polygon; with fillColor="none" those anchors render as a visible drop at the start/end of the stroked line. Added a closePath param (q-nuxt-layer/utils/svg.js) and had DataMetricSpark pass fillColor !== 'none', so line-only sparklines render clean. Also fixes the same latent artifact in SecurityPolicyCard's three sparklines (verified, no regression). SparkChartOld untouched — deprecated, out of scope.
  • 2026-09-17 — Replaced the static sparkNoise/sparkUp fixtures with a new generateVelocitySpark() helper in app/data/sparklines.ts — a damped random walk (velocity carries forward instead of each point being independent) so the line moves in short organic runs like real traffic, with an optional drift for a biased trend (used for the positive-delta "Devices Sensored" preset).
  • 2026-09-17 — Added optional slotGap prop (Number, px) — extra spacing between #left/#right slot content and the main value/delta group, on top of the row's default gap. Implemented as conditional margin on v-if="$slots.left/right" wrappers so it costs nothing when a slot is unused. Demoed with a dedicated "Slot Gap" comparison (default vs. slotGap="24") and documented in the registry.

Outcome

Shipped DataMachine composing existing DataMetric primitives with no changes required to them, proving the base+presets pattern didn't need new primitive work — just new composition markup (title/hairline/description/provenance) that has no reuse case outside this component, hence the flat index.vue convention rather than the _/ split. Presets stayed at the design-site-demo level rather than named layer wrappers, deferring that decision until real qcontrol usage validates which configs are worth freezing. The pattern itself is now named and cross-referenced in both philosophy docs, closing the loop qmap/qflow opened independently.

Visual record

2 captures — heroes, page slices, and full-page renders. Click to view.

/components/data-machine — adminProps harness above the two copyable presets (User Coverage, Devices Sensored) and the scenario grid
/components/data-machine — adminProps harness above the two copyable presets (User Coverage, Devices Sensored) and the scenario grid open page →history · 2 moments →
c91 full
open page →history · 2 moments →

Artifacts

Qpoint Brand Style Guide