feat(editor): animate the canvas in step with the simulation

A simulation store owns one run and one playhead, so the chart and the canvas
read off the same instant. While the panel is open, Stocks show a live value and
a fill gauge, Flows and Converters their current value; a play/pause + scrubber
drives the playhead (a wall-clock-paced clock in usePlayback), and a marker
tracks it on the chart.
This commit is contained in:
Julien Calixte
2026-06-20 14:35:45 +02:00
parent c361b05ec4
commit 69435b1315
8 changed files with 290 additions and 75 deletions

View File

@@ -9,6 +9,8 @@ import { computed } from "vue"
import { useNodeLoopRing } from "@/composables/useLoopHighlight"
import { HANDLE_IN, HANDLE_OUT, type NodeData } from "@/model/projection"
import type { ConverterNode } from "@/model/types"
import { useSimulationStore } from "@/store/simulation"
import { formatValue } from "./format"
import NodeLabel from "./NodeLabel.vue"
const props = defineProps<NodeProps<NodeData>>()
@@ -16,6 +18,9 @@ const props = defineProps<NodeProps<NodeData>>()
// The projection guarantees a converter-typed node here.
const converter = computed(() => props.data.node as ConverterNode)
const loopRing = useNodeLoopRing(props.id)
const sim = useSimulationStore()
const value = computed(() => sim.valueAt(props.id))
</script>
<template>
@@ -25,6 +30,12 @@ const loopRing = useNodeLoopRing(props.id)
:class="[props.selected ? 'border-primary' : 'border-base-300', loopRing]"
>
<Handle :id="HANDLE_IN" type="target" :position="Position.Left" />
<span
v-if="value !== null"
class="pointer-events-none absolute inset-0 flex items-center justify-center font-mono text-xs tabular-nums text-base-content/70"
>
{{ formatValue(value) }}
</span>
<Handle :id="HANDLE_OUT" type="source" :position="Position.Right" />
</div>
<NodeLabel :node-id="props.id" :name="converter.name" />