WIP: iunno where i'm at tbh
|
@ -1,15 +0,0 @@
|
||||||
main._default-list {
|
|
||||||
display: flex;
|
|
||||||
flex-flow: column;
|
|
||||||
.pages {
|
|
||||||
flex-grow: 1;
|
|
||||||
display: flex;
|
|
||||||
padding-inline: var(--pad-x, 1rem);
|
|
||||||
.container {
|
|
||||||
flex-grow: 1;
|
|
||||||
.paginator {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
main._default-single {
|
|
||||||
.container {
|
|
||||||
display: grid;
|
|
||||||
gap: 1em;
|
|
||||||
@media (min-width: 40rem) {
|
|
||||||
grid-template-columns: 1fr minmax(auto, 80ch) 1fr;
|
|
||||||
> * {
|
|
||||||
grid-column: 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.page {
|
|
||||||
@media (min-width: 40rem) {
|
|
||||||
font-size: 1.25em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.page-header {
|
|
||||||
hr {display: none;}
|
|
||||||
padding-block: 2em;
|
|
||||||
}
|
|
||||||
.page-title {
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 1.953em;
|
|
||||||
line-height: 1;
|
|
||||||
}
|
|
||||||
.page-summary {
|
|
||||||
max-inline-size: 65ch;
|
|
||||||
font-size: 1.25em;
|
|
||||||
line-height: 1.4;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
.page-date {
|
|
||||||
font-size: 1em;
|
|
||||||
line-height: 1;
|
|
||||||
}
|
|
||||||
.page-author {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.page-content {
|
|
||||||
padding-block: 2em;
|
|
||||||
blockquote {
|
|
||||||
padding-block: 1rem;
|
|
||||||
padding-inline-start: 1rem;
|
|
||||||
border-inline-start: 4px solid black;
|
|
||||||
background: #eee;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
h1 {font-size: 1.953em}
|
|
||||||
h2 {font-size: 1.563em}
|
|
||||||
h3 {font-size: 1.25em}
|
|
||||||
h4 {font-size: 1em}
|
|
||||||
h1, h2, h3, h4 {margin-block-start: 1em}
|
|
||||||
ul, ol {
|
|
||||||
margin-inline-start: 1em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
https://mastodon.social/@trwnh/110329802576726213
|
|
||||||
|
|
||||||
services aren't communities
|
|
||||||
|
|
||||||
the gmail community
|
|
||||||
|
|
||||||
imo the biggest mistake of fedi is tying together the social and technical layers. local timelines should have been group chats all along
|
|
||||||
|
|
||||||
it's a huge misunderstanding because some people want services and some people want communities and they are not the same thing. some people can run a community but offer bad service. some people offer great service but can't run a community
|
|
||||||
|
|
||||||
instances shouldn't exist as the only model. the service layer and the community layer should be separate. combining the two makes both of them worse -- as can be seen if you violate the rules of your community, you lose access not just to the community, but to the service entirely. and if the community cannot continue to provide service, you again lose both.
|
|
||||||
|
|
||||||
i do think there is some value in being both, because then people feel more likely to donate as they are personally invested. but you could have incentives to donate even while keeping them separate.
|
|
|
@ -1,7 +0,0 @@
|
||||||
the more i think about and research communication paradigms, i'm starting to think more and more that this whole "social network" thing is just fundamentally flawed. in pure terms you might send a message or publish a resource. but with these social networks it's not that clear cut. you're never unambiguously sending a message or publishing a resource, but instead, some weird hybrid that we call a "post". not quite message, not quite resource. it exists in part or in whole exclusively on-network
|
|
||||||
|
|
||||||
and i guess that makes it easier to put in a silo which is how companies maintain their profit motive.
|
|
||||||
|
|
||||||
but in replicating the design of these social networks we replicate their properties too. fedi hasn't entirely moved past silos because it's embedded in the design level. thankfully not the protocol level, but still. it's going to persist in implementations as long as we limit ourselves to "twitter but better", "instagram but better", etc. we're not building the commons that we could build.
|
|
||||||
|
|
||||||
and the lack of clarity in our metaphors and associated abstractions leads to subtle violations of what people expect. there should be a clearer split. consider the duality of tumblr as both a social network and a publishing platform. they're making this split more apparent than it used to be. in addition to username.tumblr.com for blogs they now have tumblr.com/username for network profiles.
|
|
|
@ -1,3 +1,10 @@
|
||||||
|
+++
|
||||||
|
title = "an analogy between activitypub and programming languages"
|
||||||
|
summary = "you don't say \"compatible with c++\" you say \"written in/with c++\". similarly, we might say that fedi is \"written with activitypub\" or \"implemented using activitypub\""
|
||||||
|
date = "2023-03-28T09:13:00-06:00"
|
||||||
|
source = "https://mastodon.social/@trwnh/110101321320240671"
|
||||||
|
+++
|
||||||
|
|
||||||
people think activitypub is a network protocol when it's really more like a programming language. you don't say "compatible with c++" you say "written in/with c++". similarly, we might say that fedi is "written with activitypub" or "implemented using activitypub", not "compatible with activitypub" or anything suggesting a network.
|
people think activitypub is a network protocol when it's really more like a programming language. you don't say "compatible with c++" you say "written in/with c++". similarly, we might say that fedi is "written with activitypub" or "implemented using activitypub", not "compatible with activitypub" or anything suggesting a network.
|
||||||
|
|
||||||
analogously:
|
analogously:
|
|
@ -1,5 +1,8 @@
|
||||||
+++
|
+++
|
||||||
date = 2023-05-02
|
title = "defining quote posts"
|
||||||
|
summary = "to me, the way i see quote posts is essentially as a \"loud reply\" or as a \"breakout thread\""
|
||||||
|
date = "2023-05-01T12:07:00-06:00"
|
||||||
|
source = "https://mastodon.social/@trwnh/110294523321644375"
|
||||||
+++
|
+++
|
||||||
|
|
||||||
fwiw my take about quotes is that either
|
fwiw my take about quotes is that either
|
||||||
|
@ -14,13 +17,13 @@ in an alternate timeline we could have had generic rendering of activities based
|
||||||
|
|
||||||
such a generic renderer would be something like...
|
such a generic renderer would be something like...
|
||||||
|
|
||||||
> <darius> <Announce> <some-post>
|
> `<alice> <Announce> <some-post>` \
|
||||||
> <Announce.summary>
|
> `<Announce.summary>` \
|
||||||
> <Announce.content>
|
> `<Announce.content>`
|
||||||
|
|
||||||
filling in the last two lines for summary and content
|
filling in the last two lines for summary and content
|
||||||
|
|
||||||
> Darius boosted a post: "The problem with this is..."
|
> alice boosted a post: "The problem with this is..." \
|
||||||
> "I disagree with this analysis."
|
> "I disagree with this analysis."
|
||||||
|
|
||||||
also this just highlights what i think a "quote post" should really be: more like a "loud reply". in a more ideal world it would use `inReplyTo` + a new `context`.
|
also this just highlights what i think a "quote post" should really be: more like a "loud reply". in a more ideal world it would use `inReplyTo` + a new `context`.
|
||||||
|
@ -59,13 +62,13 @@ the other functional difference between those two is whether the "quote" gets ad
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
also tangentially i've thought about what people think a quote is vs what it actually is, the dimensions, its primary function, etc
|
also tangentially i've thought about what people think a quote post is vs what it actually is, the dimensions, its primary function, etc
|
||||||
|
|
||||||
to me, the way i see quotes is essentially as a "loud reply" or as a "breakout thread".
|
to me, the way i see quote posts is essentially as a "loud reply" or as a "breakout thread".
|
||||||
|
|
||||||
the former use-case could be handled by reply+boost. this is actually very easy in the API: just make a button that fires off 2 API calls.
|
the former use-case could be handled by reply+boost. this is actually very easy in the API: just make a button that fires off 2 API calls.
|
||||||
|
|
||||||
the latter could be handled by copypasting a link into a new post. this is much harder to detect and display. optinally mention
|
the latter could be handled by copypasting a link into a new post. this is much harder to detect and display. optionally mention
|
||||||
|
|
||||||
really the problem with twitter "quote tweets" is that they conflated the two use-cases
|
really the problem with twitter "quote tweets" is that they conflated the two use-cases
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
+++
|
+++
|
||||||
date = "2023-01-20"
|
title = "drowning in awareness"
|
||||||
|
summary = "if you don't have a material call to action, you have nothing. [...] \"awareness\" on its own is not enough; it can even be an actively bad thing if you end up paralyzed by inaction and despair [...] like, ok, i'm aware. now what?"
|
||||||
|
date = "2023-01-20T00:16:00-0600"
|
||||||
|
source = "https://mastodon.social/@trwnh/109720070743856424"
|
||||||
+++
|
+++
|
||||||
|
|
||||||
i am reminded of an essay i read once called "avoid news" which might sound extreme to some people but it actually has a simple premise: most of what you encounter in media suffers from context collapse and/or is not actionable. therefore it can never truly be relevant. what is far more valuable is filtering through the news for anything actionable worth educating people about, and presenting it in a more relevant and digestible way. not everyone should have to do this.
|
i am reminded of an essay i read once called "avoid news" which might sound extreme to some people but it actually has a simple premise: most of what you encounter in media suffers from context collapse and/or is not actionable. therefore it can never truly be relevant. what is far more valuable is filtering through the news for anything actionable worth educating people about, and presenting it in a more relevant and digestible way. not everyone should have to do this.
|
|
@ -1,9 +1,10 @@
|
||||||
+++
|
+++
|
||||||
date = 2023-04-30
|
title = "fedi as a reformist option"
|
||||||
|
summary = "[...] it's holding us back from better things. it's like the \"reform\" option when we need radical change. and it keeps getting \"worse\" [...] ad-free and chronological ain't enough."
|
||||||
|
date = "2023-04-30T20:27:00-0600"
|
||||||
|
source = "https://mastodon.social/@trwnh/110290827199480228"
|
||||||
+++
|
+++
|
||||||
|
|
||||||
https://mastodon.social/@trwnh/110290827199480228
|
|
||||||
|
|
||||||
nobody asked but i think fedi as a whole is actually kinda "bad" in the sense that it's holding us back from better things. it's like the "reform" option when we need radical change. and it keeps getting "worse". somewhere along the way we seem to have dropped the "blogging" from "microblogging", and what remains is incredibly muddled. contextual and ergonomic failure. we're copying "social media" and inheriting its flaws. ad-free and chronological ain't enough.
|
nobody asked but i think fedi as a whole is actually kinda "bad" in the sense that it's holding us back from better things. it's like the "reform" option when we need radical change. and it keeps getting "worse". somewhere along the way we seem to have dropped the "blogging" from "microblogging", and what remains is incredibly muddled. contextual and ergonomic failure. we're copying "social media" and inheriting its flaws. ad-free and chronological ain't enough.
|
||||||
|
|
||||||
see, we're all mostly here to just hang out and spill a stream of consciousness, right? but there are problems inherent to the structure. context collapse (or no context at all), misuse of the medium (doing a "thread" instead of writing an article), and so on. everything just goes into the square hole.
|
see, we're all mostly here to just hang out and spill a stream of consciousness, right? but there are problems inherent to the structure. context collapse (or no context at all), misuse of the medium (doing a "thread" instead of writing an article), and so on. everything just goes into the square hole.
|
After Width: | Height: | Size: 1.5 MiB |
|
@ -1,3 +1,14 @@
|
||||||
|
+++
|
||||||
|
title = "collections should be explicitly managed"
|
||||||
|
summary = "the way to maintain an authoritative collection is [...] not to have everyone send out Create and then expect everyone else to reconstruct the collection for themselves [...] we're just replicating stuff around and then every server assembles it however it *thinks* it should be put together."
|
||||||
|
date = "2023-03-18T03:51:00-06:00"
|
||||||
|
source = "https://mastodon.social/@trwnh/110043428576595588"
|
||||||
|
+++
|
||||||
|
|
||||||
|
how it feels to talk about #activitypub and how #fedi implements it
|
||||||
|
|
||||||
|
![](create-note.png)
|
||||||
|
|
||||||
the way to maintain an authoritative collection is to send out Add/Remove, not to have everyone send out Create and then expect everyone else to reconstruct the collection for themselves
|
the way to maintain an authoritative collection is to send out Add/Remove, not to have everyone send out Create and then expect everyone else to reconstruct the collection for themselves
|
||||||
|
|
||||||
i can't say i blame developers for taking the lazy route and doing the bare minimum to be compatible with what already exists, but that is so limiting and i'm not here for it
|
i can't say i blame developers for taking the lazy route and doing the bare minimum to be compatible with what already exists, but that is so limiting and i'm not here for it
|
|
@ -1,5 +1,8 @@
|
||||||
+++
|
+++
|
||||||
date = "2023-02-02"
|
title = "mainstreaming mastodon"
|
||||||
|
summary = "[...] one of the replies was something along the lines of how we should be \"turning Mastodon from a small platform for the fringes and oppressed minorities to a platform that welcomes more mainstream members\" and i legit shuddered while reading that. what a terrifying thought."
|
||||||
|
date = "2023-02-02T08:40:00-06:00"
|
||||||
|
source = "private"
|
||||||
+++
|
+++
|
||||||
|
|
||||||
the shit i see on the mastodon issue tracker is driving me to just build my own thing because i honestly think whatever good culture mastodon has is quite possibly not long for this world
|
the shit i see on the mastodon issue tracker is driving me to just build my own thing because i honestly think whatever good culture mastodon has is quite possibly not long for this world
|
|
@ -0,0 +1,10 @@
|
||||||
|
+++
|
||||||
|
title = "making better stuff is unprofitable"
|
||||||
|
summary = "there will inevitably be a point where it is unprofitable to improve a product any further."
|
||||||
|
date = "2017-12-22T06:06:00-0600"
|
||||||
|
source = "https://mastodon.social/@trwnh/99217860566004390"
|
||||||
|
+++
|
||||||
|
|
||||||
|
There will inevitably be a point where it is unprofitable to improve a product any further.
|
||||||
|
|
||||||
|
i.e., if Apple's primary goal was to make useful products, it would make choices that result in a better product even if it was slightly more expensive. But their primary goal is profit, as it is for every corporation under capitalism. Making better stuff is unprofitable.
|
|
@ -1,10 +1,10 @@
|
||||||
+++
|
+++
|
||||||
date = 2023-02-06
|
title = "the primary value of mastodon is in its api"
|
||||||
published = 2023-02-06T00:56:00Z
|
summary = "mastodon isn't really all that special [...] but the second you try to have a mobile app, you immediately recognize the value of the mastodon api [...] it's a shame it isn't a real standard..."
|
||||||
|
date = "2023-02-06T00:56:00Z"
|
||||||
|
source = "https://mastodon.social/@trwnh/109815069913581608"
|
||||||
+++
|
+++
|
||||||
|
|
||||||
https://mastodon.social/@trwnh/109815069913581608
|
|
||||||
|
|
||||||
to what extent can it be said that the primary value of mastodon is in its api
|
to what extent can it be said that the primary value of mastodon is in its api
|
||||||
|
|
||||||
mastodon isn't really all that special in the fediverse or as a software, because you have so many options and differing implementations of the activitypub protocol. but the second you try to have a mobile app, you immediately recognize the value of the mastodon api. it's a pseudo-standard at this point because it mostly just works, and pleroma/pixelfed/gotosocial copied it for compatibility with existing clients. it's a shame it isn't a real standard...
|
mastodon isn't really all that special in the fediverse or as a software, because you have so many options and differing implementations of the activitypub protocol. but the second you try to have a mobile app, you immediately recognize the value of the mastodon api. it's a pseudo-standard at this point because it mostly just works, and pleroma/pixelfed/gotosocial copied it for compatibility with existing clients. it's a shame it isn't a real standard...
|
|
@ -1,7 +1,7 @@
|
||||||
+++
|
+++
|
||||||
title = "re: starting to investigate other protocols"
|
title = "re: starting to investigate other protocols"
|
||||||
summary = "The main thing I'm trying to formulate right now is a generic understanding of what is a protocol and what makes up a protocol."
|
summary = "The main thing I'm trying to formulate right now is a generic understanding of what is a protocol and what makes up a protocol [...] The \"implicit protocol of the fediverse\" is not sufficiently described by \"the ActivityPub specification\""
|
||||||
date = "2023-01-02T21:00:00-06:00"
|
date = "2024-09-29T19:53:00-06:00"
|
||||||
source = "https://socialhub.activitypub.rocks/t/socialwebfoundation-what-do-people-think/4564/13"
|
source = "https://socialhub.activitypub.rocks/t/socialwebfoundation-what-do-people-think/4564/13"
|
||||||
inReplyTo = "https://socialhub.activitypub.rocks/t/socialwebfoundation-what-do-people-think/4564/12"
|
inReplyTo = "https://socialhub.activitypub.rocks/t/socialwebfoundation-what-do-people-think/4564/12"
|
||||||
+++
|
+++
|
42
blog.hugo/content/blog/one-piece-thematic-breakdown/index.md
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
+++
|
||||||
|
title = "a thematic breakdown of one piece"
|
||||||
|
summary = "east blue = dreams. paradise = family. new world = liberation."
|
||||||
|
date = "2024-09-30T11:22:54-0600"
|
||||||
|
source = "original"
|
||||||
|
+++
|
||||||
|
|
||||||
|
i was idly thinking about one piece this morning, as one does. mainly thinking about how east blue was peak one piece for me, and those first 100 chapters could honestly stand as their own self-contained story. one piece could have ended right there and i would have come away satisfied with what i read. but of course, it didn't end there, and i'm also glad it didn't end there. but it got me thinking about the overall theme of one piece, and specifically the overall theme of east blue as a self-contained saga.
|
||||||
|
|
||||||
|
<aside>
|
||||||
|
|
||||||
|
(this article generally contains spoilers for the entirety of one piece. read on if you dare or have already read one piece or just don't care. but if you don't care then why are you reading this)
|
||||||
|
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
## from "romance dawn" onward to the "grand line"
|
||||||
|
|
||||||
|
honestly, we could go further and say that the first chapter of one piece is also a self-contained story, and in fact, it actually *was* a self-contained story. romance dawn was of course released in various forms as one-shots, before it eventually became the first chapter of one piece.
|
||||||
|
|
||||||
|
the story of that first chapter is very simple: it's about a boy with a dream. but it's everything else about the story that grips you, like the reason for that dream, and the magnitude of that dream, and what that dream involves.
|
||||||
|
|
||||||
|
for the time spent in east blue, the story mainly covers a great adventure filled with romanticism. the character arcs in this part of the story are mainly centered around following your dreams. as you meet new characters, you learn about their dreams, and in learning about their dreams, you get to know them as people. everyone has a reason to keep going. everyone has drive and motivation. it's honestly a dynamic world that feels alive, even though it's pretty small at this point in the series.
|
||||||
|
|
||||||
|
throughout it all, there is the end goal of entering the grand line, which is portrayed as a paradise for pirates, where wacky things happen all the time, and the adventure never ends. everyone has their reasons for seeking it out. luffy wants to become the pirate king, and to do that he needs to find the great treasure "one piece" at the end of the grand line. zoro wants to become the world's greatest swordsman, and to do that he needs to challenge the current world's greatest swordsman who lives in the grand line. nami wants to draw a map of the world, and that means she'll need to enter the grand line at some point. usopp wants to be a brave warrior of the sea, and the grand line is just the thing to toughen him up. sanji wants to find the all blue, which might exist somewhere in the grand line.
|
||||||
|
|
||||||
|
## i still have my nakama
|
||||||
|
|
||||||
|
once things go into the grand line, the theme of adventure is still there, but the focus of each arc is better summarized by the theme of "family". chopper is abandoned by his reindeer family, but finds new family in dr. hiruluk and later dr. kureha before eventually joining the crew. vivi knows that the straw hats will always be her family because of the whole x thing. robin finds family in the ohara researchers and in saul, only for the buster call to take it all. franky has tom and iceberg and later the franky family. brook's entire crew dies and his dream is to reunite with laboon. luffy's entire crew gets sent flying by kuma and he despairs over this because he lost his family. then he finds out his sworn brother is set to be executed, and he goes to save him. when he loses his brother he feels like he has no family left. until he is reminded that he still has his crew.
|
||||||
|
|
||||||
|
## power, authority, and liberation
|
||||||
|
|
||||||
|
by the time we enter the new world, it's endgame territory. this is the realm of the emperors. luffy has always been a liberator, but this part of the story is where it takes center stage. every arc has luffy liberating people and islands. and then you find out he's literally the warrior of liberation.
|
||||||
|
|
||||||
|
it's all about the power struggle, the emperors who rule their territories, the world government who controls everything, and the warrior of liberation who is being set up to set the whole world free.
|
||||||
|
|
||||||
|
## wealth. fame. power. he had it all
|
||||||
|
|
||||||
|
in that order.
|
||||||
|
|
||||||
|
## so what's the conclusion here
|
||||||
|
|
||||||
|
idk i don't have a conclusion i'm just rambling
|
|
@ -1,3 +1,10 @@
|
||||||
|
+++
|
||||||
|
title = "publishing vs discussing"
|
||||||
|
summary = "eventually this kind of \"posting\" we have today would be split up and merged into the two new things. the UI would give you an option: do you want to publish a Post, or do you want to start a Discussion?"
|
||||||
|
date = "2023-03-24T10:33:00-0600"
|
||||||
|
source = "https://mastodon.social/@trwnh/110078983668243890"
|
||||||
|
+++
|
||||||
|
|
||||||
i am more and more taking the position that we should have forums, and we should have blogs, and nothing in between. "social media" carries inherently poor ergonomics and a lack of clarity of purpose. you're never clearly "publishing" anything when you post on social media, unlike when you post on your own blog or website. you're never clearly "discussing" anything either, because threads aren't actual topics or conversations.
|
i am more and more taking the position that we should have forums, and we should have blogs, and nothing in between. "social media" carries inherently poor ergonomics and a lack of clarity of purpose. you're never clearly "publishing" anything when you post on social media, unlike when you post on your own blog or website. you're never clearly "discussing" anything either, because threads aren't actual topics or conversations.
|
||||||
|
|
||||||
so my ideal flow is kinda like
|
so my ideal flow is kinda like
|
24
blog.hugo/content/blog/services-vs-communities/index.md
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
+++
|
||||||
|
title = "services aren't communities"
|
||||||
|
summary = "imo the biggest mistake of fedi is tying together the social and technical layers [...] some people want services and some people want communities and they are not the same thing"
|
||||||
|
date = "2023-05-07T17:39:00-06:00"
|
||||||
|
source = "https://mastodon.social/@trwnh/110329802576726213"
|
||||||
|
+++
|
||||||
|
|
||||||
|
services aren't communities
|
||||||
|
|
||||||
|
the gmail community
|
||||||
|
|
||||||
|
imo the biggest mistake of fedi is tying together the social and technical layers. local timelines should have been group chats all along
|
||||||
|
|
||||||
|
it's a huge misunderstanding because some people want services and some people want communities and they are not the same thing. some people can run a community but offer bad service. some people offer great service but can't run a community
|
||||||
|
|
||||||
|
instances shouldn't exist as the only model. the service layer and the community layer should be separate. combining the two makes both of them worse -- as can be seen if you violate the rules of your community, you lose access not just to the community, but to the service entirely. and if the community cannot continue to provide service, you again lose both.
|
||||||
|
|
||||||
|
i do think there is some value in being both, because then people feel more likely to donate as they are personally invested. but you could have incentives to donate even while keeping them separate.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> Yes! I think I've been spiralling towards a less well articulated version of this for a while. Too many people have been trying to make the Fediverse just one big social network with many servers and erase the aspect that's many small social networks that can communicate, and it's exactly that they're viewing it purely as service and not as community, and it absolutely needs to be both or else it can't meaningfully be either.
|
||||||
|
|
||||||
|
i have a slightly different view, which is that multiple communities exist here and their organization and distribution is very dysfunctional because of the "instance" model being both and neither at the same time
|
|
@ -1 +1,8 @@
|
||||||
|
+++
|
||||||
|
title = "shorts are too long"
|
||||||
|
summary = "if you're going to take away the video controls, prevent me from seeking, maybe autoloop? then i am NOT sitting there for a whole minute while you fail to get to the point."
|
||||||
|
date = "2023-01-25T08:40:00-06:00"
|
||||||
|
source = "https://mastodon.social/@trwnh/109750363384335885"
|
||||||
|
+++
|
||||||
|
|
||||||
i fucking hate the "shorts" format. vine was okay purely because it was limited to 6 or 7 seconds -- if you're going to take away the video controls, prevent me from seeking, maybe autoloop? then i am NOT sitting there for a whole minute while you fail to get to the point. i'm not doing more than 10 seconds, maybe 15 seconds at the most. anything over that should let me seek through the video!!!! videos should always be seekable but if you're not going to make them seekable then at least limit them to one coherent logical "moment"
|
i fucking hate the "shorts" format. vine was okay purely because it was limited to 6 or 7 seconds -- if you're going to take away the video controls, prevent me from seeking, maybe autoloop? then i am NOT sitting there for a whole minute while you fail to get to the point. i'm not doing more than 10 seconds, maybe 15 seconds at the most. anything over that should let me seek through the video!!!! videos should always be seekable but if you're not going to make them seekable then at least limit them to one coherent logical "moment"
|
14
blog.hugo/content/blog/social-media-flawed/index.md
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
+++
|
||||||
|
title = "social media is fundamentally flawed"
|
||||||
|
summary = "in pure terms you might send a message or publish a resource. but with these social networks [...] you're never unambiguously sending a message or publishing a resource, but instead, some weird hybrid that we call a \"post\". not quite message, not quite resource"
|
||||||
|
date = "2023-02-16T19:43:00-06:00"
|
||||||
|
source = "https://mastodon.social/@trwnh/109877540362444317"
|
||||||
|
+++
|
||||||
|
|
||||||
|
the more i think about and research communication paradigms, i'm starting to think more and more that this whole "social media" thing is just fundamentally flawed. in pure terms you might send a message or publish a resource. but with these social media platforms it's not that clear cut. you're never unambiguously sending a message or publishing a resource, but instead, some weird hybrid that we call a "post". not quite message, not quite resource. it exists in part or in whole exclusively on the platform.
|
||||||
|
|
||||||
|
and i guess that makes it easier to put in a silo which is how companies maintain their profit motive.
|
||||||
|
|
||||||
|
but in replicating the design of these social media sites we replicate their properties too. fedi hasn't entirely moved past silos because it's embedded in the design level. thankfully not the protocol level, but still. it's going to persist in implementations as long as we limit ourselves to "twitter but better", "instagram but better", etc. we're not building the commons that we could build.
|
||||||
|
|
||||||
|
and the lack of clarity in our metaphors and associated abstractions leads to subtle violations of what people expect. there should be a clearer split. consider the duality of tumblr as both a social network and a publishing platform. they're making this split more apparent than it used to be. in addition to username.tumblr.com for blogs they now have tumblr.com/username for network profiles.
|
|
@ -1,8 +1,13 @@
|
||||||
https://mastodon.social/@trwnh/109979200684979970
|
+++
|
||||||
|
title = "specs aren't enough"
|
||||||
|
summary = "the question of \"interoperability\" makes no sense on its own. you must always ask, interoperability with what? and on which conditions? [...] is your view of the \"fediverse\" limited only to the conceptual space of existing projects? and, if so, then which ones?"
|
||||||
|
date = "2023-03-06T18:37:00-06:00"
|
||||||
|
source = "https://mastodon.social/@trwnh/109979200684979970"
|
||||||
|
+++
|
||||||
|
|
||||||
@ people who keep saying we should rewrite the activitypub spec to ensure better interoperability with existing fedi projects
|
@ people who keep saying we should rewrite the activitypub spec to ensure better interoperability with existing fedi projects
|
||||||
|
|
||||||
[](specs-are-enough.jpg)
|
![](specs-are-enough.png)
|
||||||
|
|
||||||
idk how else to say that if you want to be compatible with a project then you need to have a shared worldview and conceptual space, and this necessarily involves communicating with that project on some level (by reading their documentation, asking their devs questions, etc) in order to know what their expectations and requirements are
|
idk how else to say that if you want to be compatible with a project then you need to have a shared worldview and conceptual space, and this necessarily involves communicating with that project on some level (by reading their documentation, asking their devs questions, etc) in order to know what their expectations and requirements are
|
||||||
|
|
||||||
|
@ -32,4 +37,4 @@ is your view of the "fediverse" limited only to the conceptual space of existing
|
||||||
|
|
||||||
or will you allow yourself to dream a little bigger?
|
or will you allow yourself to dream a little bigger?
|
||||||
|
|
||||||
https://www.youtube.com/watch?v=WcGbnX8Ay38
|
{{<youtube WcGbnX8Ay38>}}
|
BIN
blog.hugo/content/blog/specs-arent-enough/specs-are-enough.png
Normal file
After Width: | Height: | Size: 270 KiB |
|
@ -1,4 +1,9 @@
|
||||||
https://mastodon.social/@trwnh/109886416964217719
|
+++
|
||||||
|
title = "http uri maximalism"
|
||||||
|
summary = "if you just wanna obtain a resource from a given organization or whatever, it is generally a given that the org has its own domain name and can assign ids on that domain. but the whole thing falls apart when you need a global namespace that can be requested from multiple domains"
|
||||||
|
date = "2023-02-18T09:20:00-06:00"
|
||||||
|
source = "https://mastodon.social/@trwnh/109886416964217719"
|
||||||
|
+++
|
||||||
|
|
||||||
reading a lot of old w3 literature and while there's a lot of good stuff in there, it is *infuriating* how they are so blindly in support of using http for everything, including identifiers. they probably just failed to predict the future, but they keep stopping just short of admitting http's biggest problem: when the server goes down, your uri can't be dereferenced anymore!
|
reading a lot of old w3 literature and while there's a lot of good stuff in there, it is *infuriating* how they are so blindly in support of using http for everything, including identifiers. they probably just failed to predict the future, but they keep stopping just short of admitting http's biggest problem: when the server goes down, your uri can't be dereferenced anymore!
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
baseURL = 'https://trwnh.com/blog/'
|
baseURL = 'https://trwnh.com/blog/'
|
||||||
languageCode = 'en-us'
|
languageCode = 'en-us'
|
||||||
title = '~a blog'
|
title = '~a blog'
|
||||||
markup.goldmark.renderer.unsafe = true
|
|
||||||
|
|
||||||
|
markup.goldmark.renderer.unsafe = true
|
||||||
pagination.pagerSize = 100
|
pagination.pagerSize = 100
|
||||||
|
|
||||||
[outputs]
|
[outputs]
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
<h1>fedi vs web</h1>
|
<h1>fedi vs web</h1>
|
||||||
<p>on the distinction between social network and social web, where activitypub straddles both</p>
|
<p>on the distinction between social network and social web, where activitypub straddles both</p>
|
||||||
<p>published around <time datetime="2024-09-25">2024-09-25</time></p>
|
<p>published around <time datetime="2024-09-25">2024-09-25</time></p>
|
||||||
|
<aside><p>this is part 1 of a series of threads that will eventually be turned into a blogpost or essay or somesuch. read on with the understanding that this is unpolished and may disappear at any time. <a href="what-is-web">part 2 is here</a></p></aside>
|
||||||
</header>
|
</header>
|
||||||
<section>
|
<section>
|
||||||
<h2>the disconnect between activitypub and the fediverse</h2>
|
<h2>the disconnect between activitypub and the fediverse</h2>
|
||||||
|
|
5
unified.test.hugo/archetypes/default.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
title = '{{ replace .File.ContentBaseName "-" " " | title }}'
|
||||||
|
date = {{ .Date }}
|
||||||
|
draft = true
|
||||||
|
+++
|
15
unified.test.hugo/assets/scripts/main.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
/*
|
||||||
|
Use a window's inner dimensions for viewport units.
|
||||||
|
This fixes some mobile bugs
|
||||||
|
*/
|
||||||
|
|
||||||
|
var root = document.documentElement;
|
||||||
|
let vh = window.innerHeight * 0.01;
|
||||||
|
root.style.setProperty('--vh', `${vh}px`);
|
||||||
|
|
||||||
|
// We listen to the resize event
|
||||||
|
window.addEventListener('resize', () => {
|
||||||
|
// We execute the same script as before
|
||||||
|
let vh = window.innerHeight * 0.01;
|
||||||
|
root.style.setProperty('--vh', `${vh}px`);
|
||||||
|
});
|
227
unified.test.hugo/assets/scripts/search.js
Normal file
|
@ -0,0 +1,227 @@
|
||||||
|
/*
|
||||||
|
tutorials used:
|
||||||
|
- https://aaronluna.dev/blog/add-search-to-static-site-lunrjs-hugo-vanillajs/#codepen-with-final-code
|
||||||
|
- https://victoria.dev/blog/add-search-to-hugo-static-sites-with-lunr/
|
||||||
|
*/
|
||||||
|
|
||||||
|
let pagesIndex, searchIndex
|
||||||
|
const MAX_SUMMARY_LENGTH = 30
|
||||||
|
const SENTENCE_BOUNDARY_REGEX = /\b\.\s/gm
|
||||||
|
const WORD_REGEX = /\b(\w*)[\W|\s|\b]?/gm
|
||||||
|
|
||||||
|
async function initSearch() {
|
||||||
|
try {
|
||||||
|
const indexJsonUrl = document.getElementById("baseUrl").dataset["baseUrl"] + "/index.json";
|
||||||
|
// const indexJsonUrl = "/wiki/index.json";
|
||||||
|
const response = await fetch(indexJsonUrl);
|
||||||
|
pagesIndex = await response.json();
|
||||||
|
searchIndex = lunr(function () {
|
||||||
|
this.field("title");
|
||||||
|
this.field("content");
|
||||||
|
this.ref("href");
|
||||||
|
pagesIndex.forEach((page) => this.add(page));
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
console.log("Search index initialized")
|
||||||
|
// Get the query parameter(s)
|
||||||
|
const params = new URLSearchParams(window.location.search)
|
||||||
|
const query = params.get('query')
|
||||||
|
|
||||||
|
// Perform a search if there is a query
|
||||||
|
if (query) {
|
||||||
|
// Retain the search input in the form when displaying results
|
||||||
|
document.getElementById('search-input').setAttribute('value', query)
|
||||||
|
|
||||||
|
// Update the list with results
|
||||||
|
console.log("search performed")
|
||||||
|
let results = searchSite(query)
|
||||||
|
renderSearchResults(query, results)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initSearch();
|
||||||
|
|
||||||
|
function searchSite(query) {
|
||||||
|
const originalQuery = query;
|
||||||
|
query = getLunrSearchQuery(query);
|
||||||
|
let results = getSearchResults(query);
|
||||||
|
return results.length
|
||||||
|
? results
|
||||||
|
: query !== originalQuery
|
||||||
|
? getSearchResults(originalQuery)
|
||||||
|
: [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLunrSearchQuery(query) {
|
||||||
|
const searchTerms = query.split(" ");
|
||||||
|
if (searchTerms.length === 1) {
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
query = "";
|
||||||
|
for (const term of searchTerms) {
|
||||||
|
query += `+${term} `;
|
||||||
|
}
|
||||||
|
return query.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSearchResults(query) {
|
||||||
|
return searchIndex.search(query).flatMap((hit) => {
|
||||||
|
if (hit.ref == "undefined") return [];
|
||||||
|
let pageMatch = pagesIndex.filter((page) => page.href === hit.ref)[0];
|
||||||
|
pageMatch.score = hit.score;
|
||||||
|
return [pageMatch];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderSearchResults(query, results) {
|
||||||
|
clearSearchResults();
|
||||||
|
updateSearchResults(query, results);
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearSearchResults() {
|
||||||
|
const results = document.querySelector("#search-results");
|
||||||
|
while (results.firstChild) results.removeChild(results.firstChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSearchResults(query, results) {
|
||||||
|
document.getElementById("results-query").innerHTML = query;
|
||||||
|
document.querySelector("#search-results").innerHTML = results
|
||||||
|
.map(
|
||||||
|
(hit) => `
|
||||||
|
<li class="search-result-item" data-score="${hit.score.toFixed(2)}">
|
||||||
|
<a href="${hit.href}" class="search-result-page-title">${createTitleBlurb(query, hit.title)}</a>
|
||||||
|
<p>${createSearchResultBlurb(query, hit.content)}</p>
|
||||||
|
</li>
|
||||||
|
`
|
||||||
|
)
|
||||||
|
.join("");
|
||||||
|
const searchResultListItems = document.querySelectorAll("#search-results li");
|
||||||
|
document.getElementById("results-count").innerHTML = searchResultListItems.length;
|
||||||
|
document.getElementById("results-count-text").innerHTML = searchResultListItems.length === 1 ? "result" : "results";
|
||||||
|
// searchResultListItems.forEach(
|
||||||
|
// (li) => (li.firstElementChild.style.color = getColorForSearchResult(li.dataset.score))
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTitleBlurb(query, title) {
|
||||||
|
const searchQueryRegex = new RegExp(createQueryStringRegex(query), "gmi");
|
||||||
|
return title.replace(
|
||||||
|
searchQueryRegex,
|
||||||
|
"<strong>$&</strong>"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function createSearchResultBlurb(query, pageContent) {
|
||||||
|
const searchQueryRegex = new RegExp(createQueryStringRegex(query), "gmi");
|
||||||
|
const searchQueryHits = Array.from(
|
||||||
|
pageContent.matchAll(searchQueryRegex),
|
||||||
|
(m) => m.index
|
||||||
|
);
|
||||||
|
const sentenceBoundaries = Array.from(
|
||||||
|
pageContent.matchAll(SENTENCE_BOUNDARY_REGEX),
|
||||||
|
(m) => m.index
|
||||||
|
);
|
||||||
|
let searchResultText = "";
|
||||||
|
let lastEndOfSentence = 0;
|
||||||
|
for (const hitLocation of searchQueryHits) {
|
||||||
|
if (hitLocation > lastEndOfSentence) {
|
||||||
|
for (let i = 0; i < sentenceBoundaries.length; i++) {
|
||||||
|
if (sentenceBoundaries[i] > hitLocation) {
|
||||||
|
const startOfSentence = i > 0 ? sentenceBoundaries[i - 1] + 1 : 0;
|
||||||
|
const endOfSentence = sentenceBoundaries[i];
|
||||||
|
lastEndOfSentence = endOfSentence;
|
||||||
|
parsedSentence = pageContent.slice(startOfSentence, endOfSentence).trim();
|
||||||
|
searchResultText += `${parsedSentence} ... `;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const searchResultWords = tokenize(searchResultText);
|
||||||
|
const pageBreakers = searchResultWords.filter((word) => word.length > 50);
|
||||||
|
if (pageBreakers.length > 0) {
|
||||||
|
searchResultText = fixPageBreakers(searchResultText, pageBreakers);
|
||||||
|
}
|
||||||
|
if (searchResultWords.length >= MAX_SUMMARY_LENGTH) break;
|
||||||
|
}
|
||||||
|
return ellipsize(searchResultText, MAX_SUMMARY_LENGTH).replace(
|
||||||
|
searchQueryRegex,
|
||||||
|
"<strong>$&</strong>"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createQueryStringRegex(query) {
|
||||||
|
const searchTerms = query.split(" ");
|
||||||
|
if (searchTerms.length == 1) {
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
query = "";
|
||||||
|
for (const term of searchTerms) {
|
||||||
|
query += `${term}|`;
|
||||||
|
}
|
||||||
|
query = query.slice(0, -1);
|
||||||
|
return `(${query})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function tokenize(input) {
|
||||||
|
const wordMatches = Array.from(input.matchAll(WORD_REGEX), (m) => m);
|
||||||
|
return wordMatches.map((m) => ({
|
||||||
|
word: m[0],
|
||||||
|
start: m.index,
|
||||||
|
end: m.index + m[0].length,
|
||||||
|
length: m[0].length,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function fixPageBreakers(input, largeWords) {
|
||||||
|
largeWords.forEach((word) => {
|
||||||
|
const chunked = chunkify(word.word, 20);
|
||||||
|
input = input.replace(word.word, chunked);
|
||||||
|
});
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
function chunkify(input, chunkSize) {
|
||||||
|
let output = "";
|
||||||
|
let totalChunks = (input.length / chunkSize) | 0;
|
||||||
|
let lastChunkIsUneven = input.length % chunkSize > 0;
|
||||||
|
if (lastChunkIsUneven) {
|
||||||
|
totalChunks += 1;
|
||||||
|
}
|
||||||
|
for (let i = 0; i < totalChunks; i++) {
|
||||||
|
let start = i * chunkSize;
|
||||||
|
let end = start + chunkSize;
|
||||||
|
if (lastChunkIsUneven && i === totalChunks - 1) {
|
||||||
|
end = input.length;
|
||||||
|
}
|
||||||
|
output += input.slice(start, end) + " ";
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ellipsize(input, maxLength) {
|
||||||
|
const words = tokenize(input);
|
||||||
|
if (words.length <= maxLength) {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
return input.slice(0, words[maxLength].end) + "...";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!String.prototype.matchAll) {
|
||||||
|
String.prototype.matchAll = function (regex) {
|
||||||
|
"use strict";
|
||||||
|
function ensureFlag(flags, flag) {
|
||||||
|
return flags.includes(flag) ? flags : flags + flag;
|
||||||
|
}
|
||||||
|
function* matchAll(str, regex) {
|
||||||
|
const localCopy = new RegExp(regex, ensureFlag(regex.flags, "g"));
|
||||||
|
let match;
|
||||||
|
while ((match = localCopy.exec(str))) {
|
||||||
|
match.index = localCopy.lastIndex - match[0].length;
|
||||||
|
yield match;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return matchAll(this, regex);
|
||||||
|
};
|
||||||
|
}
|
27
unified.test.hugo/assets/styles/common.scss
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
@import "common/reset";
|
||||||
|
@import "common/colors";
|
||||||
|
@import "common/base";
|
||||||
|
@import "common/content";
|
||||||
|
|
||||||
|
@import "features/links";
|
||||||
|
|
||||||
|
// default layout
|
||||||
|
|
||||||
|
@import "layouts/_default/list";
|
||||||
|
@import "layouts/_default/single";
|
||||||
|
|
||||||
|
@import "partials/mf2/h-card";
|
||||||
|
@import "shortcodes/mf2/h-cite";
|
||||||
|
|
||||||
|
// wiki layout
|
||||||
|
|
||||||
|
@import "layouts/wiki/list";
|
||||||
|
@import "layouts/wiki/single";
|
||||||
|
@import "partials/wiki/site-header";
|
||||||
|
|
||||||
|
@import "partials/wiki/breadcrumbs";
|
||||||
|
|
||||||
|
@import "features/autonumbering";
|
||||||
|
@import "features/search";
|
||||||
|
|
||||||
|
@import "components/table-of-contents";
|
48
unified.test.hugo/assets/styles/common/base.scss
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
:root {
|
||||||
|
--site-max-width: 120ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-family: sans-serif;
|
||||||
|
background: var(--ui-background);
|
||||||
|
color: var(--ui-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Single column layout, where main content stretches to fill. */
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
min-height: calc(var(--vh, 1vh) * 100);
|
||||||
|
max-width: 100vw;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
main {flex-grow: 1;}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Sections are primary block units, usually of type <section>.
|
||||||
|
Containers are an immediate child <div>, purely for constraining width.
|
||||||
|
*/
|
||||||
|
.section {
|
||||||
|
padding: 2em 0; /* we apply a vertical padding only to sections */
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
max-width: var(--site-max-width);
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 1em; /* and we apply a horizontal padding only to containers */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure consistent colors for text selection and element focus */
|
||||||
|
::selection {
|
||||||
|
background: var(--primary-accent);
|
||||||
|
color: var(--primary-accent-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
*:focus {
|
||||||
|
border-radius: 2px;
|
||||||
|
text-decoration: none;
|
||||||
|
outline: 1px dashed var(--ui-text);
|
||||||
|
outline-offset: 4px;
|
||||||
|
}
|
35
unified.test.hugo/assets/styles/common/colors.scss
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
:root {
|
||||||
|
--link-color: #3371cf;
|
||||||
|
--link-visited: #594288;
|
||||||
|
|
||||||
|
--primary-accent: hsl(210, 100%, 80%);
|
||||||
|
--primary-accent-transparent: hsla(210, 100%, 20%, 0.25);
|
||||||
|
--primary-accent-text: #fff;
|
||||||
|
|
||||||
|
--ui-background: hsl(210, 100%, 92.5%);
|
||||||
|
--ui-text: hsl(210, 100%, 10%);
|
||||||
|
--ui-text-muted: #666;
|
||||||
|
--ui-text-bold: #000;
|
||||||
|
|
||||||
|
--ui-overlay: hsl(210, 100%, 87.5%);
|
||||||
|
--ui-overlay-text: var(--ui-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root {
|
||||||
|
--link-color: hsl(210, 100%, 65%);
|
||||||
|
--link-visited: hsl(270, 100%, 75%);
|
||||||
|
|
||||||
|
--primary-accent: hsl(210, 100%, 20%);
|
||||||
|
--primary-accent-transparent: hsla(210, 100%, 20%, 0.45);
|
||||||
|
--primary-accent-text: #fff;
|
||||||
|
|
||||||
|
--ui-background: hsl(210, 100%, 10%);
|
||||||
|
--ui-text: hsl(210, 100%, 90%);
|
||||||
|
--ui-text-muted: #999;
|
||||||
|
--ui-text-bold: #fff;
|
||||||
|
|
||||||
|
--ui-overlay: hsl(210, 100%, 20%);
|
||||||
|
--ui-overlay-text: var(--ui-text);
|
||||||
|
}
|
||||||
|
}
|
206
unified.test.hugo/assets/styles/common/content.scss
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
.hugo-content {
|
||||||
|
/* text */
|
||||||
|
p, li {max-inline-size: 80ch;}
|
||||||
|
h1 {font-size: 1.8em}
|
||||||
|
h2 {font-size: 1.6em}
|
||||||
|
h3 {font-size: 1.423em}
|
||||||
|
h4 {font-size: 1.265em}
|
||||||
|
h5 {font-size: 1.125em}
|
||||||
|
h6 {font-size: 1em}
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
line-height: 1.2;
|
||||||
|
margin-block-start: 2rem;
|
||||||
|
margin-block-end: 1rem;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
line-height: 2;
|
||||||
|
margin-block-end: 1em;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
/* semantics */
|
||||||
|
em {font-style: italic}
|
||||||
|
strong {font-weight: 700}
|
||||||
|
/* text formatting */
|
||||||
|
--script-size: 0.65em;
|
||||||
|
sup {
|
||||||
|
position: relative;
|
||||||
|
font-size: var(--script-size);
|
||||||
|
inset-block-start: -1em;
|
||||||
|
}
|
||||||
|
sub {
|
||||||
|
position: relative;
|
||||||
|
font-size: var(--script-size);
|
||||||
|
}
|
||||||
|
@supports #{'selector\(:has(kbd))'} {
|
||||||
|
/* style individual keys only (for the innermost <kbd> element) */
|
||||||
|
kbd kbd,
|
||||||
|
kbd:not(:has(kbd)) {
|
||||||
|
font-family: monospace;
|
||||||
|
padding: 0.25em;
|
||||||
|
background: var(--ui-overlay);
|
||||||
|
color: var(--ui-overlay-text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@supports not #{'selector\(:has(kbd))'} {
|
||||||
|
/* style the entire key sequence */
|
||||||
|
kbd {
|
||||||
|
font-family: monospace;
|
||||||
|
padding: 0.25em;
|
||||||
|
background: var(--ui-overlay);
|
||||||
|
color: var(--ui-overlay-text);
|
||||||
|
}
|
||||||
|
/* and prevent double-styling for nested keys */
|
||||||
|
kbd kbd {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mark {
|
||||||
|
background: var(--primary-accent-transparent);
|
||||||
|
color: var(--ui-text);
|
||||||
|
--pad-x-highlight: 0.125em;
|
||||||
|
padding-inline-start: var(--pad-x-highlight);
|
||||||
|
padding-inline-end: var(--pad-x-highlight);
|
||||||
|
}
|
||||||
|
abbr[title]:after {
|
||||||
|
content: '?';
|
||||||
|
font-size: var(--script-size);
|
||||||
|
color: var(--ui-text-muted);
|
||||||
|
}
|
||||||
|
/* lists */
|
||||||
|
ul, ol {
|
||||||
|
padding-inline-start: 0;
|
||||||
|
margin-block: 1em;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
ul {list-style: disc;}
|
||||||
|
ol {list-style: decimal;}
|
||||||
|
li {margin-block-end: 1em; line-height: 1.4; margin-inline-start: 1em;}
|
||||||
|
dl {margin-block: 1em; line-height: 1.4;}
|
||||||
|
dt {font-weight: 700;}
|
||||||
|
dd {margin-inline-start: 1em;}
|
||||||
|
/* block elements */
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
margin-block-end: 1em;
|
||||||
|
}
|
||||||
|
blockquote {
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 1em;
|
||||||
|
margin: 1em 0;
|
||||||
|
border-inline-start: 0.25rem solid var(--ui-text-bold);
|
||||||
|
padding-inline-start: 0.75em;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
font-family: monospace;
|
||||||
|
padding: 1em;
|
||||||
|
line-height: 1.4;
|
||||||
|
overflow-inline: auto;
|
||||||
|
white-space: pre;
|
||||||
|
display: grid;
|
||||||
|
tab-size: 3;
|
||||||
|
margin-block-end: 1em;
|
||||||
|
}
|
||||||
|
code {
|
||||||
|
font-family: monospace;
|
||||||
|
background: var(--ui-overlay);
|
||||||
|
color: var(--ui-overlay-text);
|
||||||
|
padding: 0.25rem;
|
||||||
|
}
|
||||||
|
:not(.highlight) > pre {
|
||||||
|
line-height: 1.5;
|
||||||
|
background: var(--ui-overlay);
|
||||||
|
color: var(--ui-overlay-text);
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
pre code {
|
||||||
|
background: inherit;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.highlight pre {
|
||||||
|
padding-block: 1em;
|
||||||
|
}
|
||||||
|
/* figures */
|
||||||
|
figure {
|
||||||
|
margin-block-end: 1em;
|
||||||
|
}
|
||||||
|
figure img {
|
||||||
|
width: 100%;
|
||||||
|
margin-block-end: -0.125em;
|
||||||
|
}
|
||||||
|
figcaption {
|
||||||
|
background: #212121;
|
||||||
|
color: white;
|
||||||
|
font-style: italic;
|
||||||
|
padding: 1em;
|
||||||
|
font-size: 0.8em;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
/* tables */
|
||||||
|
table {text-align: center;}
|
||||||
|
thead {
|
||||||
|
font-weight: 700;
|
||||||
|
background: var(--ui-overlay);
|
||||||
|
color: var(--ui-overlay-text);
|
||||||
|
}
|
||||||
|
th, td {
|
||||||
|
border: 1px solid var(--ui-text);
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
/* {{<hint>}} shortcode */
|
||||||
|
.hint, .callout {
|
||||||
|
padding: 1em;
|
||||||
|
line-height: 2;
|
||||||
|
&.info, &.tip
|
||||||
|
{
|
||||||
|
background: rgba(142, 226, 142, 0.2);
|
||||||
|
border-inline-start: 4px solid rgb(142, 226, 142);
|
||||||
|
}
|
||||||
|
&.warning {
|
||||||
|
background: rgba(218, 226, 142, 0.2);
|
||||||
|
border-inline-start: 4px solid rgb(218, 226, 142);
|
||||||
|
}
|
||||||
|
&.danger {
|
||||||
|
background: rgba(226, 142, 142, 0.2);
|
||||||
|
border-inline-start: 4px solid rgb(226, 142, 142);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* hugo-specific citation footnote */
|
||||||
|
cite sup {
|
||||||
|
position: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
a {
|
||||||
|
padding: 0.25em;
|
||||||
|
}
|
||||||
|
&:before {
|
||||||
|
content: ' [';
|
||||||
|
}
|
||||||
|
&:after {
|
||||||
|
content: ']';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* the actual footnotes section */
|
||||||
|
.footnotes {
|
||||||
|
hr {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
border: 0;
|
||||||
|
&:before {
|
||||||
|
content: 'Footnotes';
|
||||||
|
color: var(--ui-text);
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: 900;
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
&:after {
|
||||||
|
content: '';
|
||||||
|
width: 100%;
|
||||||
|
margin-inline-start: 1rem;
|
||||||
|
border-block-end: 1px solid var(--ui-text-muted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
unified.test.hugo/assets/styles/common/reset.scss
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
.toc-title {
|
||||||
|
margin-block-end: 0.5em;
|
||||||
|
font-weight: 900;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
#TableOfContents {
|
||||||
|
ul, ol {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
margin-block: 0.5em;
|
||||||
|
margin-inline: 0;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
li > ul, li > ol { /* indent subheadings */
|
||||||
|
margin-inline-start: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.toc details {
|
||||||
|
max-width: 45ch;
|
||||||
|
background: rgba(0,0,0,0.1);
|
||||||
|
padding: 1em;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
}
|
94
unified.test.hugo/assets/styles/features/autonumbering.scss
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
h2.heading {
|
||||||
|
border-block-end: 1px solid var(--ui-text-muted);
|
||||||
|
padding-block-end: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* headings with no numbers */
|
||||||
|
|
||||||
|
article:not([autonumbering]) .heading {
|
||||||
|
position: relative;
|
||||||
|
margin-inline-end: 2.5rem;
|
||||||
|
&__anchor-link {
|
||||||
|
display: inline-flex;
|
||||||
|
align-content: center;
|
||||||
|
margin-inline-start: 0.25em;
|
||||||
|
position: absolute;
|
||||||
|
inset-inline-end: -2.5rem;
|
||||||
|
inset-block-start: 3px;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* headings with autonumbering support */
|
||||||
|
|
||||||
|
body {counter-reset: h2}
|
||||||
|
h2 {counter-reset: h3}
|
||||||
|
h3 {counter-reset: h4}
|
||||||
|
h4 {counter-reset: h5}
|
||||||
|
|
||||||
|
article[autonumbering] {
|
||||||
|
h2:before {
|
||||||
|
counter-increment: h2;
|
||||||
|
content: counter(h2) " ";
|
||||||
|
}
|
||||||
|
h3:before {
|
||||||
|
counter-increment: h3;
|
||||||
|
content: counter(h2) "." counter(h3) " ";
|
||||||
|
}
|
||||||
|
h4:before {
|
||||||
|
counter-increment: h4;
|
||||||
|
content: counter(h2) "." counter(h3) "." counter(h4) " ";
|
||||||
|
}
|
||||||
|
h2:before,
|
||||||
|
h3:before,
|
||||||
|
h4:before
|
||||||
|
{
|
||||||
|
margin-inline-end: 1em;
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr auto;
|
||||||
|
grid-template-rows: auto auto;
|
||||||
|
grid-gap: 0.5rem;
|
||||||
|
&__text {
|
||||||
|
grid-column: span 2;
|
||||||
|
}
|
||||||
|
&__anchor-link {
|
||||||
|
font-size: 1rem;
|
||||||
|
grid-column: 2;
|
||||||
|
grid-row: 1;
|
||||||
|
justify-self: end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#TableOfContents :is(ol, ul) {
|
||||||
|
/*
|
||||||
|
each list gets a new counter
|
||||||
|
*/
|
||||||
|
counter-reset: item;
|
||||||
|
margin-inline-start: 0;
|
||||||
|
}
|
||||||
|
#TableOfContents li:before {
|
||||||
|
/*
|
||||||
|
the counter is added as a pseudo-element,
|
||||||
|
and nested counters are joined by a dot
|
||||||
|
*/
|
||||||
|
content: counters(item, ".") " ";
|
||||||
|
counter-increment: item;
|
||||||
|
/* ensure the counters align visually */
|
||||||
|
font-family: monospace;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-inline-end: 1em;
|
||||||
|
}
|
||||||
|
#TableOfContents > ul > li {
|
||||||
|
/*
|
||||||
|
top-level items wrap after the number,
|
||||||
|
in order to add some visual separation
|
||||||
|
*/
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
}
|
||||||
|
}
|
37
unified.test.hugo/assets/styles/features/links.scss
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
a:link {
|
||||||
|
transition: all 0.1s ease-out;
|
||||||
|
color: var(--link-color);
|
||||||
|
text-decoration-thickness: .0625rem;
|
||||||
|
text-underline-offset: 0.125em;
|
||||||
|
text-decoration-skip-ink: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:visited {
|
||||||
|
color: var(--link-visited);
|
||||||
|
}
|
||||||
|
|
||||||
|
a:focus {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
text-decoration-thickness: 0.125em;
|
||||||
|
text-underline-offset: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion) {
|
||||||
|
a:link {transition: none}
|
||||||
|
}
|
||||||
|
|
||||||
|
a:link[target=_blank] {
|
||||||
|
svg {
|
||||||
|
margin-inline-start: 0.35em;
|
||||||
|
margin-inline-end: 0.15em;
|
||||||
|
vertical-align: baseline;
|
||||||
|
font-size: 0.65em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a:link[title] {
|
||||||
|
text-decoration-style: dotted;
|
||||||
|
}
|
71
unified.test.hugo/assets/styles/features/search.scss
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
.search-results__title {
|
||||||
|
display: block;
|
||||||
|
font-size: 2em;
|
||||||
|
line-height: 1;
|
||||||
|
margin-block-end: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-results strong {
|
||||||
|
font-weight: 900;
|
||||||
|
background: var(--primary-accent-transparent);
|
||||||
|
color: var(--ui-text-bold);
|
||||||
|
}
|
||||||
|
|
||||||
|
#search-results {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
max-inline-size: 80ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
#search-results li:not(:first-child) {
|
||||||
|
border-block-start: 1px solid var(--ui-text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
#search-results li {
|
||||||
|
padding-block: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-result-page-title {
|
||||||
|
font-size: 1.25em;
|
||||||
|
display: block;
|
||||||
|
margin-block-end: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-result-item p {
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
#search-form {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 18rem;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 20ch 8ch;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#search-input {
|
||||||
|
background: var(--ui-overlay);
|
||||||
|
color: var(--ui-overlay-text);
|
||||||
|
border-radius: 100rem;
|
||||||
|
border: 0;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
box-sizing: border-box;
|
||||||
|
resize: horizontal;
|
||||||
|
width: 100%;
|
||||||
|
grid-column: 1;
|
||||||
|
block-size: 2rem;
|
||||||
|
line-height: 1rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#search-submit {
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
border: 0;
|
||||||
|
background: var(--primary-accent);
|
||||||
|
color: var(--primary-accent-text);
|
||||||
|
border-radius: 4px;
|
||||||
|
grid-column: 2;
|
||||||
|
block-size: 2rem;
|
||||||
|
line-height: 1rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
/* syntax highlighting */
|
||||||
|
|
||||||
|
.highlight {
|
||||||
|
--background: var(--ui-overlay);
|
||||||
|
--error: #cc0000;
|
||||||
|
--keyword: rgb(25, 80, 162);
|
||||||
|
--class: #f57900;
|
||||||
|
--variable: #194869;
|
||||||
|
--number: #323030;
|
||||||
|
--operator: #5400c2;
|
||||||
|
--highlight: rgb(196, 196, 196);
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
--background: var(--ui-overlay);
|
||||||
|
--error: #cc0000;
|
||||||
|
--keyword: #85ddff;
|
||||||
|
--class: #8700f5;
|
||||||
|
--variable: #bed5f2;
|
||||||
|
--number: #53ca24;
|
||||||
|
--operator: #ebe995;
|
||||||
|
--highlight: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Background */ .bg { background-color: var(--background); }
|
||||||
|
/* PreWrapper */ .chroma { background-color: var(--background); }
|
||||||
|
/* Other */ .chroma .x { color: var(--ui-text-bold) }
|
||||||
|
/* Error */ .chroma .err { color: var(--error) }
|
||||||
|
/* CodeLine */ .chroma .cl { color: var(--ui-text) }
|
||||||
|
/* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; }
|
||||||
|
/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; }
|
||||||
|
/* LineHighlight */ .chroma .hl { background-color: var(--highlight) }
|
||||||
|
/* LineNumbersTable */ .chroma .lnt { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
|
||||||
|
/* LineNumbers */ .chroma .ln { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
|
||||||
|
/* Line */ .chroma .line { display: flex; white-space: pre }
|
||||||
|
/* Keyword */ .chroma .k { color: var(--keyword); font-weight: bold }
|
||||||
|
/* KeywordConstant */ .chroma .kc { color: var(--keyword); font-weight: bold }
|
||||||
|
/* KeywordDeclaration */ .chroma .kd { color: var(--keyword); font-weight: bold }
|
||||||
|
/* KeywordNamespace */ .chroma .kn { color: var(--keyword); font-weight: bold }
|
||||||
|
/* KeywordPseudo */ .chroma .kp { color: var(--keyword); font-weight: bold }
|
||||||
|
/* KeywordReserved */ .chroma .kr { color: var(--keyword); font-weight: bold }
|
||||||
|
/* KeywordType */ .chroma .kt { color: var(--keyword); font-weight: bold }
|
||||||
|
/* Name */ .chroma .n { color: var(--ui-text-bold) }
|
||||||
|
/* NameAttribute */ .chroma .na { color: var(--ui-text-bold) }
|
||||||
|
/* NameBuiltin */ .chroma .nb { color: var(--name) }
|
||||||
|
/* NameBuiltinPseudo */ .chroma .bp { color: #3465a4 }
|
||||||
|
/* NameClass */ .chroma .nc { color: var(--ui-text-bold) }
|
||||||
|
/* NameConstant */ .chroma .no { color: var(--ui-text-bold) }
|
||||||
|
/* NameDecorator */ .chroma .nd { color: var(--class); font-weight: bold }
|
||||||
|
/* NameEntity */ .chroma .ni { color: var(--name) }
|
||||||
|
/* NameException */ .chroma .ne { color: var(--error); font-weight: bold }
|
||||||
|
/* NameFunction */ .chroma .nf { color: var(--ui-text-bold) }
|
||||||
|
/* NameFunctionMagic */ .chroma .fm { color: var(--ui-text-bold) }
|
||||||
|
/* NameLabel */ .chroma .nl { color: var(--name) }
|
||||||
|
/* NameNamespace */ .chroma .nn { color: var(--ui-text-bold) }
|
||||||
|
/* NameOther */ .chroma .nx { color: var(--ui-text-bold)}
|
||||||
|
/* NameProperty */ .chroma .py { color: var(--ui-text-bold) }
|
||||||
|
/* NameTag */ .chroma .nt { color: var(--keyword); font-weight: bold }
|
||||||
|
/* NameVariable */ .chroma .nv { color: var(--variable) }
|
||||||
|
/* NameVariableClass */ .chroma .vc { color: var(--ui-text-bold)}
|
||||||
|
/* NameVariableGlobal */ .chroma .vg { color: var(--ui-text-bold) }
|
||||||
|
/* NameVariableInstance */ .chroma .vi { color: var(--ui-text-bold) }
|
||||||
|
/* NameVariableMagic */ .chroma .vm { color: var(--ui-text-bold) }
|
||||||
|
/* Literal */ .chroma .l { color: var(--ui-text-bold) }
|
||||||
|
/* LiteralDate */ .chroma .ld { color: var(--ui-text-bold) }
|
||||||
|
/* LiteralString */ .chroma .s { color: var(--variable) }
|
||||||
|
/* LiteralStringAffix */ .chroma .sa { color: var(--variable) }
|
||||||
|
/* LiteralStringBacktick */ .chroma .sb { color: var(--variable) }
|
||||||
|
/* LiteralStringChar */ .chroma .sc { color: var(--variable) }
|
||||||
|
/* LiteralStringDelimiter */ .chroma .dl { color: var(--variable) }
|
||||||
|
/* LiteralStringDoc */ .chroma .sd { color: var(--keyword); font-style: italic }
|
||||||
|
/* LiteralStringDouble */ .chroma .s2 { color: var(--variable) }
|
||||||
|
/* LiteralStringEscape */ .chroma .se { color: var(--variable) }
|
||||||
|
/* LiteralStringHeredoc */ .chroma .sh { color: var(--variable) }
|
||||||
|
/* LiteralStringInterpol */ .chroma .si { color: var(--variable) }
|
||||||
|
/* LiteralStringOther */ .chroma .sx { color: var(--variable) }
|
||||||
|
/* LiteralStringRegex */ .chroma .sr { color: var(--variable) }
|
||||||
|
/* LiteralStringSingle */ .chroma .s1 { color: var(--variable) }
|
||||||
|
/* LiteralStringSymbol */ .chroma .ss { color: var(--variable) }
|
||||||
|
/* LiteralNumber */ .chroma .m { color: var(--number); font-weight: bold }
|
||||||
|
/* LiteralNumberBin */ .chroma .mb { color: var(--number); font-weight: bold }
|
||||||
|
/* LiteralNumberFloat */ .chroma .mf { color: var(--number); font-weight: bold }
|
||||||
|
/* LiteralNumberHex */ .chroma .mh { color: var(--number); font-weight: bold }
|
||||||
|
/* LiteralNumberInteger */ .chroma .mi { color: var(--number); font-weight: bold }
|
||||||
|
/* LiteralNumberIntegerLong */ .chroma .il { color: var(--number); font-weight: bold }
|
||||||
|
/* LiteralNumberOct */ .chroma .mo { color: var(--number); font-weight: bold }
|
||||||
|
/* Operator */ .chroma .o { color: var(--operator); font-weight: bold }
|
||||||
|
/* OperatorWord */ .chroma .ow { color: var(--keyword); font-weight: bold }
|
||||||
|
/* Punctuation */ .chroma .p { color: var(--ui-text-bold); font-weight: bold }
|
||||||
|
/* Comment */ .chroma .c { color: var(--ui-text-muted); font-style: italic }
|
||||||
|
/* CommentHashbang */ .chroma .ch { color: var(--ui-text-muted); font-style: italic }
|
||||||
|
/* CommentMultiline */ .chroma .cm { color: var(--ui-text-muted); font-style: italic }
|
||||||
|
/* CommentSingle */ .chroma .c1 { color: var(--ui-text-muted); font-style: italic }
|
||||||
|
/* CommentSpecial */ .chroma .cs { color: var(--ui-text-muted); font-style: italic }
|
||||||
|
/* CommentPreproc */ .chroma .cp { color: var(--ui-text-muted); font-style: italic }
|
||||||
|
/* CommentPreprocFile */ .chroma .cpf { color: var(--ui-text-muted); font-style: italic }
|
||||||
|
/* Generic */ .chroma .g { color: var(--ui-text-bold) }
|
||||||
|
/* GenericDeleted */ .chroma .gd { color: var(--error) }
|
||||||
|
/* GenericEmph */ .chroma .ge { color: var(--ui-text-bold); font-style: italic }
|
||||||
|
/* GenericError */ .chroma .gr { color: var(--error) }
|
||||||
|
/* GenericHeading */ .chroma .gh { color: var(--ui-text-bold); font-weight: bold }
|
||||||
|
/* GenericInserted */ .chroma .gi { color: var(--ui-text) }
|
||||||
|
/* GenericOutput */ .chroma .go { color: var(--ui-text-bold); font-style: italic }
|
||||||
|
/* GenericPrompt */ .chroma .gp { color: var(--ui-text) }
|
||||||
|
/* GenericStrong */ .chroma .gs { color: var(--ui-text-bold); font-weight: bold }
|
||||||
|
/* GenericSubheading */ .chroma .gu { color: var(--ui-text-bold); font-weight: bold }
|
||||||
|
/* GenericTraceback */ .chroma .gt { color: var(--error); font-weight: bold }
|
||||||
|
/* GenericUnderline */ .chroma .gl { color: var(--ui-text-bold); text-decoration: underline }
|
||||||
|
/* TextWhitespace */ .chroma .w { color: var(--ui-text-muted); text-decoration: underline }
|
27
unified.test.hugo/assets/styles/layouts/_default/list.scss
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
._default-list {
|
||||||
|
.list-header {
|
||||||
|
padding: 1em;
|
||||||
|
hr {display: none;}
|
||||||
|
}
|
||||||
|
.list-title {
|
||||||
|
margin-block: 0;
|
||||||
|
}
|
||||||
|
.list-author {}
|
||||||
|
.list-summary {}
|
||||||
|
.list-content {}
|
||||||
|
.list-permalink {
|
||||||
|
.u-url {font-family: monospace;}
|
||||||
|
}
|
||||||
|
.list-pages {
|
||||||
|
padding-inline: 1em;
|
||||||
|
}
|
||||||
|
.list-page {
|
||||||
|
max-width: 80ch;
|
||||||
|
.p-name {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.p-summary {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
41
unified.test.hugo/assets/styles/layouts/_default/single.scss
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
._default-single {
|
||||||
|
.page-header {
|
||||||
|
padding: 2em 1em;
|
||||||
|
hr {display: none;}
|
||||||
|
.container {
|
||||||
|
max-width: 80ch;
|
||||||
|
margin-inline: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.page-title {
|
||||||
|
margin-block-start: 0;
|
||||||
|
font-size: 2.025rem;
|
||||||
|
line-height: 1.15;
|
||||||
|
letter-spacing: -0.022rem;
|
||||||
|
grid-area: title;
|
||||||
|
}
|
||||||
|
.page-summary {
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 1.266rem;
|
||||||
|
line-height: 1.15;
|
||||||
|
letter-spacing: -0.022rem;
|
||||||
|
margin-block-start: 0.5rem;
|
||||||
|
grid-area: summary;
|
||||||
|
}
|
||||||
|
.page-author {
|
||||||
|
grid-area: author;
|
||||||
|
margin-block: 0;
|
||||||
|
}
|
||||||
|
.page-date {
|
||||||
|
grid-area: date;
|
||||||
|
margin-block-end: 0;
|
||||||
|
}
|
||||||
|
.page-permalink {
|
||||||
|
margin-block-end: 0;
|
||||||
|
align-self: end;
|
||||||
|
}
|
||||||
|
.page-content {
|
||||||
|
max-width: 80ch;
|
||||||
|
margin-inline: auto;
|
||||||
|
}
|
||||||
|
}
|
29
unified.test.hugo/assets/styles/layouts/wiki/list.scss
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
.wiki-list {
|
||||||
|
.subsections,
|
||||||
|
.subpages {
|
||||||
|
list-style: disc;
|
||||||
|
padding: 0;
|
||||||
|
margin-block-start: 1em;
|
||||||
|
margin-block-end: 2em;
|
||||||
|
li {
|
||||||
|
margin-inline-start: 1em;
|
||||||
|
margin-block-end: 1em;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.section-title {
|
||||||
|
font-size: 2em;
|
||||||
|
border-block-end: 1px solid var(--ui-text-muted);
|
||||||
|
padding-block-end: 0.5em;
|
||||||
|
margin-block-start: 0;
|
||||||
|
margin-block-end: 1em;
|
||||||
|
}
|
||||||
|
.subsections-title,
|
||||||
|
.subpages-title {
|
||||||
|
margin-block-start: 1em;
|
||||||
|
font-weight: 500;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
5
unified.test.hugo/assets/styles/layouts/wiki/single.scss
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
.wiki-single {
|
||||||
|
.content {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
}
|
14
unified.test.hugo/assets/styles/partials/mf2/h-card.scss
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
.h-card {
|
||||||
|
.u-url {
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
font-weight: bold;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5em;
|
||||||
|
}
|
||||||
|
.u-photo {
|
||||||
|
width: 3em;
|
||||||
|
border-radius: 100em;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
.breadcrumbs {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row wrap;
|
||||||
|
padding: 0;
|
||||||
|
li:not(:first-child) {
|
||||||
|
margin-inline-start: 1.5rem;
|
||||||
|
margin-block-end: 1rem;
|
||||||
|
}
|
||||||
|
li::marker {
|
||||||
|
content: "/ ";
|
||||||
|
}
|
||||||
|
li:first-child::marker {
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
li:first-child {
|
||||||
|
margin-inline-start: 0;
|
||||||
|
}
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
.breadcrumb-nav {
|
||||||
|
.title {
|
||||||
|
margin-block-end: 0.5em;
|
||||||
|
color: var(--ui-text-muted);
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
.wiki {
|
||||||
|
.site-masthead {
|
||||||
|
display: inline-flex;
|
||||||
|
flex-flow: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1em;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.site-icon {
|
||||||
|
block-size: 2em;
|
||||||
|
}
|
||||||
|
.site-title {
|
||||||
|
font-weight: 900;
|
||||||
|
letter-spacing: -0.5px;
|
||||||
|
font-size: 1.25em;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.site-masthead, .site-masthead:visited {
|
||||||
|
color: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-masthead:focus {
|
||||||
|
color: var(--primary-accent-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-header {padding: 1em 0;}
|
||||||
|
|
||||||
|
.site-header a {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.site-header .container {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row wrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-nav {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row wrap;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
.menu {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row wrap;
|
||||||
|
gap: 1em;
|
||||||
|
a {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5em;
|
||||||
|
&:after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
unified.test.hugo/assets/styles/print.scss
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
@import "common";
|
||||||
|
|
||||||
|
#search-form,
|
||||||
|
.header-nav,
|
||||||
|
.docs-nav,
|
||||||
|
.site-footer,
|
||||||
|
.edit-link,
|
||||||
|
.footnote-backref,
|
||||||
|
.heading__anchor-link,
|
||||||
|
.section-nav
|
||||||
|
{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.page-header {padding: 0;}
|
||||||
|
|
||||||
|
.page abbr[title]::after {
|
||||||
|
content: " (" attr(title) ") ";
|
||||||
|
}
|
||||||
|
|
||||||
|
a[href^="http"]:after {
|
||||||
|
content: " (" attr(href) ") ";
|
||||||
|
}
|
3
unified.test.hugo/assets/styles/screen.scss
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
@import "common";
|
||||||
|
|
||||||
|
@import "features/syntax-highlighting";
|
|
@ -0,0 +1,7 @@
|
||||||
|
.h-cite {
|
||||||
|
background: #eee;
|
||||||
|
padding-inline-start: 1em;
|
||||||
|
padding-block: 1em;
|
||||||
|
margin-inline-start: 0;
|
||||||
|
border-inline-start: 0.5em solid black;
|
||||||
|
}
|
0
unified.test.hugo/content/_dump/articles/_index.md
Normal file
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 25 KiB |
|
@ -0,0 +1,33 @@
|
||||||
|
+++
|
||||||
|
title = "AT&T is pulling some serious doublespeak right now."
|
||||||
|
summary = "Is AT&T a common carrier, according to AT&T? It depends on who's asking."
|
||||||
|
date = "2015-01-10T12:00:00-0600"
|
||||||
|
tags = []
|
||||||
|
categories = []
|
||||||
|
syndication = [
|
||||||
|
"https://medium.com/trwnh/at-t-is-pulling-some-serious-doublespeak-right-now-8fc64f268f36"
|
||||||
|
]
|
||||||
|
inReplyTo = [
|
||||||
|
"https://arstechnica.com/tech-policy/2015/01/att-defends-unlimited-data-throttling-says-the-ftc-cant-stop-it/",
|
||||||
|
"https://arstechnica.com/information-technology/2015/01/att-tells-fcc-it-cant-treat-mobile-data-as-a-common-carrier-service/"
|
||||||
|
]
|
||||||
|
[[resources]]
|
||||||
|
name = "featured"
|
||||||
|
src = "opengraph.jpg"
|
||||||
|
+++
|
||||||
|
|
||||||
|
The FTC is suing AT&T over its mobile data policies, particularly throttling "unlimited" customers. [AT&T filed a motion to dismiss this suit](https://arstechnica.com/tech-policy/2015/01/att-defends-unlimited-data-throttling-says-the-ftc-cant-stop-it/), saying that since AT&T is a common carrier, they fall under the jurisdiction of the FCC instead.
|
||||||
|
|
||||||
|
<figure>
|
||||||
|
<img src="ftc.jpg" alt="Ars Technica headline, January 8, 2015: AT&T defends unlimited data throttling, says the FTC can't stop it" />
|
||||||
|
<figcaption>"You have no power here. Only the FCC can stop us."</figcaption>
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
Except just a few days later, [AT&T tells the FCC](https://arstechnica.com/information-technology/2015/01/att-tells-fcc-it-cant-treat-mobile-data-as-a-common-carrier-service/) that mobile data doesn't fall under common carrier rules, and cannot be regulated without Title II.
|
||||||
|
|
||||||
|
<figure>
|
||||||
|
<img src="fcc.jpg" alt="Ars Technica headline, January 9, 2015: AT&T tells FCC it can't treat mobile data as a common carrier service." />
|
||||||
|
<figcaption>"You can't stop us. You don't have that power."</figcaption>
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
So, which is it?
|
After Width: | Height: | Size: 61 KiB |
After Width: | Height: | Size: 6.5 KiB |
|
@ -0,0 +1,54 @@
|
||||||
|
+++
|
||||||
|
title = "You don't have a right to profit."
|
||||||
|
summary = "People will go to ridiculous lengths in the name of protecting the “right” to profit. Let’s be real here. No one has a “right” to profit."
|
||||||
|
indieweb_type = "article"
|
||||||
|
tags = ["capitalism", "profit", "music", "music industry", "piracy", "distribution", "access"]
|
||||||
|
categories = ["Uncategorized"]
|
||||||
|
date = "2015-07-08T12:00:00-0600"
|
||||||
|
attachment = []
|
||||||
|
syndication = [
|
||||||
|
"https://medium.com/trwnh/you-dont-have-a-right-to-profit-2a0f977d4917"
|
||||||
|
]
|
||||||
|
[[resources]]
|
||||||
|
name = "featured"
|
||||||
|
src = "download.png"
|
||||||
|
+++
|
||||||
|
|
||||||
|
<p>These days, you see a lot of ridiculous things like <a href="https://torrentfreak.com/the-worlds-most-idiotic-copyright-complaint-150222/">copyright claims on the download pages of free software</a>, because they contain the word “download”. A lot of these stupid actions are done in the name of “protecting the artists”. People will go to ridiculous lengths in the name of protecting the “right” to profit.</p>
|
||||||
|
|
||||||
|
<figure>
|
||||||
|
<img src="download.png">
|
||||||
|
<figcaption>Pages for Skype, Java, CCleaner, OpenOffice, Eclipse, Ubuntu, Python, and more were claimed to be infringing copyright, simply because the URL contained the word "download".</figcaption>
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
<p>Let’s be real here. No one has a “right” to profit. No one is guaranteed to make money just because they make something. If you are offering something, then you are an entrepreneur. You have to make people WANT to give you money. If you can’t do that, you find a better business plan, or you quit.</p>
|
||||||
|
|
||||||
|
<p class="has-pullquote after" data-pullquote="No one is guaranteed to make money just because they make something. If you are offering something, then you are an entrepreneur. You have to make people WANT to give you money.">I’m really tired of these “protect the artists” sentiments that are only used to prop up an archaic business model. Do we have problems? Sure, but egregious litigation is definitely not the answer. Smart competition is. Wanna reduce piracy? Be more convenient. It should be pretty well-established by now that people are willing to pay for something if it’s available in an easy-to-access way.<p>
|
||||||
|
|
||||||
|
Ask yourself: why do people even pirate? Reasons people pirate:
|
||||||
|
|
||||||
|
1) no legal alternative
|
||||||
|
2) drm failed after purchase
|
||||||
|
3) it’s easier
|
||||||
|
4) no money
|
||||||
|
5) too greedy to pay
|
||||||
|
|
||||||
|
<p>You’re never getting money from #5, and chances are you’ll never be able to stop them. #4 has no money to begin with, so they’re not worth considering when analyzing piracy, either. But #1, #2, and #3 are access issues. <strong>Make your stuff available in all countries, with no DRM, in an easily accessible way, and piracy is no longer a compelling alternative to most people.</strong> (Personally, I’m 3+4. I have no money, but when I do have money, I’ll pay if something is easier and worth paying for.)</p>
|
||||||
|
|
||||||
|
To date, I have bought exactly one album: Circa Survive’s Violent Waves. Why?
|
||||||
|
|
||||||
|
1) It was $5 self-produced.
|
||||||
|
2) It was available for purchase directly.
|
||||||
|
3) I WANTED to give them my money.
|
||||||
|
|
||||||
|
<p class="has-pullquote before" data-pullquote="Make your stuff available in all countries, with no DRM, in an easily accessible way, and piracy is no longer a compelling alternative to most people.">What converts me from a pirate in that situation to a paying customer is that the purchase was accessible. $5 is a low price, that I am perfectly capable of paying without too much thought. All I had to do was give them my money directly, no intermediaries, no DRM, no BS, just one payment, immediate delivery of MP3 + FLAC files, and a CD shipped out soon after. For $25, I could get the exclusive pre-order t-shirt, too. And Circa Survive is my favorite band, so I wanted to support them and their indie efforts.</p>
|
||||||
|
|
||||||
|
For any other artist? For the rest of my music collection? There are excellently tagged discographies, in high quality or ripped straight from a CD. Even the legal copy isn’t that good. [edit July 2015] Since writing this post, I’ve also purchased Anberlin’s Never Take Friendship Personal: Live in NYC. There were spelling mistakes and other incorrect things in the tags. This was the OFFICIAL RELEASE, and it wasn’t tagged properly. Not to mention it came in MP3 only. Not a pleasant shopping experience. [edit February 2018] And furthermore, the download link to that album has expired due to Tooth & Nail abandoning SendOwl for digital deliveries. The link claims to allow 3 download attempts, but as of now, it will allow 0. The only thing you’ll get is a 404 error.
|
||||||
|
|
||||||
|
Basically, I’ll only ever buy CDs or high quality FLAC files, because buying anything else cannot match the alternative of just downloading the pirated copy. My copy of Violent Waves is right here, and I got the FLAC digital download immediately after purchase. Much of the pirating scene is dedicated to quality releases, so when a legal alternative can’t match up, it needs to offer something else. It needs to offer a compelling reason to give up your money.
|
||||||
|
|
||||||
|
<p class="has-pullquote after" data-pullquote="Much of the pirating scene is dedicated to quality releases, so when a legal alternative can’t match up, it needs to offer [...] a compelling reason to give up your money.">If you can match the quality of pirated CD-rips, then you can differentiate your legal option with convenience. Why do you think streaming services are gaining popularity? Because it’s easier to pay one fee and listen to anything you want, ever. At the touch of a button, you can play millions of songs spanning decades of creativity and culture. But even at its core, streaming is just plain convenient. No dealing with physical CDs, which take up space and need to be stored carefully. No giving up your storage space to MP3s. You don’t even have to bother with the payment processing. No downloads to make. Just play songs immediately. That kind of convenience is unmatched, and is a big reason why Spotify can compete seriously with piracy. Pure convenience, and there’s a free tier that’s ad-supported, so they can generate slightly more revenue than $0.00.</p>
|
||||||
|
|
||||||
|
My ideal purchasing situation: when you buy an album, not only can you get a CD, but you also get streaming rights, with an option to download. No DRM, no BS. You bought it. A smart label would partner up and get something like that done. Amazon does this to some extent with their AutoRip service, and Google Play Music gives you streaming + download when you purchase music. Since originally writing this, Apple Music has been introduced, which means you should get streaming rights to your iTunes purchases as well (to a limited extent). I just wish that this was more standardized somehow. Perhaps if labels started their own streaming service (and again updated, with the seizure of Grooveshark and its intellectual property, this is an opportunity for labels if they wish to increase their revenues…), or gave streaming rights on particular services (or all services) if you have a purchase code of some sort that could be included with each CD physical. This could even be accomplished with a more innocuous form of DRM like linking each code to one account only, so that only you can get streaming rights.
|
||||||
|
|
||||||
|
<p class="has-pullquote before" data-pullquote="Much of the pirating scene is dedicated to quality releases, so when a legal alternative can’t match up, it needs to offer [...] a compelling reason to give up your money.">I realize a lot of people don’t buy albums anymore, but that’s the music industry’s fault for commoditizing the individual tracks. Labels like to complain that various things are ruining the music industry, but the truth is that the music industry is ruining the music industry. Rather than innovating, they litigated. Then they devalued albums with the era of the digital single. Then they focused on mega-stardom and manufactured celebrity, pouring a lot of money into already-established artists and causing the music industry to contract and shrink. If the music industry had capitalized on the growth of the internet, if they had competed with Napster instead of shutting it down, if they hadn’t relied on iTunes for so long, if they had been quicker to adopt streaming and worked with Grooveshark and Spotify, if the labels reorganized their business plan from owning artists to doing publicity and media management and distribution… maybe things would be going better for them right about now, huh?</p>
|
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,75 @@
|
||||||
|
+++
|
||||||
|
title = "What makes a unified messaging client perfect?"
|
||||||
|
summary = "A rant in which I focus on what I like and hate about messaging apps, the characteristics I would implement if I were designing the perfect unified mobile messenger, and which current offerings are the closest to perfect."
|
||||||
|
date = "2014-08-08T12:00:00-0600"
|
||||||
|
tags = []
|
||||||
|
categories = []
|
||||||
|
syndication = [
|
||||||
|
"https://medium.com/trwnh/what-makes-a-unified-messaging-client-perfect-322a83e3aa64"
|
||||||
|
]
|
||||||
|
[[resources]]
|
||||||
|
name = "featured,opengraph"
|
||||||
|
src = "messaging-apps-folder.jpg"
|
||||||
|
+++
|
||||||
|
|
||||||
|
## A brief history of (mobile) communication.
|
||||||
|
|
||||||
|
I've grown a bit frustrated sometimes with contacting people. Why can't I just send a message through a nonspecific service and get a reply? What features are missing from today's current offerings that would REALLY make things better? If I made my own app, what aspects would I include in its design?
|
||||||
|
|
||||||
|
In the 2000s, if you wanted to send a message to someone, you would either use SMS to reach them on their phone, or some IM platform if they were sitting at their computer. With the rise of mobile data and smartphones, however, the line between the two became blurred. Suddenly, we had phones that could be always-connected, just like computers. This led to the proliferation of a wide swathe of mobile messaging apps that utilize our new mobile data connections.
|
||||||
|
|
||||||
|
## Mobile messaging is extremely diverse and fragmented.
|
||||||
|
|
||||||
|
<figure>
|
||||||
|
<img src="messaging-apps-folder.jpg" alt='11 apps in a folder titled "Communication". The apps are: Hangouts, Gmail, Allo, Duo, Skype, Wire, Kik, the stock SMS Messages app, Outlook, Sid, and Riot.im.' />
|
||||||
|
<figcaption>These are the apps I use... AFTER actively trying to reduce how many apps I use.</figcaption>
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
Mobile messaging apps are a dime a dozen — there are too many out there, and they all do basically the exact same things. There's not much differentiation between these apps; every app will let you send text messages to your friends, and probably picture messages, too. Many will let you send different types of media, like videos, voice recordings, or files. Some will let you make voice or video calls. Certain characteristics make each app notable, but no one app is perfect.
|
||||||
|
|
||||||
|
Among Whatsapp, Facebook Messenger, Google Hangouts, Apple iMessage, LINE, WeChat, GroupMe, Kik, Viber, Tango, Skype, KakaoTalk, and Nimbuzz (to name only a few of the most popular offerings), there's [less and less reason to use SMS](https://www.gsmaintelligence.com/research/2011/11/sms-on-the-decline-as-third-party-messaging-gains-traction/307/) for most people around the world. Despite that, SMS remains in high usage for most people (at least in the USA), but for the most part, [different methods of communication control different regions](https://techcrunch.com/2012/12/04/global-messaging-market/), and no one app has a real majority worldwide.
|
||||||
|
|
||||||
|
## Apps have different approaches to handling your contacts.
|
||||||
|
|
||||||
|
Most apps fall into one of two categories: phone-number-based or email-based, the only truly federated communication systems that are widespread. Mobile phones are a staple in communication, and if you're online, chances are you've got an email address. Most services ask for an email upon signing up, to create your account. Generally, you'll also choose a username. (This is the case for Skype and Kik.) Some services won't ask for a username, opting to use account IDs internally and connect via your name. (This is the case for Facebook Messenger and Google Hangouts.) Other services will choose to link with your mobile phone number instead. (This is the case for Whatsapp and Viber.)
|
||||||
|
|
||||||
|
These approaches cause subtle differences in the philosophy that an app has towards contacts. Either you connect with people through the phone number you already have, or you connect through an email that you already have. Or, you find people by name.
|
||||||
|
|
||||||
|
<figure>
|
||||||
|
<img src="hangouts-new-conversation.png" alt='The "new conversation" UI in Hangouts provides you with a search bar and asks you to "Enter name, email, or phone".' />
|
||||||
|
<figcaption>This is where Hangouts does something right.</figcaption>
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
## All these apps have issues, but some are better than others.
|
||||||
|
|
||||||
|
The biggest problem with all these apps is that they don't intercommunicate. This means that using an app locks you into your circle of friends who also use the same app. In order to build a meaningful user base, an app has to provide a clear benefit for its use case. So, which app do you pick?
|
||||||
|
|
||||||
|
Personally, my primary communication method is Google Hangouts, for a few reasons:
|
||||||
|
|
||||||
|
1. it integrates into the Gmail account I have (and most people use Gmail, so it's easy to get others to join me),
|
||||||
|
2. it has all the necessary features (like picture messaging, group chat, voice/video calls),
|
||||||
|
3. it integrates some telephony (thanks to my Google Voice, and hopefully this integration will grow),
|
||||||
|
4. it works across many platforms (including web, iPhone, and Android, but not Blackberry, Windows Phone, or Symbian), and
|
||||||
|
5. it syncs messages across all my devices (thanks to it being cloud-based).
|
||||||
|
|
||||||
|
Other apps have other advantages. Facebook Messenger relies on the large user-base that Facebook already has worldwide, as after email and phone numbers, Facebook may be the third-most widely used communication platform. (That said, some people do not use Facebook, either due to refusal or lack of interest.) Whatsapp lowers the barrier to entry by automatically linking with a user's phone number, minimizing the interaction necessary to start using their service. iMessage is tightly integrated into Apple's ecosystem, and it requires zero thought from users since messages will automatically be converted if both people are using iDevices (plus, it has SMS as a fallback, but more on that later).
|
||||||
|
|
||||||
|
## These are the features that I would implement in my app.
|
||||||
|
|
||||||
|
In the last section, I mentioned that iMessage is seamless because it has SMS as a fallback, and this is the biggest pain point for most apps: in addition to lock-in, mobile messaging apps fail to be backwards-compatible or accessible. The reality is that, while mobile messaging apps are rising, and mobile data (or Wi-Fi) availability spreads, most people still rely on SMS and email. Those technologies aren't dead. Hangouts is the closest to "perfect" for me because it (independently) handles SMS and exists inside my Gmail, and the things it lacks are features of Google Talk and Google Voice that haven't made their way in yet. (The Android app for Facebook Messenger was my SMS app previously, due only to Chat Heads. I'd made a Facebook account only for Chat Heads, and once Facebook stopped supporting SMS, I deleted that account.) The perfect app would include some sort of federation.
|
||||||
|
|
||||||
|
A truly unified mobile messaging app would be completely channel-agnostic. It wouldn't matter if you were communication with someone by telephony, email, or data. Obviously, data would be preferred as the primary channel, but it needs fallbacks to email and SMS for people who haven't made the switch yet.
|
||||||
|
|
||||||
|
Consider iMessage's transition back to SMS for people who are offline. Google lets you do something similar with [SMS for Hangouts](https://www.google.com/settings/smsextensions) <aside>[edit: not anymore]</aside>, a setting hidden in the Google Account settings menu (accessed by clicking on your profile icon in the upper right and clicking "Account") that lets you "receive your conversation messages as SMS, when you don't use Hangouts elsewhere" (similar to Twitter's "tweet via SMS" option), but this only applies to you. Google Voice lets you send SMS, but it's not fully integrated into Hangouts at the time of this writing. SMS fallback when offline should go both ways.
|
||||||
|
|
||||||
|
Email fallback is something that is mostly overlooked. Facebook messages can be optionally sent as email notifications, and Hangouts shows up in Gmail as "Chats", but most services tend to avoid this. Hop, an email app for iOS (formerly called Ping), [turns email inboxes into a chat analogy](https://gethop.com/). This would be useful for a chat app, which could communicate with people who haven't signed up yet and don't have accounts. It would be possible for Hangouts to send a message as an email to someone not using Hangouts, and the other user could reply to that email to have it show up in Hangouts, much like Google Voice's SMS-to-email feature works.
|
||||||
|
|
||||||
|
Imagine the following use-case diagram: A message is sent to Friend. If Friend is online, the app sends a push notification. If Friend isn't online, the app sends an email notification that Friend can reply to, and/or an SMS that Friend can reply to. A picture message would have the picture attached to an email, and/or utilize MMS. Group messages would be sent to all involved emails, and/or create a group MMS. The app would make no distinction between friends that haven't signed up and friends that have. When starting a conversation with friends that haven't signed up, messages would go straight to the specified email or phone number, unless matched to a contact that has signed up.
|
||||||
|
|
||||||
|
For voice calls, the app would have the option to call either contacts (over data) or phone numbers (still over data, but your friend is connected through telephony). Video calls would obviously have to be data-only, and would require your friend to use the app, at least until federated video chat becomes possible.
|
||||||
|
|
||||||
|
## A final summary...
|
||||||
|
|
||||||
|
A perfect app would communicate with friends through its service, through email, or through SMS. For friends that don't use the service, emails or phone numbers are used. Attachments would be handled with email attachments or MMS attachments. For friends that use the service, messages are pushed to the client if online, and fallback to SMS/email if not. These fallbacks can be optionally disabled/enabled by your friend.
|
||||||
|
|
||||||
|
Of the current apps, Google Hangouts + Google Voice would be the closest, once it integrates VoIP, full SMS integration, adds in better fallback options, and handles federation or open access through APIs. Chat Heads would be cool, but Google probably won't add them (which is why open APIs are important, because [someone could just write an app with floating bubbles like Tweet Balloon](https://forum.xda-developers.com/showthread.php?t=2751745)).
|
After Width: | Height: | Size: 50 KiB |
|
@ -0,0 +1,30 @@
|
||||||
|
+++
|
||||||
|
title = "RIP Grooveshark."
|
||||||
|
summary = "I last used Grooveshark earlier today. I refreshed the page and found that it was dead. [...] I find myself feeling about Grooveshark similarly as when I found out that Megaupload had been shut down, and that many of my files were lost forever."
|
||||||
|
date = "2015-05-01T10:11:00-0600"
|
||||||
|
tags = ["grooveshark", "music", "music industry", "culture", "user generated content", "capitalism", "copyright"]
|
||||||
|
categories = ["Uncategorized"]
|
||||||
|
syndication = [
|
||||||
|
"https://medium.com/trwnh/rip-grooveshark-e28cbda5911b"
|
||||||
|
]
|
||||||
|
[[resources]]
|
||||||
|
name = "featured"
|
||||||
|
src = "rip.png"
|
||||||
|
+++
|
||||||
|
|
||||||
|
I last used Grooveshark earlier today. I refreshed the page and found that it was dead. Grooveshark has finally shut down. UMG et al have won. Effective immediately, the Grooveshark service no longer works, all music has been wiped entirely from the site, user data has been lost, curated playlists are inaccessible, VIP users are unable to get refunds, all social media accounts have been deleted, and the grooveshark.com website shows only an apology that admits wrongdoing and directs users to whymusicmatters.org, the RIAA’s website.
|
||||||
|
|
||||||
|
<figure>
|
||||||
|
<img src="rip.png">
|
||||||
|
<figcaption>This message almost reads like it was written by someone with a mafia gun pointed to their head.</figcaption>
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
<p class="has-pullquote after" data-pullquote="I find it amazing that the music labels found absolutely nothing of value in the remains of Grooveshark.">I find it amazing that the music labels found absolutely nothing of value in the remains of Grooveshark. They seized the intellectual property and the resources, and simply shuttered the rest. You couldn’t have done anything with the massive social media userbase? Grooveshark had 142,000 followers. You couldn’t have come up with a tweet to send to all of them? The Grooveshark service itself could have been legitimized, or could have had its infringing content deleted. Why wipe ALL of it? <strong>Why abandon a userbase of 35 million users?</strong> Surely you could do something more profitable or useful with Grooveshark than just shutting it down.</p>
|
||||||
|
|
||||||
|
<p>There are things that Grooveshark was legitimately good at. Things that weren’t illegal. Things that could be used to improve other services. Things like being able to share a song with a URL and have someone be able to listen to it without logging in. Being able to do the same with an entire playlist. Only YouTube does this, and YouTube of course includes additional overhead from having to load videos with the songs. (As an app, Atraci is built around loading audio-only YouTube, but sharing a URL does not allow for this functionality.) Spotify forces me to create an account and login. Could Spotify not monetize anonymous users by simply playing an ad before allowing users to listen to shared music? Spotify could even allow logged-in users to skip the pre-roll ad and start listening to the playlist immediately. As it currently stands, it’s not at all friendly to share music from Spotify to the public. Nor is it like that for any other music service besides YouTube.</p>
|
||||||
|
|
||||||
|
<p class="has-pullquote after" data-pullquote="[…] it’s the obscure stuff that Grooveshark excelled at. Nowhere else could you find that one-of-a-kind glitch song, or that video-game remix that someone made and decided to upload it to Grooveshark, because Grooveshark had an ecosystem built around user uploads.">As a personal user of Grooveshark VIP (renewed just a week ago on April 23, ironically), my losses don’t include the ability to access licensed content. I never cared for the licensed content, but it’s the obscure stuff that Grooveshark excelled at. Nowhere else could you find that one-of-a-kind glitch song, or that video-game remix that someone made and decided to upload it to Grooveshark, because Grooveshark had an ecosystem built around user uploads. No surprise that users chose to upload infringing songs at first, but I find myself feeling about Grooveshark similarly as when I found out that Megaupload had been shut down, and that many of my files were lost forever. The feeling I had walking into 11th-grade precalculus class on my phone, in disbelief and shock, realizing I would never be able to access the wealth of papercraft that was no longer accessible. The OSTs that people had meticulously created, the indie games that people had made, all of it was gone and I would never be able to download it again. And now, the feeling of sitting down at my computer, refreshing my Grooveshark tab, seeing that message, and realizing that my carefully-built playlists were gone, that I could never again easily discover new ambient and glitch and video-game music, that I could never again simply look for something that I wanted to try and figure out if it was worth downloading it and supporting that artist directly. Where are the broadcasts of people choosing tracks that are much better curated than anything you could ever find on Pandora?</p>
|
||||||
|
|
||||||
|
<p>UMG et al didn’t have to shut down Grooveshark, and it would have been wiser not to do so. There would have been much to gain from spinning Grooveshark into a licensed service, or allowing it to continue without infringing material, or even perhaps turning Grooveshark into a streaming service wholly owned by the major labels, [a concept I’ve been thinking about and might write about later.] Any of those options would have been much more beneficial to the music labels than to have simply wiped every record that Grooveshark had ever existed. And of course, the eternal debate about music piracy rages on. What possible effects did this closure have? What repercussions will be felt in the music piracy scene? Knowing how things always play out, absolutely nothing will happen. Music piracy will continue unabated, just as it has outside of Grooveshark all this time. Will people start to buy more music now that Grooveshark is dead? Probably not. Will any of this matter to anyone outside of the Grooveshark community? Nope, not a chance.</p>
|
||||||
|
|
||||||
|
<p>I will say this: I enjoyed all that Grooveshark offered while it lasted. I have bought more music due to Grooveshark and supported more artists than I ever would have without it. But absolutely none of that money would have ever gone to UMG, anyway.</p>
|
BIN
unified.test.hugo/content/_dump/articles/rip-grooveshark/rip.png
Normal file
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 23 KiB |
|
@ -0,0 +1,65 @@
|
||||||
|
+++
|
||||||
|
title = "Twitter is no longer a social network."
|
||||||
|
summary = ""
|
||||||
|
indieweb_type = "article"
|
||||||
|
tags = ["twitter", "social network", "social media", "analysis", "capitalism"]
|
||||||
|
categories = ["Communication"]
|
||||||
|
date = "2018-04-27T12:00:00-0600"
|
||||||
|
attachment = []
|
||||||
|
syndication = [
|
||||||
|
"https://medium.com/trwnh/twitter-is-no-longer-a-social-network-3cd03f51cd5f"
|
||||||
|
]
|
||||||
|
+++
|
||||||
|
|
||||||
|
<blockquote><a href="https://deadline.com/2018/04/twitter-reports-second-profitable-quarter-touts-fifa-world-cup-video-1202376120/"><p>"We are not a social network. We do not benefit from social graphs," Dorsey said. "People come to us when they're interested in events happening in the world or with a niche interest. We've been biasing a lot more of the service towards interest and topics."</p></a></blockquote>
|
||||||
|
|
||||||
|
<p>Perhaps this is something many of us suspected, as we stared at our timelines, watching them devolve steadily from 2014 onward. But for the first time ever, here it is, in written form, straight from the CEO, staring right back at us.</p>
|
||||||
|
|
||||||
|
<p>An admittance that Twitter, the social network, is dead.</p>
|
||||||
|
|
||||||
|
<blockquote>"We are not a social network."</blockquote>
|
||||||
|
|
||||||
|
<p>What are "we", then?</p>
|
||||||
|
|
||||||
|
<blockquote>"We do not benefit from social graphs."</blockquote>
|
||||||
|
|
||||||
|
<p>What does this mean for the social graphs we've all built over the past decade?</p>
|
||||||
|
|
||||||
|
<blockquote>"We've been biasing a lot more of the service towards interest and topics."</blockquote>
|
||||||
|
|
||||||
|
<p>What does this mean for those of us who used Twitter as a conversational platform and not as a source for "topics"?</p>
|
||||||
|
|
||||||
|
<p>Twitter, the social network, is dead.</p>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<p>Thanks, Jack. Twitter the social network is dead. That service that started out as a way to send status updates to your friends has been replaced by Twitter, a bloated, lumbering mess trying to force-feed you a stale diet of whatever Content™ floats to the top of the river of shit.</p>
|
||||||
|
|
||||||
|
<figure>
|
||||||
|
<img src="failwhale.png" alt="failwhale" />
|
||||||
|
<figcaption>Pictured above: a whale being lifted out of sludgy waters, which, aside from being reminiscent of a more whimiscal Twitter dot com from 2008, is also an apt metaphor for massively-viral content being surfaced from what is otherwise a toxic environment.</figcaption>
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
<p class="has-pullquote before right" data-pullquote="[Twitter] gave up on being an open, conversational platform, and they are now a content aggregator.">The short and bitter truth is that Twitter found out, regrettably, that being a conversational platform is not monetizable or profitable. It just took about four years for them to finally admit that they gave up on being an open, conversational platform and they are now a content aggregator.</p>
|
||||||
|
|
||||||
|
<p>Now, anyone looking for a conversational platform is not going to find it on Twitter. How can there be conversation when you can't even be sure of the visibility of your messages? I, for one, have already mostly abandoned this network-that-is-not-a-network-anymore, as have several others.</p>
|
||||||
|
|
||||||
|
<p>In a world where the big "social networks" are trying very hard to no longer be social networks — with Facebook trying to be your news feed and Twitter trying much the same before pivoting to surfacing viral content — there is a big void for people who still want to <em>communicate</em>. To be <em>social</em>, among their <em>network</em> of friends.</p>
|
||||||
|
|
||||||
|
<p>At least for me, I'm filling that void with Mastodon, which — *gasp* — doesn't try to be something that it's not. Just a way to keep up with other people, with no ads and no algorithmic shuffling — just your friends' statuses, in reverse-chronological order.</p>
|
||||||
|
|
||||||
|
<p>And even though Mastodon has only been usable for barely over a year, it's growing and improving quickly enough that I feel comfortable enough to use it full-time. It's absolutely refreshing to have a laid-back conversational hangout again. You can find me at <a href="https://mastodon.social/@trwnh">https://mastodon.social/@trwnh</a> for now — and if you want to learn more, go to <a href="https://joinmastodon.org">https://joinmastodon.org</a> and read about how it works.</p>
|
||||||
|
|
||||||
|
<p>It's probably going to be a bit of a shock at first, and hard to understand if you're used to being a product. But it makes way more sense when you do get it. Because we've been conditioned by the past decade to view everything through the lens of capital and profit; we've grown dependent on corporations to provide our platforms, for their benefit and not for ours. We're just a metric for them, another pair of eyeballs to view ads.</p>
|
||||||
|
|
||||||
|
<p class="has-pullquote before left" data-pullquote="We think it's ridiculous for things to be open and accessible and free, because we're used to everything being locked down and user-hostile.">We think it's ridiculous for things to be open and accessible and free, because we're used to everything being locked down and user-hostile. It's absolutely heartbreaking — the darkest timeline. But not inevitably so. We have an actual chance to redeem ourselves, however slim. And that starts with realizing where we came from — how everything used to be open and free, before it was encircled and carved up by corporations for profit. You can email anyone, on any service. You can call/text anyone, on any carrier. But NOT on the internet. That's sad.</p>
|
||||||
|
|
||||||
|
<p class="has-pullquote before right" data-pullquote="[E]verything used to be open and free, before it was encircled and carved up by corporations for profit.">Our phone networks are free.<br>
|
||||||
|
Our email networks are free.<br>
|
||||||
|
Our browsers are free.<br>
|
||||||
|
Our World Wide Web is free, with some challenges and attacks.<br>
|
||||||
|
Our internet platforms are not free. They are fiefdoms and empires.</p>
|
||||||
|
|
||||||
|
<p>Is this what we've sunk to? To give away our social interactions and let other people make money off of it? To surrender our discourse, our very zeitgeist, to entities that couldn't care less about any of that? To lock our public participation behind an advertising paywall?</p>
|
||||||
|
|
||||||
|
<p>It doesn't have to be this way.</p>
|
|
@ -0,0 +1,23 @@
|
||||||
|
2017-11-12 13:43 | https://mastodon.social/@trwnh/98991746572627131
|
||||||
|
|
||||||
|
problem with diaspora*'s aspects (and by extension, Google+ circles which aped it) is that it's a bidirectional metaphor for a unidirectional relationship. you're supposed to pick who can see a post, but they might not even follow you. I would understand if instead it functioned and was advertised as a way to split your timeline into multiple timelines. As is, sharing to aspects/circles/etc. is needlessly confusing.
|
||||||
|
|
||||||
|
although having a way to tag/categorize your own toots could come in handy as well, if you post about multiple disparate topics. it's a nightmare to maintain one Twitter account per interest/community.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
2017-12-17 09:55 | https://mastodon.social/@trwnh/99189033326279405
|
||||||
|
|
||||||
|
unrelated thought: been trying to hash out a solution to the "multiple accounts" issue with social media. namely: why/when do people use multiple accounts, and what features can be implemented to reduce the friction in using just one account? would appreciate feedback.
|
||||||
|
|
||||||
|
off the top of my head:
|
||||||
|
|
||||||
|
- private vs public accounts for trusted people (answered by privacy options on toots)
|
||||||
|
- multiple interests (not really solved currently; perhaps implementing a tag system and letting people mute certain tags? Diaspora*-style aspects can get complicated)
|
||||||
|
- separate identity (unsolvable and would be insecure to attempt with one account)
|
||||||
|
|
||||||
|
wrt multiple interests, this really is my biggest pain point with ANY social media (coming from someone who has had like 15 birdsite accounts at once)
|
||||||
|
|
||||||
|
perhaps not exactly tags, but having a category system like google+ would be nice and perhaps easiest to manage when considering tootboosts. but this also might complicate the issue? nevertheless, it could be optional (default behavior would be to boost to your profile, no categorization involved)
|
||||||
|
|
||||||
|
the tag approach would be easiest for your own toots, but the categories wouldn't be too bad and would also allow for separating different boosts
|
35
unified.test.hugo/content/_dump/blocklists-as-hoa.md
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
+++
|
||||||
|
draft = true
|
||||||
|
+++
|
||||||
|
|
||||||
|
it's a bit weird that some fedi blocklists use language like "fence" because whenever i see that, i don't think "safety", i think "homeowners association", and i think the HOA characterization of certain blocklist efforts is actually not wrong. it is reminiscent of the abstract desire for "safety" rather than any sort of concrete safety or just treatment. "freedom of association" only goes so far to justify punitive and destructive actions at an instance-state level
|
||||||
|
|
||||||
|
of course, what is to be done? what is a more appropriate solution? i think whenever such blocklists are circulated, it usually represents a failure mode at an institutional level. the rise of blocktogether on twitter was due to the systemic failure of their moderation. earlier fedi users may or may not remember the infamous "wil wheaton blocklist" that imported from infamous terf randi harper, who billed her list as "99% gaters and mras" (and i guess 1% trans ppl?)
|
||||||
|
|
||||||
|
so i think the "question of the day" now, is, what is the failure of fedi and how could we have avoided it and how can we proceed to mitigate it.
|
||||||
|
|
||||||
|
for my part i think it comes down to the "instance" model. no one cares if you have to ban someone from a building, but evicting them from their house or expelling them from their country is disproportionate. so naturally, it becomes an issue when the "community" and "living space" are the same thing.
|
||||||
|
|
||||||
|
every day more and more it becomes clear we need to restructure around actual communities at a separate layer.
|
||||||
|
|
||||||
|
similar to the dynamics of a cliquey community instance, but without the expanded audience that federation brings. imagine just turning off federation.
|
||||||
|
|
||||||
|
maybe in some ways that's exactly what is going on -- clique communities are feeling threatened by the inherent lack of control. overblocking is in that vein similar to defensive centralization; after all, what is centralization if not simply blocking *all* remotes? and the balance is set by how much control they want to wrest back.
|
||||||
|
|
||||||
|
i think the "objectionable" part to me is that clique mentality. especially as it tries to assert itself over others. the other day i had someone ask me which instance to join and i realized for the first time in 6 or 7 years that i didn't have an answer. they just wanted to exist. they didn't want to have to care about border controls and digital embargoes. and they didn't really have *any* good options.
|
||||||
|
|
||||||
|
there isn't really any well-connected generalist instance that isn't overly blocked or doesn't overly block. much less an art-focused one. or a fandom-based one. so they stayed on tumblr and discord even though they *want* to join fedi. there just isn't anywhere for them to find a home in an area that is both good to live in *and* free of HOA type behavior. they don't want a gated community and they don't want a place with drive-by harassment. and they want to actually reach people.
|
||||||
|
|
||||||
|
> [I] suspect that the reaching people, the lack of harassment, and lack of blocking are kind of corners of a triangle.
|
||||||
|
|
||||||
|
yeah it certainly does seem like a trilemma
|
||||||
|
|
||||||
|
instance moderation is absolutely a huge job if you want to stay on top of it. it can be easier if you take a reactive rather than proactive stance. but the problem with proactive stances is that you now need to judge someone *before* they have harassed you. and the way people approach recommended blocks, they might not have been harassed either. you'll never know the difference unless you investigate for yourself... and that's hard rn.
|
||||||
|
|
||||||
|
now, if people just said "hey we dont like them, they failed the vibe check and we're not gonna spill any tears", that's more respectable than making something up. i can't count how many times i've seen people blocked for reasons that are patently absurd if you know the people. you use a reclaimed slur, you get blocked for using slurs. somewhere along the line that becomes "hate speech". a while ago it was "federates with the usual suspects". guilt by association morphed into "alt fedi"
|
||||||
|
|
||||||
|
the hard part is... they're not always wrong! a lot of blocks make sense when you look into them. but it's a mix, and the false positive rate is a bit too high imo. and there's no indication when you lose friends over your admin's decisions. and the policies aren't always visible, bc some admins are hiding them now to prevent scrapers tracking them. it just becomes this whole uncertain mess where you never know who blocks who and why.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
my problem with oliphant is that there really should be a "tier negative one", given that the "tier 0" list doesn't have 100% consensus. my problem with thebadspace is that every single entry has the same tags, even where it makes no sense. my problem with blocklist culture in general is that there's zero accountability, review, or forgiveness built into them; often, they lack any sort of context, and if there is any reason given, the reasons are laughably flat-out ridiculous, incorrect, or inaccurate. i've seen blocks for being "channers" or "edgelord" being levelled against people who couldn't be any further than that. i've seen blocks for "no moderation" when no reports were filed. i've seen blocks for reasons such as "underage" or "reclaimed slurs" or vague unspecified "accusations". there's no differentiation between "hosts twitter crosspost bots" and "contains literal nazis that will send you death threats". fundamentally, i do not think that it is healthy to conflate safety with mere annoyance or a misalignment of "our" values. this is before you even get into the subjectivity of all such judgements... it is, of course, everyone's freedom of association to do whatever they want for themselves, but it is the point at which people start recommending or expecting that you do the same, that it then becomes a problem. and the real problem is not who you do or do not block. the problem is that there are no clear boundaries or clearly-established spaces or contexts for people's communications. you talk to someone that happens to be on someone else's shitlist, and you just might end up on that same shitlist for "federating with the usual suspects", where "the usual suspects" is an unbounded and growing set of people that seems to propagate further every time you look at it. it very frequently leads into policing who any given person mentions offhand or boosts in passing.
|
13
unified.test.hugo/content/_dump/default-server-paradigm.md
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
https://mastodon.social/@trwnh/110310774875374491
|
||||||
|
|
||||||
|
re: mastodon and matrix having "default servers" that end up being too big: i feel like if they were easier to selfhost it would be less of a problem. the "default server" paradigm is more effective when you can't easily set up other servers.
|
||||||
|
|
||||||
|
you ever try to host matrix? it's awful. like 2GB memory usage just for a single user in a big room.
|
||||||
|
|
||||||
|
mastodon is getting to be pretty similar, not because of the base software per se, but because of how many moving parts it has and how much resource usage accrues as a result. rails, postgres, redis, optional elasticsearch if you want working search, a nodejs streaming server and frontend... that's before you even get to the network traffic due to architectural decisions
|
||||||
|
|
||||||
|
sure, but you can at least block entire bad servers with little-to-no collateral damage. and you can also use allowlist federation or some other restriction mechanism to avoid fully open federation. just like avoiding fully open registrations.
|
||||||
|
|
||||||
|
i've oft thought about an opt-in federation of instances that require human approval for registrations. or a closed "federation" in the irc distributed sense.
|
||||||
|
|
||||||
|
it'll never happen because gargron wants more users, and approval-based signup makes a lot of disinterested people bounce before actually trying the software. but it's worth considering imo at least as a thought experiment
|
5
unified.test.hugo/content/_dump/documentation-first.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
https://mastodon.social/@trwnh/109826683171183861
|
||||||
|
|
||||||
|
if/when i get around to building [untitled social app] i want to set some hard design expectations for it before even thinking about if/when/how to release it (and which parts of it). there's a lot of expectations i want to challenge, i don't want to take anything for granted. if anything, whatever i build will simply be the practical application of my grand unified communication theory. it's as much an experiment and learning process as it is a tool or utility.
|
||||||
|
|
||||||
|
which is to say: any code i write or software i build, it will not be the primary product. the primary product will be the documentation and reasoning behind it. it will be in researching existing protocols and ecosystems, then identifying how they map onto the theoretical patterns and structures. nail the recipe before baking the cake.
|
40
unified.test.hugo/content/_dump/domain-number-system.md
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
https://mastodon.social/@trwnh/109965906891374818
|
||||||
|
|
||||||
|
we have a domain name system but why don't we have a domain number system
|
||||||
|
|
||||||
|
just like we can register human-friendly names, we should be able to register persistent machine-friendly numbers to websites and domains. the name and number are aliased together, or we map name => number => ip address
|
||||||
|
|
||||||
|
yes this idea is copied from xri i-names and i-numbers, it's one of the best ideas to come out of that effort (aside from delegation of authority at any point in the identifier)
|
||||||
|
|
||||||
|
the world if xri took off
|
||||||
|
|
||||||
|
future.jpg
|
||||||
|
|
||||||
|
i've talked/thought about doing something similar with webfinger, but the "authority delegation" bit is really hard without a persistent unchanging identifier in some common authoritative namespace. you can defer to some other DNS domain's webfinger endpoint, but that doesn't get rid of the fragility in expiring or reassigning domain names.
|
||||||
|
|
||||||
|
it's interesting that bluesky comes to a similar conclusion with its "placeholder" DID scheme, did:plc: -- identifiers are centralized around a single "PLC server". the DNS stuff maps to a did:plc: that gets resolved by the centralized resolution server.
|
||||||
|
|
||||||
|
we could do something similar with a centralized server/domain that did nothing but assign identifiers and map to current location... of course, that doesn't solve the problem, it just shifts the burden.
|
||||||
|
|
||||||
|
so here's a crackpot idea that requires "minimal" changes to the way the world works
|
||||||
|
|
||||||
|
1. register a TLD with the IANA/ICANN -- let's call it something like .uuid
|
||||||
|
2. allow anyone to register UUIDs on this TLD -- this should be as easy as registering any other domain name, but instead of getting to pick the name, it's auto-assigned to you
|
||||||
|
3. CNAME your desired public-facing domain name to the .uuid domain you registered
|
||||||
|
4. optionally: run some software to "reverse map" your .uuid URIs (Webfinger)
|
||||||
|
|
||||||
|
you could also use plain old HTTP redirects instead of Webfinger, if you trusted the thing at the other end to stay online
|
||||||
|
|
||||||
|
but the main thing would be being able to use
|
||||||
|
|
||||||
|
trwnh.com/some-resource => 05517367-0a6a-42c1-9810-9fcf264a505b.uuid/some-resource
|
||||||
|
|
||||||
|
and then later change trwnh.com to some other domain
|
||||||
|
|
||||||
|
any software/application dealing with identifiers SHOULD support using the "canonical" identifier, so you can signal that the .uuid-assigned URI is the canonical one
|
||||||
|
|
||||||
|
crucially, the .uuid registry would never expire, and probably it should be free. the goal is to never let the .uuid registration lapse, ever
|
||||||
|
|
||||||
|
maybe your domain name registrar could even host a reverse-mapping server for you, if they wanted to expand their services?
|
||||||
|
|
||||||
|
also something to consider: under what circumstances might an entire TLD lapse? like this is super unlikely, sure, but what happens if the entity behind some TLD in the IANA root zone database goes insolvent?
|
|
@ -0,0 +1,11 @@
|
||||||
|
+++
|
||||||
|
indieweb_type = "note"
|
||||||
|
tags = []
|
||||||
|
date = "2018-05-16T20:40:00Z"
|
||||||
|
attachment = []
|
||||||
|
original = "https://mastodon.social/@trwnh/100040916509633482"
|
||||||
|
+++
|
||||||
|
|
||||||
|
I like Mastodon but I'm scared it might become a de facto standard, basically the IE6 of the fediverse. there's plenty of opportunities to learn from the "mistakes" of Mastodon but the longer it remains the only usable experience, the more entrenched it becomes and the more all new projects will have to make concessions to maintain compatibility.
|
||||||
|
|
||||||
|
if i ever did go ahead with making my own alternative to mastodon, then i think i'd focus on making it MUCH easier to run and manage... but i'm all talk tho. i haven't got the time or energy to do it or to teach myself enough to be able to pursue it. :/
|
After Width: | Height: | Size: 755 KiB |
|
@ -0,0 +1,7 @@
|
||||||
|
+++
|
||||||
|
indieweb_type = "note"
|
||||||
|
tags = []
|
||||||
|
date = "2022-07-04T05:15:00Z"
|
||||||
|
attachment = ["image.png"]
|
||||||
|
+++
|
||||||
|
is this anything
|
|
@ -0,0 +1,8 @@
|
||||||
|
+++
|
||||||
|
indieweb_type = "note"
|
||||||
|
tags = ["boktai"]
|
||||||
|
date = "2018-04-15T19:54:00Z"
|
||||||
|
attachment = []
|
||||||
|
original = "https://mastodon.social/@trwnh/99865201213509948"
|
||||||
|
+++
|
||||||
|
i'm so emo that boktai 3 never launched outside of japan and also that boktai as a series is super dead and konami will never continue it and kojima probably can't/won't either due to copyright and the fact that it's been over 10 years since boktai ds and also kojima doesn't work for konami anymore UGH. where do you go to find quirky existentialist video games based on norse mythology and spaghetti westerns in the year of your lord 2018, you ask? you don't ;_; [#boktai](/tags/boktai)
|
|
@ -0,0 +1,8 @@
|
||||||
|
+++
|
||||||
|
indieweb_type = "note"
|
||||||
|
tags = []
|
||||||
|
date = "2018-04-25T04:16:00Z"
|
||||||
|
attachment = []
|
||||||
|
original = "https://mastodon.social/@trwnh/99918136079992108"
|
||||||
|
+++
|
||||||
|
hello friends it is almost may 2018 and i am down to using pretty much only mastodon and inoreader, and dropping into twitter once a week or so. it's been almost a year since i posted on instagram and at least half a year since i last logged in. i'm only really checking 2 of my twitter accounts and only very sporadically since january 2018. and about half a month ago or so i stopped absentmindedly browsing reddit. i... i'm almost free... wow, this feels... zen
|
|
@ -0,0 +1,14 @@
|
||||||
|
+++
|
||||||
|
indieweb_type = "note"
|
||||||
|
tags = []
|
||||||
|
date = "2018-05-03T04:53:00Z"
|
||||||
|
attachment = []
|
||||||
|
original = "https://mastodon.social/@trwnh/99963583159619719"
|
||||||
|
+++
|
||||||
|
sometimes you come across a youtube video from an alt-righter indirectly calling you out (or a thing you worked on) and you wanna respond, but... the video has 48 views and it's from september 2017, so i think i'll let it slide. it's not like it's logically consistent or significant, either.
|
||||||
|
|
||||||
|
i wonder if i'll ever be able to safely take credit for all the work i've done? not that i really have a reason to except perhaps if i'm in a really tight spot and need money to live... and i've mostly given up on twitter anyway, so it feels a bit... "late".
|
||||||
|
|
||||||
|
there's just a very real danger of fascists targeting me if they ever connect me to that account, though. "hey i maintained this thing for over a year, can anyone help me survive" doesn't really balance out with "oh, we finally have a name to track down and harass"
|
||||||
|
|
||||||
|
then again i've gotten private offers of donations and turned them down bc idk, i don't feel worthy of accepting money for it, it's simple (if occasionally time-consuming) to me, even if it helps hundreds or thousands of people on twitter... i don't really know what to do about the whole thing.
|
|
@ -0,0 +1,12 @@
|
||||||
|
+++
|
||||||
|
indieweb_type = "note"
|
||||||
|
tags = []
|
||||||
|
date = "2018-05-07T08:13:00Z"
|
||||||
|
attachment = []
|
||||||
|
original = "https://mastodon.social/@trwnh/99987017261137486"
|
||||||
|
+++
|
||||||
|
tbh like 90% of my day-to-day angst against capitalism is from how shit the smartphone market has become. if capitalism is so great then where the fuck is my <70mm-wide phone with a removable battery? fucking profit motives means that the entire market has abandoned me. I haven't been satisfied with any phone since 2010. hell, I'd buy an updated Nexus One with newer, more efficient internals.
|
||||||
|
|
||||||
|
"capitalism brought you your smartphone!" yeah, and that phone /fucking sucks/.
|
||||||
|
|
||||||
|
I wish I could build my own phone or have one built to spec, but alas, I do not own a machining and assembly factory, and I don't have the requisite circuitry knowledge... if only I could, I dunno, *cooperate* with some like-minded people, and we had *public ownership of those factories*...
|
|
@ -0,0 +1,8 @@
|
||||||
|
+++
|
||||||
|
indieweb_type = "note"
|
||||||
|
tags = []
|
||||||
|
date = "2018-05-09T14:48:00Z"
|
||||||
|
attachment = []
|
||||||
|
original = "https://mastodon.social/@trwnh/99999893512052394"
|
||||||
|
+++
|
||||||
|
physical bodies are so encumbering. it would be great to never again have to feel pain from a stomach too empty, or perhaps too full; to never have crusty eyes after sleeping too much, or perhaps too little; to never suffer from physiology that at best will decay, and at worst will actively punish us.
|