{
    "ready": true,
    "site": {
        "id": 0,
        "domain": "tonisagrista.com",
        "display_name": "Langur Monkey",
        "primary_country_code": "",
        "category_name": "Art & Design: Photography"
    },
    "metrics": {
        "global_rank": 35894,
        "country_rank": 19044,
        "category_rank": 31,
        "daily_pageviews_per_visitor": 3.89,
        "daily_time_on_site_seconds": 310,
        "bounce_rate": 35.38,
        "search_visits_percent": 38.57,
        "total_sites_linking_in": 2,
        "monthly_unique_visitors": 82,
        "recorded_at": "2026-03-18 21:01:45"
    },
    "audit": {
        "score": 91
    },
    "traffic_sources": {
        "direct_percent": 29.14,
        "search_percent": 36.41,
        "social_percent": 5.04,
        "referral_percent": 13.57,
        "email_percent": 6.48,
        "paid_percent": 9.36
    },
    "seo_profile": {
        "backlinks_total": 2,
        "referring_domains": 2,
        "dofollow_backlinks_percent": 50,
        "organic_keywords": 68,
        "indexed_pages": 156,
        "page_speed_score": 92,
        "mobile_friendliness_score": 89,
        "authority_score": 40,
        "spam_risk_score": 52
    },
    "crawl_report": {
        "robots_status": 200,
        "sitemap_status": 200,
        "sitemap_total_urls": 156,
        "crawl_blocked": false,
        "crawl_blocked_by": "",
        "crawl_blocked_reason": "",
        "notes": [],
        "created_at": "2026-03-18 21:01:45"
    },
    "keywords": [
        {
            "keyword": "Langur Monkey",
            "position": 21,
            "search_engine": "Estimated",
            "checked_at": "2026-05-03 08:15:02",
            "is_estimated": true
        },
        {
            "keyword": "Langur Monkey art & design: photography",
            "position": 23,
            "search_engine": "Estimated",
            "checked_at": "2026-05-03 08:15:02",
            "is_estimated": true
        },
        {
            "keyword": "Langur Monkey reviews",
            "position": 25,
            "search_engine": "Estimated",
            "checked_at": "2026-05-03 08:15:02",
            "is_estimated": true
        },
        {
            "keyword": "langur",
            "position": 27,
            "search_engine": "Estimated",
            "checked_at": "2026-05-03 08:15:02",
            "is_estimated": true
        },
        {
            "keyword": "monkey",
            "position": 29,
            "search_engine": "Estimated",
            "checked_at": "2026-05-03 08:15:02",
            "is_estimated": true
        },
        {
            "keyword": "tonisagrista",
            "position": 31,
            "search_engine": "Estimated",
            "checked_at": "2026-05-03 08:15:02",
            "is_estimated": true
        },
        {
            "keyword": "toni",
            "position": 33,
            "search_engine": "Estimated",
            "checked_at": "2026-05-03 08:15:02",
            "is_estimated": true
        },
        {
            "keyword": "sagrist",
            "position": 35,
            "search_engine": "Estimated",
            "checked_at": "2026-05-03 08:15:02",
            "is_estimated": true
        }
    ],
    "rating": {
        "overall": 42,
        "label": "Average",
        "breakdown": [
            {
                "label": "Technical foundation",
                "score": 17,
                "max": 18
            },
            {
                "label": "Authority & trust",
                "score": 12,
                "max": 30
            },
            {
                "label": "Reach & market presence",
                "score": 3,
                "max": 18
            },
            {
                "label": "Search visibility",
                "score": 4,
                "max": 12
            },
            {
                "label": "Engagement & retention",
                "score": 8,
                "max": 10
            },
            {
                "label": "Channels & diversification",
                "score": 4,
                "max": 6
            },
            {
                "label": "Registry stability",
                "score": 5,
                "max": 6
            },
            {
                "label": "Quality system",
                "score": 94,
                "max": 100
            },
            {
                "label": "Reputation system",
                "score": 44,
                "max": 100
            },
            {
                "label": "Safety system",
                "score": 100,
                "max": 100
            },
            {
                "label": "Evidence confidence",
                "score": 100,
                "max": 100
            },
            {
                "label": "External intelligence",
                "score": 50,
                "max": 100
            }
        ],
        "authority_score": 40,
        "quality_score": 94,
        "reputation_score": 44,
        "safety_score": 100,
        "confidence_score": 100,
        "fraud_score": 2,
        "authority_signals": {
            "backlinks": 2,
            "referring_domains": 2,
            "organic_keywords": 68,
            "indexed_pages": 156,
            "monthly_visitors": 82,
            "global_rank": 35894,
            "engagement_score": 78,
            "crawl_quality_score": 100,
            "brand_completeness_score": 60,
            "link_diversity_score": 93,
            "technical_reliability_score": 95,
            "whois_score": 81,
            "whois_age_years": 15.1,
            "whois_stability_score": 100,
            "spam_penalty": 6
        },
        "whois_signals": {
            "age_years": 15.1,
            "days_to_expiry": 678,
            "days_since_last_registry_update": 83,
            "stability_score": 100,
            "registrar_changes": 0,
            "ownership_changes": 0,
            "nameserver_changes": 0,
            "status_changes": 0,
            "history_entries": 1,
            "privacy_protected": false,
            "dnssec_enabled": false,
            "has_registrant_country": false,
            "registrant_country": "",
            "nameserver_count": 2,
            "status_count": 1
        }
    },
    "authority_score": 40,
    "trust_score": 42,
    "domain_tags": {
        "primary_tag": "T",
        "primary_tag_score": 71,
        "primary_candidate": "T",
        "primary_candidate_score": 71,
        "tag_codes": "T,Uncertain,C",
        "tags": [
            {
                "code": "T",
                "label": "Trusted",
                "tone": "good",
                "description": "Strong trust, stability, and low-risk signals were detected.",
                "reason": "Low spam indicators plus strong trust, quality, registry, and stability signals were detected. Showing the stored external intelligence snapshot. New search and review intelligence only runs after a visitor uses Refresh data manually.",
                "message": "The site shows a reasonably trustworthy and stable profile.",
                "priority": 71,
                "score": 71,
                "match_percent": 71,
                "threshold_band": "strong"
            },
            {
                "code": "Uncertain",
                "label": "Uncertain",
                "tone": "unknown",
                "description": "External checks stayed inconclusive, so the model avoided a harder verdict.",
                "reason": "The evidence is mixed and external checks stayed inconclusive, so the system kept an uncertainty buffer instead of a harder automated verdict.",
                "message": "The evidence is materially mixed or partially corroborated, so the model is avoiding a harder verdict.",
                "priority": 68,
                "score": 68,
                "match_percent": 68,
                "threshold_band": "strong"
            },
            {
                "code": "C",
                "label": "Caution",
                "tone": "caution",
                "description": "Signals are mixed or weak, so this domain should be treated carefully.",
                "reason": "Review carefully: mixed trust signals. Showing the stored external intelligence snapshot. New search and review intelligence only runs after a visitor uses Refresh data manually.",
                "message": "The signal mix leans cautious and the site should be treated carefully until more evidence arrives.",
                "priority": 62,
                "score": 62,
                "match_percent": 62,
                "threshold_band": "strong"
            }
        ],
        "tag_breakdown": [
            {
                "code": "T",
                "label": "Trusted",
                "tone": "good",
                "description": "Strong trust, stability, and low-risk signals were detected.",
                "reason": "Low spam indicators plus strong trust, quality, registry, and stability signals were detected. Showing the stored external intelligence snapshot. New search and review intelligence only runs after a visitor uses Refresh data manually.",
                "message": "The site shows a reasonably trustworthy and stable profile.",
                "priority": 71,
                "score": 71,
                "match_percent": 71,
                "threshold_band": "strong"
            },
            {
                "code": "Uncertain",
                "label": "Uncertain",
                "tone": "unknown",
                "description": "External checks stayed inconclusive, so the model avoided a harder verdict.",
                "reason": "The evidence is mixed and external checks stayed inconclusive, so the system kept an uncertainty buffer instead of a harder automated verdict.",
                "message": "The evidence is materially mixed or partially corroborated, so the model is avoiding a harder verdict.",
                "priority": 68,
                "score": 68,
                "match_percent": 68,
                "threshold_band": "strong"
            },
            {
                "code": "C",
                "label": "Caution",
                "tone": "caution",
                "description": "Signals are mixed or weak, so this domain should be treated carefully.",
                "reason": "Review carefully: mixed trust signals. Showing the stored external intelligence snapshot. New search and review intelligence only runs after a visitor uses Refresh data manually.",
                "message": "The signal mix leans cautious and the site should be treated carefully until more evidence arrives.",
                "priority": 62,
                "score": 62,
                "match_percent": 62,
                "threshold_band": "strong"
            },
            {
                "code": "Infra",
                "label": "Risky infrastructure",
                "tone": "caution",
                "description": "The hosting / registrar / nameserver neighbourhood looks unusually risky.",
                "reason": "The infrastructure neighbourhood looks riskier than normal.",
                "message": "Infrastructure risk does not currently stand out.",
                "priority": 11,
                "score": 11,
                "match_percent": 11,
                "threshold_band": "none"
            },
            {
                "code": "D",
                "label": "Dangerous",
                "tone": "toxic",
                "description": "Strong signs of phishing, malware, or other harmful behaviour were detected.",
                "reason": "Multiple high-risk signals pushed this domain into the dangerous range. Showing the stored external intelligence snapshot. New search and review intelligence only runs after a visitor uses Refresh data manually.",
                "message": "No meaningful dangerous-signal match was detected.",
                "priority": 1,
                "score": 1,
                "match_percent": 1,
                "threshold_band": "none"
            }
        ],
        "nsfw_score": 0,
        "trust_score": 43,
        "manual": {
            "has_changes": false,
            "verified_status": "",
            "tag_codes": "",
            "rating_delta": 0,
            "authority_delta": 0,
            "trust_delta": 0,
            "note": "",
            "adjusted_by": 0,
            "adjusted_at": "",
            "lock_scores": false,
            "lock_flags": false
        },
        "summary": "Trusted (71% match) because low spam indicators plus strong trust, quality, registry, and stability signals were detected. showing the stored external intelligence snapshot. new search and review intelligence only runs after a visitor uses refresh data manually.",
        "external_intel": {
            "domain": "tonisagrista.com",
            "candidate_tag": "",
            "checked_at": "2026-03-18T21:01:49+00:00",
            "status": "fresh",
            "snapshot_version": 5,
            "summary": "Showing the stored external intelligence snapshot. New search and review intelligence only runs after a visitor uses Refresh data manually.",
            "search_intelligence": {
                "queries": [
                    "\"tonisagrista.com\" -site:tonisagrista.com -site:www.tonisagrista.com",
                    "\"tonisagrista.com\" official site -site:tonisagrista.com -site:www.tonisagrista.com",
                    "\"tonisagrista.com\" wikipedia -site:tonisagrista.com -site:www.tonisagrista.com",
                    "\"tonisagrista.com\" reviews OR complaints -site:tonisagrista.com -site:www.tonisagrista.com",
                    "\"tonisagrista.com\" reputation OR scam OR legit OR safe -site:tonisagrista.com -site:www.tonisagrista.com",
                    "\"tonisagrista.com\" BBB OR LinkedIn OR Crunchbase OR \"Companies House\" OR wikipedia -site:tonisagrista.com -site:www.tonisagrista.com",
                    "tonisagrista website -site:tonisagrista.com -site:www.tonisagrista.com",
                    "tonisagrista company -site:tonisagrista.com -site:www.tonisagrista.com",
                    "tonisagrista wikipedia -site:tonisagrista.com -site:www.tonisagrista.com",
                    "tonisagrista reviews -site:tonisagrista.com -site:www.tonisagrista.com",
                    "tonisagrista complaints -site:tonisagrista.com -site:www.tonisagrista.com",
                    "tonisagrista trustpilot -site:tonisagrista.com -site:www.tonisagrista.com"
                ],
                "providers": [
                    "duckduckgo"
                ],
                "provider_result_counts": {
                    "duckduckgo": 0
                },
                "results_found": 1,
                "external_results_found": 0,
                "used_direct_fallback": true,
                "results": [
                    {
                        "provider": "direct-domain-fallback",
                        "url": "https://tonisagrista.com/",
                        "host": "tonisagrista.com",
                        "title": "tonisagrista.com",
                        "snippet": "First-party fallback captured directly from the domain when public search engines returned no usable results.",
                        "is_direct_fallback": true,
                        "source_meta": {
                            "host": "tonisagrista.com",
                            "source_type": "official_site",
                            "label": "General web result",
                            "trust_weight": 55,
                            "evidence_weight": 26,
                            "noise_penalty": 0,
                            "requires_exact_domain_match": true,
                            "supports_positive_verdicts": false,
                            "supports_negative_verdicts": true,
                            "freshness_ttl_days": 21
                        },
                        "entity": {
                            "score": 100,
                            "exactness": "exact_domain",
                            "reasons": [
                                "The result host matches the exact domain.",
                                "The exact domain is mentioned in the page snippet or document text.",
                                "The result URL contains the exact domain string."
                            ]
                        },
                        "query": "direct-fallback",
                        "rank": 1
                    }
                ],
                "source_mix": {
                    "official_site": 1
                },
                "entity_coverage_score": 100,
                "high_trust_result_count": 0,
                "exact_match_result_count": 1,
                "high_entity_result_count": 1,
                "query_hit_count": 1,
                "query_count": 12,
                "deadline_hit": true
            },
            "review_intelligence": {
                "documents_fetched": 1,
                "external_documents_fetched": 0,
                "documents": [
                    {
                        "provider": "direct-domain-fallback",
                        "url": "https://tonisagrista.com/",
                        "host": "tonisagrista.com",
                        "title": "tonisagrista.com",
                        "snippet": "First-party fallback captured directly from the domain when public search engines returned no usable results.",
                        "is_direct_fallback": true,
                        "source_meta": {
                            "host": "tonisagrista.com",
                            "source_type": "official_site",
                            "label": "General web result",
                            "trust_weight": 55,
                            "evidence_weight": 26,
                            "noise_penalty": 0,
                            "requires_exact_domain_match": true,
                            "supports_positive_verdicts": false,
                            "supports_negative_verdicts": true,
                            "freshness_ttl_days": 21
                        },
                        "entity": {
                            "score": 100,
                            "exactness": "exact_domain",
                            "reasons": [
                                "The result host matches the exact domain.",
                                "The exact domain is mentioned in the page snippet or document text.",
                                "The result URL contains the exact domain string."
                            ]
                        },
                        "query": "direct-fallback",
                        "rank": 1,
                        "body": "Langur Monkey - Toni SagristÃ SellÃ©slangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchWell, hello there!Since you are already here, I think a short introduction is in order. My name is Toni SagristÃ SellÃ©s and I am an informatics engineer and hold a Ph.D. in Scientific Visualization and Astronomy and an M.Sc. in Astrophysics, Particle Physics and Cosmology. I like computer graphics and visualization, astronomy, photography (sometimes), snowboarding, playing and watching football, drawing horribly, playing with my kids, and occasionally gaming. I sometimes use the aliases langurmonkey and jumpinglangur.Here is a summary of the content in this site:bloglistprojectspapersphotorÃ©sumÃ©tagscategssearchLatest posts7Artisans EF-FX adapter review 10 Mar 26GGUF quantization guide 04 Mar 26LM Studio on systemd linger 27 Feb 26Yet another architectural update for Play Kid 28 Jan 26Game Boy emulator tech stack update 26 Jan 26 Implementing a Game Boy emulator 20 Jan 26 Google unkills JPEG XL? 28 Nov 25 Motion trails in Gaia Sky 14 Jun 25 More âRSSCodebergMastodon.socialPixelfedPGPEmailWebsite design by myself. See the privacy policy.Content licensed under CC-BY-NC-SA 4.0 .",
                        "html": "<!doctype html><html lang=en><head><meta name=generator content=\"Hugo 0.157.0\"><title>Langur Monkey - Toni Sagristà Sellés</title><meta name=color-scheme content=\"dark light\"><meta charset=utf-8><meta name=viewport content=\"width=device-width,initial-scale=1\"><link rel=icon href=/favicon.ico><meta name=description content=\"Personal website and portfolio\"><link rel=stylesheet href=https://tonisagrista.com/css/site-bundle.css><link rel=canonical href=https://tonisagrista.com/></head><body><script src=/js/darkmode.js></script><div id=wrapper><header id=header><h2><a href=/>langur@monkey</a><span class=homefolder>:~/</span><span class=shell>$</span></h2><nav class=links><ul><li><a href=/blog/>~/blog</a></li><li><a href=/projects/>~/projects</a></li><li><a href=/papers/>~/publications</a></li><li><a href=/resume/>~/cv</a></li><li><a href=/photography/>~/photo</a></li><li><a href=/search/>~/search</a></li></ul></nav><nav class=main><ul><li class=menu><a href=javascript:darkModeToggle() style=border:none title=\"Toggle dark mode\"><i id=toggle-theme class=\"fa fa-moon\"></i><span style=display:none>Theme</span></a></li><li class=menu><a href=#menu title=Menu><i id=icon-menu class=\"fa fa-bars fa-fw\"></i><span style=display:none>Menu</span></a></li></ul></nav></header><section id=menu><section><ul class=links><li><a href=/blog/><h3>~/blog</h3></a></li><li><a href=/projects/><h3>~/projects</h3></a></li><li><a href=/papers/><h3>~/publications</h3></a></li><li><a href=/resume/><h3>~/cv</h3></a></li><li><a href=/photography/><h3>~/photo</h3></a></li><li><a href=/search/><h3>~/search</h3></a></li></ul></section></section><main><article class=post><header><div class=title><h1><a href>Well, hello there!</a></h1></div></header><picture><source srcset=/img/profile/toni-funny-edit.jxl type=image/jxl><source srcset=/img/profile/toni-funny-edit.avif type=image/avif><img src=/img/profile/toni-funny-edit.jpg alt=\"My photo\" style=float:right;margin-left:50px;width:25%></picture><p>Since you are already here, I think a short introduction is in order. My name is <strong>Toni Sagristà Sellés</strong> and I am an informatics engineer and hold a Ph.D. in Scientific Visualization and Astronomy and an M.Sc. in Astrophysics, Particle Physics and Cosmology. I like computer graphics and visualization, astronomy, photography (sometimes), snowboarding, playing and watching football, drawing horribly, playing with my kids, and occasionally gaming. I sometimes use the aliases <code>langurmonkey</code> and <code>jumpinglangur</code>.</p><br>Here is a summary of the content in this site:<br><div class=content-table><a href=/blog><div class=menu-table-item><i class=\"fa fa-file-word-o\"></i><br>blog</div></a><a href=/posts-list><div class=menu-table-item><i class=\"fa fa-list\"></i><br>list</div></a><a href=/projects><div class=menu-table-item><i class=\"fa fa-cube\"></i><br>projects</div></a><a href=/papers><div class=menu-table-item><i class=\"fa fa-file-text-o\"></i><br>papers</div></a><a href=/photography><div class=menu-table-item><i class=\"fa fa-camera-retro\"></i><br>photo</div></a><a href=/resume><div class=menu-table-item><i class=\"fa fa-address-card-o\"></i><br>résumé</div></a><a href=/tags><div class=menu-table-item><i class=\"fa fa-tags\"></i><br>tags</div></a><a href=/categories><div class=menu-table-item><i class=\"fa fa-th\"></i><br>categs</div></a><a href=/search><div class=menu-table-item><i class=\"fa fa-search\"></i><br>search</div></a></div><section class=latest-posts><h2 id=latest-posts class=latest-posts-bottom>Latest posts</h2><div class=posts-container><div class=recent-posts-item><a class=recent-posts-link href=/blog/2026/7artisans-ef-fx/>7Artisans EF-FX adapter review</a> <time class=published datetime='2026-03-10 00:00:00 +0000 UTC' title='Posted: 2026-03-10 00:00:00 +0000 UTC'>10 Mar 26</time></div><div class=recent-posts-item><a class=recent-posts-link href=/blog/2026/quantization/>GGUF quantization guide</a> <time class=published datetime='2026-03-04 00:00:00 +0000 UTC' title='Posted: 2026-03-04 00:00:00 +0000 UTC'>04 Mar 26</time></div><div class=recent-posts-item><a class=recent-posts-link href=/blog/2026/lmster-service/>LM Studio on systemd linger</a> <time class=published datetime='2026-02-27 00:00:00 +0000 UTC' title='Posted: 2026-02-27 00:00:00 +0000 UTC'>27 Feb 26</time></div><div class=recent-posts-item><a class=recent-posts-link href=/blog/2026/playkid-update-again/>Yet another architectural update for Play Kid</a> <time class=published datetime='2026-01-28 00:00:00 +0000 UTC' title='Posted: 2026-01-28 00:00:00 +0000 UTC'>28 Jan 26</time></div><div class=recent-posts-item><a class=recent-posts-link href=/blog/2026/playkid-update/>Game Boy emulator tech stack update</a> <time class=published datetime='2026-01-26 00:00:00 +0000 UTC' title='Posted: 2026-01-26 00:00:00 +0000 UTC'>26 Jan 26 </time><i class=\"fa fa-arrow-circle-o-up last-update\" aria-hidden=true title=\"Updated: 2026-01-28 20:34:43 +0100 CET\"></i></div><div class=recent-posts-item><a class=recent-posts-link href=/blog/2026/playkid/>Implementing a Game Boy emulator</a> <time class=published datetime='2026-01-20 00:00:00 +0000 UTC' title='Posted: 2026-01-20 00:00:00…",
                        "status_code": 200,
                        "final_url": "https://tonisagrista.com/"
                    }
                ],
                "facts": [],
                "ignored_candidates": [],
                "blocked_candidates": 0,
                "source_diversity": 0,
                "host_coverage": 1,
                "source_type_coverage": 1,
                "exact_match_documents": 1,
                "external_exact_match_documents": 0,
                "elapsed_ms": 416,
                "candidates_considered": 1,
                "fetch_success_rate": 100,
                "avg_source_trust": 55,
                "avg_entity_score": 100
            },
            "evidence": {
                "scores": {
                    "legit": 0,
                    "safe": 0,
                    "trusted": 0,
                    "caution": 0,
                    "scam": 0,
                    "dangerous": 0,
                    "spam": 0,
                    "nsfw": 0
                },
                "counts": {
                    "official_presence": 0,
                    "business_profiles": 0,
                    "positive_reviews": 0,
                    "negative_reviews": 0,
                    "scam_reports": 0,
                    "dangerous_reports": 0,
                    "spam_reports": 0,
                    "adult_reports": 0
                },
                "tag_support": [],
                "top_supporting_facts": [],
                "top_positive_facts": []
            },
            "quality": {
                "source_diversity_score": 0,
                "entity_coverage_score": 100,
                "freshness_score": 18,
                "confidence": 24,
                "documents_fetched": 1,
                "external_documents_fetched": 0,
                "fact_count": 0,
                "avg_source_trust": 55,
                "avg_entity_score": 100,
                "fetch_success_rate": 100,
                "exact_match_score": 0,
                "query_coverage_score": 100,
                "host_coverage_score": 20,
                "source_type_coverage_score": 25,
                "qualified_evidence_score": 0,
                "exact_match_documents": 0,
                "blocked_candidates": 0,
                "used_direct_fallback": true,
                "external_results_found": 0
            },
            "decision": {
                "state": "insufficient",
                "uncertainty": true,
                "candidate_support": 0,
                "candidate_contradiction": 0,
                "supports": {
                    "dangerous": false,
                    "scam": false,
                    "spam": false,
                    "nsfw": false,
                    "trusted": false
                },
                "evidence_quality": "low",
                "state_label": "Inconclusive",
                "state_reason": "Public search did not yield usable third-party matches, so the system fell back to first-party inspection only."
            },
            "signals": {
                "scores": {
                    "legit": 0,
                    "safe": 0,
                    "trusted": 0,
                    "caution": 0,
                    "scam": 0,
                    "dangerous": 0,
                    "spam": 0,
                    "nsfw": 0
                },
                "counts": {
                    "official_presence": 0,
                    "business_profiles": 0,
                    "positive_reviews": 0,
                    "negative_reviews": 0,
                    "scam_reports": 0,
                    "dangerous_reports": 0,
                    "spam_reports": 0,
                    "adult_reports": 0
                },
                "candidate_support": 0,
                "candidate_contradiction": 0,
                "highlights": [
                    "External evidence remained inconclusive because diversity, exact matching, or confidence was still too weak."
                ]
            },
            "citations": [],
            "debug": {
                "top_supporting_facts": [],
                "top_positive_facts": [],
                "ignored_candidates": [],
                "budget_ms": 3000,
                "search_budget_ms": 3000,
                "review_budget_ms": 1500,
                "search_mode": "post-crawl",
                "query_cap": 12,
                "provider_cap": 2,
                "reason": "post-crawl",
                "priority": 92
            },
            "last_good": {
                "checked_at": "2026-03-18T21:01:49+00:00",
                "summary": "External checks ran, but the verified result set was still too sparse to harden the verdict.",
                "decision": {
                    "state": "insufficient",
                    "uncertainty": true,
                    "candidate_support": 0,
                    "candidate_contradiction": 0,
                    "supports": {
                        "dangerous": false,
                        "scam": false,
                        "spam": false,
                        "nsfw": false,
                        "trusted": false
                    },
                    "evidence_quality": "low",
                    "state_label": "Inconclusive",
                    "state_reason": "Public search did not yield usable third-party matches, so the system fell back to first-party inspection only."
                },
                "signals": {
                    "scores": {
                        "legit": 0,
                        "safe": 0,
                        "trusted": 0,
                        "caution": 0,
                        "scam": 0,
                        "dangerous": 0,
                        "spam": 0,
                        "nsfw": 0
                    },
                    "counts": {
                        "official_presence": 0,
                        "business_profiles": 0,
                        "positive_reviews": 0,
                        "negative_reviews": 0,
                        "scam_reports": 0,
                        "dangerous_reports": 0,
                        "spam_reports": 0,
                        "adult_reports": 0
                    },
                    "candidate_support": 0,
                    "candidate_contradiction": 0,
                    "highlights": [
                        "External evidence remained inconclusive because diversity, exact matching, or confidence was still too weak."
                    ]
                },
                "citations": []
            }
        },
        "external_decision": {
            "state": "insufficient",
            "uncertainty": true,
            "candidate_support": 0,
            "candidate_contradiction": 0,
            "supports": {
                "dangerous": false,
                "scam": false,
                "spam": false,
                "nsfw": false,
                "trusted": false
            },
            "evidence_quality": "low",
            "state_label": "Inconclusive",
            "state_reason": "Public search did not yield usable third-party matches, so the system fell back to first-party inspection only."
        },
        "signal_scores": [
            {
                "label": "Strongest tag heuristic",
                "value": "T · 71%",
                "tone": "good",
                "detail": "The highest raw tag match from the heuristic engine before visibility thresholds and manual overrides."
            },
            {
                "label": "Trust score",
                "value": "43/100",
                "tone": "spam",
                "detail": "Confidence derived from authority, crawl quality, stability, and risk signals."
            },
            {
                "label": "Authority score",
                "value": "40/100",
                "tone": "caution",
                "detail": "A higher authority score usually means broader reputation and backlink confidence."
            },
            {
                "label": "Spam risk",
                "value": "19/100",
                "tone": "good",
                "detail": "Lower is better. This blends spam indicators with false-positive protections for legitimate sites."
            },
            {
                "label": "Quality score",
                "value": "89/100",
                "tone": "good",
                "detail": "Based on crawl quality, content completeness, and technical evidence."
            },
            {
                "label": "Safety score",
                "value": "100/100",
                "tone": "good",
                "detail": "Higher is safer. Direct fraud signals can heavily cap this even when SEO signals look strong."
            },
            {
                "label": "Fraud score",
                "value": "2/100",
                "tone": "good",
                "detail": "Lower is better. This reflects phishing, drainer, fake-support, fake-shop, and malware signals."
            },
            {
                "label": "Infrastructure risk",
                "value": "11/100",
                "tone": "good",
                "detail": "Lower is better. This reflects the IP, registrar, and nameserver neighbourhood seen by the crawler."
            },
            {
                "label": "Evidence confidence",
                "value": "100/100",
                "tone": "good",
                "detail": "Higher means the crawler had enough pages and registry evidence to make a stronger call."
            },
            {
                "label": "External evidence",
                "value": "Low",
                "tone": "unknown",
                "detail": "Quality of the structured search and review evidence cluster."
            },
            {
                "label": "External decision",
                "value": "Inconclusive",
                "tone": "unknown",
                "detail": "How third-party evidence compares with the current candidate tag."
            },
            {
                "label": "NSFW score",
                "value": "0/100",
                "tone": "good",
                "detail": "Context-aware adult-content detection with medical / educational false-positive reduction."
            },
            {
                "label": "Registry stability",
                "value": "100/100",
                "tone": "good",
                "detail": "Based on age, expiry runway, and the amount of ownership / registrar churn."
            }
        ],
        "signal_sections": [
            {
                "title": "Registry & ownership",
                "items": [
                    {
                        "label": "Domain age",
                        "value": "15.1 years",
                        "tone": "good",
                        "detail": "Older domains generally carry more historical trust than very new ones."
                    },
                    {
                        "label": "Stability score",
                        "value": "100/100",
                        "tone": "good",
                        "detail": "Penalised by registrar, ownership, and nameserver churn."
                    },
                    {
                        "label": "Days to expiry",
                        "value": "678",
                        "tone": "good",
                        "detail": "Very short renewal windows can be a weak trust signal."
                    },
                    {
                        "label": "Registrar / ownership changes",
                        "value": "0 / 0",
                        "tone": "good",
                        "detail": "Frequent ownership churn can weaken trust."
                    },
                    {
                        "label": "Nameserver changes",
                        "value": "0",
                        "tone": "good",
                        "detail": "Repeated infrastructure changes can indicate instability."
                    },
                    {
                        "label": "DNSSEC / privacy",
                        "value": "DNSSEC off · privacy off",
                        "tone": "caution",
                        "detail": "DNSSEC strengthens DNS trust; privacy is neutral on its own."
                    }
                ]
            },
            {
                "title": "Reputation & search evidence",
                "items": [
                    {
                        "label": "Backlinks",
                        "value": "2",
                        "tone": "unknown",
                        "detail": "Broader backlink evidence usually improves confidence."
                    },
                    {
                        "label": "Referring domains",
                        "value": "2",
                        "tone": "unknown",
                        "detail": "Unique linking domains are more useful than raw link volume."
                    },
                    {
                        "label": "Organic keywords",
                        "value": "68",
                        "tone": "caution",
                        "detail": "Search footprint helps distinguish real sites from thin shells."
                    },
                    {
                        "label": "Indexed pages",
                        "value": "156",
                        "tone": "good",
                        "detail": "Larger index coverage usually means more evidence to classify from."
                    },
                    {
                        "label": "Brand strength",
                        "value": "60/100",
                        "tone": "good",
                        "detail": "Stronger brand signals reduce false positives for legitimate sites."
                    },
                    {
                        "label": "Risk label",
                        "value": "SUSPICIOUS",
                        "tone": "caution",
                        "detail": "This is the raw crawl / heuristic risk label feeding the tag model."
                    }
                ]
            },
            {
                "title": "Crawl, content & technicals",
                "items": [
                    {
                        "label": "HTTP status",
                        "value": "200",
                        "tone": "good",
                        "detail": "Healthy responses make classification more reliable."
                    },
                    {
                        "label": "HTTPS / speed",
                        "value": "HTTPS OK · 502 ms",
                        "tone": "good",
                        "detail": "Slow or broken technical signals weaken confidence."
                    },
                    {
                        "label": "Content words",
                        "value": "163",
                        "tone": "caution",
                        "detail": "Thin pages are harder to trust and easier to manipulate."
                    },
                    {
                        "label": "Schema / structure",
                        "value": "0 schema · meta · H1",
                        "tone": "caution",
                        "detail": "Structured markup and basic on-page hygiene improve quality confidence."
                    },
                    {
                        "label": "Links on page",
                        "value": "26 internal · 4 external",
                        "tone": "good",
                        "detail": "Link patterns help detect thin directories and promo pages."
                    },
                    {
                        "label": "Page speed / mobile",
                        "value": "92/100 · 89/100",
                        "tone": "good",
                        "detail": "Better technical quality generally reduces low-effort site patterns."
                    },
                    {
                        "label": "Crawl access",
                        "value": "Open",
                        "tone": "good",
                        "detail": "The crawler reached the site without an anti-bot challenge."
                    }
                ]
            },
            {
                "title": "External evidence & explainability",
                "items": [
                    {
                        "label": "Decision state",
                        "value": "Inconclusive",
                        "tone": "unknown",
                        "detail": "Public search did not yield usable third-party matches, so the system fell back to first-party inspection only."
                    },
                    {
                        "label": "Evidence quality",
                        "value": "Low",
                        "tone": "unknown",
                        "detail": "Blends source trust, domain matching, evidence diversity, and freshness."
                    },
                    {
                        "label": "Support vs contradiction",
                        "value": "0 / 0",
                        "tone": "unknown",
                        "detail": "Compares how much structured external evidence supports the candidate tag against evidence that contradicts it."
                    },
                    {
                        "label": "Qualified risk sources",
                        "value": "No",
                        "tone": "good",
                        "detail": "Risk tags only promote from external evidence when source diversity or source trust thresholds are met."
                    },
                    {
                        "label": "Uncertainty buffer",
                        "value": "Active",
                        "tone": "caution",
                        "detail": "Prevents thin or mixed external evidence from forcing a stronger tag than the evidence can justify."
                    }
                ]
            }
        ],
        "positives": [
            "Established domain age: 15.1 years.",
            "Low registrar / ownership churn with solid registry stability.",
            "Healthy crawl quality and on-page completeness.",
            "Search evidence is broad enough to classify with better confidence."
        ],
        "risks": [
            "External evidence was mixed or sparse, so the tag model keeps an uncertainty buffer instead of overcommitting."
        ]
    },
    "traffic_confidence": 51,
    "whois": {
        "current": {
            "id": 23136,
            "domain": "tonisagrista.com",
            "source_type": "rdap",
            "rdap_url": "https://rdap.verisign.com/com/v1/domain/TONISAGRISTA.COM",
            "registrar_name": "PDR Ltd. d/b/a PublicDomainRegistry.com",
            "registrar_handle": "303",
            "registrant_name": "",
            "registrant_org": "",
            "registrant_country": "",
            "registrant_email": "",
            "abuse_email": "abuse-contact@publicdomainregistry.com",
            "created_date": "2011-03-11 11:49:10",
            "updated_date": "2026-02-09 06:58:57",
            "expires_date": "2028-03-11 10:49:10",
            "nameservers_json": "[\"ns.phx2.nearlyfreespeech.net\",\"ns.phx3.nearlyfreespeech.net\"]",
            "status_json": "[\"client transfer prohibited\"]",
            "dnssec": "unsigned",
            "privacy_protected": 0,
            "content_hash": "d470b3c13ce097d26737d94ad8dc120de21f09ce6dccf1d5f94a2af6a98d61d0",
            "history_count": 1,
            "last_checked_at": "2026-03-18 21:01:39",
            "last_changed_at": "2026-03-18 21:01:39",
            "created_at": "2026-03-18 21:01:40",
            "updated_at": "2026-03-18 21:01:40"
        },
        "history": [
            {
                "id": 23618,
                "domain": "tonisagrista.com",
                "source_type": "rdap",
                "registrar_name": "PDR Ltd. d/b/a PublicDomainRegistry.com",
                "registrar_handle": "303",
                "registrant_name": "",
                "registrant_org": "",
                "registrant_country": "",
                "registrant_email": "",
                "abuse_email": "abuse-contact@publicdomainregistry.com",
                "created_date": "2011-03-11 11:49:10",
                "updated_date": "2026-02-09 06:58:57",
                "expires_date": "2028-03-11 10:49:10",
                "nameservers_json": "[\"ns.phx2.nearlyfreespeech.net\",\"ns.phx3.nearlyfreespeech.net\"]",
                "status_json": "[\"client transfer prohibited\"]",
                "dnssec": "unsigned",
                "privacy_protected": 0,
                "content_hash": "d470b3c13ce097d26737d94ad8dc120de21f09ce6dccf1d5f94a2af6a98d61d0",
                "checked_at": "2026-03-18 21:01:39",
                "change_summary": "Initial WHOIS snapshot captured.",
                "created_at": "2026-03-18 21:01:39"
            }
        ],
        "signals": {
            "age_years": 15.1,
            "days_to_expiry": 678,
            "days_since_last_registry_update": 83,
            "stability_score": 100,
            "registrar_changes": 0,
            "ownership_changes": 0,
            "nameserver_changes": 0,
            "status_changes": 0,
            "history_entries": 1,
            "privacy_protected": false,
            "dnssec_enabled": false,
            "has_registrant_country": false,
            "registrant_country": "",
            "nameserver_count": 2,
            "status_count": 1
        }
    },
    "discovered_domain": {
        "id": 96613,
        "domain": "tonisagrista.com",
        "first_seen_at": "2026-03-15 21:47:47",
        "last_crawled_at": "2026-03-18 21:01:45",
        "last_title": "Langur Monkey - Toni SagristÃ  SellÃ©s",
        "last_http_status": 200,
        "discovered_from_domain": "512kb.club",
        "depth": 0,
        "backlinks_count": 2,
        "rating_cache": 55,
        "spam_score": 52,
        "risk_label": "suspicious",
        "category_name": "Art & Design: Photography",
        "primary_country_code": "",
        "internal_links_count": 26,
        "external_links_count": 4,
        "social_profiles_count": 0,
        "content_word_count": 163,
        "title_quality_score": 93,
        "has_meta_description": 1,
        "has_h1": 1,
        "language_code": "en",
        "response_time_ms": 502,
        "robots_status": 200,
        "sitemap_status": 200,
        "sitemap_total_urls": 156,
        "quality_score": 89,
        "site_name": "",
        "canonical_domain": "",
        "favicon_present": 1,
        "schema_org_count": 0,
        "noindex_detected": 0,
        "feed_links_count": 0,
        "https_working": 1,
        "estimated_authority_score": 31,
        "trust_score": 76,
        "nsfw_score": 0,
        "overall_rank_estimate": 12172,
        "primary_tag": "C",
        "tag_codes": "C,Uncertain",
        "manual_verified_status": "",
        "manual_tag_codes": "",
        "manual_rating_delta": 0,
        "manual_authority_delta": 0,
        "manual_trust_delta": 0,
        "manual_note": null,
        "manual_adjusted_by": null,
        "manual_adjusted_at": null,
        "manual_lock_scores": 0,
        "manual_lock_flags": 0,
        "crawl_blocked": 0,
        "crawl_blocked_by": "",
        "crawl_blocked_reason": null,
        "safety_score": 100,
        "fraud_score": 2,
        "legitimacy_score": 55,
        "infrastructure_risk_score": 11,
        "score_confidence": 100,
        "tag_confidence": 72,
        "category_confidence": 18,
        "deep_crawl_pages": 49,
        "resolved_ip": "208.94.117.34",
        "category_candidates_json": "[{\"category\":\"Art & Design: Photography\",\"score\":17},{\"category\":\"Technology: AI & Machine Learning\",\"score\":17},{\"category\":\"News & Media\",\"score\":17},{\"category\":\"E-commerce\",\"score\":17}]",
        "page_signals_json": "[{\"path\":\"/about\",\"status\":200,\"title\":\"Well, hello there! - Langur Monkey - Toni SagristÃ  SellÃ©s\",\"word_count\":113,\"summary_text\":\"Well, hello there! - Langur Monkey - Toni SagristÃ  SellÃ©s Well, hello there! - Langur Monkey - Toni Sagristà Selléslangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchWell, hello there!Feb 28, 2019 May 7, 20251 minute readSince you are already here, I think a short introduction is in order. My name is Toni Sagristà Sellés and I am an informatics engineer and hold a Ph.D. in Scientific Visualization and Astronomy and an M.Sc. in Astrophysics, Particle Physics and Cosmology. I like computer graphics and visualization, astronomy, photography (sometimes), snowboarding, playing and watching football, drawing horribly, playing with my kids, and occasionally gaming. I sometimes use the aliases langurmonkey and jumpinglangur.Here is a summary of the content in this site:bloglistproje\",\"classification_terms\":[\"about\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":1},{\"path\":\"/blog/\",\"status\":200,\"title\":\"Blog - Langur Monkey - Toni SagristÃ  SellÃ©s\",\"word_count\":898,\"summary_text\":\"Blog - Langur Monkey - Toni SagristÃ  SellÃ©s Blog - Langur Monkey - Toni Sagristà Selléslangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/search&nbsp;Posts list7Artisans EF-FX adapter reviewSecond attempt at adapting Canon EF lenses to Fuji X, this time with much better resultsMar 10, 20265 minute readA while back I reviewed the Viltrox EF-FX1 adapter, my first attempt at bridging my old Canon EF and EF-S lenses over to my Fujifilm X-S10. The abridged version of that experience: it was frustrating. Firmware roulette, random errors, camera freezes requiring battery pulls, and auto focus performance that varied wildly between versions. I kept it because it was just good enough, but it never stopped feeling like a workaround rather than a solution. Moreover, Viltrox nev\",\"classification_terms\":[\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":1},{\"path\":\"/projects/\",\"status\":200,\"title\":\"Projects - Langur Monkey - Toni SagristÃ  SellÃ©s\",\"word_count\":457,\"summary_text\":\"Projects - Langur Monkey - Toni SagristÃ  SellÃ©s Projects - Langur Monkey - Toni Sagristà Selléslangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchProjectsApplications and softwaredotfiles &mdash; My dotfiles project. Contains the configuration, bootstrapping and deploying of my i3 (X11) and Sway (Wayland) environments.Gaia Sky &mdash; A real-time 3D visualisation application developed in OpenGL in the framework of Gaia outreach. Gestated in the Astronomisches Rechen-Institut of Heidelberg University.Gaia Sky docs &mdash; Documentation pages of Gaia Sky, written in reSyncText with Sphinx.Gaia Sky catgen &mdash; LOD catalog generation for Gaia Sky written in Rust. It supports the integration of multiple catalogs using cross-match information, additional columns cross\",\"classification_terms\":[\"projects\",\"support\",\"docs\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":4,\"depth\":1},{\"path\":\"/papers/\",\"status\":200,\"title\":\"Papers and Academic material - Langur Monkey - Toni SagristÃ  SellÃ©s\",\"word_count\":1608,\"summary_text\":\"Papers and Academic material - Langur Monkey - Toni SagristÃ  SellÃ©s Papers and Academic material - Langur Monkey - Toni Sagristà Selléslangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchPapers and Academic materialNov 8, 2016 Jul 25, 20248 minute readPh.D. ThesisVisualization of Astrometric and Astrophysical Data &mdash; A. Sagristà &ndash; 2024. Published as Open Access in Heidelberg University library document server. 10.11588/heidok.00034797.Peer-reviewed Papers &mdash; First AuthorVisual Analysis of the Finite-Time Lyapunov Exponent &mdash; A. Sagristà, S. Jordan, F. Sadlo &ndash; 2020, Computer Graphics Forum, 10.1111/cgf.13984Gaia Sky: Navigating the Gaia Catalog &mdash; A. Sagristà, S. Jordan, T. Müller, F. Sadlo &ndash; 2019, IEEE Transactions on Visualization and Computer Gra\",\"classification_terms\":[\"papers\",\"forum\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":40,\"depth\":1},{\"path\":\"/resume/\",\"status\":200,\"title\":\"RÃ©sumÃ© - Langur Monkey - Toni SagristÃ  SellÃ©s\",\"word_count\":1140,\"summary_text\":\"RÃ©sumÃ© - Langur Monkey - Toni SagristÃ  SellÃ©s Résumé - Langur Monkey - Toni Sagristà Selléslangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchRésuméToni Sagristà SellésSoftware Engineer, Ph.D. in Scientific Visualization and Astrophysics[PDF version]Email: me@tonisagrista.comPGP: 0x2FD2A59C1D734C1FBorn: August 5, 1983I am a software engineer with a strong interest in computer graphics, scientific visualization, data science and astrophysics. I'm currently doing research in scientific visualization. I am fascinated by the physics of nature and have a strong interest for physics simulations. I have lately developed a passion for game programming techniques.Experience11/2013 &ndash; currently&nbsp;&nbsp;&nbsp;ARI/University of Heidelberg, software engineer, postdoc\",\"classification_terms\":[\"resume\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":1},{\"path\":\"/photography/\",\"status\":200,\"title\":\"Photography - Langur Monkey - Toni SagristÃ  SellÃ©s\",\"word_count\":362,\"summary_text\":\"Photography - Langur Monkey - Toni SagristÃ  SellÃ©s Photography - Langur Monkey - Toni Sagristà Selléslangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchPhotographyI got my first DSLR camera in the latter half of 2007 and I have been interested in photography ever since. In all this time, I&rsquo;ve combined periods where I&rsquo;m very excited to go out and shoot with others where I&rsquo;ve felt quite apathetic about it. My guess is that that&rsquo;s a quite common pattern among enthusiasts, and even a healthy one. Anyway, this page contains a description of my gear and a link to a photo gallery containing some of the photos that I&rsquo;ve captured over the years.Photo galleryFrom time to time I publish some of my pictures in my photo gallery and also in Pixelfed.  \",\"classification_terms\":[\"photography\",\"about\",\"blog\",\"gallery\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":1},{\"path\":\"/search/\",\"status\":200,\"title\":\"Search - Langur Monkey - Toni SagristÃ  SellÃ©s\",\"word_count\":40,\"summary_text\":\"Search - Langur Monkey - Toni SagristÃ  SellÃ©s Search - Langur Monkey - Toni Sagristà Selléslangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchSearchClient-side search. No external servers involved.window.addEventListener(\\\"DOMContentLoaded\\\",e=>{new PagefindUI({element:\\\"#search\\\",resetStyles:!1,showSubResults:!0,showImages:!1,translations:{placeholder:\\\"Enter your search query here\\\"}})}).search-container{width:100%;margin-top:2rem}:root{--pagefind-ui-font:open sans, sans-serif;--pagefind-ui-primary:var(--fg-color);--pagefind-ui-text:#393939;--pagefind-ui-background:var(--bg-color);--pagefind-ui-border:#eeeeee;--pagefind-ui-tag:#f4f4f4}body.dark-mode{--pagefind-ui-font:open sans, sans-serif;--pagefind-ui-primary:#8ab4f8;--pagefind-ui-text:#e8eaed;--pagefind-ui-backgro\",\"classification_terms\":[\"search\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":1},{\"path\":\"/blog\",\"status\":200,\"title\":\"Blog - Langur Monkey - Toni SagristÃ  SellÃ©s\",\"word_count\":898,\"summary_text\":\"Blog - Langur Monkey - Toni SagristÃ  SellÃ©s Blog - Langur Monkey - Toni Sagristà Selléslangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/search&nbsp;Posts list7Artisans EF-FX adapter reviewSecond attempt at adapting Canon EF lenses to Fuji X, this time with much better resultsMar 10, 20265 minute readA while back I reviewed the Viltrox EF-FX1 adapter, my first attempt at bridging my old Canon EF and EF-S lenses over to my Fujifilm X-S10. The abridged version of that experience: it was frustrating. Firmware roulette, random errors, camera freezes requiring battery pulls, and auto focus performance that varied wildly between versions. I kept it because it was just good enough, but it never stopped feeling like a workaround rather than a solution. Moreover, Viltrox nev\",\"classification_terms\":[\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":1},{\"path\":\"/posts-list\",\"status\":200,\"title\":\"Posts list - Langur Monkey - Toni SagristÃ  SellÃ©s\",\"word_count\":911,\"summary_text\":\"Posts list - Langur Monkey - Toni SagristÃ  SellÃ©s Posts list - Langur Monkey - Toni Sagristà Selléslangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchPosts list20267Artisans EF-FX adapter review 10 MarGGUF quantization guide 04 MarLM Studio on systemd linger 27 FebYet another architectural update for Play Kid 28 JanGame Boy emulator tech stack update 26 Jan Implementing a Game Boy emulator 20 Jan 2025Google unkills JPEG XL? 28 Nov Motion trails in Gaia Sky 14 Jun Quadruple joins the fight! 10 MayBenchmarking arbitrary precision libraries in Java 07 May Oh Garmin, not you! 29 MarBuilding a local AI assistant with user context 26 Mar Local LLM with Retrieval-Augmented Generation 24 Mar Gaia Sky gets new website 19 Feb2024Rendering volume aurorae and nebulae 18 Dec Juju\",\"classification_terms\":[\"posts-list\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":1},{\"path\":\"/projects\",\"status\":200,\"title\":\"Projects - Langur Monkey - Toni SagristÃ  SellÃ©s\",\"word_count\":457,\"summary_text\":\"Projects - Langur Monkey - Toni SagristÃ  SellÃ©s Projects - Langur Monkey - Toni Sagristà Selléslangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchProjectsApplications and softwaredotfiles &mdash; My dotfiles project. Contains the configuration, bootstrapping and deploying of my i3 (X11) and Sway (Wayland) environments.Gaia Sky &mdash; A real-time 3D visualisation application developed in OpenGL in the framework of Gaia outreach. Gestated in the Astronomisches Rechen-Institut of Heidelberg University.Gaia Sky docs &mdash; Documentation pages of Gaia Sky, written in reSyncText with Sphinx.Gaia Sky catgen &mdash; LOD catalog generation for Gaia Sky written in Rust. It supports the integration of multiple catalogs using cross-match information, additional columns cross\",\"classification_terms\":[\"projects\",\"support\",\"docs\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":4,\"depth\":1},{\"path\":\"/papers\",\"status\":200,\"title\":\"Papers and Academic material - Langur Monkey - Toni SagristÃ  SellÃ©s\",\"word_count\":1608,\"summary_text\":\"Papers and Academic material - Langur Monkey - Toni SagristÃ  SellÃ©s Papers and Academic material - Langur Monkey - Toni Sagristà Selléslangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchPapers and Academic materialNov 8, 2016 Jul 25, 20248 minute readPh.D. ThesisVisualization of Astrometric and Astrophysical Data &mdash; A. Sagristà &ndash; 2024. Published as Open Access in Heidelberg University library document server. 10.11588/heidok.00034797.Peer-reviewed Papers &mdash; First AuthorVisual Analysis of the Finite-Time Lyapunov Exponent &mdash; A. Sagristà, S. Jordan, F. Sadlo &ndash; 2020, Computer Graphics Forum, 10.1111/cgf.13984Gaia Sky: Navigating the Gaia Catalog &mdash; A. Sagristà, S. Jordan, T. Müller, F. Sadlo &ndash; 2019, IEEE Transactions on Visualization and Computer Gra\",\"classification_terms\":[\"papers\",\"forum\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":40,\"depth\":1},{\"path\":\"/photography\",\"status\":200,\"title\":\"Photography - Langur Monkey - Toni SagristÃ  SellÃ©s\",\"word_count\":362,\"summary_text\":\"Photography - Langur Monkey - Toni SagristÃ  SellÃ©s Photography - Langur Monkey - Toni Sagristà Selléslangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchPhotographyI got my first DSLR camera in the latter half of 2007 and I have been interested in photography ever since. In all this time, I&rsquo;ve combined periods where I&rsquo;m very excited to go out and shoot with others where I&rsquo;ve felt quite apathetic about it. My guess is that that&rsquo;s a quite common pattern among enthusiasts, and even a healthy one. Anyway, this page contains a description of my gear and a link to a photo gallery containing some of the photos that I&rsquo;ve captured over the years.Photo galleryFrom time to time I publish some of my pictures in my photo gallery and also in Pixelfed.  \",\"classification_terms\":[\"photography\",\"about\",\"blog\",\"gallery\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":1},{\"path\":\"/resume\",\"status\":200,\"title\":\"RÃ©sumÃ© - Langur Monkey - Toni SagristÃ  SellÃ©s\",\"word_count\":1140,\"summary_text\":\"RÃ©sumÃ© - Langur Monkey - Toni SagristÃ  SellÃ©s Résumé - Langur Monkey - Toni Sagristà Selléslangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchRésuméToni Sagristà SellésSoftware Engineer, Ph.D. in Scientific Visualization and Astrophysics[PDF version]Email: me@tonisagrista.comPGP: 0x2FD2A59C1D734C1FBorn: August 5, 1983I am a software engineer with a strong interest in computer graphics, scientific visualization, data science and astrophysics. I'm currently doing research in scientific visualization. I am fascinated by the physics of nature and have a strong interest for physics simulations. I have lately developed a passion for game programming techniques.Experience11/2013 &ndash; currently&nbsp;&nbsp;&nbsp;ARI/University of Heidelberg, software engineer, postdoc\",\"classification_terms\":[\"resume\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":1},{\"path\":\"/tags\",\"status\":200,\"title\":\"Tags - Langur Monkey - Toni SagristÃ  SellÃ©s\",\"word_count\":199,\"summary_text\":\"Tags - Langur Monkey - Toni SagristÃ  SellÃ©s Tags - Langur Monkey - Toni Sagristà Sellés langur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchtagsprogramming 46english 35gaia sky 18opengl 17android 15astronomy 14erasmus 14linux 14simulation 10astrophysics 9gaia 9privacy 9website 9open-source 7graphics 6i3wm 6technical 6design 5git 5java 5qutebrowser 5cli 4html5 4hugo 4photo 4projects 4release 4rice 4version 4videos 4web 4gaiasky 3game 3gear 3image 3jpeg xl 3physics 3scripts 3security 3travel 3anonymity 2archlinux 2avif 2camera 2computer architecture 2education 2formats 2glsl 2i3blocks 2javascript 2jpeg 2jxl 2life 2mastodon 2music 2n-body 2neovim 2pass 2phd 2png 2polybar 2procedural 2rust 2search 2simulator 2snake 2technology 2terminal 2thesis 2vcs 2webp 2welcome 2\",\"classification_terms\":[\"tags\",\"privacy\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":1},{\"path\":\"/categories\",\"status\":200,\"title\":\"Categories - Langur Monkey - Toni SagristÃ  SellÃ©s\",\"word_count\":67,\"summary_text\":\"Categories - Langur Monkey - Toni SagristÃ  SellÃ©s Categories - Langur Monkey - Toni Sagristà Selléslangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchcategoriesgaia sky 23old blog 20linux 17particle physics simulator 16website 11programming 8photography 6privacy 6projects 5ai 4emulators 4jpeg xl 3life 3design 2java 2rust 2about 1academic 1astronomy 1computer graphics 1computers 1garmin 1general 1git 1graphics 1hardware 1libgdx 1n-body live wallpaper 1nostr 1raspberrypi 1resume 1rts engine 1security 1steam deck 1syncthing 1texteditor 1vcs 1RSSCodebergMastodon.socialPixelfedPGPEmailWebsite design by myself. See the privacy policy.Content licensed under CC-BY-NC-SA 4.0 .\",\"classification_terms\":[\"categories\",\"about\",\"privacy\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":1},{\"path\":\"/search\",\"status\":200,\"title\":\"Search - Langur Monkey - Toni SagristÃ  SellÃ©s\",\"word_count\":40,\"summary_text\":\"Search - Langur Monkey - Toni SagristÃ  SellÃ©s Search - Langur Monkey - Toni Sagristà Selléslangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchSearchClient-side search. No external servers involved.window.addEventListener(\\\"DOMContentLoaded\\\",e=>{new PagefindUI({element:\\\"#search\\\",resetStyles:!1,showSubResults:!0,showImages:!1,translations:{placeholder:\\\"Enter your search query here\\\"}})}).search-container{width:100%;margin-top:2rem}:root{--pagefind-ui-font:open sans, sans-serif;--pagefind-ui-primary:var(--fg-color);--pagefind-ui-text:#393939;--pagefind-ui-background:var(--bg-color);--pagefind-ui-border:#eeeeee;--pagefind-ui-tag:#f4f4f4}body.dark-mode{--pagefind-ui-font:open sans, sans-serif;--pagefind-ui-primary:#8ab4f8;--pagefind-ui-text:#e8eaed;--pagefind-ui-backgro\",\"classification_terms\":[\"search\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":1},{\"path\":\"/blog/2026/7artisans-ef-fx/\",\"status\":200,\"title\":\"7Artisans EF-FX adapter review\",\"word_count\":953,\"summary_text\":\"7Artisans EF-FX adapter review 7Artisans EF-FX adapter reviewlangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchContentsLenses and bodyBuild qualityAuto focus performanceNo firmware archaeology requiredAperture control and EXIFWrap-up7Artisans EF-FX adapter reviewSecond attempt at adapting Canon EF lenses to Fuji X, this time with much better resultsMar 10, 20265 minute readA while back I reviewed the Viltrox EF-FX1 adapter, my first attempt at bridging my old Canon EF and EF-S lenses over to my Fujifilm X-S10. The abridged version of that experience: it was frustrating. Firmware roulette, random errors, camera freezes requiring battery pulls, and auto focus performance that varied wildly between versions. I kept it because it was just good enough,\",\"classification_terms\":[\"blog/2026/7artisans-ef-fx\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":1},{\"path\":\"/blog/2026/quantization/\",\"status\":200,\"title\":\"GGUF quantization guide\",\"word_count\":796,\"summary_text\":\"GGUF quantization guide GGUF quantization guidelangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchContentsNaming conventionsUnquantized formatsLegacy quantization formats (Q*_0, Q*_1)K-Quant formats (modern default)I-Quant formats (aggressive compression)Special formatsDecision guideConclusionsGGUF quantization guideA quick guide to understanding modern and legacy quantization methods in LLMs for local inference with GGUF/llama.cppMar 4, 20265 minute readI like running my own LLMs locally. Open models are becoming more and more powerful, with exciting releases like the latest Qwen 3.5 family scoring highly in benchmarks even in their smaller variants. This makes managing and running your own models more viable, as it becomes increasingly eas\",\"classification_terms\":[\"blog/2026/quantization\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":1},{\"path\":\"/blog/2026/lmster-service/\",\"status\":200,\"title\":\"LM Studio on systemd linger\",\"word_count\":503,\"summary_text\":\"LM Studio on systemd linger LM Studio on systemd lingerlangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchLM Studio on systemd lingerHow I set up an old laptop as a persistent inference machine using LM Studio, system-level services, and systemd lingering.Feb 27, 20263 minute readThe release of LM Studio 0.4.5 has introduced a much needed feature in this local LLM suite that has it much more attractive with respect to other similar projects. LM Link allows you to connect multiple LM Studio instances across your network to share models and perform inference seamlessly.By sheer chance, I was just playing around with setting up an LM Studio server in an old laptop that I planned to use for inference. I would connect AnythingLLM clients to it to mak\",\"classification_terms\":[\"blog/2026/lmster-service\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":1},{\"path\":\"/blog/2026/playkid-update-again/\",\"status\":200,\"title\":\"Yet another architectural update for Play Kid\",\"word_count\":657,\"summary_text\":\"Yet another architectural update for Play Kid Yet another architectural update for Play Kidlangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchYet another architectural update for Play KidMy Game Boy emulator gets yet another architectural update to drop the pixels dependency. This is the final one. I promise, maybe.Jan 28, 20263 minute readI finished my previous post on Play Kid, only two days ago, with the following words:Next, I&rsquo;ll probably think about adding Game Boy Color support, but not before taking some time off from this project.Yeah, this was a lie.I have previously written about Play Kid, my Game Boy emulator. Here, I introduced it and talked about the base implementation and the quirks of the Game Boy CPU, PPU, and hardware in general. Here, I e\",\"classification_terms\":[\"blog/2026/playkid-update-again\",\"about\",\"support\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":1},{\"path\":\"/blog/2026/playkid-update/\",\"status\":200,\"title\":\"Game Boy emulator tech stack update\",\"word_count\":663,\"summary_text\":\"Game Boy emulator tech stack update Game Boy emulator tech stack updatelangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchContentsDebug panelDependency hellConclusionGame Boy emulator tech stack updatePlay Kid update from SDL2 to a modern Rust stack using pixels, winit, and eguiJan 26, 2026 Jan 28, 20263 minute read&nbsp;&nbsp;NoticeThis post is about Play Kid version 0.2.0, which uses pixels to create and manage the pixel frame buffer. Since then, versions 0.3.0 and 0.4.0 have been released, which dropped pixels in favor of rendering directly to a texture. See this write-up for more information.In my previous post, I shared the journey of building Play Kid, my Game Boy emulator. At the time, I was using SDL2 to handle the &ldquo;heavy lifting&rdquo; of\",\"classification_terms\":[\"blog/2026/playkid-update\",\"about\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":1},{\"path\":\"/blog/2026/playkid/\",\"status\":200,\"title\":\"Implementing a Game Boy emulator\",\"word_count\":7180,\"summary_text\":\"Implementing a Game Boy emulator Implementing a Game Boy emulatorlangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchContentsForewordGame Boy essentialsThe CPUMemoryThe PPUThe APUCartridgesUI and debug modeFuture workConclusionsImplementing a Game Boy emulatorWrite-up about Play Kid, my own homegrown Game Boy emulator.Jan 20, 2026 Feb 27, 202635 minute read&nbsp;&nbsp;NoticeThis post is about Play Kid version 0.1.0, which works with SDL2. Since then, version 0.2.0 has been released. This new version uses Rust native crates like winit, egui, rodio, and pixels. See this write-up for more information on the new version.When I was a kid my parents got me and my brothers a brand new Game Boy. I used to play it a lot, and I was mesmerized and amazed at how\",\"classification_terms\":[\"blog/2026/playkid\",\"about\",\"cart\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":1},{\"path\":\"/blog/2025/google-unkills-jpegxl/\",\"status\":200,\"title\":\"Google *unkills* JPEG XL?\",\"word_count\":995,\"summary_text\":\"Google *unkills* JPEG XL? Google *unkills* JPEG XL?langur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchContentsLet&rsquo;s recapChromium&rsquo;s new stanceAbout JPEG XLConclusionGoogle unkills JPEG XL?A quick summary of the format&rsquo;s road to stardomNov 28, 2025 Jan 20, 20265 minute readI&rsquo;ve written about JPEG XL in the past. First, I noted Google&rsquo;s move to kill the format in Chromium in favor of the homegrown and inferior AVIF.12 Then, I had a deeper look at the format, and visually compared JPEG XL with AVIF on a handful of images.The latter post started with a quick support test:&ldquo;If you are browsing this page around 2023, chances are that your browser supports AVIF but does not support JPEG XL.&rdquo;Well, here we are a\",\"classification_terms\":[\"blog/2025/google-unkills-jpegxl\",\"about\",\"support\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":1},{\"path\":\"/blog/2025/motion-trails/\",\"status\":200,\"title\":\"Motion trails in Gaia Sky\",\"word_count\":1130,\"summary_text\":\"Motion trails in Gaia Sky Motion trails in Gaia Skylangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchContentsTraditional approachOur approachThe shader0. Initial orientation1. Rotation and velocity projection2. Estimate screen-space movement3. Calculate trail stretch amount4. Distance-based fadeout5. Apply trail effect6. Final assemblyResultsConclusionMotion trails in Gaia SkyVertex-based motion trails implementation using screen-space velocityJun 14, 2025 Jun 18, 20256 minute readAstronomical scenes, especially those rendered interactively, often feature supraluminal camera motion over immense distances. Sometimes, these motions are rendered by applying trail effects to light-emitting objects to enhance the faster-than-light velocity sensati\",\"classification_terms\":[\"blog/2025/motion-trails\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[\"bsky.app\"],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":1},{\"path\":\"/privacypolicy\",\"status\":200,\"title\":\"Privacy Policy - Langur Monkey - Toni SagristÃ  SellÃ©s\",\"word_count\":176,\"summary_text\":\"Privacy Policy - Langur Monkey - Toni SagristÃ  SellÃ©s Privacy Policy - Langur Monkey - Toni Sagristà Selléslangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchPrivacy PolicyThis site strives to be as bloat-free as possible. It does not use cookies, tracking codes, analytics scripts or anything else that can be used to invade personal privacy. We use, however, the privacy-respecting sessionStorage1 to store the user&rsquo;s theme preference, if any.This site serves, along with the HTML page, 2 JavaScript files (theme manager, which loads at the top of the body element, and a bundle with the rest, loaded in the footer), 1 font file (fork awesome) and 1 CSS file. Some special pages may need an additional JS file fetch. The posts that contain mathematical formulas are less th\",\"classification_terms\":[\"privacypolicy\",\"privacy\",\"blog\",\"store\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":1},{\"path\":\"/about/\",\"status\":200,\"title\":\"Well, hello there! - Langur Monkey - Toni SagristÃ  SellÃ©s\",\"word_count\":113,\"summary_text\":\"Well, hello there! - Langur Monkey - Toni SagristÃ  SellÃ©s Well, hello there! - Langur Monkey - Toni Sagristà Selléslangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchWell, hello there!Feb 28, 2019 May 7, 20251 minute readSince you are already here, I think a short introduction is in order. My name is Toni Sagristà Sellés and I am an informatics engineer and hold a Ph.D. in Scientific Visualization and Astronomy and an M.Sc. in Astrophysics, Particle Physics and Cosmology. I like computer graphics and visualization, astronomy, photography (sometimes), snowboarding, playing and watching football, drawing horribly, playing with my kids, and occasionally gaming. I sometimes use the aliases langurmonkey and jumpinglangur.Here is a summary of the content in this site:bloglistproje\",\"classification_terms\":[\"about\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":2},{\"path\":\"/blog/2021/viltrox-ef-fx1-review\",\"status\":200,\"title\":\"Viltrox EF-FX1 lens adapter review\",\"word_count\":1117,\"summary_text\":\"Viltrox EF-FX1 lens adapter review Viltrox EF-FX1 lens adapter reviewlangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchContentsLenses and bodyBuild qualityThe firmware problemFlashing firmware versions like there&rsquo;s no tomorrowWrap-upViltrox EF-FX1 lens adapter reviewDoes this adapter work well? Is the auto focus it provides usable? Is the device worth it?Nov 16, 2021 Mar 10, 20266 minute read&nbsp;&nbsp;NoticeI have also reviewed the newer 7Artisans EF-FX and have found it much better. Check out my review.A few days ago I got my new camera, a brand new Fujifilm X-S10. Since I&rsquo;m coming from the Canon ecosystem I have a few EF and EF-S lenses which I like. In order to use them with my new system I also acquired the auto focus lens mount adap\",\"classification_terms\":[\"blog/2021/viltrox-ef-fx1-review\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":3,\"depth\":2},{\"path\":\"/projects/rts-engine\",\"status\":200,\"title\":\"RTS engine - Langur Monkey - Toni SagristÃ  SellÃ©s\",\"word_count\":508,\"summary_text\":\"RTS engine - Langur Monkey - Toni SagristÃ  SellÃ©s RTS engine - Langur Monkey - Toni Sagristà Selléslangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchRTS engineA real time strategy game engine written in JavaJul 22, 2013 Jan 20, 20263 minute read&nbsp;&nbsp;DisclaimerThis is a work-in-progress. The master branch is up to date with the latest development and may very possibly crash. Use it at your own risk.Repository: https://codeberg.org/langurmonkey/rts-engineThis is an RTS engine project that I used to enjoy working on. It is a testing sandbox and does not have much focus.Screenshot of the RTS engine running.I started playing around with the idea as a time killer some years ago, kicking off the development with a fast version of the A* path-finding algorithm backed\",\"classification_terms\":[\"projects/rts-engine\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":2},{\"path\":\"/blog/2021/chip8-spec\",\"status\":200,\"title\":\"CHIP-8 virtual machine specification\",\"word_count\":3250,\"summary_text\":\"CHIP-8 virtual machine specification CHIP-8 virtual machine specificationlangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchContentsSome historyBird&rsquo;s eye viewMemoryRegistersStackInputDisplayTimersInstruction setCLS — 00E0RET — 00EEJMP — 1NNNCALL NNN — 2NNNSE VX, NN — 3XNNSNE VX, NN — 4XNNSE VX, VY — 5XY0LD VX, NN — 6XNNADD VX, NN — 7XNNLD VX, VY — 8XY0OR VX, VY — 8XY1AND VX, VY — 8XY2XOR VX, VY — 8XY3ADD VX, VY — 8XY4SUB VX, VY — 8XY5SHR VX {, VY} — 8XY6SUBN VX, VY — 8XY7SHL VX {, VY} — 8XYESNE VX, VY — 9XY0LD I, NNN — ANNNJMP V0, NNN — BNNNRND VX, NN – CXNNDRW VX, VY, N — DXYNSKP VX — EX9ESKNP VX — EXA1LD VX, DT — FX07LD VX, K — FX0ALD DT, VX — FX15LD ST, VX — FX18ADD I, VX — FX1ELD F, VX — FX29LD B, VX — FX33LD [I], VX — FX55LD VX, [I] — FX65Con\",\"classification_terms\":[\"blog/2021/chip8-spec\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":4,\"depth\":2},{\"path\":\"/blog/2021/chip8-implementation\",\"status\":200,\"title\":\"Implementing a CHIP-8 emulator\",\"word_count\":2664,\"summary_text\":\"Implementing a CHIP-8 emulator Implementing a CHIP-8 emulatorlangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchContentsBasic structureThe main moduleThe machineThe cycle() methodThe displayAudioKeyboardTimeDebugConclusionImplementing a CHIP-8 emulatorWriting a simple emulator from scratch is fun: rCHIP8Jul 14, 2021 Jan 20, 202613 minute readI&rsquo;ve written about the CHIP-8 machine before. It is a very simple interpreted programming language that can be implemented without much hassle by anyone interested in getting their feet wet with emulators. It is commonly regarded as the &ldquo;hello world&rdquo; of emulators.Some time ago I decided to implement a CHIP-8 emulator in Rust as my second project written in that language. My first foray into th\",\"classification_terms\":[\"blog/2021/chip8-implementation\",\"about\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":7,\"depth\":2},{\"path\":\"/blog/2019/learning-ncurses\",\"status\":200,\"title\":\"Learning ncurses\",\"word_count\":1155,\"summary_text\":\"Learning ncurses Learning ncurseslangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchContentsHow to startDrawing maps with ncursesThe game loopConclusionLearning ncursesImplementing a snake game in the terminalMar 16, 2019 Feb 19, 20256 minute readtsnake, a snake game in the terminalLately, I have been kicking the dust off my C++ skills, and decided to start by learning to use a library which I have been eyeing for a while, ncurses. ncurses is a C library which lets you create text-based UI programs for the terminal, in the same fashion as the gif above. Basically, you can use the terminal to implement text-based user interfaces. Since I seem to have an obsession with snake games, I figured I&rsquo;d create a snake game for the termina\",\"classification_terms\":[\"blog/2019/learning-ncurses\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":2,\"depth\":2},{\"path\":\"/projects/pps/\",\"status\":200,\"title\":\"Particle Physics Simulator - Langur Monkey - Toni SagristÃ  SellÃ©s\",\"word_count\":726,\"summary_text\":\"Particle Physics Simulator - Langur Monkey - Toni SagristÃ  SellÃ©s Particle Physics Simulator - Langur Monkey - Toni Sagristà Selléslangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchParticle Physics SimulatorFully-feature physics simulator in your pocketSep 20, 2011 Jan 20, 20264 minute readThe Particle Physics Simulator is a physics application for Android devices (v2.2+) in which real gravitational systems of particles can be created, simulated and interacted with in real time. It is an N-body particle simulator where the behaviour of the system is driven only by each particle&rsquo;s gravity and its interaction with all the other particles in it. It is turning more into a physics playground lately though, with the addition of accelerometer support, elastic collisions, ability to\",\"classification_terms\":[\"projects/pps\",\"support\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":2,\"depth\":2},{\"path\":\"/projects/nblw/\",\"status\":200,\"title\":\"N-Body Live Wallpaper - Langur Monkey - Toni SagristÃ  SellÃ©s\",\"word_count\":269,\"summary_text\":\"N-Body Live Wallpaper - Langur Monkey - Toni SagristÃ  SellÃ©s N-Body Live Wallpaper - Langur Monkey - Toni Sagristà Selléslangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchN-Body Live WallpaperFully-feature physics simulator in your desktop wallSep 20, 2011 Feb 19, 20252 minute read This is a retired, unmaintained app!The N-Body Live Wallpaper is an application for Android (v2.1+) powered devices that enables the user to have a particle zoo of gravity interactions as a home screen wallpaper. The application is heavily based on the first version fo the Particle Physics Simulator, but adapted to suit a live wallaper needs. Features:Real n-body simulation, pure gravitational interactions between particles.Allow or not physically realistic collisions and mergers between particles.S\",\"classification_terms\":[\"projects/nblw\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":2},{\"path\":\"/projects/celestial-pole/\",\"status\":200,\"title\":\"Celestial Pole Motion - Langur Monkey - Toni SagristÃ  SellÃ©s\",\"word_count\":209,\"summary_text\":\"Celestial Pole Motion - Langur Monkey - Toni SagristÃ  SellÃ©s Celestial Pole Motion - Langur Monkey - Toni Sagristà Selléslangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchCelestial Pole MotionMotion of the celestial poles with respect to the ICRSNov 12, 2014 Feb 19, 20251 minute readThis is a wee graphical application to visualise the movement of the celestial pole (J2000.0) with respect to the ICRS due to the precession and nutation of the Earth. There is a basic GUI which lets you switch between north and south pole and lets you control the time speed. The program uses the IAU2000 equations for the two sets of angles and yields good results for at least a span of 6000 years. It also features the latitude lines and a background with some of the most important Hipparcos stars.\",\"classification_terms\":[\"projects/celestial-pole\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":2},{\"path\":\"/projects/snake/\",\"status\":200,\"title\":\"HTML5 Snake Game - Langur Monkey - Toni SagristÃ  SellÃ©s\",\"word_count\":943,\"summary_text\":\"HTML5 Snake Game - Langur Monkey - Toni SagristÃ  SellÃ©s HTML5 Snake Game - Langur Monkey - Toni Sagristà Selléslangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchHTML5 Snake GameSnake game and javascript source codeOct 29, 2013 Feb 19, 20255 minute readinput[type=checkbox],input[type=radio]{display:inline;opacity:1;float:none;-webkit-appearance:radio;margin-right:0}input[type=text]{margin-top:.1em;margin-bottom:.1em;height:1.5em;width:15em;margin-right:0;margin-left:auto}table td{padding:.1em}This is my modification of the HTML5 snake game seen in thecodeplayer.com. You can change all the start parameters using the input form below, just remember to hit r to reload so that the new values take effect. It is very customizable, try it!p - pause game&nbsp;&nbsp;&nbsp;&nbsp;r -\",\"classification_terms\":[\"projects/snake\",\"blog\",\"source code\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":1,\"depth\":2},{\"path\":\"/photo-gallery\",\"status\":200,\"title\":\"Toni Sagristà Sellés - Photo gallery - Home\",\"word_count\":161,\"summary_text\":\"Toni Sagristà Sellés - Photo gallery - Home Toni Sagristà Sellés - Photo gallery - Home Toni Sagristà Sellés - Photo gallery Home Back to website scenery 41 photos manmade 19 photos gear 64 photos architecture 12 photos people 27 photos animals 23 photos other 21 photos nepal-2013 19 photos turkey-2012 11 photos india-2011 18 photos canada-2009 9 photos us-2009 19 photos sport 2 photos $(document).ready(function() { $(\\\"#media\\\").lightGallery({ thumbWidth: 80, controls: true, loop : false, download: true, counter: true, videojs: true, exThumbImage: 'data-exthumbimage', }); // Init justified gallery for albums $(\\\"#albums\\\").justifiedGallery({ margins: 10, rowHeight: 300, maxRowHeight: 325, }); // Init justified gallery for photos $(\\\"#media\\\").justifiedGallery({ selector: '.albumList', waitThumbnailsLoad: false, margins: 10, rowHeight: 25\",\"classification_terms\":[\"photo-gallery\",\"gallery\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":2},{\"path\":\"/blog/2021/static-photo-gallery\",\"status\":200,\"title\":\"Create your static photo gallery with thumbsup\",\"word_count\":751,\"summary_text\":\"Create your static photo gallery with thumbsup Create your static photo gallery with thumbsuplangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchContentsInstalling thumbsupGenerating your first galleryChoosing a themeRunning the scriptLinking vs including the photosConclusionCreate your static photo gallery with thumbsupDo not post your photos in online services that do not respect your rights, create your own static HTML photo gallery for your website with thumbsupNov 5, 2021 Nov 14, 20214 minute readIt is nowadays commonplace to upload your valued photos to online services that don&rsquo;t respect your rights like Flickr, Google Photos or Instagram. While these sites have a social component that may help you build an audience and have a wider reach, usually their\",\"classification_terms\":[\"blog/2021/static-photo-gallery\",\"help\",\"blog\",\"gallery\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":2},{\"path\":\"/photo-gallery/gear.html\",\"status\":200,\"title\":\"Toni Sagristà Sellés - Photo gallery - gear\",\"word_count\":70,\"summary_text\":\"Toni Sagristà Sellés - Photo gallery - gear Toni Sagristà Sellés - Photo gallery - gear Toni Sagristà Sellés - Photo gallery Home&nbsp;/&nbsp;gear Back to website $(document).ready(function() { $(\\\"#media\\\").lightGallery({ thumbWidth: 80, controls: true, loop : false, download: true, counter: true, videojs: true, exThumbImage: 'data-exthumbimage', }); // Init justified gallery for albums $(\\\"#albums\\\").justifiedGallery({ margins: 10, rowHeight: 300, maxRowHeight: 325, }); // Init justified gallery for photos $(\\\"#media\\\").justifiedGallery({ selector: '.albumList', waitThumbnailsLoad: false, margins: 10, rowHeight: 250, maxRowHeight: 275, }); });\",\"classification_terms\":[\"photo-gallery/gear.html\",\"gallery\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":2},{\"path\":\"/posts-list/\",\"status\":200,\"title\":\"Posts list - Langur Monkey - Toni SagristÃ  SellÃ©s\",\"word_count\":911,\"summary_text\":\"Posts list - Langur Monkey - Toni SagristÃ  SellÃ©s Posts list - Langur Monkey - Toni Sagristà Selléslangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchPosts list20267Artisans EF-FX adapter review 10 MarGGUF quantization guide 04 MarLM Studio on systemd linger 27 FebYet another architectural update for Play Kid 28 JanGame Boy emulator tech stack update 26 Jan Implementing a Game Boy emulator 20 Jan 2025Google unkills JPEG XL? 28 Nov Motion trails in Gaia Sky 14 Jun Quadruple joins the fight! 10 MayBenchmarking arbitrary precision libraries in Java 07 May Oh Garmin, not you! 29 MarBuilding a local AI assistant with user context 26 Mar Local LLM with Retrieval-Augmented Generation 24 Mar Gaia Sky gets new website 19 Feb2024Rendering volume aurorae and nebulae 18 Dec Juju\",\"classification_terms\":[\"posts-list\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":2},{\"path\":\"/blog/2025/quadruple-joins-party/\",\"status\":200,\"title\":\"Quadruple joins the fight!\",\"word_count\":858,\"summary_text\":\"Quadruple joins the fight! Quadruple joins the fight!langur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchContentsEnter QuadrupleResultsAdditionSubtractionMultiplicationDivisionAllocation (from string)Allocation (from double)AnalysisCaveatsQuadruple joins the fight!This float-128 implementation beats others at same precisionMay 10, 20254 minute readA few days ago I wrote about benchmarking arbitrary precision floating-point libraries in Java. I found out that BigDecimal is not as slow as it is said to be, beating Apfloat at the same precision level by a long margin in most operations. However, for Gaia Sky, I don&rsquo;t need hundreds of significant digits at all. It turns out 27 significant digits are enough to represent the whole universe with\",\"classification_terms\":[\"blog/2025/quadruple-joins-party\",\"about\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":2},{\"path\":\"/blog/2025/apfloat-bigdecimal/\",\"status\":200,\"title\":\"Benchmarking arbitrary precision libraries in Java\",\"word_count\":1113,\"summary_text\":\"Benchmarking arbitrary precision libraries in Java Benchmarking arbitrary precision libraries in Javalangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchContentsWhy JMH?The Benchmark ImplementationThe ResultsAdditionSubtractionMultiplicationDivisionLogSinPowAllocationAnalysisQuestions and Next StepsBenchmarking arbitrary precision libraries in JavaApfloat vs BigDecimal, a surprising outcomeMay 7, 2025 May 10, 20256 minute readEdit (2025-05-08): Changed some test parameters and re-run the tests. Also added bar plots.Note: I have since written a new blog which includes Quadruple to the benchmarks, beating both Apfloat and BigDecimal consistently.I recently set out to compare the performance of Apfloat and BigDecimal for arbitrary precision arithmetic in Java. I use arbit\",\"classification_terms\":[\"blog/2025/apfloat-bigdecimal\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":4,\"depth\":2},{\"path\":\"/blog/2025/garmin-not-you/\",\"status\":200,\"title\":\"Oh Garmin, not you!\",\"word_count\":531,\"summary_text\":\"Oh Garmin, not you! Oh Garmin, not you!langur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchOh Garmin, not you!Garmin announces new subscription plan for ConnectMar 29, 20253 minute readI&rsquo;ve been a Garmin user for many years, shelling out non-trivial amounts of monies for their sports watches. My first Garmin watch was a Forerunner 10 (black/red). Battery life was abysmal, but back then this was the norm. Today, I&rsquo;m sporting a Forerunner 255, which I love. It&rsquo;s not top-of-the-line, but it is more than enough for my modest purposes. These devices have been my trusty companions on countless runs, football matches, and hikes, providing invaluable data without any hidden costs. But now, Garmin has decided to introduce Garmin\",\"classification_terms\":[\"blog/2025/garmin-not-you\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":2},{\"path\":\"/blog/2025/gaiasky-ai-assistant/\",\"status\":200,\"title\":\"Building a local AI assistant with user context\",\"word_count\":5150,\"summary_text\":\"Building a local AI assistant with user context Building a local AI assistant with user contextlangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchContentsScraping the websitesStoring embeddings with ChromaDBQuerying with OllamaSystem promptOther parametersImplementation detailsEvaluationMistral Small 3 instruct, 22B Q4-K-MLlama 3.1 instruct, 8B Q5-K-MPerformanceConclusionBuilding a local AI assistant with user contextWe use Ollama and Chroma DB to build a personalized assistant from scraped web contentMar 26, 2025 Jun 18, 202525 minute readIn my last post, I explored the concept of Retrieval-Augmented Generation (RAG) to enable a locally running generative AI model to access and incorporate new information. To achieve this, I used hardcoded documents as context, wh\",\"classification_terms\":[\"blog/2025/gaiasky-ai-assistant\",\"api\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":6,\"depth\":2},{\"path\":\"/blog/2025/local-llm-rag/\",\"status\":200,\"title\":\"Local LLM with Retrieval-Augmented Generation\",\"word_count\":2240,\"summary_text\":\"Local LLM with Retrieval-Augmented Generation Local LLM with Retrieval-Augmented Generationlangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchContentsIngredients and set-upOllama model setupVector storageProvide context for retrievalFinally, the chatbot logicConclusionLocal LLM with Retrieval-Augmented GenerationLet&rsquo;s build a simple RAG application using a local LLM through Ollama.Mar 24, 2025 Feb 27, 202611 minute readEdit (2025-03-26): Added some words about next steps in conclusion.Edit (2025-03-25): I re-ran the example with a clean database and the results are better. I also cleaned up the code a bit.Over the past few months I have been running local LLMs on my computer with various results, ranging from &lsquo;unusable&rsquo; to &lsquo;pretty good&rsq\",\"classification_terms\":[\"blog/2025/local-llm-rag\",\"about\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":2,\"depth\":2},{\"path\":\"/blog/2025/phd-successfully-defended/\",\"status\":200,\"title\":\"Gaia Sky gets new website\",\"word_count\":289,\"summary_text\":\"Gaia Sky gets new website Gaia Sky gets new websitelangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchGaia Sky gets new websiteA brand new website and a brand new domainFeb 19, 20252 minute readOver the past few weeks I&rsquo;ve been working on a new standalone website for Gaia Sky. It uses the same technology stack as my personal website (essentially Hugo), so it is a static website generated from templates and content. This is enough for Gaia Sky. I am no graphic designer or UX person, but I tried my best to make it look potable.The new Gaia Sky website, gaiasky.spaceWhy did I create a standalone website instead of keeping the old section in the ZAH site? A few reasons:It is much easier to update and maintain.We now have a news section to ma\",\"classification_terms\":[\"blog/2025/phd-successfully-defended\",\"news\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":0,\"depth\":2},{\"path\":\"/blog/2024/rendering-aurorae-nebulae/\",\"status\":200,\"title\":\"Rendering volume aurorae and nebulae\",\"word_count\":2908,\"summary_text\":\"Rendering volume aurorae and nebulae Rendering volume aurorae and nebulaelangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchContentsLi&rsquo;l nebulae detourAnatomy of a nebula shaderApproaching aurora rendering1. Mesh w/ custom shader2. Isolated noise aurora3. True volume auroraFuture workConclusionRendering volume aurorae and nebulaeSome notes on my trials and tribulations adding aurorae to Gaia SkyDec 18, 2024 Dec 20, 202414 minute readA few weeks ago someone created an issue in the Gaia Sky Codeberg repository requesting the addition of aurorae to the Earth. They used as an example the aurora add-on in Cosmographia1, which, at the time, looked to me like it was using some kind of billboard particle system to generate the effect. I never thought it lo\",\"classification_terms\":[\"blog/2024/rendering-aurorae-nebulae\",\"blog\"],\"external_refs\":[],\"password_input_count\":0,\"email_input_count\":0,\"tel_input_count\":0,\"otp_term_count\":0,\"login_form_count\":0,\"checkout_form_count\":0,\"wallet_prompt_count\":0,\"offdomain_form_actions\":0,\"suspicious_script_refs_count\":0,\"external_script_hosts\":[],\"executable_download_count\":0,\"archive_download_count\":0,\"apk_download_count\":0,\"phone_number_count\":2,\"depth\":2},{\"path\":\"/blog/2024/jujutsu/\",\"status\":200,\"title\":\"Jujutsu, a modern version control system\",\"word_count\":6155,\"summary_text\":\"Jujutsu, a modern version control system Jujutsu, a modern version control systemlangur@monkey:~/$~/blog~/projects~/publications~/cv~/photo~/searchThemeMenu~/blog~/projects~/publications~/cv~/photo~/searchContentsWhere to LearnJujutsu OverviewQuick Start GuideInitialize a RepositoryOur First ChangeEditing ChangesBranches and BookmarksConflictsRevsetsBookmarksRemotesOperation LogConcl",
        "score_reasons_json": "[]",
        "route_domain": "tonisagrista.com",
        "display_domain": "tonisagrista.com"
    },
    "explainability": {
        "summary": "tonisagrista.com currently scores 42/100. The score is being shaped by a mixed signal profile rather than one dominant factor. Evidence confidence is strong enough for a relatively stable read. This is an estimated profile rather than a manually tracked one. Crawler access looks clean.",
        "badges": [
            {
                "label": "Profile",
                "value": "Estimated profile",
                "tone": "unknown",
                "detail": null
            },
            {
                "label": "Evidence confidence",
                "value": "High confidence",
                "tone": "good",
                "detail": "100/100"
            },
            {
                "label": "Traffic confidence",
                "value": "Moderate confidence",
                "tone": "caution",
                "detail": "51/100"
            },
            {
                "label": "Crawler access",
                "value": "Clean visibility",
                "tone": "good",
                "detail": null
            }
        ],
        "weighted_contributions": [
            {
                "label": "Quality system",
                "points": "+32.0",
                "tone": "good",
                "detail": "Technical quality, crawl depth, page structure, and implementation hygiene. Current subsystem score: 94/100."
            },
            {
                "label": "Reputation system",
                "points": "+15.0",
                "tone": "caution",
                "detail": "Authority, search visibility, reach, engagement, and registry stability. Current subsystem score: 44/100."
            },
            {
                "label": "Safety system",
                "points": "+32.0",
                "tone": "good",
                "detail": "Fraud, spam, and trust signals from infrastructure, crawl, and registry evidence. Current subsystem score: 100/100."
            },
            {
                "label": "Risk clamp",
                "points": "-37.0",
                "tone": "risk",
                "detail": "Safety thresholds capped the final score until the risk profile improves."
            }
        ],
        "evidence_cards": [
            {
                "label": "Authority and trust",
                "value": "40/100 · trust 42/100",
                "tone": "risk",
                "detail": "82 monthly visitors, 68 organic keywords, brand completeness 60/100, engagement 78/100."
            },
            {
                "label": "Backlink and search evidence",
                "value": "2 referring domains",
                "tone": "good",
                "detail": "2 backlinks across 2 referring domains. Diversity 93/100; spam penalty 6."
            },
            {
                "label": "Registry and domain stability",
                "value": "15.1 years old",
                "tone": "good",
                "detail": "Stability 100/100 · age 15.1 years · registrar PDR Ltd. d/b/a PublicDomainRegistry.com · expires in 678 days."
            },
            {
                "label": "Safety and fraud posture",
                "value": "Safety 100/100 · fraud 2/100",
                "tone": "good",
                "detail": "Primary tag T · safety 100/100 · fraud 2/100."
            }
        ],
        "positives": [
            "Established domain age: 15.1 years.",
            "Low registrar / ownership churn with solid registry stability.",
            "Healthy crawl quality and on-page completeness.",
            "Search evidence is broad enough to classify with better confidence.",
            "Registry history looks stable, which supports legitimacy and trust.",
            "The domain has been registered for years, which usually improves trust confidence."
        ],
        "risks": [
            "External evidence was mixed or sparse, so the tag model keeps an uncertainty buffer instead of overcommitting."
        ],
        "freshness": [
            {
                "label": "Crawl evidence",
                "value": "2026-03-18 21:01:45",
                "tone": "risk",
                "detail": "Crawl and page content sample. Age: 1mo ago."
            },
            {
                "label": "WHOIS snapshot",
                "value": "2026-03-18 21:01:39",
                "tone": "risk",
                "detail": "Registry profile and stability signals. Age: 1mo ago."
            },
            {
                "label": "Keyword view",
                "value": "2026-05-03 08:15:02",
                "tone": "good",
                "detail": "Estimated visibility until tracked keyword snapshots exist. Age: 0s ago."
            },
            {
                "label": "Rank history",
                "value": "2026-05-03 08:15:02",
                "tone": "good",
                "detail": "Estimated trend derived from current profile and crawl signals. Age: 0s ago."
            },
            {
                "label": "Audience geography",
                "value": "Not captured yet",
                "tone": "unknown",
                "detail": "Audience mix is estimated from available signals rather than first-party audience logs."
            }
        ],
        "section_notes": {
            "audience": "Audience geography is estimated from category, country, traffic mix, and brand signals until first-party audience data is collected.",
            "keywords": "Top keywords are estimated from crawl language, brand, category, and visibility signals until tracked keyword snapshots are stored.",
            "history": "Rank history is estimated from the current profile because no stored history exists for this domain yet."
        },
        "base_weighted_score": 79,
        "fraud_clamp_penalty": 37,
        "final_score": 42
    },
    "insight_snapshot": {
        "version": 1,
        "generated_at": "2026-05-03T08:15:02+00:00",
        "domain": "tonisagrista.com",
        "display_name": "Langur Monkey",
        "is_tracked": false,
        "is_estimated": true,
        "overall_score": 42,
        "authority_score": 40,
        "trust_score": 42,
        "safety_score": 100,
        "fraud_score": 2,
        "confidence_score": 100,
        "traffic_confidence": 51,
        "last_crawled_at": "2026-03-18 21:01:45",
        "crawl_blocked": false,
        "summary": "tonisagrista.com currently scores 42/100. The score is being shaped by a mixed signal profile rather than one dominant factor. Evidence confidence is strong enough for a relatively stable read. This is an estimated profile rather than a manually tracked one. Crawler access looks clean.",
        "badges": [
            {
                "label": "Profile",
                "value": "Estimated profile",
                "tone": "unknown",
                "detail": null
            },
            {
                "label": "Evidence confidence",
                "value": "High confidence",
                "tone": "good",
                "detail": "100/100"
            },
            {
                "label": "Traffic confidence",
                "value": "Moderate confidence",
                "tone": "caution",
                "detail": "51/100"
            },
            {
                "label": "Crawler access",
                "value": "Clean visibility",
                "tone": "good",
                "detail": null
            }
        ],
        "top_positive_signals": [
            "Established domain age: 15.1 years.",
            "Low registrar / ownership churn with solid registry stability.",
            "Healthy crawl quality and on-page completeness.",
            "Search evidence is broad enough to classify with better confidence.",
            "Registry history looks stable, which supports legitimacy and trust."
        ],
        "top_risk_signals": [
            "External evidence was mixed or sparse, so the tag model keeps an uncertainty buffer instead of overcommitting."
        ],
        "freshness": [
            {
                "label": "Crawl evidence",
                "value": "2026-03-18 21:01:45",
                "tone": "risk",
                "detail": "Crawl and page content sample. Age: 1mo ago."
            },
            {
                "label": "WHOIS snapshot",
                "value": "2026-03-18 21:01:39",
                "tone": "risk",
                "detail": "Registry profile and stability signals. Age: 1mo ago."
            },
            {
                "label": "Keyword view",
                "value": "2026-05-03 08:15:02",
                "tone": "good",
                "detail": "Estimated visibility until tracked keyword snapshots exist. Age: 0s ago."
            },
            {
                "label": "Rank history",
                "value": "2026-05-03 08:15:02",
                "tone": "good",
                "detail": "Estimated trend derived from current profile and crawl signals. Age: 0s ago."
            },
            {
                "label": "Audience geography",
                "value": "Not captured yet",
                "tone": "unknown",
                "detail": "Audience mix is estimated from available signals rather than first-party audience logs."
            }
        ],
        "top_tags": [
            {
                "code": "T",
                "label": "Trusted",
                "tone": "good"
            },
            {
                "code": "Uncertain",
                "label": "Uncertain",
                "tone": "unknown"
            },
            {
                "code": "C",
                "label": "Caution",
                "tone": "caution"
            }
        ]
    },
    "is_tracked": false,
    "is_estimated": true,
    "live_state": {
        "status": "processing",
        "status_label": "Cache build running",
        "message": "The refreshed page cache is still being built for this domain.",
        "updated_at": "2026-05-03T09:16:03+00:00"
    },
    "refresh_state": {
        "canRequest": false,
        "queued": true,
        "processing": true,
        "stageKey": "cache-queued",
        "stageLabel": "Cache build running",
        "cooldownUntil": null,
        "message": "The refreshed page cache is still being built for this domain.",
        "action": "/domain/tonisagrista.com/refresh",
        "isGuestCooldown": false,
        "cooldownSeconds": 0
    },
    "urlscan_report": {
        "domain": "tonisagrista.com",
        "status": "idle",
        "submitted_at": null,
        "completed_at": null,
        "last_checked_at": null,
        "last_error": "",
        "submitted_url": "https://tonisagrista.com/",
        "uuid": "",
        "result_url": "",
        "api_result_url": "",
        "visibility": "public",
        "summary": "No urlscan.io report has been requested for this domain yet.",
        "report": [],
        "report_summary": [],
        "is_fresh": false,
        "can_retry": true,
        "poll_after_seconds": 20
    }
}