Compare commits

...

4 Commits

Author SHA1 Message Date
Nathan Schneider
912e209b80 Added contextual content to the web app, some aesthetic improvements 2025-12-02 22:28:15 -07:00
Nathan Schneider
f123db6faf Added description table to the ascii output 2025-12-02 15:27:09 -07:00
Nathan Schneider
8edc0df755 Updated bicorder.txt with last json change 2025-12-02 15:10:54 -07:00
Nathan Schneider
8691ee0f7f Replaced exclusive with monopolistic/pluralistic 2025-12-02 14:46:45 -07:00
11 changed files with 409 additions and 264 deletions

View File

@@ -56,8 +56,10 @@ def generate_bicorder_text(json_data):
lines = [] lines = []
# First pass: calculate maximum widths for left and right terms # First pass: calculate maximum widths for left and right terms
# Also collect all terms for the glossary
max_left_width = 0 max_left_width = 0
max_right_width = 0 max_right_width = 0
glossary_terms = {} # Dictionary to store term: description mappings
# Check diagnostic gradients # Check diagnostic gradients
for diagnostic_set in json_data.get("diagnostic", []): for diagnostic_set in json_data.get("diagnostic", []):
@@ -67,6 +69,12 @@ def generate_bicorder_text(json_data):
max_left_width = max(max_left_width, len(term_left)) max_left_width = max(max_left_width, len(term_left))
max_right_width = max(max_right_width, len(term_right)) max_right_width = max(max_right_width, len(term_right))
# Collect terms for glossary
if term_left:
glossary_terms[term_left] = gradient.get("term_left_description", "")
if term_right:
glossary_terms[term_right] = gradient.get("term_right_description", "")
# Check analysis items # Check analysis items
for analysis_item in json_data.get("analysis", []): for analysis_item in json_data.get("analysis", []):
term_left = analysis_item.get("term_left", "") term_left = analysis_item.get("term_left", "")
@@ -74,6 +82,12 @@ def generate_bicorder_text(json_data):
max_left_width = max(max_left_width, len(term_left)) max_left_width = max(max_left_width, len(term_left))
max_right_width = max(max_right_width, len(term_right)) max_right_width = max(max_right_width, len(term_right))
# Collect terms for glossary
if term_left:
glossary_terms[term_left] = analysis_item.get("term_left_description", "")
if term_right:
glossary_terms[term_right] = analysis_item.get("term_right_description", "")
# Calculate the width needed for centering # Calculate the width needed for centering
# Gradient line format: "{left_term} < [|||||||||] > {right_term}" # Gradient line format: "{left_term} < [|||||||||] > {right_term}"
# That's: max_left_width + 3 + 11 + 3 + max_right_width # That's: max_left_width + 3 + 11 + 3 + max_right_width
@@ -136,6 +150,31 @@ def generate_bicorder_text(json_data):
lines.append("") lines.append("")
# Glossary section
lines.append(center_text("GLOSSARY", center_width))
lines.append("")
# Generate pandoc-compatible table
# Sort terms alphabetically (case-insensitive) for consistent output
sorted_terms = sorted(glossary_terms.items(), key=lambda x: x[0].lower())
if sorted_terms:
# Calculate column widths for the table
max_term_width = max(len(term) for term, _ in sorted_terms)
max_term_width = max(max_term_width, len("Term")) # At least as wide as header
# Build the table
# Header row
lines.append(f"| {'Term'.ljust(max_term_width)} | Description |")
# Separator row
lines.append(f"| {'-' * max_term_width} | {'-' * 11} |")
# Data rows
for term, description in sorted_terms:
lines.append(f"| {term.ljust(max_term_width)} | {description} |")
lines.append("")
return "\n".join(lines) return "\n".join(lines)

View File

@@ -4,7 +4,9 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" type="image/x-icon" href="/favicon.ico" /> <link rel="icon" type="image/x-icon" href="/favicon.ico" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="apple-touch-icon" sizes="192x192" href="/icon-192.png" /> <link rel="apple-touch-icon" href="/icon-192.png" />
<link rel="icon" type="image/png" sizes="192x192" href="/icon-192.png" />
<link rel="icon" type="image/png" sizes="512x512" href="/icon-512.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
<meta name="description" content="A diagnostic tool for the study of protocols" /> <meta name="description" content="A diagnostic tool for the study of protocols" />
<meta name="theme-color" content="#1a1a2e" /> <meta name="theme-color" content="#1a1a2e" />

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@@ -0,0 +1,47 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<defs>
<linearGradient id="bgGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#1a1a2e;stop-opacity:1" />
<stop offset="100%" style="stop-color:#16213e;stop-opacity:1" />
</linearGradient>
<linearGradient id="accentGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#0f4c75;stop-opacity:1" />
<stop offset="100%" style="stop-color:#3282b8;stop-opacity:1" />
</linearGradient>
</defs>
<!-- Full bleed background for maskable icon -->
<rect width="512" height="512" fill="url(#bgGradient)"/>
<!-- Outer frame - scaled to fit safe zone (80% diameter = 40% radius from center) -->
<rect x="102" y="102" width="308" height="308" fill="none" stroke="url(#accentGradient)" stroke-width="6" rx="15"/>
<!-- Bicorder pattern "|#|" scaled for safe zone -->
<g font-family="'Courier New', monospace" font-weight="bold" text-anchor="middle">
<!-- Left bar -->
<text x="200" y="290" font-size="140" fill="#3282b8">|</text>
<!-- Center hash -->
<text x="256" y="290" font-size="140" fill="#bbe1fa">#</text>
<!-- Right bar -->
<text x="312" y="290" font-size="140" fill="#3282b8">|</text>
</g>
<!-- Decorative scan lines -->
<line x1="130" y1="160" x2="382" y2="160" stroke="#3282b8" stroke-width="2" opacity="0.3"/>
<line x1="130" y1="352" x2="382" y2="352" stroke="#3282b8" stroke-width="2" opacity="0.3"/>
<!-- Corner accents -->
<rect x="115" y="115" width="25" height="3" fill="#bbe1fa" opacity="0.8"/>
<rect x="115" y="115" width="3" height="25" fill="#bbe1fa" opacity="0.8"/>
<rect x="372" y="115" width="25" height="3" fill="#bbe1fa" opacity="0.8"/>
<rect x="394" y="115" width="3" height="25" fill="#bbe1fa" opacity="0.8"/>
<rect x="115" y="394" width="25" height="3" fill="#bbe1fa" opacity="0.8"/>
<rect x="115" y="372" width="3" height="25" fill="#bbe1fa" opacity="0.8"/>
<rect x="372" y="394" width="25" height="3" fill="#bbe1fa" opacity="0.8"/>
<rect x="394" y="372" width="3" height="25" fill="#bbe1fa" opacity="0.8"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -1,250 +0,0 @@
{
"name": "Protocol Bicorder",
"schema": "bicorder.schema.json",
"version": "1.1.0",
"description": "A diagnostic tool for the study of protocols",
"author": "Nathan Schneider",
"date_modified": "2025-11-21",
"metadata": {
"protocol": "IB Learner Profile",
"analyst": "Kids at the school",
"standpoint": "Students at the school",
"timestamp": "2025-11-24T03:16:26.468Z"
},
"diagnostic": [
{
"set_name": "Design",
"set_description": "How the protocol is created and remembered",
"gradients": [
{
"term_left": "explicit",
"term_left_description": "The design is stated explicitly somewhere that is accessible to participants",
"term_right": "implicit",
"term_right_description": "The design is not stated explicitly but is learned by participants in another way",
"value": 2,
"notes": null
},
{
"term_left": "precise",
"term_left_description": "The design is specified with a high level of precision that eliminates ambiguity in implementation",
"term_right": "interpretive",
"term_right_description": "The design is ambiguous, allowing participants a wide range of interpretation",
"value": 4,
"notes": null
},
{
"term_left": "institutional",
"term_left_description": "Design occurs through processes that involve powerful institutions and widespread recognition as normative",
"term_right": "vernacular",
"term_right_description": "Design occurs through evolving, peer-to-peer community interactions in order to suit participant-defined goals",
"value": 1,
"notes": null
},
{
"term_left": "documenting",
"term_left_description": "The primary purpose is to document or validate activity that is occurring",
"term_right": "enabling",
"term_right_description": "The primary purpose is to enable activity that might not happen otherwise",
"value": 5,
"notes": null
},
{
"term_left": "static",
"term_left_description": "Designed to be as fixed and unchanging as possible",
"term_right": "malleable",
"term_right_description": "Designed to be changed by participants according to evolving needs",
"value": 1,
"notes": null
},
{
"term_left": "technical",
"term_left_description": "Primarily concerned with interactions among technologies",
"term_right": "social",
"term_right_description": "Primarily concerned with interactions among people or groups",
"value": 9,
"notes": null
},
{
"term_left": "universal",
"term_left_description": "Addressed to a global audience",
"term_right": "particular",
"term_right_description": "Addressed to a specific community",
"value": 5,
"notes": null
},
{
"term_left": "durable",
"term_left_description": "Designed to be persistently available",
"term_right": "ephemeral",
"term_right_description": "Designed to vanish when no longer needed",
"value": 1,
"notes": null
}
]
},
{
"set_name": "Entanglement",
"set_description": "How the protocol relates with participant agents",
"gradients": [
{
"term_left": "macro",
"term_left_description": "Operates at large scales involving many participants or broad scope",
"term_right": "micro",
"term_right_description": "Operates at small scales with few participants or narrow scope",
"value": 3,
"notes": null
},
{
"term_left": "sovereign",
"term_left_description": "A distinctive operating logic, not subject to any other entity",
"term_right": "subsidiary",
"term_right_description": "An operating logic under the control of a particular entity",
"value": 8,
"notes": null
},
{
"term_left": "self-enforcing",
"term_left_description": "Rules are automatically enforced through its own mechanisms",
"term_right": "enforced",
"term_right_description": "Rules require external enforcement by authorities or institutions",
"value": 7,
"notes": null
},
{
"term_left": "abstract",
"term_left_description": "Participants learn the protocol by studying it intellectually",
"term_right": "embodied",
"term_right_description": "Participants learn the protocol by physically practicing it",
"value": 2,
"notes": null
},
{
"term_left": "obligatory",
"term_left_description": "Participation is compulsory for a certain class of agents",
"term_right": "voluntary",
"term_right_description": "Participation in the protocol is optional and not coerced",
"value": 2,
"notes": null
},
{
"term_left": "flocking",
"term_left_description": "Coordination occurs through centralized direction or direct mimicry",
"term_right": "swarming",
"term_right_description": "Coordination occurs through distributed interactions without central direction",
"value": 8,
"notes": null
},
{
"term_left": "defensible",
"term_left_description": "Strong boundaries and protections against external influence",
"term_right": "exposed",
"term_right_description": "Weak boundaries and vulnerable to external influence",
"value": null,
"notes": null
},
{
"term_left": "exclusive",
"term_left_description": "Excludes the use of other protocols that might be available to adopt",
"term_right": "non-exclusive",
"term_right_description": "Does not exclude the use of any other protocols",
"value": 8,
"notes": null
}
]
},
{
"set_name": "Experience",
"set_description": "How the protocol is perceived in the context of its implementation",
"gradients": [
{
"term_left": "sufficient",
"term_left_description": "Adequately meets the needs and goals of participants",
"term_right": "insufficient",
"term_right_description": "Does not, on its own, adequately meet the needs and goals of participants",
"value": 8,
"notes": null
},
{
"term_left": "crystallized",
"term_left_description": "Content and meaning are settled and widely agreed upon",
"term_right": "contested",
"term_right_description": "Content and meaning are disputed or under debate",
"value": 1,
"notes": null
},
{
"term_left": "trust-evading",
"term_left_description": "Minimizes the need for trust among participants",
"term_right": "trust-inducing",
"term_right_description": "Relies on or cultivates trust among participants",
"value": 9,
"notes": null
},
{
"term_left": "predictable",
"term_left_description": "Produces expected and consistent outcomes",
"term_right": "emergent",
"term_right_description": "Produces unexpected or novel outcomes",
"value": 9,
"notes": null
},
{
"term_left": "exclusion",
"term_left_description": "The protocol creates barriers or excludes certain participants",
"term_right": "inclusion",
"term_right_description": "The protocol reduces barriers and includes diverse participants",
"value": 9,
"notes": null
},
{
"term_left": "Kafka",
"term_left_description": "Fosters experiences of absurd complexity, alienation, and powerlessness",
"term_right": "Whitehead",
"term_right_description": "Enables participants to carry out desired activities with less work or thought",
"value": 6,
"notes": null
},
{
"term_left": "dead",
"term_left_description": "Not actively utilized by relevant participants",
"term_right": "alive",
"term_right_description": "Actively utilized by relevant participants",
"value": 8,
"notes": null
}
]
}
],
"analysis": [
{
"term_left": "hardness",
"term_left_description": "The protocol tends toward properties characterized by hardness",
"term_right": "softness",
"term_right_description": "The protocol tends toward properties characterized by softness",
"instructions": "Take all the 'value' fields in the gradients above and determine a mean. Round it to the nearest integer. That is the 'value' here.",
"automated": true,
"value": 5,
"notes": null
},
{
"term_left": "polarized",
"term_left_description": "The analyst tended toward more extreme high or low readings",
"term_right": "centrist",
"term_right_description": "The analyst tended toward readings at the middle of the gradients",
"instructions": "Take all the 'value' fields in the gradients above. Assess their degree of polarization. For instance, if all the values are either 1 or 9, the output would be 1, and if all of them are 5, the output would be 9.",
"automated": true,
"value": 3,
"notes": null
},
{
"term_left": "not useful",
"term_left_description": "The bicorder was not useful or relevant for analyzing this protocol",
"term_right": "very useful",
"term_right_description": "The bicorder was very useful and relevant for analyzing this protocol",
"instructions": "Evaluate the usefulness of this bicorder as a tool for analyzing this protocol, considering whether the gradient terms seemed revealing or irrelevant.",
"automated": false,
"value": 7,
"notes": null
}
]
}

View File

@@ -5,6 +5,7 @@
import MetadataFields from './components/MetadataFields.svelte'; import MetadataFields from './components/MetadataFields.svelte';
import AnalysisDisplay from './components/AnalysisDisplay.svelte'; import AnalysisDisplay from './components/AnalysisDisplay.svelte';
import ExportControls from './components/ExportControls.svelte'; import ExportControls from './components/ExportControls.svelte';
import HelpModal from './components/HelpModal.svelte';
// Load bicorder data from build-time constant // Load bicorder data from build-time constant
let data: BicorderState = JSON.parse(JSON.stringify(__BICORDER_DATA__)); let data: BicorderState = JSON.parse(JSON.stringify(__BICORDER_DATA__));
@@ -19,6 +20,7 @@
let viewMode: ViewMode = 'focused'; // Focused is default let viewMode: ViewMode = 'focused'; // Focused is default
let currentScreen = 0; let currentScreen = 0;
let refreshKey = 0; // Used to force component refresh in focused mode let refreshKey = 0; // Used to force component refresh in focused mode
let isHelpOpen = false;
// Screen types // Screen types
type Screen = type Screen =
@@ -212,10 +214,17 @@
location.reload(); location.reload();
} }
} }
function openHelp() {
isHelpOpen = true;
}
</script> </script>
<HelpModal bind:isOpen={isHelpOpen} />
<main> <main>
<div class="header"> <div class="header">
<button class="help-btn" on:click={openHelp} aria-label="About the Bicorder">?</button>
<div class="title">Protocol</div> <div class="title">Protocol</div>
<div class="title">BICORDER</div> <div class="title">BICORDER</div>
<button class="mode-toggle" on:click={toggleViewMode} aria-label="Toggle view mode"> <button class="mode-toggle" on:click={toggleViewMode} aria-label="Toggle view mode">
@@ -225,6 +234,10 @@
{#if viewMode === 'list'} {#if viewMode === 'list'}
<!-- LIST MODE: Show all sections --> <!-- LIST MODE: Show all sections -->
<div class="description">
<p>A diagnostic tool for the study of protocols</p>
</div>
<MetadataFields <MetadataFields
metadata={data.metadata} metadata={data.metadata}
on:update={handleMetadataUpdate} on:update={handleMetadataUpdate}
@@ -277,6 +290,12 @@
{:else} {:else}
<!-- FOCUSED MODE: Show one screen at a time --> <!-- FOCUSED MODE: Show one screen at a time -->
{#if currentScreen === 0}
<div class="description">
<p>A diagnostic tool for the study of protocols</p>
</div>
{/if}
<div class="focused-container"> <div class="focused-container">
{#if currentScreenData.type === 'metadata'} {#if currentScreenData.type === 'metadata'}
<div class="focused-screen"> <div class="focused-screen">
@@ -393,6 +412,10 @@
</div> </div>
</div> </div>
{/if} {/if}
<footer class="footer">
<p>Initiated by <a href="https://nathanschneider.info" rel="nofollow">Nathan Schneider</a>; <a href="https://git.medlab.host/ntnsndr/protocol-bicorder/src/branch/main/bicorder-app" rel="nofollow">source code</a> licensed under the <a href="https://firstdonoharm.dev/" rel="nofollow">Hippocratic License</a> (do no harm!).</p>
</footer>
</main> </main>
<style> <style>
@@ -407,7 +430,7 @@
.header { .header {
text-align: center; text-align: center;
margin-bottom: 2rem; margin-bottom: 1rem;
border-bottom: 2px solid var(--border-color); border-bottom: 2px solid var(--border-color);
padding-bottom: 1rem; padding-bottom: 1rem;
position: relative; position: relative;
@@ -419,6 +442,32 @@
letter-spacing: 0.2rem; letter-spacing: 0.2rem;
} }
.help-btn {
position: absolute;
top: 0;
left: 0;
width: 2rem;
height: 2rem;
padding: 0;
font-size: 1.2rem;
font-weight: bold;
cursor: pointer;
background: var(--bg-color);
color: var(--fg-color);
border: 1px solid var(--border-color);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
opacity: 0.4;
transition: opacity 0.2s, background-color 0.2s;
}
.help-btn:hover {
opacity: 0.8;
background-color: var(--input-bg);
}
.mode-toggle { .mode-toggle {
position: absolute; position: absolute;
top: 0; top: 0;
@@ -440,6 +489,33 @@
border-color: var(--border-color); border-color: var(--border-color);
} }
.description {
text-align: center;
padding: 1rem;
margin-bottom: 2rem;
border: 1px solid var(--border-color);
background-color: var(--input-bg);
font-size: 0.9rem;
line-height: 1.6;
}
.description p {
margin: 0;
}
.footer {
margin-top: auto;
padding: 2rem 1rem 1rem;
border-top: 2px solid var(--border-color);
text-align: center;
font-size: 0.85rem;
opacity: 0.7;
}
.footer p {
margin: 0.5rem 0;
}
.diagnostic-set, .analysis-section { .diagnostic-set, .analysis-section {
margin: 2rem 0; margin: 2rem 0;
padding: 1rem 0; padding: 1rem 0;
@@ -502,9 +578,7 @@
} }
.gradient-focused { .gradient-focused {
padding: 2rem; padding: 0;
border: 2px solid var(--border-color);
background-color: var(--bg-color);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 2rem; gap: 2rem;
@@ -603,11 +677,28 @@
font-size: 1rem; font-size: 1rem;
} }
.help-btn {
width: 1.75rem;
height: 1.75rem;
font-size: 1rem;
}
.mode-toggle { .mode-toggle {
font-size: 0.85rem; font-size: 0.85rem;
padding: 0.25rem 0.5rem; padding: 0.25rem 0.5rem;
} }
.description {
padding: 0.75rem;
font-size: 0.85rem;
margin-bottom: 1.5rem;
}
.footer {
padding: 1.5rem 0.5rem 0.5rem;
font-size: 0.8rem;
}
.progress-bar { .progress-bar {
font-size: 0.85rem; font-size: 0.85rem;
letter-spacing: 0.05rem; letter-spacing: 0.05rem;
@@ -622,7 +713,7 @@
} }
.gradient-focused { .gradient-focused {
padding: 1rem; padding: 0;
gap: 1.5rem; gap: 1.5rem;
} }

View File

@@ -0,0 +1,146 @@
<script lang="ts">
export let isOpen = false;
function closeModal() {
isOpen = false;
}
function handleKeyDown(e: KeyboardEvent) {
if (e.key === 'Escape') {
closeModal();
}
}
</script>
<svelte:window on:keydown={handleKeyDown} />
{#if isOpen}
<div class="modal-backdrop" on:click={closeModal} on:keydown={() => {}} role="button" tabindex="-1">
<div class="modal-content" on:click|stopPropagation on:keydown={() => {}} role="dialog" aria-modal="true">
<div class="modal-header">
<h2>Help & Instructions</h2>
<button class="close-btn" on:click={closeModal} aria-label="Close help">×</button>
</div>
<div class="modal-body">
<p>The Protocol Bicorder is a diagnostic tool for the study of protocols. It allows a human or machine user to evaluate protocol characteristics along a series of gradients between opposing terms.</p>
<p>The name is a tribute to the tricorder, a fictional device in the Star Trek universe that the characters can use to obtain all manner of empirical data about their surroundings.</p>
<p>To carry out the diagnostic, the analyst should consider the protocol from the perspective of one of the <code>gradients</code> at a time. The gradients invite the analyst to determine where the protocol lies between two terms.</p>
<p>This is inevitably an interpretive exercise, but do your best to identify the most accurate <code>value</code>, with <code>1</code> being closest to <code>term_left</code> and <code>9</code> being closest to <code>term_right</code>.</p>
<p>Choosing a <code>value</code> in the middle, such as <code>5</code>, can mean "a bit of both." Leaving the gradient <code>value</code> as <code>null</code> means "not applicable."</p>
<p>There is a <code>notes</code> field for the analyst to add additional context or explanation.</p>
<p>The <code>shortform</code> option allows the use of an abbreviated version of the bicorder, including only the most salient gradients.</p>
<p>Happy protocol watching!</p>
</div>
</div>
</div>
{/if}
<style>
.modal-backdrop {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.7);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
padding: 1rem;
}
.modal-content {
background-color: var(--bg-color);
border: 2px solid var(--border-color);
max-width: 600px;
width: 100%;
max-height: 80vh;
display: flex;
flex-direction: column;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1.5rem;
border-bottom: 2px solid var(--border-color);
}
.modal-header h2 {
margin: 0;
font-size: 1.3rem;
letter-spacing: 0.1rem;
}
.close-btn {
background: none;
border: none;
color: var(--fg-color);
font-size: 2rem;
line-height: 1;
cursor: pointer;
padding: 0;
width: 2rem;
height: 2rem;
display: flex;
align-items: center;
justify-content: center;
opacity: 0.6;
transition: opacity 0.2s;
}
.close-btn:hover {
opacity: 1;
}
.modal-body {
padding: 1.5rem;
overflow-y: auto;
line-height: 1.6;
}
.modal-body h3 {
margin-top: 1.5rem;
margin-bottom: 0.75rem;
font-size: 1.1rem;
letter-spacing: 0.05rem;
}
.modal-body p {
margin-bottom: 1rem;
}
.modal-body code {
font-family: inherit;
font-size: inherit;
background: none;
padding: 0;
color: #888;
}
.modal-body strong {
color: var(--accent-color);
}
@media (max-width: 768px) {
.modal-content {
max-height: 90vh;
}
.modal-header {
padding: 1rem;
}
.modal-header h2 {
font-size: 1.1rem;
}
.modal-body {
padding: 1rem;
}
}
</style>

View File

@@ -15,7 +15,7 @@ export default defineConfig({
svelte(), svelte(),
VitePWA({ VitePWA({
registerType: 'autoUpdate', registerType: 'autoUpdate',
includeAssets: ['favicon.ico', 'favicon.svg', 'icon-192.png', 'icon-512.png'], includeAssets: ['favicon.ico', 'favicon.svg', 'icon-192.png', 'icon-512.png', 'icon-maskable-192.png', 'icon-maskable-512.png'],
manifest: { manifest: {
name: 'Protocol Bicorder', name: 'Protocol Bicorder',
short_name: 'Bicorder', short_name: 'Bicorder',
@@ -36,6 +36,18 @@ export default defineConfig({
type: 'image/png', type: 'image/png',
purpose: 'any' purpose: 'any'
}, },
{
src: '/icon-maskable-192.png',
sizes: '192x192',
type: 'image/png',
purpose: 'maskable'
},
{
src: '/icon-maskable-512.png',
sizes: '512x512',
type: 'image/png',
purpose: 'maskable'
},
{ {
src: '/icon.svg', src: '/icon.svg',
sizes: 'any', sizes: 'any',

View File

@@ -1,10 +1,10 @@
{ {
"name": "Protocol Bicorder", "name": "Protocol Bicorder",
"schema": "bicorder.schema.json", "schema": "bicorder.schema.json",
"version": "1.2.0", "version": "1.2.1",
"description": "A diagnostic tool for the study of protocols", "description": "A diagnostic tool for the study of protocols",
"author": "Nathan Schneider", "author": "Nathan Schneider",
"date_modified": "2025-11-21", "date_modified": "2025-12-02",
"metadata": { "metadata": {
"protocol": null, "protocol": null,
@@ -161,10 +161,10 @@
"shortform": false "shortform": false
}, },
{ {
"term_left": "exclusive", "term_left": "monopolistic",
"term_left_description": "Excludes the use of other protocols that might be available to adopt", "term_left_description": "Excludes the use of other protocols that might be available to adopt",
"term_right": "non-exclusive", "term_right": "pluralistic",
"term_right_description": "Does not exclude the use of any other protocols", "term_right_description": "Interoperates with other protocols and does not exclude their use",
"value": null, "value": null,
"notes": null, "notes": null,
"shortform": false "shortform": false

View File

@@ -9,7 +9,7 @@
DESIGN DESIGN
explicit < [|||||||||] > implicit explicit < [|||||||||] > implicit
precise < [|||||||||] > interpretive precise < [|||||||||] > interpretive
elite < [|||||||||] > vernacular institutional < [|||||||||] > vernacular
documenting < [|||||||||] > enabling documenting < [|||||||||] > enabling
static < [|||||||||] > malleable static < [|||||||||] > malleable
technical < [|||||||||] > social technical < [|||||||||] > social
@@ -24,7 +24,7 @@ self-enforcing < [|||||||||] > enforced
obligatory < [|||||||||] > voluntary obligatory < [|||||||||] > voluntary
flocking < [|||||||||] > swarming flocking < [|||||||||] > swarming
defensible < [|||||||||] > exposed defensible < [|||||||||] > exposed
exclusive < [|||||||||] > non-exclusive monopolistic < [|||||||||] > pluralistic
EXPERIENCE EXPERIENCE
sufficient < [|||||||||] > insufficient sufficient < [|||||||||] > insufficient
@@ -38,3 +38,61 @@ self-enforcing < [|||||||||] > enforced
ANALYSIS ANALYSIS
hardness < [|||||||||] > softness hardness < [|||||||||] > softness
polarized < [|||||||||] > centrist polarized < [|||||||||] > centrist
not useful < [|||||||||] > very useful
GLOSSARY
| Term | Description |
| -------------- | ----------- |
| abstract | Participants learn the protocol by studying it intellectually |
| alive | Actively utilized by relevant participants |
| centrist | The analyst tended toward readings at the middle of the gradients |
| contested | Content and meaning are disputed or under debate |
| crystallized | Content and meaning are settled and widely agreed upon |
| dead | Not actively utilized by relevant participants |
| defensible | Strong boundaries and protections against external influence |
| documenting | The primary purpose is to document or validate activity that is occurring |
| durable | Designed to be persistently available |
| embodied | Participants learn the protocol by physically practicing it |
| emergent | Produces unexpected or novel outcomes |
| enabling | The primary purpose is to enable activity that might not happen otherwise |
| enforced | Rules require external enforcement by authorities or institutions |
| ephemeral | Designed to vanish when no longer needed |
| exclusion | The protocol creates barriers or excludes certain participants |
| explicit | The design is stated explicitly somewhere that is accessible to participants |
| exposed | Weak boundaries and vulnerable to external influence |
| flocking | Coordination occurs through centralized direction or direct mimicry |
| hardness | The protocol tends toward properties characterized by hardness |
| implicit | The design is not stated explicitly but is learned by participants in another way |
| inclusion | The protocol reduces barriers and includes diverse participants |
| institutional | Design occurs through processes that involve powerful institutions and widespread recognition as normative |
| insufficient | Does not, on its own, adequately meet the needs and goals of participants |
| interpretive | The design is ambiguous, allowing participants a wide range of interpretation |
| Kafka | Fosters experiences of absurd complexity, alienation, and powerlessness |
| macro | Operates at large scales involving many participants or broad scope |
| malleable | Designed to be changed by participants according to evolving needs |
| micro | Operates at small scales with few participants or narrow scope |
| monopolistic | Excludes the use of other protocols that might be available to adopt |
| not useful | The bicorder was not useful or relevant for analyzing this protocol |
| obligatory | Participation is compulsory for a certain class of agents |
| particular | Addressed to a specific community |
| pluralistic | Interoperates with other protocols and does not exclude their use |
| polarized | The analyst tended toward more extreme high or low readings |
| precise | The design is specified with a high level of precision that eliminates ambiguity in implementation |
| predictable | Produces expected and consistent outcomes |
| self-enforcing | Rules are automatically enforced through its own mechanisms |
| social | Primarily concerned with interactions among people or groups |
| softness | The protocol tends toward properties characterized by softness |
| sovereign | A distinctive operating logic, not subject to any other entity |
| static | Designed to be as fixed and unchanging as possible |
| subsidiary | An operating logic under the control of a particular entity |
| sufficient | Adequately meets the needs and goals of participants |
| swarming | Coordination occurs through distributed interactions without central direction |
| technical | Primarily concerned with interactions among technologies |
| trust-evading | Minimizes the need for trust among participants |
| trust-inducing | Relies on or cultivates trust among participants |
| universal | Addressed to a global audience |
| vernacular | Design occurs through evolving, peer-to-peer community interactions in order to suit participant-defined goals |
| very useful | The bicorder was very useful and relevant for analyzing this protocol |
| voluntary | Participation in the protocol is optional and not coerced |
| Whitehead | Enables participants to carry out desired activities with less work or thought |