Website: machine estimator v3 — the bar shows what the box's memory is used for (still unlisted, R-997)
gates / gates (push) Successful in 6m29s
gates / gates (push) Successful in 6m29s
The bar keeps its length (the fits-well box memory) and is split into base system (box - guest), Felhom's own services, each app's peak (largest first, the dashboard's palette minus amber and its first blue; beyond 8 apps one group) and spare room (guest - peak) — all from the one rule; a test proves the parts sum to the bar within 1 MB. A legend under it (not sticky) and one sentence explain the recommended size. Typical figure moved into the method fold-out. English: 'an 8 GB machine'.
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -1,3 +1,12 @@
|
||||
## 2026-10-13 (evening) — estimator v3: segments and the English article under test
|
||||
|
||||
- `build_sizing_web.py`: `bar_app_colours` (8) in the data file, so the script holds no number of its own.
|
||||
- `test_build_sizing_web.py` (10 tests): the bar's segments (base system = box − guest, Felhom, each app's peak,
|
||||
spare = guest − peak) add up to the bar within 1 MB for the four cases and for nothing selected; base and spare are
|
||||
never negative; the household preset by hand (spare = 5,515 × 0.5, base = 4,096 + 612); every English
|
||||
recommendation gets „an 8" / „a 12" … Red-proofed: the „an 8" rule removed, the JS computing spare from the typical
|
||||
figure, and segments off by 50 MB each convicted.
|
||||
|
||||
## 2026-10-13 (afternoon) — estimator v2: `build_sizing_web.py` box sizes, tests for the inverse
|
||||
|
||||
- `build_sizing_web.py`: `boxes_gb` = 8, 12, 16, 24, 32, 48, 64; new `bar_marks_gb` and `bar_max_gb`.
|
||||
|
||||
@@ -36,6 +36,7 @@ GUEST_RULE = {"reserve_mib": 4096, "max_gap_mib": 2048, "min_mib": 4096, "ceilin
|
||||
BOXES_GB = [8, 12, 16, 24, 32, 48, 64] # the common sizes a recommendation names (v2: 12, 24, 48, 64 added)
|
||||
BAR_MARKS_GB = [8, 16, 24, 32, 48, 64] # the memory bar's marks; the last one reads "64+"
|
||||
BAR_MAX_GB = 64 # the bar's linear scale is 0..BAR_MAX_GB
|
||||
BAR_APP_COLOURS = 8 # v3: apps get their own colour up to this many; the rest join one segment
|
||||
BUILTIN = {"filebrowser"}
|
||||
|
||||
# One short line per medium / heavy-in-bursts app (the 9 of 2026-10-13). sizing.json's English notes, tidied.
|
||||
@@ -119,6 +120,7 @@ def build():
|
||||
boxes_gb=BOXES_GB,
|
||||
bar_marks_gb=BAR_MARKS_GB,
|
||||
bar_max_gb=BAR_MAX_GB,
|
||||
bar_app_colours=BAR_APP_COLOURS,
|
||||
categories=[dict(id=h[0], id_en=e[0], name_hu=h[1], name_en=e[1]) for h, e in zip(hu_cats, en_cats)],
|
||||
apps=apps,
|
||||
)
|
||||
|
||||
@@ -59,6 +59,16 @@ def estimate(d, slugs): # mirrors sizing.js estimate()
|
||||
return peak, out
|
||||
|
||||
|
||||
def segments(d, slugs): # mirrors estimate().segments in sizing.js (v3)
|
||||
by = {a["slug"]: a for a in d["apps"]}
|
||||
apps = sorted((by[s] for s in slugs if not by[s].get("builtin")), key=lambda a: -a["peak_mb"])
|
||||
peak = d["platform_mb"] + sum(a["peak_mb"] for a in apps)
|
||||
well = min_box_gb(d, peak * d["headroom"])
|
||||
box, guest = well * 1024, guest_mib(d, well)
|
||||
return well, [("base", box - guest), ("platform", d["platform_mb"])] + \
|
||||
[(a["slug"], a["peak_mb"]) for a in apps] + [("spare", guest - peak)]
|
||||
|
||||
|
||||
def first(d, verdicts, want): # mirrors recommend_gb / tight_box_gb in sizing.js
|
||||
return next((gb for gb, v in zip(d["boxes_gb"], verdicts) if v == want), None)
|
||||
|
||||
@@ -112,6 +122,32 @@ class SizingWeb(unittest.TestCase):
|
||||
if rec is not None:
|
||||
self.assertGreaterEqual(rec, gb - 1 / 1024)
|
||||
|
||||
def test_segments_add_up_to_the_bar(self):
|
||||
for name, sel in {"household": HOUSEHOLD, "household without immich": [x for x in HOUSEHOLD if x != "immich"],
|
||||
"immich alone": ["immich"], "all 62": self.all, "nothing": []}.items():
|
||||
well, segs = segments(self.d, sel)
|
||||
self.assertAlmostEqual(sum(mb for _, mb in segs), well * 1024, delta=1, msg=name)
|
||||
self.assertGreaterEqual(dict(segs)["base"], 0, name + ": base system negative")
|
||||
self.assertGreaterEqual(dict(segs)["spare"], 0, name + ": spare negative")
|
||||
# the household preset, by hand: peak 5,515 MiB; the bar holds 5,515 * 1.5 = 8,272.5 in the guest
|
||||
well, segs = segments(self.d, HOUSEHOLD)
|
||||
self.assertAlmostEqual(dict(segs)["spare"], 5515 * 0.5, delta=1)
|
||||
self.assertAlmostEqual(dict(segs)["base"], 4708, delta=1) # 4,096 for Proxmox + 612 MemTotal shortfall
|
||||
|
||||
def test_english_article(self):
|
||||
with io.open(os.path.join(ROOT, "website", "en", "sizing.html"), encoding="utf-8-sig") as f:
|
||||
t = json.loads(re.search(r'id="sizer-strings">(.*?)</script>', f.read(), re.S).group(1))
|
||||
def say(tpl, gb): # mirrors fill() in sizing.js
|
||||
art = t["an"] if str(gb) in t["an_before"] else t["a"]
|
||||
return tpl.replace("{a}", art).replace("{gb}", str(gb))
|
||||
got = {gb: say(t["recommend"], gb) for gb in self.d["boxes_gb"]}
|
||||
self.assertEqual(got[8], "Recommended: an 8 GB machine.")
|
||||
for gb in self.d["boxes_gb"]:
|
||||
if gb != 8:
|
||||
self.assertEqual(got[gb], "Recommended: a %d GB machine." % gb)
|
||||
for k in ("tight_on", "only_tight", "none_fits"):
|
||||
self.assertNotRegex(say(t[k], 8), r"\ba 8\b", k)
|
||||
|
||||
def test_sizing_md_table_agrees_with_the_rule(self):
|
||||
with io.open(SIZING_MD, encoding="utf-8") as f:
|
||||
s = f.read()
|
||||
@@ -146,7 +182,8 @@ class SizingWeb(unittest.TestCase):
|
||||
nums = set(re.findall(r"(?<![\w.])\d+(?:\.\d+)?", code))
|
||||
allowed = {"0", "1", "2", "100", "1024"} # 100 = percent, 1024 = MiB per GiB; no rule constant
|
||||
self.assertTrue(nums <= allowed, "sizing.js holds its own numbers: %s" % sorted(nums - allowed))
|
||||
for need in ("data.bar_max_gb", "data.bar_marks_gb", "function minBoxGb", "guestMib(data, mid) >= needMib"):
|
||||
for need in ("data.bar_max_gb", "data.bar_marks_gb", "function minBoxGb", "guestMib(data, mid) >= needMib",
|
||||
"data.bar_app_colours", "boxMb - guestMb", "guestMb - peak"):
|
||||
self.assertIn(need, js)
|
||||
|
||||
def test_data_has_no_peak_below_typical(self):
|
||||
|
||||
+18
-1
@@ -1,4 +1,21 @@
|
||||
## 2026-10-13 (afternoon) — machine estimator v2: fold-out categories and the memory bar
|
||||
## 2026-10-13 (evening) — machine estimator v3: the bar shows what the box's memory is used for
|
||||
|
||||
v2 said the apps use 5 GB at peak and then recommended 16 GB; the reason was invisible. Still unlisted (R-997).
|
||||
|
||||
- **The bar is split** into the parts that make up its length (the „fits well" box memory, unchanged): the machine's
|
||||
base system (grey, as the dashboard's „Rendszer"), Felhom's own services (accent blue), each selected app at its
|
||||
peak (largest first, one colour each — the dashboard's „Memória eloszlás" palette without its amber and its
|
||||
first blue; beyond 8 apps the smallest join „további N alkalmazás"), and spare room (striped). Every part has a
|
||||
`title` with its name and MB; the thin „tight" mark stays; `role="meter"` keeps its value.
|
||||
- **A legend** under the bar (not sticky): a dot, the name, the size in GB with one decimal, in that order, plus the
|
||||
„tight from" mark. Only the bar and the recommendation line stay on screen while scrolling.
|
||||
- **One explaining sentence** replaces the typical/peak line: the peak, the base system and the 50 % spare room —
|
||||
three numbers from the rule — and why that makes the recommended size. The typical figure moved into
|
||||
„Hogyan számol az oldal?".
|
||||
- **English article:** „an 8 GB machine" (the article comes from the page's own strings).
|
||||
- Cache versions `?v=3` for `sizing.css`, `sizing.js` and the data file.
|
||||
|
||||
## 2026-10-13 (afternoon) — machine estimator v2: fold-out categories and the memory bar
|
||||
|
||||
The page was 4,592 px tall on a phone (the reviewer's browser check of v1). Still unlisted (R-997).
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
64
|
||||
],
|
||||
"bar_max_gb": 64,
|
||||
"bar_app_colours": 8,
|
||||
"categories": [
|
||||
{
|
||||
"id": "fajlkezeles",
|
||||
|
||||
@@ -8,12 +8,32 @@
|
||||
.sizer-sticky { position: sticky; top: 0; z-index: 5; background: var(--bg-0); border-bottom: 1px solid var(--line); padding: 0.75rem 0 0.6rem; margin: 0 0 1rem; }
|
||||
.sizer-meter { padding: 0 0 1.4rem; }
|
||||
.sizer-track { position: relative; height: 12px; background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--radius); }
|
||||
.sizer-fill { position: absolute; left: 0; top: 0; bottom: 0; width: 0; background: var(--blue); border-radius: var(--radius); transition: width 0.25s ease; }
|
||||
.sizer-stack { position: absolute; inset: 0; display: flex; overflow: hidden; border-radius: var(--radius); }
|
||||
.sizer-seg { flex: 0 0 auto; height: 100%; transition: width 0.25s ease; }
|
||||
.sizer-tightmark { position: absolute; top: -4px; bottom: -4px; width: 2px; margin-left: -1px; background: var(--warn); transition: left 0.25s ease; }
|
||||
.sizer-scale { position: relative; height: 1rem; margin-top: 0.3rem; }
|
||||
.sizer-mark { position: absolute; transform: translateX(-100%); padding-right: 2px; border-right: 1px solid var(--line); font-family: var(--font-data); font-size: 0.72rem; color: var(--text-3); white-space: nowrap; line-height: 1rem; }
|
||||
.sizer-line { margin: 0; color: var(--text-1); font-weight: 600; line-height: 1.45; }
|
||||
.sizer-legend { margin: 0.2rem 0 0; color: var(--text-3); font-size: 0.78rem; }
|
||||
|
||||
/* v3: what the box's memory is used for — the controller's „Memória eloszlás” bar, same palette (monitoring.html),
|
||||
minus its amber (amber is the warning colour here) and its first blue (Felhom's own services wear the accent) */
|
||||
.sizer { --sz-c1: #8E7CE8; --sz-c2: #5EC4B6; --sz-c3: #D67BB5; --sz-c4: #7FA6E8;
|
||||
--sz-c5: #59B88C; --sz-c6: #E8935E; --sz-c7: #6FCADF; --sz-c8: #B3A1F0; }
|
||||
.sizer-c1 { background: var(--sz-c1); } .sizer-c2 { background: var(--sz-c2); } .sizer-c3 { background: var(--sz-c3); }
|
||||
.sizer-c4 { background: var(--sz-c4); } .sizer-c5 { background: var(--sz-c5); } .sizer-c6 { background: var(--sz-c6); }
|
||||
.sizer-c7 { background: var(--sz-c7); } .sizer-c8 { background: var(--sz-c8); }
|
||||
.sizer-seg-base { background: var(--text-3); opacity: 0.5; }
|
||||
.sizer-seg-platform { background: var(--blue); }
|
||||
.sizer-seg-more { background: var(--text-2); }
|
||||
.sizer-seg-spare { background: repeating-linear-gradient(135deg, var(--line) 0 4px, var(--bg-2) 4px 8px); }
|
||||
.sizer-seg-tightmark { background: var(--warn); }
|
||||
.sizer-why-line { margin: 0 0 0.5rem; color: var(--text-2); line-height: 1.6; }
|
||||
.sizer-why-line .sizer-num { font-family: var(--font-ui); }
|
||||
.sizer-legend { list-style: none; margin: 0 0 1rem; padding: 0; display: flex; flex-wrap: wrap; gap: 0.3rem 1rem; font-size: 0.85rem; color: var(--text-2); }
|
||||
.sizer-legend-item { display: inline-flex; align-items: center; gap: 0.4rem; }
|
||||
.sizer-dot { width: 10px; height: 10px; border-radius: var(--radius); flex: 0 0 auto; }
|
||||
.sizer-dot.sizer-seg-spare { border: 1px solid var(--line); }
|
||||
.sizer-dot.sizer-seg-tightmark { width: 3px; height: 14px; }
|
||||
|
||||
.sizer-result { margin: 0 0 1.25rem; }
|
||||
.sizer-totals { color: var(--text-2); margin: 0; line-height: 1.7; }
|
||||
|
||||
+77
-19
@@ -11,7 +11,10 @@
|
||||
* tight peak <= guest < peak * headroom
|
||||
* no guest < peak
|
||||
* the memory bar: minBoxGb() inverts guestMib() by SEARCHING it — the smallest box memory whose guest
|
||||
* holds peak * headroom (solid fill) and peak (thin marker). It never restates the installer's rule.
|
||||
* holds peak * headroom (the bar's length) and peak (thin marker). It never restates the installer's rule.
|
||||
* v3: the bar is split into what that box memory is used for, every part from the same rule:
|
||||
* base system = box - guest(box) · Felhom = platform · each app = its peak · spare = guest(box) - peak
|
||||
* so the parts add up to the box exactly (scripts/test_build_sizing_web.py proves it).
|
||||
*
|
||||
* The page text is not here: each page carries its own strings (#sizer-strings), so this file is the
|
||||
* same for both languages.
|
||||
@@ -64,10 +67,19 @@
|
||||
if (tightBox === null && b.verdict === 'tight') { tightBox = b.gb; }
|
||||
});
|
||||
var heavy = busy.filter(function (a) { return a.cpu_class === 'heavy-in-bursts'; });
|
||||
var wellGb = minBoxGb(data, peak * data.headroom);
|
||||
var boxMb = wellGb * 1024, guestMb = guestMib(data, wellGb);
|
||||
var apps = slugs.map(function (s) { return bySlug[s]; })
|
||||
.filter(function (a) { return a && !a.builtin; })
|
||||
.sort(function (x, y) { return y.peak_mb - x.peak_mb; });
|
||||
var segments = [{ kind: 'base', mb: boxMb - guestMb }, { kind: 'platform', mb: data.platform_mb }];
|
||||
apps.forEach(function (a) { segments.push({ kind: 'app', app: a, mb: a.peak_mb }); });
|
||||
segments.push({ kind: 'spare', mb: guestMb - peak });
|
||||
return {
|
||||
typical_mb: typical, peak_mb: peak, boxes: boxes, busy: busy, heavy: heavy, unmeasured: unmeasured,
|
||||
well_gb: minBoxGb(data, peak * data.headroom), tight_gb: minBoxGb(data, peak),
|
||||
recommend_gb: recommend, tight_box_gb: tightBox
|
||||
well_gb: wellGb, tight_gb: minBoxGb(data, peak),
|
||||
recommend_gb: recommend, tight_box_gb: tightBox,
|
||||
segments: segments, base_mb: boxMb - guestMb, apps_peak_mb: peak - data.platform_mb
|
||||
};
|
||||
}
|
||||
|
||||
@@ -106,6 +118,13 @@
|
||||
var meter = document.getElementById('sizer-meter');
|
||||
var line = document.getElementById('sizer-line');
|
||||
var result = document.getElementById('sizer-result');
|
||||
var stack = document.getElementById('sizer-stack');
|
||||
var legend = document.getElementById('sizer-legend');
|
||||
var why = document.getElementById('sizer-why-line');
|
||||
var typicalLine = document.getElementById('sizer-typical');
|
||||
// English needs "an 8 GB machine"; the article comes from the page's strings (none in Hungarian)
|
||||
var article = function (gb) { return (T.an_before || []).indexOf(String(gb)) !== -1 ? T.an : T.a; };
|
||||
var fill = function (tpl, gb) { return tpl.replace('{a}', article(gb) || '').replace('{gb}', gb); };
|
||||
|
||||
fetch(host.getAttribute('data-src')).then(function (r) { return r.json(); }).then(function (data) {
|
||||
var max = data.bar_max_gb;
|
||||
@@ -160,11 +179,44 @@
|
||||
g.count.textContent = n ? T.selected.replace('{n}', n) : '';
|
||||
});
|
||||
|
||||
// the bar: solid fill = fits well, thin marker = fits, but tight
|
||||
var wellPct = Math.min(r.well_gb / max, 1) * 100;
|
||||
var tightPct = Math.min(r.tight_gb / max, 1) * 100;
|
||||
document.getElementById('sizer-fill').style.width = wellPct + '%';
|
||||
document.getElementById('sizer-tight').style.left = tightPct + '%';
|
||||
// the bar: its length is the "fits well" box memory, split into what that memory is used for
|
||||
// (estimate().segments); beyond the colour count the smallest apps join one segment
|
||||
var basis = Math.max(r.well_gb, max) * 1024;
|
||||
var segs = [], rest = { kind: 'more', mb: 0, n: 0 }, nApps = 0;
|
||||
r.segments.forEach(function (sg) {
|
||||
if (sg.kind === 'app') {
|
||||
nApps += 1;
|
||||
if (nApps > data.bar_app_colours) { rest.mb += sg.mb; rest.n += 1; return; }
|
||||
sg.colour = 'sizer-c' + nApps;
|
||||
}
|
||||
if (sg.kind === 'spare' && rest.n) { segs.push(rest); }
|
||||
segs.push(sg);
|
||||
});
|
||||
var label = function (sg) {
|
||||
if (sg.kind === 'app') { return lang === 'en' ? sg.app.name_en : sg.app.name_hu; }
|
||||
if (sg.kind === 'more') { return T.seg_more.replace('{n}', sg.n); }
|
||||
return T['seg_' + sg.kind];
|
||||
};
|
||||
stack.textContent = '';
|
||||
legend.textContent = '';
|
||||
segs.forEach(function (sg) {
|
||||
var cls = sg.kind === 'app' ? sg.colour : 'sizer-seg-' + sg.kind;
|
||||
var part = el('div', 'sizer-seg ' + cls);
|
||||
part.style.width = (sg.mb / basis * 100) + '%';
|
||||
part.title = label(sg) + ': ' + Math.round(sg.mb) + ' MB';
|
||||
stack.appendChild(part);
|
||||
var li = el('li', 'sizer-legend-item');
|
||||
li.appendChild(el('span', 'sizer-dot ' + cls));
|
||||
li.appendChild(el('span', '', label(sg) + ' '));
|
||||
li.appendChild(el('span', 'sizer-num', gbText(sg.mb)));
|
||||
legend.appendChild(li);
|
||||
});
|
||||
var tli = el('li', 'sizer-legend-item');
|
||||
tli.appendChild(el('span', 'sizer-dot sizer-seg-tightmark'));
|
||||
tli.appendChild(el('span', '', T.seg_tight + ' '));
|
||||
tli.appendChild(el('span', 'sizer-num', dec(r.tight_gb) + ' GB'));
|
||||
legend.appendChild(tli);
|
||||
document.getElementById('sizer-tight').style.left = (Math.min(r.tight_gb / max, 1) * 100) + '%';
|
||||
var over = r.well_gb > max;
|
||||
var needText = over ? T.over_max.replace('{gb}', max) : dec(r.well_gb) + ' GB';
|
||||
meter.setAttribute('aria-valuenow', String(Math.min(r.well_gb, max).toFixed(1)));
|
||||
@@ -173,23 +225,29 @@
|
||||
// one line: which box to buy, and where it is tight
|
||||
var biggest = data.boxes_gb[data.boxes_gb.length - 1];
|
||||
if (r.recommend_gb !== null) {
|
||||
line.textContent = T.recommend.replace('{gb}', r.recommend_gb) +
|
||||
(r.tight_box_gb !== null ? ' ' + T.tight_on.replace('{gb}', r.tight_box_gb) : '');
|
||||
line.textContent = fill(T.recommend, r.recommend_gb) +
|
||||
(r.tight_box_gb !== null ? ' ' + fill(T.tight_on, r.tight_box_gb) : '');
|
||||
} else if (r.tight_box_gb !== null) {
|
||||
line.textContent = T.only_tight.replace('{gb}', r.tight_box_gb);
|
||||
line.textContent = fill(T.only_tight, r.tight_box_gb);
|
||||
} else {
|
||||
line.textContent = T.none_fits.replace('{gb}', biggest);
|
||||
line.textContent = fill(T.none_fits, biggest);
|
||||
}
|
||||
|
||||
// under the bar: totals, why tight is tight, the CPU lines
|
||||
result.textContent = '';
|
||||
var totals = el('p', 'sizer-totals');
|
||||
totals.appendChild(el('span', '', T.typical + ': '));
|
||||
totals.appendChild(el('strong', 'sizer-num', gbText(r.typical_mb)));
|
||||
totals.appendChild(el('span', '', ' · ' + T.peak + ': '));
|
||||
totals.appendChild(el('strong', 'sizer-num', gbText(r.peak_mb)));
|
||||
result.appendChild(totals);
|
||||
result.appendChild(el('p', 'sizer-fine', T.platform_note));
|
||||
// the explaining sentence: three numbers, all from the rule; bold parts are {b}…{/b}
|
||||
why.textContent = '';
|
||||
var tpl = r.apps_peak_mb > 0
|
||||
? (r.recommend_gb !== null ? T.why : T.why_over)
|
||||
: T.why_empty;
|
||||
var spare = Math.round((data.headroom - 1) * 100);
|
||||
tpl.replace('{peak}', dec(r.peak_mb / 1024)).replace('{base}', dec(r.base_mb / 1024))
|
||||
.replace('{base_platform}', dec((r.base_mb + data.platform_mb) / 1024))
|
||||
.replace('{spare}', spare).replace('{rec}', r.recommend_gb === null ? max : r.recommend_gb)
|
||||
.split(/\{b\}|\{\/b\}/).forEach(function (part, i) {
|
||||
why.appendChild(i % 2 ? el('strong', 'sizer-num', part) : document.createTextNode(part));
|
||||
});
|
||||
typicalLine.textContent = T.typical_line.replace('{typical}', gbText(r.typical_mb)).replace('{peak}', gbText(r.peak_mb));
|
||||
if (r.tight_box_gb !== null) { result.appendChild(el('p', 'sizer-why', T.tight_why)); }
|
||||
|
||||
if (r.busy.length) {
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
<link rel="stylesheet" href="/assets/shell.css?v=25">
|
||||
<link rel="icon" type="image/png" href="/assets/logo_favicon_2.svg">
|
||||
<script defer src="https://stats.felhom.eu/script.js" data-website-id="d419db57-5e1c-48df-bdb3-c29f25fb1661"></script>
|
||||
<link rel="stylesheet" href="/assets/sizing.css?v=2">
|
||||
<script defer src="/assets/sizing.js?v=2"></script>
|
||||
<link rel="stylesheet" href="/assets/sizing.css?v=3">
|
||||
<script defer src="/assets/sizing.js?v=3"></script>
|
||||
</head>
|
||||
<body class="shell page-gepigeny">
|
||||
<header class="mobile-topbar">
|
||||
@@ -73,7 +73,7 @@
|
||||
<p class="page-lede">Tick what you would run on the box, and the page shows how much machine memory it needs. This is an estimate from my own measurements on an N100 mini PC (13 October 2026), not a promise.</p>
|
||||
<noscript><p class="sizer-noscript">This page needs JavaScript. Turn it on and reload the page.</p></noscript>
|
||||
|
||||
<section class="shell-section sizer" id="sizer" data-src="/assets/sizing-data.json?v=2" hidden>
|
||||
<section class="shell-section sizer" id="sizer" data-src="/assets/sizing-data.json?v=3" hidden>
|
||||
<div class="sizer-presets" role="group" aria-label="Quick picks">
|
||||
<button type="button" class="btn btn-outline btn-sm" data-preset="immich,jellyfin,nextcloud,home-assistant,vaultwarden,paperless-ngx">Family starter set</button>
|
||||
<button type="button" class="btn btn-outline btn-sm" data-preset="nextcloud,vaultwarden">Just files and passwords</button>
|
||||
@@ -81,12 +81,13 @@
|
||||
</div>
|
||||
<div class="sizer-sticky">
|
||||
<div class="sizer-meter" id="sizer-meter" role="meter" aria-label="Machine memory needed" aria-valuemin="0" aria-valuemax="64" aria-valuenow="0">
|
||||
<div class="sizer-track"><div class="sizer-fill" id="sizer-fill"></div><div class="sizer-tightmark" id="sizer-tight"></div></div>
|
||||
<div class="sizer-track"><div class="sizer-stack" id="sizer-stack"></div><div class="sizer-tightmark" id="sizer-tight"></div></div>
|
||||
<div class="sizer-scale" id="sizer-scale" aria-hidden="true"></div>
|
||||
</div>
|
||||
<p class="sizer-line" id="sizer-line" aria-live="polite"></p>
|
||||
<p class="sizer-legend">Solid bar: fits well · Thin mark: fits, but tight</p>
|
||||
</div>
|
||||
<p class="sizer-why-line" id="sizer-why-line"></p>
|
||||
<ul class="sizer-legend" id="sizer-legend"></ul>
|
||||
<div class="sizer-result" id="sizer-result"></div>
|
||||
<h2 class="sizer-sub">Applications</h2>
|
||||
<div class="sizer-cats" id="sizer-apps"></div>
|
||||
@@ -102,12 +103,13 @@
|
||||
</ul>
|
||||
<details class="sizer-how">
|
||||
<summary>How does the page count?</summary>
|
||||
<p id="sizer-typical"></p>
|
||||
<p>The box's own services use about 470 MB of memory (Dashboard, tunnel, file manager, Docker). The page adds the measured figures of the apps you tick: once their typical use, once their peak, as if every app were busy at the same moment. That is a deliberately cautious count.</p>
|
||||
<p>On a machine, the Felhom system gets the memory the installer gives it; the rest is for the base system. Fits well: one and a half times the peak still fits — the solid bar shows this, and it is the recommended size. Fits, but tight: the peak fits, one and a half times it does not — the thin mark shows this. The recommendation is the smallest of 8, 12, 16, 24, 32, 48 and 64 GB where it fits well.</p>
|
||||
<p>On a machine, the Felhom system gets the memory the installer gives it; the rest is for the base system. Fits well: one and a half times the peak still fits — the bar's length shows this, and the recommended size comes from it. Fits, but tight: the peak fits, one and a half times it does not — the thin mark shows this. The recommendation is the smallest of 8, 12, 16, 24, 32, 48 and 64 GB where it fits well.</p>
|
||||
<p>The figures were measured on an N100 mini PC (13 October 2026): every app installed and at rest, the heavier ones also during one real task (a photo import, a film conversion, text recognition). A larger photo library or more users can need more.</p>
|
||||
</details>
|
||||
</section>
|
||||
<script type="application/json" id="sizer-strings">{"typical": "Typical use", "peak": "At peak, if everything works at once", "platform_note": "Both include the box's own services (about 0.5 GB).", "selected": "{n} selected", "recommend": "Recommended: a {gb} GB machine.", "tight_on": "It fits on {gb} GB, but tight.", "only_tight": "None of the sizes fits well; from {gb} GB it fits, but tight.", "none_fits": "It does not fit any size, not even {gb} GB.", "over_max": "more than {gb} GB", "meter_text": "Machine memory needed: {x}", "tight_why": "Tight: it works, but a large photo import or a backup at the same time can slow it down.", "cpu_head": "These make the processor work hard for a short time", "heavy_pair": "{names}: they slow each other down only while both are working.", "and": " and ", "unmeasured": "Not yet measured", "builtin": "built in, part of every box", "load_error": "The estimate's data did not load. Reload the page."}</script>
|
||||
<script type="application/json" id="sizer-strings">{"selected": "{n} selected", "recommend": "Recommended: {a} {gb} GB machine.", "tight_on": "It fits on {gb} GB, but tight.", "only_tight": "None of the sizes fits well; from {gb} GB it fits, but tight.", "none_fits": "It does not fit any size, not even {gb} GB.", "over_max": "more than {gb} GB", "meter_text": "Machine memory needed: {x}", "tight_why": "Tight: it works, but a large photo import or a backup at the same time can slow it down.", "cpu_head": "These make the processor work hard for a short time", "heavy_pair": "{names}: they slow each other down only while both are working.", "and": " and ", "unmeasured": "Not yet measured", "builtin": "built in, part of every box", "load_error": "The estimate's data did not load. Reload the page.", "seg_base": "The machine's base system", "seg_platform": "Felhom's own services", "seg_spare": "Spare room", "seg_more": "{n} more apps", "seg_tight": "Fits, but tight, from", "why": "At peak your apps and Felhom's own services use {b}{peak} GB{/b}. The machine needs more than that: about {b}{base} GB{/b} stays with its base system, and we leave {spare} % spare room on top. That is why we recommend {b}{rec} GB{/b}.", "why_over": "At peak your apps and Felhom's own services use {b}{peak} GB{/b}. The machine needs more than that: about {b}{base} GB{/b} stays with its base system, and we leave {spare} % spare room on top. That is why it needs more than {b}{rec} GB{/b}.", "why_empty": "The machine's base system and Felhom's own services use about {b}{base_platform} GB{/b}.", "typical_line": "With Felhom's own services, the selected apps use {typical} on average and {peak} at peak.", "a": "a", "an": "an", "an_before": ["8", "11", "18", "80"]}</script>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
<link rel="stylesheet" href="/assets/shell.css?v=25">
|
||||
<link rel="icon" type="image/png" href="/assets/logo_favicon_2.svg">
|
||||
<script defer src="https://stats.felhom.eu/script.js" data-website-id="d419db57-5e1c-48df-bdb3-c29f25fb1661"></script>
|
||||
<link rel="stylesheet" href="/assets/sizing.css?v=2">
|
||||
<script defer src="/assets/sizing.js?v=2"></script>
|
||||
<link rel="stylesheet" href="/assets/sizing.css?v=3">
|
||||
<script defer src="/assets/sizing.js?v=3"></script>
|
||||
</head>
|
||||
<body class="shell page-gepigeny">
|
||||
<header class="mobile-topbar">
|
||||
@@ -73,7 +73,7 @@
|
||||
<p class="page-lede">Jelöld be, mit futtatnál a dobozon, és az oldal megmutatja, mekkora memóriájú gép kell hozzá. Ez becslés a saját mérésemből egy N100-as mini PC-n (2026. október 13.), nem ígéret.</p>
|
||||
<noscript><p class="sizer-noscript">Ehhez az oldalhoz JavaScript kell. Kapcsold be, és töltsd újra az oldalt.</p></noscript>
|
||||
|
||||
<section class="shell-section sizer" id="sizer" data-src="/assets/sizing-data.json?v=2" hidden>
|
||||
<section class="shell-section sizer" id="sizer" data-src="/assets/sizing-data.json?v=3" hidden>
|
||||
<div class="sizer-presets" role="group" aria-label="Gyors választás">
|
||||
<button type="button" class="btn btn-outline btn-sm" data-preset="immich,jellyfin,nextcloud,home-assistant,vaultwarden,paperless-ngx">Családi alapcsomag</button>
|
||||
<button type="button" class="btn btn-outline btn-sm" data-preset="nextcloud,vaultwarden">Csak fájlok és jelszavak</button>
|
||||
@@ -81,12 +81,13 @@
|
||||
</div>
|
||||
<div class="sizer-sticky">
|
||||
<div class="sizer-meter" id="sizer-meter" role="meter" aria-label="Szükséges gépmemória" aria-valuemin="0" aria-valuemax="64" aria-valuenow="0">
|
||||
<div class="sizer-track"><div class="sizer-fill" id="sizer-fill"></div><div class="sizer-tightmark" id="sizer-tight"></div></div>
|
||||
<div class="sizer-track"><div class="sizer-stack" id="sizer-stack"></div><div class="sizer-tightmark" id="sizer-tight"></div></div>
|
||||
<div class="sizer-scale" id="sizer-scale" aria-hidden="true"></div>
|
||||
</div>
|
||||
<p class="sizer-line" id="sizer-line" aria-live="polite"></p>
|
||||
<p class="sizer-legend">Teli sáv: bőven elfér · Vékony jel: elfér, de szűkösen</p>
|
||||
</div>
|
||||
<p class="sizer-why-line" id="sizer-why-line"></p>
|
||||
<ul class="sizer-legend" id="sizer-legend"></ul>
|
||||
<div class="sizer-result" id="sizer-result"></div>
|
||||
<h2 class="sizer-sub">Alkalmazások</h2>
|
||||
<div class="sizer-cats" id="sizer-apps"></div>
|
||||
@@ -102,12 +103,13 @@
|
||||
</ul>
|
||||
<details class="sizer-how">
|
||||
<summary>Hogyan számol az oldal?</summary>
|
||||
<p id="sizer-typical"></p>
|
||||
<p>A doboz saját szolgáltatásai kb. 470 MB memóriát használnak (vezérlőpult, alagút, fájlkezelő, Docker). Ehhez adja hozzá a bejelölt alkalmazások mért értékeit: egyszer az átlagos használatot, egyszer a csúcsot, mintha minden alkalmazás egyszerre dolgozna. Ez szándékosan óvatos számítás.</p>
|
||||
<p>Egy gépen a Felhom-rendszer annyi memóriát kap, amennyit a telepítő ad neki; a többi az alaprendszeré. „Bőven elfér”: a csúcs másfélszerese is belefér — ezt mutatja a teli sáv, és ez az ajánlott gépméret. „Elfér, de szűkösen”: a csúcs belefér, a másfélszerese nem — ezt mutatja a vékony jel. Az ajánlás a 8, 12, 16, 24, 32, 48 és 64 GB-os méretek közül a legkisebb, amelybe bőven elfér.</p>
|
||||
<p>Egy gépen a Felhom-rendszer annyi memóriát kap, amennyit a telepítő ad neki; a többi az alaprendszeré. „Bőven elfér”: a csúcs másfélszerese is belefér — ezt mutatja a sáv hossza, és ebből jön az ajánlott gépméret. „Elfér, de szűkösen”: a csúcs belefér, a másfélszerese nem — ezt mutatja a vékony jel. Az ajánlás a 8, 12, 16, 24, 32, 48 és 64 GB-os méretek közül a legkisebb, amelybe bőven elfér.</p>
|
||||
<p>A számok egy N100-as mini PC-n mért értékek (2026. október 13.): minden alkalmazás telepítve, nyugalomban, a nehezebbek egy valódi feladat közben is (fotóimport, filmátalakítás, szövegfelismerés). Egy nagyobb fotótár vagy több felhasználó többet kérhet.</p>
|
||||
</details>
|
||||
</section>
|
||||
<script type="application/json" id="sizer-strings">{"typical": "Átlagos használat", "peak": "Csúcson, ha minden egyszerre dolgozik", "platform_note": "Mindkettőben benne vannak a doboz saját szolgáltatásai (kb. 0,5 GB).", "selected": "{n} kiválasztva", "recommend": "Ajánlott: {gb} GB-os gép.", "tight_on": "{gb} GB-on szűkösen elfér.", "only_tight": "Bőven egyik méretbe sem fér; {gb} GB-tól szűkösen elfér.", "none_fits": "Egyik méretbe sem fér bele, {gb} GB-ba sem.", "over_max": "több mint {gb} GB", "meter_text": "Szükséges gépmemória: {x}", "tight_why": "Szűkösen: működik, de egy nagy fotóimport vagy egy közben futó mentés lelassíthatja.", "cpu_head": "Rövid ideig erősen dolgoztatják a processzort", "heavy_pair": "{names}: csak akkor lassítják egymást, amikor éppen egyszerre dolgoznak.", "and": " és ", "unmeasured": "Még nem mértük", "builtin": "beépítve, minden dobozban benne van", "load_error": "A becslés adatai nem töltődtek be. Töltsd újra az oldalt."}</script>
|
||||
<script type="application/json" id="sizer-strings">{"selected": "{n} kiválasztva", "recommend": "Ajánlott: {gb} GB-os gép.", "tight_on": "{gb} GB-on szűkösen elfér.", "only_tight": "Bőven egyik méretbe sem fér; {gb} GB-tól szűkösen elfér.", "none_fits": "Egyik méretbe sem fér bele, {gb} GB-ba sem.", "over_max": "több mint {gb} GB", "meter_text": "Szükséges gépmemória: {x}", "tight_why": "Szűkösen: működik, de egy nagy fotóimport vagy egy közben futó mentés lelassíthatja.", "cpu_head": "Rövid ideig erősen dolgoztatják a processzort", "heavy_pair": "{names}: csak akkor lassítják egymást, amikor éppen egyszerre dolgoznak.", "and": " és ", "unmeasured": "Még nem mértük", "builtin": "beépítve, minden dobozban benne van", "load_error": "A becslés adatai nem töltődtek be. Töltsd újra az oldalt.", "seg_base": "A gép alaprendszere", "seg_platform": "Felhom saját szolgáltatásai", "seg_spare": "Tartalék", "seg_more": "további {n} alkalmazás", "seg_tight": "Szűkösen elfér innen:", "why": "Az alkalmazásaid a Felhom saját szolgáltatásaival együtt csúcson {b}{peak} GB{/b}-ot használnak. A gép ennél többet igényel: kb. {b}{base} GB{/b} a gép alaprendszeréé, és {spare} % tartalékot hagyunk mellé. Ezért ajánlott a {b}{rec} GB{/b}.", "why_over": "Az alkalmazásaid a Felhom saját szolgáltatásaival együtt csúcson {b}{peak} GB{/b}-ot használnak. A gép ennél többet igényel: kb. {b}{base} GB{/b} a gép alaprendszeréé, és {spare} % tartalékot hagyunk mellé. Ezért {b}{rec} GB{/b}-nál is több kell.", "why_empty": "A gép alaprendszere és a Felhom saját szolgáltatásai kb. {b}{base_platform} GB{/b}-ot használnak.", "typical_line": "A kiválasztott alkalmazások a Felhom saját szolgáltatásaival együtt átlagosan {typical}-ot, csúcson {peak}-ot használnak.", "a": "", "an": "", "an_before": []}</script>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
|
||||
Reference in New Issue
Block a user