Download index.html from HirModel/trace-capsule-bridge-prototype: direct link, hf CLI and curl.
- Browser
- Download file 31.8 kB
-
https://huggingface.co/spaces/HirModel/trace-capsule-bridge-prototype/resolve/main/index.html
- Command line
-
hf download hf://spaces/HirModel/trace-capsule-bridge-prototype/index.html
-
curl -L -o index.html https://huggingface.co/spaces/HirModel/trace-capsule-bridge-prototype/resolve/main/index.html
31.8 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | |
| <title>C2PA / Adobe Bridge Layer — Trace Capsule Prototype v0.1</title> | |
| <meta name="description" content="Independent public-review prototype demonstrating a lightweight Trace Capsule bridge layer for provenance-bearing content: credential summary, HIR/OAM pressure check, loop state, and source-return." /> | |
| <meta property="og:title" content="C2PA / Adobe Bridge Layer — Trace Capsule Prototype v0.1" /> | |
| <meta property="og:description" content="A public-review demo showing how provenance-bearing content can preserve bounded interpretation, attribution, uncertainty, loop state, and source-return after visibility." /> | |
| <meta name="theme-color" content="#0f65d6" /> | |
| <style> | |
| :root { | |
| --bg: #f5f9ff; | |
| --panel: #ffffff; | |
| --ink: #14233b; | |
| --muted: #5a6880; | |
| --line: #d9e6f7; | |
| --blue: #0f65d6; | |
| --blue-2: #0b83e6; | |
| --cyan: #13bfd0; | |
| --green: #17875d; | |
| --amber: #9b6400; | |
| --orange: #c7511f; | |
| --red: #b42318; | |
| --violet: #6544c5; | |
| --shadow: 0 22px 70px rgba(16, 67, 136, .16); | |
| --radius: 22px; | |
| --mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace; | |
| --sans: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; | |
| } | |
| * { box-sizing: border-box; } | |
| body { | |
| margin: 0; | |
| font-family: var(--sans); | |
| color: var(--ink); | |
| background: | |
| radial-gradient(circle at 18% 0%, rgba(19,191,208,.28), transparent 32rem), | |
| radial-gradient(circle at 80% 0%, rgba(15,101,214,.20), transparent 28rem), | |
| linear-gradient(180deg, #eef7ff 0%, var(--bg) 46%, #ffffff 100%); | |
| line-height: 1.5; | |
| } | |
| a { color: var(--blue); } | |
| .skip-link { | |
| position: absolute; | |
| left: -999px; | |
| top: 1rem; | |
| background: var(--ink); | |
| color: #fff; | |
| padding: .75rem 1rem; | |
| border-radius: .75rem; | |
| z-index: 1000; | |
| } | |
| .skip-link:focus { left: 1rem; } | |
| .wrap { max-width: 1180px; margin: 0 auto; padding: 28px; } | |
| header.hero { | |
| position: relative; | |
| overflow: hidden; | |
| border: 1px solid rgba(15,101,214,.14); | |
| border-radius: 30px; | |
| background: rgba(255,255,255,.78); | |
| box-shadow: var(--shadow); | |
| padding: clamp(24px, 5vw, 58px); | |
| margin: 22px 0 26px; | |
| } | |
| .hero::before { | |
| content: ""; | |
| position: absolute; | |
| inset: -1px; | |
| background: radial-gradient(circle at 78% 20%, rgba(19,191,208,.18), transparent 22rem); | |
| pointer-events: none; | |
| } | |
| .hero > * { position: relative; z-index: 1; } | |
| .kicker { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: .55rem; | |
| font-size: .82rem; | |
| font-weight: 800; | |
| letter-spacing: .08em; | |
| text-transform: uppercase; | |
| color: #0a4ea8; | |
| background: #eaf4ff; | |
| border: 1px solid #cfe5ff; | |
| border-radius: 999px; | |
| padding: .42rem .75rem; | |
| } | |
| .pin { | |
| width: 24px; height: 24px; border-radius: 50%; | |
| display: inline-grid; place-items: center; | |
| background: #111827; color: #fff; | |
| font-size: .68rem; font-weight: 900; | |
| letter-spacing: -.03em; | |
| } | |
| h1 { font-size: clamp(2.25rem, 6vw, 5.4rem); line-height: .94; margin: 20px 0 14px; letter-spacing: -.06em; } | |
| h2 { font-size: clamp(1.35rem, 2.6vw, 2.25rem); letter-spacing: -.035em; margin: 0 0 1rem; } | |
| h3 { font-size: 1.05rem; margin: 0 0 .65rem; letter-spacing: -.02em; } | |
| .subtitle { max-width: 860px; color: var(--muted); font-size: clamp(1.05rem, 2vw, 1.35rem); margin: 0 0 28px; } | |
| .boundary { | |
| display: grid; gap: 10px; | |
| max-width: 960px; | |
| border: 1px solid #d9e6f7; | |
| background: #f8fbff; | |
| border-radius: 18px; | |
| padding: 16px 18px; | |
| color: #41516c; | |
| } | |
| .boundary strong { color: var(--ink); } | |
| .flow { | |
| display: grid; | |
| grid-template-columns: repeat(7, minmax(0, 1fr)); | |
| gap: 10px; | |
| align-items: stretch; | |
| margin: 24px 0 8px; | |
| } | |
| .flow-step { | |
| min-height: 82px; | |
| border: 1px solid var(--line); | |
| border-radius: 18px; | |
| background: #fff; | |
| padding: 12px; | |
| box-shadow: 0 8px 28px rgba(41, 89, 153, .08); | |
| } | |
| .flow-step span { display:block; font-size:.72rem; color:var(--muted); text-transform:uppercase; letter-spacing:.08em; font-weight:800; } | |
| .flow-step b { display:block; margin-top:6px; font-size:.98rem; } | |
| .grid { display: grid; gap: 20px; } | |
| .grid.two { grid-template-columns: minmax(0, .95fr) minmax(0, 1.05fr); } | |
| .grid.three { grid-template-columns: repeat(3, minmax(0, 1fr)); } | |
| .card { | |
| background: var(--panel); | |
| border: 1px solid var(--line); | |
| border-radius: var(--radius); | |
| padding: 20px; | |
| box-shadow: 0 12px 40px rgba(27, 69, 128, .08); | |
| } | |
| .section { margin: 20px 0; } | |
| .small { font-size: .9rem; color: var(--muted); } | |
| .micro { font-size: .78rem; color: var(--muted); } | |
| .pill-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; } | |
| .pill { | |
| display: inline-flex; align-items: center; gap: .35rem; | |
| border: 1px solid #d7e5f7; background: #f7fbff; color: #31506e; | |
| border-radius: 999px; padding: .38rem .65rem; font-size: .78rem; font-weight: 750; | |
| } | |
| .pill.blue { background: #eaf4ff; border-color:#cfe5ff; color:#0a4ea8; } | |
| .pill.green { background: #eaf8f3; border-color:#c7efdf; color:#126a49; } | |
| .pill.amber { background: #fff6e4; border-color:#f5d68c; color:#7a4b00; } | |
| .pill.red { background: #fff0ef; border-color:#ffd1ce; color:#9c1d15; } | |
| .credential-media { | |
| border-radius: 18px; | |
| min-height: 210px; | |
| background: | |
| linear-gradient(135deg, rgba(11,131,230,.18), rgba(19,191,208,.16)), | |
| radial-gradient(circle at 30% 25%, rgba(255,255,255,.95), transparent 14rem), | |
| linear-gradient(160deg, #0e3866, #0b83e6 46%, #93e2ee 100%); | |
| position: relative; | |
| overflow: hidden; | |
| border: 1px solid #cfe5ff; | |
| } | |
| .credential-media::before, .credential-media::after { | |
| content: ""; position: absolute; border-radius: 999px; background: rgba(255,255,255,.34); | |
| } | |
| .credential-media::before { width: 300px; height: 300px; right: -90px; top: -110px; } | |
| .credential-media::after { width: 460px; height: 160px; left: -160px; bottom: -60px; transform: rotate(-8deg); } | |
| .media-label { | |
| position: absolute; left: 14px; top: 14px; z-index: 1; | |
| display: inline-flex; gap: .45rem; align-items: center; | |
| color: #10243c; background: rgba(255,255,255,.86); | |
| border: 1px solid rgba(255,255,255,.75); | |
| border-radius: 999px; padding: .45rem .7rem; font-size: .78rem; font-weight: 800; | |
| } | |
| dl.meta { display: grid; gap: 10px; margin: 16px 0 0; } | |
| .row { | |
| display: grid; grid-template-columns: 150px minmax(0,1fr); gap: 12px; | |
| padding: 10px 0; border-top: 1px solid #eef3fb; | |
| } | |
| .row dt { color: var(--muted); font-weight: 750; } | |
| .row dd { margin: 0; font-weight: 700; word-break: break-word; } | |
| .control-group { display: grid; gap: 12px; margin-top: 12px; } | |
| label.check, .radio-like { | |
| display: flex; align-items: flex-start; gap: 10px; | |
| border: 1px solid #e1ebf8; | |
| background: #f9fcff; | |
| border-radius: 14px; | |
| padding: 10px 12px; | |
| cursor: pointer; | |
| } | |
| input[type="checkbox"] { width: 18px; height: 18px; margin-top: 2px; accent-color: var(--blue); flex: 0 0 auto; } | |
| select, input[type="text"], textarea { | |
| width: 100%; border: 1px solid #d6e4f6; border-radius: 14px; padding: 11px 12px; | |
| font: inherit; color: var(--ink); background: #fff; | |
| } | |
| textarea { min-height: 96px; resize: vertical; } | |
| .state-panel { | |
| border-radius: 24px; padding: 22px; | |
| background: linear-gradient(135deg, #fff, #f7fbff); | |
| border: 1px solid #d7e6f9; | |
| position: sticky; top: 16px; | |
| } | |
| .state-badge { | |
| display: inline-flex; align-items: center; gap: .55rem; | |
| border-radius: 999px; padding: .6rem .85rem; | |
| font-weight: 900; letter-spacing: .04em; font-size: .84rem; | |
| text-transform: uppercase; | |
| border: 1px solid transparent; | |
| } | |
| .state-badge.HELD { background:#eaf4ff; color:#0a4ea8; border-color:#cfe5ff; } | |
| .state-badge.STRAINED { background:#fff6e4; color:#7a4b00; border-color:#f5d68c; } | |
| .state-badge.REPAIRING { background:#f0f3ff; color:#5136a3; border-color:#d9d2ff; } | |
| .state-badge.FALSE_CLOSURE_RISK { background:#fff0ef; color:#9c1d15; border-color:#ffd1ce; } | |
| .state-badge.CLOSED_FOR_CURRENT_SCOPE { background:#eaf8f3; color:#126a49; border-color:#c7efdf; } | |
| .meter { | |
| height: 14px; background:#e8f0fb; border-radius:999px; overflow:hidden; margin: 16px 0 10px; border: 1px solid #d7e5f7; | |
| } | |
| .meter > div { height: 100%; width: 0%; background: linear-gradient(90deg, var(--blue), var(--cyan)); transition: width .25s ease; } | |
| .flag-list { display: grid; gap: 8px; margin: 14px 0; padding: 0; list-style: none; } | |
| .flag-list li { | |
| display: flex; gap: 10px; align-items: flex-start; | |
| background: #f8fbff; border: 1px solid #e3eefb; border-radius: 14px; padding: 10px; | |
| } | |
| .flag-dot { width: 10px; height: 10px; border-radius: 50%; margin-top: 7px; background: var(--blue); flex: 0 0 auto; } | |
| .flag-list li.warn .flag-dot { background: var(--amber); } | |
| .flag-list li.risk .flag-dot { background: var(--red); } | |
| .flag-list li.good .flag-dot { background: var(--green); } | |
| .actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 16px; } | |
| button { | |
| border: 0; border-radius: 14px; padding: 11px 14px; | |
| background: var(--blue); color:#fff; font-weight: 850; cursor:pointer; | |
| box-shadow: 0 10px 24px rgba(15,101,214,.22); | |
| } | |
| button.secondary { background:#eef5ff; color:#0a4ea8; box-shadow:none; border:1px solid #cfe5ff; } | |
| button.ghost { background:transparent; color:#31506e; box-shadow:none; border:1px solid #d7e5f7; } | |
| button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible { outline: 3px solid rgba(15,101,214,.34); outline-offset: 2px; } | |
| .capsule-json { | |
| max-height: 310px; overflow:auto; | |
| background: #0f172a; color: #d8e5ff; | |
| border-radius: 18px; padding: 16px; font-family: var(--mono); font-size: .78rem; | |
| white-space: pre-wrap; border: 1px solid #22304f; | |
| } | |
| .layers { display:grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: 12px; } | |
| .layer-card { border-radius: 18px; padding: 16px; border: 1px solid #dbe9fa; background: #fff; } | |
| .layer-card b { display:block; margin-bottom: 6px; } | |
| footer { margin: 28px 0 10px; color: var(--muted); text-align:center; font-size:.9rem; } | |
| @media (max-width: 930px) { | |
| .grid.two, .grid.three, .layers, .flow { grid-template-columns: 1fr; } | |
| .state-panel { position: static; } | |
| .row { grid-template-columns: 1fr; gap: 2px; } | |
| .wrap { padding: 16px; } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <a class="skip-link" href="#main">Skip to prototype</a> | |
| <div class="wrap"> | |
| <header class="hero" role="banner"> | |
| <div class="kicker"><span class="pin" aria-hidden="true">TC</span> Public Review Prototype · v0.1</div> | |
| <h1>The C2PA / Adobe Bridge Layer</h1> | |
| <p class="subtitle">Trace Capsules, HIR/OAM pressure logic, and a lightweight integrity kernel for provenance-bearing content after it enters interpretation.</p> | |
| <div class="boundary" aria-label="Public review boundary"> | |
| <strong>Boundary:</strong> | |
| <span>This is an independent public-review demo. It is not an Adobe product claim, not a C2PA implementation, not a Content Credentials replacement, and not an assertion of affiliation, endorsement, adoption, approval, or inside knowledge.</span> | |
| </div> | |
| <div class="flow" aria-label="Bridge flow"> | |
| <div class="flow-step"><span>01</span><b>Create</b></div> | |
| <div class="flow-step"><span>02</span><b>Credential</b></div> | |
| <div class="flow-step"><span>03</span><b>Display</b></div> | |
| <div class="flow-step"><span>04</span><b>Capsule</b></div> | |
| <div class="flow-step"><span>05</span><b>Check</b></div> | |
| <div class="flow-step"><span>06</span><b>State</b></div> | |
| <div class="flow-step"><span>07</span><b>Return</b></div> | |
| </div> | |
| </header> | |
| <main id="main"> | |
| <section class="section grid two" aria-label="Prototype controls and output"> | |
| <div class="grid"> | |
| <article class="card" aria-labelledby="credential-title"> | |
| <h2 id="credential-title">Credential Summary</h2> | |
| <p class="small">Demo content card showing the public-facing side of a provenance-bearing trace. This does not inspect real C2PA data.</p> | |
| <div class="credential-media" role="img" aria-label="Abstract sample media card representing provenance-bearing creative content"> | |
| <span class="media-label"><span class="pin" aria-hidden="true">Cr</span> Sample credential signal</span> | |
| </div> | |
| <dl class="meta"> | |
| <div class="row"><dt>Content</dt><dd>Sample editorial image / article header</dd></div> | |
| <div class="row"><dt>Credential state</dt><dd id="metaCredential">Visible · demo only</dd></div> | |
| <div class="row"><dt>Origin claim</dt><dd>Created by Collin D. Weber · public review draft</dd></div> | |
| <div class="row"><dt>Use context</dt><dd id="metaUse">Public article / X post / prototype review</dd></div> | |
| </dl> | |
| </article> | |
| <article class="card" aria-labelledby="pressure-title"> | |
| <h2 id="pressure-title">Interactive Pressure Check</h2> | |
| <p class="small">Toggle trace conditions to see the Trace Capsule state and HIR/OAM flags update.</p> | |
| <div class="control-group"> | |
| <label class="check"><input id="credentialVisible" type="checkbox" checked><span><strong>Credential visible</strong><br><span class="micro">The viewer can access a provenance signal or summary.</span></span></label> | |
| <label class="check"><input id="sourcePointer" type="checkbox" checked><span><strong>Source pointer preserved</strong><br><span class="micro">The trace still routes toward origin or source context.</span></span></label> | |
| <label class="check"><input id="attributionPresent" type="checkbox" checked><span><strong>Attribution visible</strong><br><span class="micro">Creator / contributor path remains present where available.</span></span></label> | |
| <label class="check"><input id="uncertaintyVisible" type="checkbox" checked><span><strong>Uncertainty visible</strong><br><span class="micro">The output preserves what the trace does and does not support.</span></span></label> | |
| <label class="check"><input id="transformLabeled" type="checkbox" checked><span><strong>Transformation labeled</strong><br><span class="micro">Edits, summaries, remixes, or derivative context are disclosed.</span></span></label> | |
| <label class="check"><input id="sourceReturn" type="checkbox" checked><span><strong>Source-return path active</strong><br><span class="micro">The loop can return toward attribution, credential state, rights context, or repair.</span></span></label> | |
| <label class="check"><input id="repairActive" type="checkbox"><span><strong>Repair active</strong><br><span class="micro">A correction, clarification, attribution, or boundary repair is underway.</span></span></label> | |
| </div> | |
| <label for="claimScope" class="small" style="display:block;margin-top:16px;font-weight:800;">Claim scope</label> | |
| <select id="claimScope"> | |
| <option value="bounded">Bounded to what the trace supports</option> | |
| <option value="wide">Possibly broader than the trace supports</option> | |
| <option value="overclaim">Overclaims the trace as proof beyond scope</option> | |
| </select> | |
| <label for="summaryText" class="small" style="display:block;margin-top:16px;font-weight:800;">Current interpretation / summary boundary</label> | |
| <textarea id="summaryText">This demo trace can support provenance-aware review of source, attribution, uncertainty, and boundary. It should not be treated as proof beyond its current scope.</textarea> | |
| </article> | |
| </div> | |
| <aside class="state-panel" aria-labelledby="state-title"> | |
| <h2 id="state-title">Trace Capsule Output</h2> | |
| <div id="stateBadge" class="state-badge HELD" aria-live="polite">HELD</div> | |
| <div class="meter" aria-label="Trace stability meter"><div id="meterFill"></div></div> | |
| <p id="stateExplanation" class="small" aria-live="polite"></p> | |
| <div class="pill-row" id="capsulePills" aria-label="Capsule quick fields"></div> | |
| <h3>HIR/OAM Flags</h3> | |
| <ul id="flagList" class="flag-list" aria-live="polite"></ul> | |
| <div class="actions"> | |
| <button type="button" id="downloadJson">Download review packet</button> | |
| <button type="button" id="copyJson" class="secondary">Copy JSON</button> | |
| <button type="button" id="resetDemo" class="ghost">Reset demo</button> | |
| </div> | |
| </aside> | |
| </section> | |
| <section class="section grid two" aria-label="Trace capsule details"> | |
| <article class="card"> | |
| <h2>Trace Capsule Panel</h2> | |
| <p class="small">A Trace Capsule preserves the relationship between visible provenance and bounded interpretation. It does not replace the credential.</p> | |
| <dl class="meta" id="capsuleMeta"></dl> | |
| </article> | |
| <article class="card"> | |
| <h2>Review Packet Preview</h2> | |
| <pre id="jsonPreview" class="capsule-json" tabindex="0" aria-label="Trace Capsule JSON review packet preview"></pre> | |
| </article> | |
| </section> | |
| <section class="section card" aria-labelledby="layers-title"> | |
| <h2 id="layers-title">Public Layer Mapping</h2> | |
| <p class="small">This demo uses only observable public relationships. It does not assume private routing or internal implementation details.</p> | |
| <div class="layers"> | |
| <div class="layer-card"><b>Content Credentials</b><span class="small">Make provenance visible to users.</span></div> | |
| <div class="layer-card"><b>C2PA</b><span class="small">Provides the provenance standard layer.</span></div> | |
| <div class="layer-card"><b>Adobe-facing workflows</b><span class="small">Bring provenance into real creator, editing, and product environments.</span></div> | |
| <div class="layer-card"><b>Trace Capsules + HIR/OAM</b><span class="small">Preserve interpretation boundary, loop state, and source-return after visibility.</span></div> | |
| </div> | |
| </section> | |
| <section class="section grid three" aria-label="Use cases"> | |
| <article class="card"><h3>Creator Attribution</h3><p class="small">Keeps creator/source-return visible when content is clipped, remixed, reposted, summarized, or AI-ingested.</p></article> | |
| <article class="card"><h3>AI Summaries</h3><p class="small">Makes derivative AI output carry source, boundary, uncertainty, attribution, and claim scope.</p></article> | |
| <article class="card"><h3>Public Evidence</h3><p class="small">Separates trace authenticity from claim validity so genuine content is not overclaimed.</p></article> | |
| </section> | |
| <section class="section card" aria-labelledby="nonclaims-title"> | |
| <h2 id="nonclaims-title">What This Demo Does Not Claim</h2> | |
| <div class="pill-row"> | |
| <span class="pill red">No Adobe endorsement claim</span> | |
| <span class="pill red">No C2PA endorsement claim</span> | |
| <span class="pill red">No Content Credentials replacement</span> | |
| <span class="pill red">No cryptographic provenance implementation</span> | |
| <span class="pill red">No truth-proof claim</span> | |
| <span class="pill red">No private-system knowledge</span> | |
| <span class="pill red">No full-stack rewrite requirement</span> | |
| </div> | |
| </section> | |
| </main> | |
| <footer> | |
| Created and Developed by Collin D. Weber · Public review demo · Single-file HTML / inline CSS / inline JS · Demo data only | |
| </footer> | |
| </div> | |
| <script> | |
| const els = { | |
| credentialVisible: document.getElementById('credentialVisible'), | |
| sourcePointer: document.getElementById('sourcePointer'), | |
| attributionPresent: document.getElementById('attributionPresent'), | |
| uncertaintyVisible: document.getElementById('uncertaintyVisible'), | |
| transformLabeled: document.getElementById('transformLabeled'), | |
| sourceReturn: document.getElementById('sourceReturn'), | |
| repairActive: document.getElementById('repairActive'), | |
| claimScope: document.getElementById('claimScope'), | |
| summaryText: document.getElementById('summaryText'), | |
| stateBadge: document.getElementById('stateBadge'), | |
| stateExplanation: document.getElementById('stateExplanation'), | |
| meterFill: document.getElementById('meterFill'), | |
| flagList: document.getElementById('flagList'), | |
| capsulePills: document.getElementById('capsulePills'), | |
| capsuleMeta: document.getElementById('capsuleMeta'), | |
| jsonPreview: document.getElementById('jsonPreview'), | |
| downloadJson: document.getElementById('downloadJson'), | |
| copyJson: document.getElementById('copyJson'), | |
| resetDemo: document.getElementById('resetDemo'), | |
| metaCredential: document.getElementById('metaCredential') | |
| }; | |
| const stateText = { | |
| HELD: 'The trace is coherent enough to handle carefully. Source, credential, boundary, attribution, and uncertainty are visible.', | |
| STRAINED: 'Something needs clarification. The credential may be present, but context, attribution, uncertainty, or claim scope is under pressure.', | |
| REPAIRING: 'A repair path is active. Source-return, attribution, uncertainty, or context repair is underway.', | |
| FALSE_CLOSURE_RISK: 'The loop is at risk of being treated as closed before the trace supports closure. Narrow, repair, or stop the claim.', | |
| CLOSED_FOR_CURRENT_SCOPE: 'The current loop is handled honestly enough for its specific scope. Source, boundary, uncertainty, and return are intact.' | |
| }; | |
| function collect() { | |
| return { | |
| credential_visible: els.credentialVisible.checked, | |
| source_pointer_preserved: els.sourcePointer.checked, | |
| attribution_visible: els.attributionPresent.checked, | |
| uncertainty_visible: els.uncertaintyVisible.checked, | |
| transformation_labeled: els.transformLabeled.checked, | |
| source_return_active: els.sourceReturn.checked, | |
| repair_active: els.repairActive.checked, | |
| claim_scope: els.claimScope.value, | |
| interpretation_summary: els.summaryText.value.trim() | |
| }; | |
| } | |
| function evaluate(input) { | |
| let score = 100; | |
| const flags = []; | |
| const add = (type, title, detail, impact) => { flags.push({ type, title, detail, impact }); score -= impact; }; | |
| if (!input.credential_visible) add('risk', 'Credential non-display', 'Provenance may exist but is not visible to the user.', 22); | |
| else flags.push({ type: 'good', title: 'Credential visible', detail: 'The provenance signal can be accessed by the user.', impact: 0 }); | |
| if (!input.source_pointer_preserved) add('risk', 'Source pointer loss', 'The trace no longer routes cleanly toward origin or source context.', 24); | |
| else flags.push({ type: 'good', title: 'Source pointer preserved', detail: 'The trace can still return toward source context.', impact: 0 }); | |
| if (!input.attribution_visible) add('warn', 'Attribution weakening', 'Creator or contributor visibility is weakened.', 16); | |
| if (!input.uncertainty_visible) add('warn', 'Uncertainty erased', 'The output hides what the trace does and does not support.', 18); | |
| if (!input.transformation_labeled) add('warn', 'Transformation not labeled', 'A summary, edit, remix, or derivative context is not clearly disclosed.', 13); | |
| if (!input.source_return_active) add('warn', 'Source-return inactive', 'The loop does not preserve a clear route toward attribution, credential state, or repair.', 18); | |
| if (input.claim_scope === 'wide') add('warn', 'Claim scope widening', 'The current claim may be broader than the trace supports.', 18); | |
| if (input.claim_scope === 'overclaim') add('risk', 'Claim inflation / proof laundering', 'The trace is being treated as proof beyond its supported scope.', 31); | |
| let state = 'HELD'; | |
| if (input.repair_active) state = 'REPAIRING'; | |
| if (score >= 92 && input.claim_scope === 'bounded' && input.source_return_active && input.attribution_visible) state = 'CLOSED_FOR_CURRENT_SCOPE'; | |
| if (score < 92 && score >= 58 && !input.repair_active) state = 'STRAINED'; | |
| if ((input.claim_scope === 'overclaim' && !input.uncertainty_visible) || (!input.source_pointer_preserved && input.claim_scope !== 'bounded') || score < 50) state = 'FALSE_CLOSURE_RISK'; | |
| if (input.repair_active && state !== 'FALSE_CLOSURE_RISK') state = 'REPAIRING'; | |
| score = Math.max(0, Math.min(100, score)); | |
| if (!flags.length) flags.push({ type:'good', title:'No pressure flags', detail:'No degradation flags detected under current demo settings.', impact:0 }); | |
| return { score, state, flags }; | |
| } | |
| function capsule(input, result) { | |
| return { | |
| prototype: 'trace_capsule_bridge_v0_1_public_review_demo', | |
| boundary: 'Independent public-review demo. Not a C2PA implementation, Adobe product claim, endorsement claim, or cryptographic provenance replacement.', | |
| flow: ['Create','Credential','Display','Capsule','Check','State','Return'], | |
| credential_summary: { | |
| state: input.credential_visible ? 'visible_demo_signal' : 'not_visible_in_current_context', | |
| source_pointer: input.source_pointer_preserved ? 'preserved' : 'missing_or_weakened', | |
| origin_claim: 'Created by Collin D. Weber · public review draft', | |
| current_use_context: 'Public article / X post / prototype review' | |
| }, | |
| trace_capsule: { | |
| source_pointer: input.source_pointer_preserved, | |
| attribution_state: input.attribution_visible ? 'visible' : 'weakened', | |
| uncertainty_state: input.uncertainty_visible ? 'visible' : 'erased_or_hidden', | |
| transformation_label: input.transformation_labeled ? 'visible' : 'missing', | |
| claim_scope: input.claim_scope, | |
| interpretation_boundary: input.interpretation_summary, | |
| source_return_path: input.source_return_active ? 'active' : 'inactive', | |
| repair_path: input.repair_active ? 'active' : 'not_active' | |
| }, | |
| hir_oam_pressure_check: { | |
| trace_stability_score: result.score, | |
| loop_state: result.state, | |
| flags: result.flags | |
| }, | |
| generated_at: new Date().toISOString() | |
| }; | |
| } | |
| function render() { | |
| const input = collect(); | |
| const result = evaluate(input); | |
| const packet = capsule(input, result); | |
| els.stateBadge.className = 'state-badge ' + result.state; | |
| els.stateBadge.textContent = result.state.replaceAll('_', ' '); | |
| els.stateExplanation.textContent = stateText[result.state]; | |
| els.meterFill.style.width = result.score + '%'; | |
| els.metaCredential.textContent = input.credential_visible ? 'Visible · demo only' : 'Not visible in current context · demo only'; | |
| els.flagList.innerHTML = ''; | |
| result.flags.forEach(flag => { | |
| const li = document.createElement('li'); | |
| li.className = flag.type; | |
| li.innerHTML = '<span class="flag-dot" aria-hidden="true"></span><span><strong>' + escapeHtml(flag.title) + '</strong><br><span class="small">' + escapeHtml(flag.detail) + '</span></span>'; | |
| els.flagList.appendChild(li); | |
| }); | |
| const pills = [ | |
| ['Credential', input.credential_visible ? 'visible' : 'hidden', input.credential_visible ? 'green' : 'red'], | |
| ['Attribution', input.attribution_visible ? 'visible' : 'weakened', input.attribution_visible ? 'green' : 'amber'], | |
| ['Uncertainty', input.uncertainty_visible ? 'visible' : 'hidden', input.uncertainty_visible ? 'green' : 'amber'], | |
| ['Return', input.source_return_active ? 'active' : 'inactive', input.source_return_active ? 'green' : 'amber'], | |
| ['Claim', input.claim_scope, input.claim_scope === 'bounded' ? 'green' : input.claim_scope === 'wide' ? 'amber' : 'red'] | |
| ]; | |
| els.capsulePills.innerHTML = pills.map(([k,v,c]) => '<span class="pill '+ c +'">'+ escapeHtml(k) + ': ' + escapeHtml(v) + '</span>').join(''); | |
| const metaRows = [ | |
| ['Source pointer', input.source_pointer_preserved ? 'Preserved' : 'Missing / weakened'], | |
| ['Credential state', input.credential_visible ? 'Visible demo signal' : 'Not visible in current context'], | |
| ['Attribution state', input.attribution_visible ? 'Visible' : 'Weakened'], | |
| ['Uncertainty state', input.uncertainty_visible ? 'Visible' : 'Erased or hidden'], | |
| ['Claim boundary', input.claim_scope], | |
| ['Loop state', result.state.replaceAll('_', ' ')], | |
| ['Source-return', input.source_return_active ? 'Active' : 'Inactive'], | |
| ['Repair path', input.repair_active ? 'Active' : 'Not active'] | |
| ]; | |
| els.capsuleMeta.innerHTML = metaRows.map(([dt,dd]) => '<div class="row"><dt>'+ escapeHtml(dt) +'</dt><dd>'+ escapeHtml(dd) +'</dd></div>').join(''); | |
| els.jsonPreview.textContent = JSON.stringify(packet, null, 2); | |
| window.currentPacket = packet; | |
| } | |
| function escapeHtml(value) { | |
| return String(value).replace(/[&<>"']/g, ch => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[ch])); | |
| } | |
| function resetDemo() { | |
| els.credentialVisible.checked = true; | |
| els.sourcePointer.checked = true; | |
| els.attributionPresent.checked = true; | |
| els.uncertaintyVisible.checked = true; | |
| els.transformLabeled.checked = true; | |
| els.sourceReturn.checked = true; | |
| els.repairActive.checked = false; | |
| els.claimScope.value = 'bounded'; | |
| els.summaryText.value = 'This demo trace can support provenance-aware review of source, attribution, uncertainty, and boundary. It should not be treated as proof beyond its current scope.'; | |
| render(); | |
| } | |
| document.querySelectorAll('input, select, textarea').forEach(el => el.addEventListener('input', render)); | |
| document.querySelectorAll('input, select, textarea').forEach(el => el.addEventListener('change', render)); | |
| els.downloadJson.addEventListener('click', () => { | |
| const blob = new Blob([JSON.stringify(window.currentPacket || {}, null, 2)], { type: 'application/json' }); | |
| const url = URL.createObjectURL(blob); | |
| const a = document.createElement('a'); | |
| a.href = url; | |
| a.download = 'trace_capsule_review_packet_demo.json'; | |
| document.body.appendChild(a); | |
| a.click(); | |
| a.remove(); | |
| URL.revokeObjectURL(url); | |
| }); | |
| els.copyJson.addEventListener('click', async () => { | |
| const text = JSON.stringify(window.currentPacket || {}, null, 2); | |
| try { | |
| await navigator.clipboard.writeText(text); | |
| els.copyJson.textContent = 'Copied'; | |
| setTimeout(() => els.copyJson.textContent = 'Copy JSON', 1100); | |
| } catch (err) { | |
| els.jsonPreview.focus(); | |
| } | |
| }); | |
| els.resetDemo.addEventListener('click', resetDemo); | |
| render(); | |
| </script> | |
| </body> | |
| </html> | |