Catalog ›Personal life ›Wellbeing
Vigor — health and training
Measurements, medications and workouts in a single diary — with data that never leaves your device.
⚖️ Measurements💊 Medications🏃 Workouts
data space «vigor-en» — the suite’s glue: on your device, multi-user with one invite (link or QR), end-to-end encrypted.
What it records
- Weight (kg)
- Blood pressure (e.g. 120/80)
- Medication / supplement
- Dose (e.g. 1 tablet)
- When (e.g. morning and evening)
- Activity...
- Duration (minutes)
Composed of 3 micro apps
One job each, over the same data: every micro app reads and writes the shared data space “vigor-en” (with your consent, asked on first open). Everything stays on your device — and with a single invite the whole suite goes multi-user, end-to-end encrypted.
How it works
This is a Reactive app: a plain text document that your browser turns into a working app — forms, live data, tables, statistics and even charts, with nothing to install or configure.
- Use it right away. Hit “Use this app”: it opens right in your browser, ready to go, with data saved only on your device.
- Your data stays yours. Everything is stored locally on your device, kept separate for each app: no account, no server, nothing to set up.
- Make it your own. The text below is the entire app: copy it, tweak fields, views and words, and your changes become interactive instantly.
- Share it as a file. An app is a simple file: save it, export it or share it with a link; and with encrypted collaboration several people edit the same data in real time.
The app’s source
# 💪 Vigor
Measurements, medications and workouts in a single diary — with data that never leaves your device.
:::::page{title="Measurements" icon="⚖️"}
## The measurements diary
::::form{path="measurements" id="fmi"}
::input{form="fmi" field="date" type="date" required="true" legend="Day"}
::input{form="fmi" field="weight" type="number" placeholder="Weight (kg)" required="true"}
::input{form="fmi" field="pressure" placeholder="Blood pressure (e.g. 120/80)"}
::add-form{form="fmi" path="measurements" label="Log"}
::::
:::table{path="measurements" headers="Day,Weight,Pressure" deletable="true" editform="fmi"}
{date} | {weight} kg | {pressure}
:::
:::python{data="measurements" packages="matplotlib"}
```
import matplotlib.pyplot as plt
rows = data.get("measurements", [])
series = sorted(
((r.get("date", ""), float(r.get("weight", 0) or 0)) for r in rows if r.get("weight")),
key=lambda x: x[0],
)
if len(series) < 2:
print("Log at least two weigh-ins to see the trend.")
else:
fig, ax = plt.subplots(figsize=(6, 3))
ax.plot([d for d, _ in series], [p for _, p in series], marker="o")
ax.set_ylabel("kg")
ax.set_title("Weight trend")
plt.xticks(rotation=30)
plt.tight_layout()
```
:::
:::::
:::::page{title="Medications" icon="💊"}
## What to take and when
::::form{path="medications" id="ffa"}
::input{form="ffa" field="name" placeholder="Medication / supplement" required="true"}
::input{form="ffa" field="dose" placeholder="Dose (e.g. 1 tablet)"}
::input{form="ffa" field="schedule" placeholder="When (e.g. morning and evening)"}
::add-form{form="ffa" path="medications" label="Add"}
::::
:::list{path="medications" deletable="true" editform="ffa"}
**{name}** — {dose} · {schedule}
:::
:::::
:::::page{title="Workouts" icon="🏃"}
## The plan on the calendar
::::form{path="workouts" id="fal"}
::input{form="fal" field="date" type="date" required="true" legend="Day"}
:::select{form="fal" field="type" placeholder="Activity..."}
- Running
- Gym
- Cycling
- Swimming
- Walking
:::
::input{form="fal" field="duration" type="number" placeholder="Duration (minutes)"}
::add-form{form="fal" path="workouts" label="Plan"}
::::
:::calendar{path="workouts" field="date"}
{type} {duration}′
:::
**Sessions:** :count[nal]{path="workouts"} —
**Total minutes:** :sum[mal]{path="workouts" field="duration"}
:::::