Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 33 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,25 @@

This repo is for all the supporting code used to find and display the longest line of sight on the planet.

The main viewshed algorithm is another repo https://github.com/tombh/total-viewsheds
The main viewshed algorithm is another repo https://github.com/AllTheLines/CacheTVS

The raw elevation data is, as of writing (October 2025), from https://www.viewfinderpanoramas.org/Coverage%20map%20viewfinderpanoramas_org3.htm Other sources of data are available, notably via AWS's https://registry.opendata.aws/terrain-tiles, but as far as I can tell viewfinderpanoramas.org offers a cleaned version, removing noisy data and filling in voids with other sources.
The raw elevation data is from [www.viewfinderpanoramas.org](https://www.viewfinderpanoramas.org/Coverage%20map%20viewfinderpanoramas_org3.htm).

There are 7 main parts to this repo:
1. The Packer
2. The Stitcher
3. Calculating Total Viewsheds
4. Preparing Assets For The Cloud
5. Atlas: Automating Steps 2, 3 and 4
6. Static Site Website
7. Map Web App

## Packer

I wrote an in-depth blog post about the Packer https://tombh.co.uk/packing-world-lines-of-sight

![Map of all the longest line of sight tiles in the world](https://alltheviews.world/world_packed.webp)

This map shows a not-terrible packing of the minimum tiles needed to guarantee searching every line of sight on the planet.
This map shows a not-terrible packing of the minimum tiles needed to guarantee searching every line of sight on the planet:
![Map of all the longest line of sight tiles in the world](https://tombh.co.uk/images/tile-packing-red.webp)

To calculate any [viewshed](https://en.wikipedia.org/wiki/Viewshed), and therefore line of sight, you must inevitably provide more data than ends up being used. This is to say that you don't know the limits of what you can see from a given point until you actually calculate it. The only limit you can calculate beforehand is the longest _theoretical_ line of sight based on the highest points within the region you're interested in.

Expand All @@ -26,7 +34,7 @@ Here are some examples, they are for 2 peaks of the same height and the maximum
* 0.5km 160km
* 1.65m 9km (height of an average human)

Formula: √(2 * Earth Radius * height) * 2
Formula: `√(2 * Earth Radius * height) * 2`

So as long as you provide the raw data within these theoretical limits then you are at least guaranteed to have complete viewsheds. The worst that can happen is that RAM and CPU cycles are wasted on calculating lines that have already terminated.

Expand Down Expand Up @@ -133,12 +141,9 @@ bunch of tiles have been processed:

* Create the gigantic (10s of GBs) global `.pmtile` that contains the TVS heatmap for the entire planet.
```
# This requires a machine with a lot of RAM and CPU. As of writing, with a ~10% world run,
# an 80Gb machine with 48 cores, took around 20 minutes.
# This requires a machine with a lot of disk, RAM and CPU. As of writing, I'd recommend
# 3TB disk, >150GB RAM and at least 48 cores.
# Replace `latest` with `local` to skip syncing files to S3.
./ctl.sh make_prod_pmtiles latest

# This is exactly the same but without some more agressive settings.
./ctl.sh make_pmtiles latest work/world.pmtiles
```

Expand All @@ -156,8 +161,22 @@ RUST_LOG=off,tasks=trace cargo run --release --bin tasks -- \
--tiffs work/longest_lines
```

## Website
## Static Site Website

Uses [Hugo](https://gohugo.io). Run development server with `hugo server --buildDrafts` in `ssg/` direectory.

Live at [alltheviews.world](https://alltheviews.world)

Automatically deployed by pushing to either `staging` or `main` branches.

Manually deploy to production from current checked out code: `.ctl.sh static_site_deploy`

## Web App

Run development server with `pnpm run dev` in `website/` direectory.

Live at [map.alltheviews.world](https://map.alltheviews.world)

https://alltheviews.world Still in development so expect daily breakages.
Automatically deployed by pushing to either `staging` or `main` branches.

`.ctl.sh website_deploy`
Manually deploy to production from current checked out code: `.ctl.sh webapp_deploy`
6 changes: 0 additions & 6 deletions scripts/website.bash

This file was deleted.

13 changes: 13 additions & 0 deletions scripts/websites.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
function webapp_deploy {
_pushd "$PROJECT_ROOT"/website
pnpm run build
npx wrangler deploy
_popd
}

function static_site_deploy {
_pushd "$PROJECT_ROOT"/ssg
hugo
npx wrangler deploy
_popd
}
6 changes: 3 additions & 3 deletions ssg/content/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@ With the help of a custom-developed algorithm, [CacheTVS](https://github.com/All
checked _every single_ view on Earth in search of the coveted **longest line of sight on the planet**.
Based on the method we detail [here](/faq/), we present the greatest view of all:

## [1. Hindu Kush to Pik Dankova (530km) ↗](https://map.alltheviews.world/longest/78.76539611816406-36.31400680541992)
## [1. Hindu Kush to Pik Dankova (530km) ↗](https://map.alltheviews.world/longest/78.76539611816406_36.31400680541992)

![Longest Line Of Site](/longest_line_1.webp 'The longest line of sight on the planet, at 530km, from the Hindu Kush to Pik Dankova')

## Runners Up

Longest lines of sight tend to group together around peaks and ridges. So the following are more of our own curated list rather than the technically correct runners up. We chose them based on being in notably different regions of the world.

## [2. Telkik Shan to Kongur Tagh (507km) ↗](https://map.alltheviews.world/longest/80.29535675048828-36.52555465698242)
## [2. Telkik Shan to Kongur Tagh (507km) ↗](https://map.alltheviews.world/longest/80.29535675048828_36.52555465698242)
![Second Longest Line Of Site](/longest_line_2.webp 'The second longest line of sight, at 507km, between the Telkik Shan and Kongur Tah')

Another long line of sight in the Himalays, over the Tarim Basin and Tibetan Plateau. With such tall mountain
ranges on either side, they're everywhere!

## [3. Antioquia to Pico Cristobal (504km) ↗](https://map.alltheviews.world/longest/-75.72223663330078-6.75514030456543)
## [3. Antioquia to Pico Cristobal (504km) ↗](https://map.alltheviews.world/longest/-75.72223663330078_6.75514030456543)
![Third Longest Line Of Site](/longest_line_3.webp 'The third longest line of sight, at 504km, from Antioquia to Pico Crostobal in Colombia')

Now we go right to the other side of the world to Colombia in South America. We've found a line of sight from the department of Antioquia to Pico Cristobal, Colombia's highest mountain.
Expand Down
9 changes: 6 additions & 3 deletions ssg/content/about.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@

# About Us
---
title: About Us
---

Tom and Ryan are two friends united behind a single problem: finding the longest line
of sight. Ryan met Tom through a tech forum, [HackerNews](https://news.ycombonator.com),
after reaching out to recruit him for a company opening. They instantly clicked and have
kept in touch since.

Recently, Tom started working on an algorithm to find the longest line of sight,
Recently (in July of 2025), Tom started working on an algorithm to find the longest line of sight,
and Ryan noticed it through a post on a tech forum explaining the project. For the last
6 months both have spent innumerous hours engineering [a tool](https://github.com/AllTheViews/CacheTVS)
for the longest line of sight for every point on the planet, and to let others explore the beautiful world and all its
long lines of sight.

You can contact us at hello@alltheviews.world

## Tom
{{<figure src="/tomisme.png" class="profile" >}}
When Tom isn't on his laptop he's meditating or getting to know a new country. He's been a digital nomad since 2015. You can find his longest lines blog posts [here](https://tombh.co.uk/packing-world-lines-of-sight) and [here](https://tombh.co.uk/longest-line-of-sight), or see what else he is up to on his website https://tombh.co.uk
Expand Down
26 changes: 21 additions & 5 deletions ssg/content/faq.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,33 @@
---
title: FAQs
---

# FAQs
## How Did You Do It?

Tom and Ryan go into detail on their respective blogs:

* [tombh.co.uk/packing-world-lines-of-sight](https://tombh.co.uk/packing-world-lines-of-sight)
* [tombh.co.uk/longest-line-of-sight](https://tombh.co.uk/longest-line-of-sight)
* [ryan.berge.rs/posts/lines-of-sight](https://ryan.berge.rs/posts/lines-of-sight)
* [ryan.berge.rs/posts/total-viewshed-algorithm](https://ryan.berge.rs/posts/total-viewshed-algorithm/)

## What Assumptions Did You Make?

* The original source of our data is from [NASA's SRTM survey](https://www.earthdata.nasa.gov/data/instruments/srtm) which is ~100m resolution analysis of the planet's elevation data. It is known to have some issues so we used a clean version kindly provided by [viewfinderpanoramas.org](https://www.viewfinderpanoramas.org/Coverage%20map%20viewfinderpanoramas_org3.htm).
* The original source of our data is from [NASA's SRTM survey](https://www.earthdata.nasa.gov/data/instruments/srtm) which is ~100m resolution analysis of the planet's elevation data. It is known to have some issues so we used a cleaned version kindly provided by [viewfinderpanoramas.org](https://www.viewfinderpanoramas.org/Coverage%20map%20viewfinderpanoramas_org3.htm).
* We used a globe earth meaning it is an approximation of earth's shape, as it is an oblate spheroid.
* We take refraction into account, and we use what the GIS community has calculated to be the world average, which is a refraction coefficient of `0.13`.
* The height of the observer is `1.65m` or `5'5"`.
* Each viewshed is calculated using 360 lines of sight each seperated by 1°. This could potentially miss some longest lines of sight, but it is considered to be the optimal resolution to balance the accumulation of errors and computational costs. For more details, see: Siham Tabik, Antonio R. Cervilla, Emilio Zapata, Luis F. Romero in their 2014 paper _Efficient Data Structure and Highly Scalable Algorithm for Total-Viewshed Computation_ https://ieeexplore.ieee.org/document/6837455
* All computation is done on [AEQD](https://en.wikipedia.org/wiki/Azimuthal_equidistant_projection) reprojections of the raw data. For the longest lines of sight on the planet, ~500km, the worst case errors caused by this projection can reach ~0.0685%. This error is only relevant to viewsheds at the edge of the computable area of the tile, therefore those viewsheds around 500km from the centre of the tile.


* All computation is done on [AEQD](https://en.wikipedia.org/wiki/Azimuthal_equidistant_projection) reprojections of the raw data. For the longest lines of sight on the planet, ~500km, the worst case errors caused by this projection can reach ~0.0685%. This error is only relevant to viewsheds at the edge of the computable area of [tiles](https://tombh.co.uk/packing-world-lines-of-sight), therefore those viewsheds around 500km from the centre of tiles.

## Is The Source Code Available?

Yes. [The core algorithm](https://github.com/AllTheLines/CacheTVS). [The pipeline and web app](https://github.com/AllTheLines/viewview).

## Why Don't You Make The Sea More Visible?

The sea actually has above average visibility, due to it generally not being blocked by hills and mountains. As such it can generate some often interesting and sometimes beautiful heatmaps, like around [the islands of South Korea](https://map.alltheviews.world/longest/126.9141495423105_33.956726689880966).

## How Do I Contact You?

💌 hello@alltheviews.world
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
+++
date = '2026-02-09T16:35:33+01:00'
date = '2026-02-09T00:00:00+00:00'
title = 'Launch day'
+++

Expand Down
2 changes: 1 addition & 1 deletion ssg/hugo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ title = 'All The Views'

[params]
mainSections = ["posts"]
nav = "[Home](/) [News](/posts/) [FAQ](/faq/) [About](/about/) |&nbsp; [Map ↗](https://map.alltheviews.world)"
nav = "[Home](/) [News](/news/) [FAQ](/faq/) [About](/about/) |&nbsp; [Map ↗](https://map.alltheviews.world)"
2 changes: 1 addition & 1 deletion ssg/themes/hugo-trainsh/assets/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,7 @@ figure figcaption {
}

.page-title {
font-size: 1.5em;
font-size: 2em;
margin: 0;
}

Expand Down
36 changes: 18 additions & 18 deletions ssg/themes/hugo-trainsh/layouts/_default/single.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,25 @@
{{- $isPost := in $sections .Section -}}

<article class="post">
{{- if $isPost -}}
<header class="post-header">
<h1 class="post-title">{{ .Title }}</h1>
<p class="post-meta">
<time datetime="{{ .Date | time.Format "2006-01-02" }}">
{{ partial "date/format.html" (dict "page" . "date" .Date "context" "single") }}
</time>
</p>
</header>
{{- else -}}
<header class="page-header">
<h1 class="page-title">{{ .Title }}</h1>
</header>
{{- end -}}
{{- if $isPost -}}
<header class="post-header">
<h1 class="post-title">{{ .Title }}</h1>
<p class="post-meta">
<time datetime="{{ .Date | time.Format " 2006-01-02" }}">
{{ partial "date/format.html" (dict "page" . "date" .Date "context" "single") }}
</time>
</p>
</header>
{{- else -}}
<header class="page-header">
<h1 class="page-title">{{ .Title }}</h1>
</header>
{{- end -}}

<div class="post-content">
{{ .Content }}
</div>
<div class="post-content">
{{ .Content }}
</div>

{{ partial "post/footer-meta.html" . }}
{{ partial "post/footer-meta.html" . }}
</article>
{{ end }}
36 changes: 0 additions & 36 deletions ssg/themes/hugo-trainsh/layouts/_partials/post/upvote.html

This file was deleted.

Binary file removed telkik_shan_to_kongur_tagh.png
Binary file not shown.
45 changes: 45 additions & 0 deletions website/src/ClickEffect.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<script lang="ts" context="module">
export function initClickEffect() {
const container = document
.getElementsByClassName('maplibregl-interactive')
.item(0) as HTMLElement;
const click_effect = document.getElementById('click_effect') as HTMLElement;

if (!container || !click_effect) {
return;
}

container.addEventListener('click', (event: MouseEvent) => {
const x = event.clientX;
const y = event.clientY;

click_effect.style.left = `${x}px`;
click_effect.style.top = `${y}px`;
click_effect.style.transform = 'scale(3)';
click_effect.style.opacity = '1';

setTimeout(() => {
click_effect.style.transform = 'scale(0)';
click_effect.style.opacity = '0';
}, 300);
});
}
</script>

<div id="click_effect"></div>

<style>
#click_effect {
width: 8px;
height: 8px;
position: absolute;
border-radius: 50%;
background: var(--longest-line);
transform: scale(0);
pointer-events: none; /* Ignore mouse events */
transition:
transform 0.3s ease,
opacity 0.3s ease;
opacity: 0;
}
</style>
Loading