From 62ea6052993053f6405be6a011b4a437c2f2c598 Mon Sep 17 00:00:00 2001 From: featurescript <114271535+featurescript@users.noreply.github.com> Date: Mon, 26 Oct 2026 16:33:16 -0700 Subject: [PATCH 1/2] docs: add a cookieless page-view counter and a privacy page --- SimLoop/docs/assets/javascripts/pageviews.js | 20 ++++++++++++++++++++ SimLoop/docs/privacy.md | 17 +++++++++++++++++ SimLoop/mkdocs.yml | 3 +++ 3 files changed, 40 insertions(+) create mode 100644 SimLoop/docs/assets/javascripts/pageviews.js create mode 100644 SimLoop/docs/privacy.md diff --git a/SimLoop/docs/assets/javascripts/pageviews.js b/SimLoop/docs/assets/javascripts/pageviews.js new file mode 100644 index 0000000..3c95b27 --- /dev/null +++ b/SimLoop/docs/assets/javascripts/pageviews.js @@ -0,0 +1,20 @@ +// Page-view counter for this docs site (GoatCounter). Horizon (FTC 36596). +// +// No cookies, no local storage, no personal data. GoatCounter records the page path, the referring +// site, the browser and screen size, and a country derived from the IP address, which it then drops. +// The privacy page (privacy.md) says the same; change both together. +// +// Both docs sites (libraries.horizon36596.org/zenith/ and /simloop/) report to ONE GoatCounter site, +// told apart by path. Until the owner creates that site, GOATCOUNTER_CODE is a placeholder and this +// file does nothing. +(function () { + var GOATCOUNTER_CODE = "REPLACE_WITH_GOATCOUNTER_CODE"; + if (GOATCOUNTER_CODE.indexOf("REPLACE_") === 0) return; + // Local previews (mkdocs serve) are not counted. + if (location.hostname !== "libraries.horizon36596.org") return; + window.goatcounter = { endpoint: "https://" + GOATCOUNTER_CODE + ".goatcounter.com/count" }; + var s = document.createElement("script"); + s.async = true; + s.src = "https://gc.zgo.at/count.js"; + document.head.appendChild(s); +})(); diff --git a/SimLoop/docs/privacy.md b/SimLoop/docs/privacy.md new file mode 100644 index 0000000..2ce098d --- /dev/null +++ b/SimLoop/docs/privacy.md @@ -0,0 +1,17 @@ +# Privacy + +SimLoop is a library. It runs on your computer and your robot and sends nothing anywhere. + +This documentation site counts page views with [GoatCounter](https://www.goatcounter.com), so we can +see which pages teams read. + +- It sets no cookies and stores nothing in your browser. +- For each page view it records the page, the site that linked you here, your browser and screen + size, and your country. GoatCounter works out the country from your IP address and then drops the + address. +- It cannot tell who you are or follow you to other sites. + +The site is hosted on GitHub Pages, which keeps the routine request logs any website has, such as +your IP address. + +Questions: open an issue on [GitHub](https://github.com/Horizon-36596/simloop/issues). diff --git a/SimLoop/mkdocs.yml b/SimLoop/mkdocs.yml index 2eb07b4..308c289 100644 --- a/SimLoop/mkdocs.yml +++ b/SimLoop/mkdocs.yml @@ -83,8 +83,10 @@ extra_css: - stylesheets/horizon.css # The one-time alpha notice; its styles are at the end of horizon.css. +# The cookieless page-view counter; see the file's header and privacy.md. extra_javascript: - javascripts/alpha-notice.js + - assets/javascripts/pageviews.js markdown_extensions: - admonition @@ -133,3 +135,4 @@ nav: - Troubleshooting: troubleshooting.md - Reporting a bug: support.md - Index for AI agents: llms.md + - Privacy: privacy.md From 161d44ec0b36c7d34c779aaf46c4eff49fd3bd9d Mon Sep 17 00:00:00 2001 From: featurescript <114271535+featurescript@users.noreply.github.com> Date: Mon, 26 Oct 2026 16:33:17 -0700 Subject: [PATCH 2/2] docs: count page views without loading a third-party script The docs share an origin with the other sites on libraries.horizon36596.org, so pageviews.js calls GoatCounter's documented /count endpoint itself instead of loading count.js. The privacy page says exactly what is sent, and that the fonts load from Google Fonts. --- SimLoop/docs/assets/javascripts/pageviews.js | 31 ++++++++++++++------ SimLoop/docs/privacy.md | 14 +++++---- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/SimLoop/docs/assets/javascripts/pageviews.js b/SimLoop/docs/assets/javascripts/pageviews.js index 3c95b27..9ada600 100644 --- a/SimLoop/docs/assets/javascripts/pageviews.js +++ b/SimLoop/docs/assets/javascripts/pageviews.js @@ -1,8 +1,15 @@ -// Page-view counter for this docs site (GoatCounter). Horizon (FTC 36596). +// Page-view counter for this docs site. Horizon (FTC 36596). // -// No cookies, no local storage, no personal data. GoatCounter records the page path, the referring -// site, the browser and screen size, and a country derived from the IP address, which it then drops. -// The privacy page (privacy.md) says the same; change both together. +// It counts with GoatCounter, but runs no GoatCounter code: this file sends one image request to +// GoatCounter's documented /count endpoint (goatcounter.com/help/pixel). No third-party script is +// loaded on purpose: these pages share an origin with the other sites under +// libraries.horizon36596.org, the Zenith web editor (/zenith/app/) among them, so a third-party +// script here could read their browser storage. +// +// No cookies, no local storage. Sent: the page path and title, the referring page, and the screen +// size. GoatCounter also sees the IP address and browser, as any web request does; it uses them to +// work out the country and to count a reload once, keeps them in memory for at most 8 hours and does +// not store them. The privacy page (privacy.md) says the same; change both together. // // Both docs sites (libraries.horizon36596.org/zenith/ and /simloop/) report to ONE GoatCounter site, // told apart by path. Until the owner creates that site, GOATCOUNTER_CODE is a placeholder and this @@ -12,9 +19,15 @@ if (GOATCOUNTER_CODE.indexOf("REPLACE_") === 0) return; // Local previews (mkdocs serve) are not counted. if (location.hostname !== "libraries.horizon36596.org") return; - window.goatcounter = { endpoint: "https://" + GOATCOUNTER_CODE + ".goatcounter.com/count" }; - var s = document.createElement("script"); - s.async = true; - s.src = "https://gc.zgo.at/count.js"; - document.head.appendChild(s); + if (document.visibilityState === "prerender") return; + var q = [ + "p=" + encodeURIComponent(location.pathname), + "t=" + encodeURIComponent(document.title), + "r=" + encodeURIComponent(document.referrer), + "s=" + [screen.width, screen.height, window.devicePixelRatio || 1].join(","), + "rnd=" + Math.random().toString(36).slice(2), + ]; + // 153 is GoatCounter's "WebDriver-based headless browser" bot flag. + if (navigator.webdriver) q.push("b=153"); + new Image().src = "https://" + GOATCOUNTER_CODE + ".goatcounter.com/count?" + q.join("&"); })(); diff --git a/SimLoop/docs/privacy.md b/SimLoop/docs/privacy.md index 2ce098d..8af2818 100644 --- a/SimLoop/docs/privacy.md +++ b/SimLoop/docs/privacy.md @@ -1,17 +1,21 @@ # Privacy -SimLoop is a library. It runs on your computer and your robot and sends nothing anywhere. +SimLoop is a library. It has no analytics and collects nothing about you. This documentation site counts page views with [GoatCounter](https://www.goatcounter.com), so we can see which pages teams read. - It sets no cookies and stores nothing in your browser. -- For each page view it records the page, the site that linked you here, your browser and screen - size, and your country. GoatCounter works out the country from your IP address and then drops the - address. +- For each page view it records the page and its title, the site that linked you here, your + browser, operating system and screen size, and your country. +- GoatCounter uses your IP address and browser to work out your country and to count a reload only + once. It keeps them in memory for at most 8 hours and never stores them. +- No outside script runs on these pages. Our own page sends one request to GoatCounter; no + GoatCounter code is loaded. - It cannot tell who you are or follow you to other sites. The site is hosted on GitHub Pages, which keeps the routine request logs any website has, such as -your IP address. +your IP address. Its fonts load from Google Fonts, which sees your IP address and browser the same +way. Questions: open an issue on [GitHub](https://github.com/Horizon-36596/simloop/issues).