Aesthetic Programming
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Help
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Write
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    :::warning **CHANGE LOG**(有任何修改請在此通知) > [name=chia0] [time=Tue, Nov 21, 2023 5:35 PM] 註腳標註已修改成跟英文版一樣的了! > [name=andrew] 2023/12/11 00:55am 已上傳至 [gitlab repo](https://gitlab.com/aesthetic-programming/book/-/tree/master/source.zh_TW/7-VocableCode) ::: ![](https://hackmd.io/_uploads/BJ8e9SLoh.png) ## setup() 之所以用「言說程式碼」作為本章標題,是為了明確點出編寫程式這個行為,並不能簡單地化約,只考慮其功能面,而我們想要強調的是,程式碼反映了人類語言在表達和解釋方面固有的不穩定性。打個比方,程式碼既是腳本,也是表演本身,從這個意義上來說,程式碼隨時都準備好開始行動,說出自己要做什麼的同時,也著手進行這些事務。這種與言語(speech),或者更具體地說,與「言語行為理論」(speech-act theory)的類比,在《說話的程式碼》(Speaking Code)等軟體研究文獻中基礎甚為穩固,並可幫助我們巧妙地演示如何運用單詞「和」程式碼來做事。[^speech] 事實上,若說編程有點像是在說話,那我們也可以說它像詩歌,不僅具有表演性,更可以被閱讀,理想情況下還能大聲朗誦[^cox1]。書面程式碼的語法特性,與程式碼的執行/表演面其實有著明顯的相似之處,若以唸一首詩的方式大聲朗誦原始碼,這種相似性就會變得顯而易見。哲學家弗蘭克・比弗・布拉迪(Franco Bifo Berardi)做了一個很好的示範,他大聲朗讀了「我愛你」病毒的原始碼,另一位學者弗洛里安・克拉默(Florian Cramer)曾稱電腦病毒可以被視為一種詩歌形式[^language],布拉迪的做法正是將此一論點付諸實踐。這個例子更廣泛地參考了將語言表達作為現成物件的藝術家,包括達達主義式的共時詩歌(simultaneous poems),這些詩歌由不同語言的文字組成,且並須同時大聲朗讀,目的為揭示詞語的表達調性,而非其含義。軟體是由語言所建構,並以原始碼為符號組成的運算程序進行處理[^love]。如此說來,原始碼就像詩歌一樣,是玩弄語言的結構,在當前的「聲音」和即將出現的「聲音」之間,建立起仰賴於時間的相互作用。透過連結人類的語言和聲音,我們強調了所有程式碼的不穩定性,以及特定的意圖或含義,是如何輕易地被誤解和重塑再造。 許多學者和藝術家都曾探索說話和編程之間的連結,他們不僅將程式設計視為一種能創造出編程和文學混合形式的美學工具,更探討了兩者之間的實質聯繫和創意張力[^examples]。「說話」這個動作,是由活生生的人體所進行,這進一步提醒了我們,編程實作亦有「體」的存在,而要理解程式設計,也只能從更廣泛的基礎設施及其編寫脈絡(或可稱「創生」,poiesis)的角度切入。在本章中,我們將循上述思路進行探討,並細究人類主體的聲音,是以何種方式涉入編程的實務操作,以及編程本身如何將更廣泛的政治議題(特別是關乎「性」的問題)付諸「言說」。作為體現這些技術和美學性質的一種手段,我們將聚焦孫詠怡(Winnie Soon)創作的軟體藝術作品《言說程式碼》(Vocable Code)。 ![](https://hackmd.io/_uploads/SkUscBUi2.jpg) *圖 7.1:《言說程式碼》裝置藝術細節* ## start() 《言說程式碼》既是軟體藝術作品(軟體本身即藝術,而非用軟體創造藝術),也是結合原始碼和批判性寫作,體現「酷兒程式碼」(queer code)的「編程作品」(codework)。《言說程式碼》由重複的文字和聲音組成,收集了以「酷兒是」(Queer is)為開頭的句子(語音和文字皆有),並將這些句子以數學方式打亂,創造出一個動態的藝術品,從而探索程式碼的表驗性、主觀性和語言。隱身在網路介面的背後的程式碼本身,即是電腦程式語言和人類語言的混合體,旨在揭示(非)二元詩歌和酷兒電腦程式碼的脈絡之下,寫作和閱讀之間實質性的語言張力[^soon1]。 這項作品以雙螢幕形式呈現:一側顯示原始碼(編程作品),另一側則為展現程式碼如何運行和執行的視覺化介面(見圖 7.1 和 7.2)。在這種特別的佈局下,原始碼不再像大多數軟體的慣例那樣,隱藏在用戶看不到的地方,而是完整地呈現出來,從而撼動了原始碼及其產生的結果之間隱含的層次結構。在作品中,酷兒程式碼的概念既是主題,也是過程,並運作於多個層面上,讓軟體及其使用的公認規範化慣例「酷兒」化,從而劍指以下議題:人們期待中的前端介面究竟是什麼?它又是如何依循規範而執行?程式碼在人類和非人類執行面的表現特性,我們都能夠體驗到。當程式碼進入可執行狀態時,便融合了「形式和功能[^execute]」,並成為可供讀取、解釋、執行和表現之物。我們能看見程式碼,聽到編寫者的相關口頭陳述,而兩者的結合,讓程式得以「開口」與我們對話。 建構《言說程式碼》的核心方法,是利用約束或規則,這些約束可以在原始碼中看到,同時也能在表達不同節奏和含義的陳述式的言說規則中被辨識出來[^constraints]。以下列舉其中幾項約束: * 編寫原始碼時,請勿使用二進制的 0 或 1(例:宣告變數的值)、單個 X 或 Y(例:常用變數名稱)、單個「>」或「<」運算子(例:條件陳述式中常用的單一運算子)。 * 編寫原始碼時,請仔細留意變數、陣列和函式的命名。 * 每個特定的語音中,句子皆以短語「酷兒是」(Queer is)開頭。 * 每個特定的語音中,每一句話都至少包含一個單詞,但單詞總數不超過五個。 ## 課堂練習(解碼) RunMe, <https://dobbeltdagger.net/VocableCode_Educational/> ![](https://hackmd.io/_uploads/r1sloHqjn.jpg) *圖 7.2:《言說程式碼》的即時編程/教育版本* **任務一(解碼文字物件):** 請看一下《言說程式碼》的教育版本,並特別關注右側的動態文字顯示。您可以觀察到文字物件的某些特徵: 1. 黑色螢幕/畫布上總是會有文字。 2. 文字會向上移動,而大部分時候也會向下移動,但有時則會在兩者之間緩慢擺動。 3. 文字會隨著時間經過而消失。 4. 文字有不同大小。 5. 文字內容有部分重疊,但至少有十個不同或獨一無二的文字。 6. 螢幕上每顯示一批新文字,就會有其中一段文字的內容被朗誦出來。 7. 螢幕上同時出現的文字有最大數量限制(與之前的物件導向程式方法類似,若滿足某些條件,螢幕上便會連續產生出文字)。 8. 您是否能繼續將這個清單列下去呢? 《言說程式碼》程式採用物件導向的編程來建構類別和文字物件。請在不查看原始碼的情況下,回想我們在上一章中學到的內容: 1. 您可否描述一下文字上的類別的屬性和方法? 2. 您能否破解(新的)文字物件是在何時,以及透過何種方式被創造/移除? **任務二(推測與對照):** 根據您的所見所聞,您是否能描述一下程式中還實現了其他哪些功能/特色(尤其是與文字和語音相關)? 現在,請看一下原始碼,並特別留意類別-物件函式區塊 `notNew(getQueer){}`。您能否將原始碼與您之前對文字物件的描述相對照? **任務三(想一想):** 閱讀原始碼時,您會發現某些程式設計的風格與我們迄今為止學到的不同,如使用 `notTrue` 和 `notFalse` 的布爾邏輯(而非「True/False」)、循環小數、`abs` 函式,以及搭配回呼函式的 `loadSound` (而非 `preload` 函式)等等。 1. 您能否發現不同的風格? 2. 能否請您大聲朗誦這些區塊的程式碼? 3. 指定的閱讀資料中,是怎麼描述這些表達和表演式特質[^cox2]的?您可否以《言說程式碼》為例,描述並闡明這些特質? ## 文字性 在《言說程式碼》中,語音和文字是相互連結的。程式一次只會挑出一個指定的文字來朗讀/播放,而其他文字則動態顯示在螢幕上。您可以探索各個詞語的含義,但詞語的位置和其他設計屬性,將會進一步改變您感知和解釋這些陳述句的方式。文字的選擇、呈現、播放和朗誦都是隨機進行,同時又透過數學混沌進一步擾亂。 於這項作品中使用,並與文字相關的語法(程式碼片段)如下: ```javascript= let withPride;//font function preload(){ withPride = loadFont('Gilbert_TypeWithPride.otf'); } … function notNew(getQueer){ this.size = random(20.34387, 35.34387); this.time = random(2.34387, 4.34387); this.yyyyy = random(height/3.0, height+10.3437); this.xxxxx = width/2.0; this.gradient = 240.0; } … this.acts=function(){ textFont(withPride); textSize(this.size); textAlign(CENTER); this.gradient-=0.5; noStroke(); fill(this.gradient); text(getQueer, this.xxxxx, this.yyyyy); } ``` * * * ### 字體 `loadFont`(第 4 行)支援 opentype 字體(.otf 和 .ttf),並會透過上面的 `withPride` 回傳一個 PFont 物件。 「Gilbert_TypeWithPride.otf」是經過〈創用CC 姓名標示-相同方式分享 4.0 國際授權條款〉(Creative Commons Attribution-ShareAlike 4.0 International License)授權的免費字體,可從網路上下載(www.typewithpride.com)[^font],乃是為紀念標誌性彩虹旗的設計者吉爾伯特・貝克(Gilbert Baker)而創造,貝克先生已於 2017 年過世。 ![](https://hackmd.io/_uploads/BJZspScjn.jpg) *圖 7.3:「Type with Pride」字體。圖片取自:https://www.typewithpride.com/* `textFont()`(第 16 行)表示請程式準備好以選定字體在螢幕上輸出或寫出文字,已於此前透過回傳的 PFont 物件 `withPride` 進行定義。 `textSize()`(第 17 行)設定了要使用的字體大小。在此草稿碼中,字體大小為 20.34387 和 35.34387 之間的隨機值。 `textAlign()`(第 18 行)採用第一個引數進行水平對齊,包含「LEFT(靠左)」、「RIGHT(靠右)」和「CENTER(置中)」三個選項。句子的長度會根據所用單詞的數量而變化。在《言說程式碼》中,無論句子多長,文字都會置中對齊。 `noStroke()` 和 `fill()`(第 20-21 行)則針對形狀執行類似的操作。前者取消繪製筆觸(輪廓),而後者則設訂了文字填充顏色。`fill()` 可接受 RGB 值以及其他顏色格式。 `text()`(第 22 行)利用特定的單詞和位置(文字的水平和垂直坐標)在螢幕上繪製文字,例如:`text(getQueer, this.xxxxx, this.yyyyy);`。 ## 條件結構 《言說程式碼》中使用了幾種不同的 `if` 陳述式。 第一個條件結構的程式碼片段如下: ```javascript if (queers[WhoIsQueer].myStatement == "null" || makingStatements == int(2.34387)) { queerRights.push(new notNew(queers[WhoIsQueer].yourStatement)); makingStatements = 2.0; }else{ queerRights.push(new notNew(queers[WhoIsQueer].myStatement)); } ``` 第一個陳述式使用稱為 OR (||) 的關係運算子來檢查這兩個條件(關係運算的完整列表,請見本書第二章〈變數幾何〉的「關係運算」部分)。如果兩者任一為真,程式便會執行接下來的兩行程式碼(參見第 3-4 行)。當然,這兩個條件也可能不被滿足,在這種情況下,就會用到 `else` 這個程式碼區塊,以確定應選擇哪個新文字物件來顯示,由於每個人只能貢獻兩個口頭/文字陳述式,且有些人可能已經提供了一個,因此我們須先實施一些檢查邏輯,才能顯示文字。 以下為第二個條件結構的程式碼片段: ```javascript if(gender==abs(2)){ //決定該朗讀哪一個陳述式:參考 json 檔案 SpeakingCode(queers[WhoIsQueer].iam, makingStatements); } ``` 上面的條件結構僅使用了 `if` 陳述式,表示著若條件滿足,它將運行 `SpeakingCode` 函式,且不會有替代路徑,意即程式會退出條件結構,並在右大括號之後繼續執行。 第二個條件結構是用來確定要大聲朗讀的文字。每一批新的文字都包含兩到四個文字(參見下文完整原始碼中的第 19 行),而程式選擇了第三個文字(陣列索引以 [0] 為始,索引為 [2] 就表示第三個項目)。程式將根據被選出文字,播放相應的語音檔案。 `abs` 是 p5 中的語法和函式,用以計算數字的「絕對」值,且僅會回傳正值。 挑選出來向大家展示的這幾行程式碼,當然是專門針對與性別和性相關,更廣泛的政治議題而建構的,並意圖表達有關「酷兒程式碼」的想法。若要大聲朗讀此程式碼區塊,我們可能會將之翻譯為:「如果性別的絕對值等於二,就朗讀程式碼,酷兒,誰是酷兒,我就是,說出陳述式。」事實上,使用 `abs` 函式並無必要,我們也可以改寫程式,來選擇另一個陣列的索引。程式碼是由語言所建構,而程式設計師可以玩弄結構,並嘗試各種符號和語法邏輯,因此,程式也能被賦予詩意。《言說程式碼》也被視為編程作品或程式碼寫成的詩歌,鼓勵觀眾和機器大聲(而自豪地)唸出程式碼。 以下為第三個條件結構的程式碼片段: ```javascript functiondraw(){ … if (support == "notFalse") { queerRights.splice(non_binary, int(1.34387)); } … //何時產生新文字 -> 檢查螢幕上剩餘的文字數量 if (queerRights.length <= 2.0) { makeVisible(); } } ``` 函式 `draw()` 中有兩個條件陳述式,第一個 if 陳述式是用來檢查畫布外的文字,這項工作必須連續不間斷地進行,因為螢幕之外的文字實例(物件)將透過 `splice` 函式被刪除,以消除程式中不需要的元素/物件(就如第六章〈物件抽象化〉中的吃豆腐遊戲)。第二個 if 陳述式則可檢查螢幕上剩餘的文字數量,若數量少於或等於兩個,便將透過函式 `makeVisible()` 產生新文字。 以下為第四個條件結構的程式碼片段: ```javascript //檢查消失的物件 this.shows = function() { let status; if (this.yyyyy <= 4.34387 || this.yyyyy >= height+10.34387) { status = "notFalse"; } else { status = "notTrue"; } return status; }; ``` 最後一個「if-else」條件結構是設置在類別方法之中,並可檢查文字是否超出畫布,特別是畫布的 y 軸沿線。在類別方法 `this.shows=function()` 中,條件陳述式納入了關係運算子「OR」( `||` ),而且其中兩個條件都不需要為「真」(`if (this.yyyyy <= 4.34387 || this.yyyyy >= height+10.34387)`)。此外,程式中還有一個 `else` 陳述式,會於檢查條件是否滿足後,對檢查結果進行處理(參見第 6 行)。因此,此陳述式的意思,就是若兩條件之中任一被滿足,變數 `status` 將被指派為 `notFalse`(表示文字位於螢幕之外,超出畫布的上下兩端),如果文字仍然保留在畫面上,則將變數 `status` 指派為 `notTrue`。`notFalse` 和 `notTrue` 為 `status` 變數的值,乃是屬於「字串」型別。然而,在一般程式設計實務中,布林邏輯(使用「布林」型別)往往被理解為絕對的「真」或「假」二進制。一開始,這似乎是運算邏輯的基礎,而此二進制更可以與機器碼中以零和一簡化資訊的方式連結。不過,從概念上說,`notFalse` 和 `notTrue` 這種用法則暗含對二進制關係的拆解。 ## JSON 除了核心原始碼之外,《言說程式碼》還利用了以文字為基礎的 JSON 格式檔案,以儲存所有語音捐贈者的資料,包括他們的書面陳述(請參閱下方的 JSON 檔案片段)。若使用 JSON(Javascript 物件表示法,Javascript Object Notation),便可輕鬆更新 JSON 檔案中的所有資料,而無須更改任何 JavaScript 原始碼級別的內容。 JSON 檔案的片段: ```json { "description": "This file contains the meta data of queer text", "condition": "yourStatement cannot be null", "copyLeft": "Creative Common Licence BY 4.0", "lastUpdate": "Apr, 2019", "queers": [ { "iam": "WinnieSoon", "yourStatement": "not fixed not null", "myStatement": "not null not closed" },{ "iam": "GeoffCox", "yourStatement": "queer and that means queer", "myStatement": "null" },{ "iam": "GoogleAlgorithm", "yourStatement": "not a manifesto", "myStatement": "here" } ] } ``` JSON 是一種開放標準且獨立的檔案格式,廣泛用於網際網路上的資料儲存、通訊以及軟體應用程式中,並可被 JavaScript等多種程式語言讀取和處理。利用運算邏輯,軟體便可以操縱資料,例如以任何顏色、尺寸和速度在螢幕上檢索並顯示資料等。在軟體開發中,這種資料和運算邏輯之間的分離相當常見,舉例來說,Google 便使用其應用程式介面(API)以 JSON 格式提供網路或圖像搜尋結果。在下一章節裡,我們將更詳細地介紹 API。 在陣列和物件的使用方面,JSON 與 JavaScript 很類似,但採用了不同的格式。以下列出幾項規則: * 資料以名稱/值對的形式儲存,例如 `"copyLeft": "創用 CC 姓名標示 4.0 國際授權條款"`(`"copyLeft": "Creative Common Licence BY 4.0"`),兩者之間以冒號分隔。 * 所有屬性名稱/值對都必須用雙引號括起來。 * 每個資料項目之間均以逗號分隔。 * 方括號「[]」包含陣列。 * 大括號「{}」包含物件,因為有許多物件實例共用了相同的結構。 * 不可使用註解。 * 無法使用其他運算邏輯,如條件結構圖或迴圈。 處理 JSON 檔案,須使用 p5.js 中的語法 `loadJSON()`。請看下文,了解這如何在草稿碼之中組合成一體: **步驟一:loadJSON(載入特定的檔案和路徑)** ```javascript let whatisQueer; function preload(){ whatisQueer = loadJSON('voices.json'); } ``` **步驟二:處理 JSON 檔案(選定程式碼行數)** ```javascript function makeVisible(){ //取得 json txt queers = whatisQueer.queers; //要朗讀哪一個陳述,參考 json 檔案 SpeakingCode(queers[WhoIsQueer].iam, makingStatements); } ``` ![](https://hackmd.io/_uploads/HJLobQk32.jpg) *圖 7.4:《言說程式碼》中關於讀取 JSON 的片段* 載入 JSON 檔案 `voices.json` 後,程式會(參見圖 7.4)轉向 `queers` 陣列,並從隨機挑選的可能陳述式中查尋找名稱/值對 `iam` 和 `makingStatements` 來呼叫(其中包含 `yourStatement` 和 `myStatement` ),最後再呼叫函式 `SpeakingCode`。圖 7.4 說明了原始碼(左側)和 JSON 檔案(右側)之間的溝通是如何受到影響,以及如何透過在JSON 檔案和程式之間傳遞資料,從而讓資料顯示在螢幕上。 **步驟三:定位並載入聲音檔案** ```javascript //選出要用哪一個聲音朗讀並載入該聲音 function SpeakingCode(iam,makingStatements){ let getVoice = "voices/" + iam + makingStatements + ".wav"; speak = loadSound(getVoice, speakingNow); } ``` **步驟四:播放聲音檔案** ```javascript function speakingNow(){ speak.play(); } ``` 所有語音檔案都以「wav」聲音檔案格式儲存,並根據 JSON 檔案中 `iam` 字段後之特定慣例進行命名。透過此方式,我們可以使用運算子 `+` 連接或「串連」(程式設計術語,concatenate)所有片段,以便檢索並播放特定的語音檔案,如下所示:`let getVoice = "voices/" + iam + makingStatements + ".wav";`(參見步驟三中的第 3 行)。如上所述,所選的語音將與螢幕上的文字同步。 p5.sound 庫納入網頁音訊功能,讓 p5 函式庫能夠處理音效,在此則是播放語音檔案。在許多與音效相關的功能(例如在第四章〈資料擷取〉中展示,自音訊輸入擷取/聆聽)中,我們只須使用一些方法來載入和播放音訊檔案。為此,我們以 `loadSound()` 作為回呼函式,以確保聲音完全載入(由於涉及檔案大小、記憶體和硬體問題,這會需要一點時間),然後再執行 `speak.play()` 函式(參見步驟四中的第 2 行)。 `loadSound()` 可以在 `Preload()` 函式裡使用,而在此函式中,我們可以透過指定檔案路徑來提前載入檔案。然而,《言說程式碼》背後的創見更具詩意,將 JavaScript 原始碼作為核心語料庫予以保留,是該作品概念中的一環。這個程式沒有使用 `Preload()`,而是以「回呼函式[^callback]」來載入聲音,這或許並非最有效的方法,因為動態載入檔案時,會產生緩衝問題,但這種使用程式碼的方式,卻開啟了對語言結構的思考:即時而重複地載入、播放/說出檔案/聲音意味著什麼?此過程又調用了哪些形式的不穩定表達式? ## 原始碼 ```javascript= //CC BY 4.0-https://creativecommons.org/licenses/by/4.0/ let withPride; //font let whatisQueer; let queerRights=[]; let makingStatements; let speak; let voices=[]; let queers=[]; function preload(){ withPride = loadFont('Gilbert_TypeWithPride.otf'); //僅可在舊版 p5.js 上使用 whatisQueer = loadJSON('voices.json'); } //創造文字、決定要朗讀哪個文字,以及使用哪種語音 functionmakeVisible(){ //取得 json txt queers = whatisQueer.queers; //新增螢幕上的陳述式數量 let addQueers = int(random(2.34387, 4.34387)); //準備好逐一選取並新增螢幕上的陳述式 for (let gender = int(0.34387); gender <= addQueers; gender++) { //從 json list 清單中選取一項 let WhoIsQueer = int(random(queers.length)); makingStatements = int(random(2.34387, 3.34387)); //檢查所有空白陳述式(因為並非每個人都擁有兩個陳述式) if (queers[WhoIsQueer].myStatement == "null" || makingStatements == int(2.34387)) { queerRights.push(new notNew(queers[WhoIsQueer].yourStatement)); makingStatements = 2.0; }else{ //兩個陳述事都帶有值,須從中擇一 queerRights.push(new notNew(queers[WhoIsQueer].myStatement)); } //每一批新加入的文字,只會選擇第一個語音來朗讀 if (gender == abs(2)) { //決定該朗讀哪一個陳述式:參考 json 檔案 SpeakingCode(queers[WhoIsQueer].iam, makingStatements); } } } //選出要用哪一個聲音朗讀並載入該聲音 function SpeakingCode(iam,makingStatements){ let getVoice = "voices/" + iam + makingStatements + ".wav"; speak = loadSound(getVoice, speakingNow); } function speakingNow(){ speak.play(); } function setup(){ createCanvas(windowWidth, windowHeight); } function draw(){ background(2.34387); //文字的移動和顯示方式 for (let non_binary in queerRights){ queerRights[non_binary].worldWide(); queerRights[non_binary].acts(); //檢查畫布外的文字並刪除物件 let support = queerRights[non_binary].shows(); if (support == "notFalse") { queerRights.splice(non_binary, int(1.34387)); } } //何時產生新文字 ->檢查螢幕上文字剩餘數量 if (queerRights.length <= 2.0) { makeVisible(); } } //每次創造新文字(類別-物件) function notNew(getQueer){ //文字屬性 this.size = random(20.34387, 35.34387); this.time = random(2.34387, 4.34387); this.yyyyy = random(height/3.0, height+10.3437); this.xxxxx = width/2.0; this.gradient = 240.0; this.worldWide = function() { this.yyyyy -= this.time; this.time += sin(radians((frameCount%360.0)*this.time)) - 0.009; }; this.acts = function() { textFont(withPride); textSize(this.size); textAlign(CENTER); this.gradient-=0.5; noStroke(); fill(this.gradient); text(getQueer, this.xxxxx, this.yyyyy); }; //檢查消失的物件 this.shows = function() { let status; if (this.yyyyy <= 4.34387 || this.yyyyy >= height+10.34387) { status = "notFalse"; } else { status = "notTrue"; } return status; }; } ``` ## 課堂練習 1. 請找好組員,分組進行。 2. 請至 <https://gitlab.com/aesthetic-programming/book/-/tree/master/public/p5_SampleCode/ch7_VocableCode> 下載整個《言說程式碼》程式,並於您的電腦上執行。 3. 簡要討論一下各種運算結構和語法,以了解一般作業原理,隨後再仔細檢視語音檔案命名和 JSON 檔案結構之間的關係。 4. 按照說明,以電腦或手機錄下自己的聲音(程式僅接受 .wav 檔案格式)。 * 拿取一張白紙,以便待會在上面寫下一句話。 * 以指定的開頭「酷兒是」(Queer is)完成句子。 * 開頭「queer is」不計,每句話的單詞數量不能超過五個。您可以只加入一個單詞。 * 您最多可以寫出兩句話/錄下兩個語音。 * 在智慧型手機上下載/找到錄音應用程式(如 Android 上的 Voice Recorder 或 iOS 上的 Voice Memos)。 * 試著找一個安靜的環境,將自己的聲音錄下,然後以此測試應用程式是否有效(能否控制錄音的開始和結束)。 * 準備朗誦您自己寫下的句子並將語音錄下來。 * 您可以自行決定錄製的時間長短和節奏。 * 您可以使用不同的語調說出完整單詞或句子。 * 請錄下你的聲音,然後用 Audacity 等免費軟體將之轉換為 .wav 檔案。 5. 新增您的語音、更新 JSON 檔案,並將您的語音檔案放入「voices」資料夾中。之後,請重新整理一下程式,聽聽看您的聲音是否有出現在這些聲音之中。 6. 進階練習:您也可以試著更改文字呈現方式,例如顏色或動畫。 7. 請針對酷兒程式碼各種不同的批判和美學面向進行討論。 ## While() 在 JavaScript 等高階程式語言中,原始碼既傳送指令給機器,亦與人類溝通。因此,編寫原始碼便涉及了和記號和符號的使用,包括語義和句法,並可在程式語言和自然語言之間運作。而除了前文提到的詩意潛能之外,還有其他可能的介入方式,例如一款由黃令東所開發,以漢語古文為基礎的深奧程式語言「文言」,就仔細地依循了中國古典文學的語法和語氣[^Wenyan]。由此可見,記號和符號的使用,以及形式邏輯與詩意表達之間的結合,是理解言說程式碼的雙重邏輯的起點。 正如我們之前介紹的,抽象是軟體開發的基本概念之一,與機器作業不同,此過程乃是專注於將抽象建構為物件。呈現和執行原始碼的方式有很多種,例如使用類別/物件結構(文字作為物件實例)、條件結構、程序,以及 for 迴圈等副程式等等。然而,機器執行時,變數名稱(語義層面)這些人類可讀的資訊卻遭到剝離。除了佔用記憶體之外,變數名稱這類「輔助符號」並不會影響程式的執行,反之,它們更確實擁有其他的潛在用途[^Andersen]。因此,正如上例所明示,之所以選擇有意義的識別字(identifier)名稱,更多是為了順利溝通表達。而這裡正是我們能聽見程式設計師的聲音的地方。 此外,在思考原始碼對理解軟體作業有何重要性之時,我們務必要釐清,原始碼並不會顯示機器如何透過物理性的記憶體來作業(例如儲存、載入、新增和停止等動作),也無法展示機器是怎麼將符號式行動轉換為實際位址,或像低階程式語言那樣公開操作序列。此處的關鍵,是原始碼僅會描述您可能聽見/看到的內容,但並不能增進您對機器如何依循原始碼運行的其他相關知識。具體來說,《言說程式碼》上並排顯示著兩個介面,其一為原始碼,其二則為執行時的景況,但您眼中所見,與程式實際的作業方式卻有著一段差距。這點或許可透過以下兩種方式來理解: 其一,我們可以取得這個作品的原始碼,但從原始碼到機器碼的翻譯過程仍隱而未現,此外,也並非每一行程式碼都會被執行。全喜卿將此過程稱為「巫術」,並對這項問題下了如此的總結:「更高階程式語言(自動編程)的賣點,或許是它們可讓程式設計師更輕鬆地控制更多事物,然而,雖說這類程式語言理應指揮機器的運行,但在作業層面,卻也免不了變得更加黑箱[^Chun]。」因此,我們必須對「原始碼的確按照它所說的那樣執行」這種說法進行仔細的審視甄別,人類讀出原始碼的方式,與機器執行的方法並不相同。不過,我們應該要說明,人類的情況亦是如此,我們的外顯之相和行動之間,也存在著介面和轉譯過程。 其次,談到原始碼及其執行(通常是以螢幕介面的形式呈現),兩者不能直接劃上等號,而應視為彼此的轉譯,這準確點出了介面原則之中的「所見即所得」(WYSIWYG)。在《言說程式碼》中,四處移動的文字只是原始碼運行結果的一部分,並不能完全捕捉其作業的複雜性。因此,這項藝術作品或許可透過同時為前端和後端賦予「聲音」,甚至讓前後端的界線變得奇異而「酷兒化」,來挑戰常見、佔主導地位的前端介面,以及不同來源之間的意義傳遞。這顛覆了狀態之間的任何二元關係,以及因果的階層式邏輯,此處我們將援引凱倫・巴拉德(Karen Barad)的主張,即因果關係是在「動作內」(intra-action,酷兒因果律)發揮作用[^Barad]。 《言說程式碼》與身體方面的實踐、發聲行為,以及聲音如何與政治實務產生共鳴有直接關係。程式或程式設計師的聲音,與人類之聲和其他社會團體之間的結合所產生的意義,是無法簡單地表現或解釋的。換句話說,我們不能僅將運算化約為簡單的輸入和輸出形式邏輯,而說話的機器也不能單純地與說話的人類並列,兩者之間顯然有更千絲萬縷的深刻糾纏[^entangle]。不只人類,變數、引數、原始碼和機器碼等非人類行為者也會說話,為了讓例子更具體,此處我們會討論到帶有 `speak.play()` 函式的聲音資料庫。聲音涉及了政治的運作,畢竟有些聲音就是比其他聲音更響亮,而有些聲音卻被邊緣化或完全壓制。透過執行函式 `SpeakingCode(iam, makingStatements)`,我們提出了以下問題:是誰在說話?說話的對象是誰?又是在什麼樣的條件下說話?我們想讓這些關係變得更加奇異(酷兒)。 若把一和零視為在數學上具備同等地位的兩個數字,那運算從根本上來說,便具有明顯的權力動態。在《零+壹》(Zeros + Ones,1997)中,薩迪・普蘭(Sadie Plant)確認了所有電腦都會將資訊翻譯成機器碼的零和一,反映潛在的「西方現實秩序」: >「無論 […] 是收集資訊、遠端通訊、讓洗衣機運行、算術,還是製作影片,所有數位電腦都會將資訊轉換為機器碼的零和一。這兩個二進制數字稱為位元,並每八個一組串連成「位元組」。機器碼的零和一似乎象徵了完美的西方現實秩序,古老的邏輯代碼區分了開與關、左與右、光明與黑暗、形式與物質、心靈與身體、白與黑、善與惡、對與錯、生與死、有與無、此與彼、這裡與那裡、內與外、主動與被動、真與假、是與否、理智與瘋狂、健康與疾病、上與下、道理與謬論、西方與東方、北方與南方。在性方面,兩個數字堪稱一對可愛的情侶。男人和女人、雄性和雌性、陽剛和陰柔。零和一看起來是如此恰到好處,天生一對,「一」具有明確、直立的線條;「零」則是一幅什麼都沒有的圖表:陰莖和陰道、存在之物和空洞 […] ,兩者密切勾連,天造地設。」[^Plant1] 要形成二元關係(並建立異性戀主義範式),需要有兩方才行,不過,在主與從[^master]、家長與小孩,以及機器與人類等這些成雙配對裡,傾向於偏重其中一方,顯然展現了權利的不平等。正如第五章〈自動產生器〉,以及本書最後一章中進一步討論的那樣,圖靈測試與這些權力動態互相呼應,而普蘭也援引了圖靈的話:「建造這些機器,最初的意圖是將它們視為奴隸(從),分派給它們的,只能是經過詳細設想,而機器使用者又能無時無刻都通盤掌握狀況的工作[^Plant2]。」針對這種支配式幻想,普蘭進一步以科幻電影《銀翼殺手》(Bladerunner,1984)為例,其中主角「銀翼殺手」會進行一種先進的圖靈測試,以識破劇中仿生人唯一的人造跡象:非人類(仿生人)眼睛的虹膜,在回應有針對性的詢問時,會微微閃爍。而在電影中,這些非人奴工已經合情合理地開始質疑起他們的條件與處境。上述例子清楚地表明,以不同的方式想像條件與處境的能力,已嵌入在系統本身當中,亦即若規定的指令或命令不合理,則有可能會無法執行。 在圖靈的時代,同性戀在英國仍屬刑事犯罪[^Hodges],圖靈作為同性戀者,更進一步讓「拒絕不合理要求」這一主張更有分量。人類不一定會遵循或同意社會所訂定的規則,而儘管圖靈的性傾向在戰時是可容忍的,但在「正常」(和平時期)條件下,卻成了一個問題,因而在一九五二年遭判「嚴重行為不檢」而入罪[^Plant3]。正如普蘭所描述的,歷史事實在這裡崩解潰散成怪誕的寓言。圖靈先是被注射雌性激素,以減少他的性衝動,而這項處方,竟是依據「他其實是女性」這一可疑的邏輯。與此相反,之前的判決是強迫男同性戀者服用睪固酮,以使他們變得更加男性化,但諷刺的是,這反而讓他們的荷爾蒙更加活躍,導致性興奮程度提高。普蘭為圖靈的故事下了這樣的結語:「兩年後,他去世了,桌旁放有一顆已經被咬了好幾口的蘋果。但這個奇怪的故事並沒有結束。Apple 的每台麥金塔機器上,都帶有被圖靈咬過[^missing_bytes]的彩虹蘋果標誌[^Plant4]。」 在此,我們想特別強調:「酷兒是 […] 讓二元關係變得奇怪」,並以此總結本章,以及我們針對《言說程式碼》中奇怪的語法(如 notFalse 和 notTrue)和多個循環小數的「酷兒評論[^berlant]」。 ## 迷你習作:E-lit **目標:** * 了解 JSON 在儲存資料方面的實際運作方式,以及如何透過程式碼檢索資料。 * 反思程式碼和語言的美學,以及電子文學(electronic literautre,e-lit)的音訊面向。 **更多靈感:** * *[Dial](http://thenewriver.us/dial/)* (2020) by Lai-Tze Fan & Nick Montfort, with JavaScript [source code](https://nickm.com/fan_montfort/dial/). * *[Mexicans in Canada](http://amiraha.com/mexicansincanada/)* by Amira Hanafi (2020). * *A House of Dust* by Alison Knowles and James Tenney (1967), reimplemented by Nick Montfort for *Memory Slam* (2014), <https://nickm.com/memslam/a_house_of_dust.html>. * *Corpora - A repository of JSON files* by Darius Kazemi (n.d.), <https://github.com/dariusk/corpora/tree/master/data>. * *[e-lit collection1](http://collection.eliterature.org/1/)*. * *[e-lit collection2](http://collection.eliterature.org/2/)*. * *[e-lit collection3](http://collection.eliterature.org/3/)*. * *[RiTa library](https://rednoise.org/rita/)* by Daniel Howe (2006-ongoing). **任務(RunMe):** 1. 請設計一個電子文學作品,其中須以文字為主要媒介(不過,文字可以有多種形式,包含程式碼和聲音等)。 2. 請透過 JSON 檔案進行文字整理、儲存和檢索。 * * * **在您的 ReadMe 檔案中可供思考的問題:** * 請為您的作品取名並撰寫一段簡短的敘述(1,000 個字元以內)。 * 請描述您的程式如何運作、所使用的語法,以及您學習到了哪些語法。 **分析並闡釋**您的作品: * 請利用《言說程式碼》和/或《產生式程式碼的美學》(The Aesthetics of Generative Code),或其他討論程式碼/聲音/語言的文字,分析您自己的 e-lit 作品。 * 在《言說程式碼》的脈絡之下,您會如何反思自己的作品? ## 指定閱讀 * Geoff Cox and Alex McLean, "Vocable Code," in *Speaking Code* (Cambridge, MA: MIT Press, 2013), 17-38. * Allison Parrish, "Text and Type" (2019), <https://creative-coding.decontextualize.com/text-and-type/>. * Daniel Shiffman, "10.2: What is JSON? Part I - p5.js Tutorial" (2017), <https://www.youtube.com/playlist?list=PLRqwX-V7Uu6a-SQiI4RtIwuOrLJGnel0r>. * Daniel Shiffman, "10.2: What is JSON? Part II - p5.js Tutorial" (2017), <https://www.youtube.com/playlist?list=PLRqwX-V7Uu6a-SQiI4RtIwuOrLJGnel0r>. ## 延伸閱讀 * Geoff Cox, Alex McLean, and Adrian Ward, "The Aesthetics of Generative Code," Proceedings of Generative Art Conference, Milan (2001). * Liz W. Faber, *The Computer's Voice: From Star Trek to Siri* (Minneapolis, MN: University of Minnesota Press, 2020). * Rita Raley, "Interferences: Net.Writing and the Practice of Codework," *Electronic Book Review* (2002), <http://electronicbookreview.com/essay/interferences-net-writing-and-the-practice-of-codework/>. * Margaret Rhee, "Reflecting on Robots, Love, and Poetry," *XRDS: Crossroads* 24, no. 2, December (2017): 44–46, <https://dl.acm.org/doi/pdf/10.1145/3155126?download=true>. * Douglas Crockford, "The application/json Media Type for JavaScript Object Notation (JSON)." *RFC 4627* (2006), <https://www.ietf.org/rfc/rfc4627.txt>. ## 註釋 [^speech]: 這裡我們參考了約翰・朗肖・奧斯丁(John Langshaw Austin)的《如何以言行事》(How To Do Things With Words),以及傑夫・考克斯(Geoff Cox)和艾力克斯・麥連(Alex McLean)的《說話的程式碼》(Cambridge, MA: MIT Press 2013)。自由軟體基金會的定義,明確體現了自由軟體與言論自由之間的類比:自由軟體一詞表示使用者可以自由地運行、複製、散佈、研究、更改和改善軟體。「因此,『自由軟體』的議題關乎自由,而非價格。想要理解此概念,『free』一字應解釋為『言論自由』裡的『自由』,而不是『免費啤酒』裡的『免費』。」請參閱:<https://www.gnu.org/philosophy/free-sw.html>。 [^cox1]: Cox, *Speaking Code*, 17. [^language]: Florian Cramer, *Language in Software Studies*, 2008, 168-173;亦請參見:Warren Sack, *The Software Arts* (Cambridge, Mass.: MIT Press, 2019)。 [^love]: 弗洛里安・克拉默(Florian Cramer)的主張是在《我愛你》展覽(I love You,2002-4)的背景下提出的,《我愛你》係由 digitalcraft.org Kulturbüro 開發,現正進行中的展覽,請參閱:<http://www.digitalcraft.org/iloveyou/>。 [^examples]: 高德納(Donald Knuth)所言之「文學程式設計」與這裡的討論關係甚深,此種研究方法將程式視為文學作品,關注的對象是人類而非電腦。欲知更多這方面的資訊,請參閱:Donald Knuth's "Literate Programming," *The Computer Journal* 27, no.2 (1984): 97–111, <https://academic.oup.com/comjnl/article/27/2/97/343244>; <https://doi.org/10.1093/comjnl/27.2.97.>。更多相關討論的例子包括 Mez Breeze (1994)、John Cayley (2002)、Michael Mateas 和 Nick Montfort (2005)、Florian Cramer (2008)、Graham Harwood (2008)、Daniel Temkin (2011)、Zach Blas 和 Micha Cárdenas 的作品 (2012、2013)、Geoff Cox & Alex McLean (2013)、Allison Parrish (2015)、Ian Hatcher (2015、2016) 以及 Winnie Soon & Geoff Cox (2018)等等。 [^soon1]: Winnie Soon, "Vocable Code, *MAI: Feminism and Visual Culture* 2 (November 10, 2018), <https://maifeminism.com/vocable-code/>. [^execute]: Roopika Risam, *The Poetry of Executable Code* (2015), <http://jacket2.org/commentary/poetry-executable-code>. [^constraints]: 以約束為基礎的《言說程式碼》編寫之相關討論,請參閱:Eva Heisler, "Winnie Soon, Time, Code, and Poetry," *Asymptote Journal*, Jan (2020), <https://www.asymptotejournal.com/visual/winnie-soon-time-code-and-poetry/>。 [^cox2]: Cox, *Speaking Code*, 24. [^font]: 同時,您也可以找到許多供線上下載的免費、開源字體樣式。舉例來說,您可參見:<https://www.1001freefonts.com/>。 [^callback]: 可當作 `preload()` 和回呼(callback)函式使用的 `loadSound()` 函式,請參見:<https://p5js.org/reference/#/p5/loadSound>。 [^Wenyan]: 參見 <https://wy-lang.org/>。 [^Andersen]: 為研究作為符號載體的電腦系統,彼得・波格・安德森(Peter Bøgh Andersen)提出了一個符號學框架,以便了解符號之產生和解釋過程。此框架著重於形式/技術結構和非形式/可解釋符號的結合,而這點與本章內容相關,請參見:Peter Bøgh Andersen, "Computer Semiotics," *Scandinavian Journal of Information Systems* 4, no.1, (1992): 1, <https://aisel.aisnet.org/sjis/vol4/iss1/1/>。 [^Chun]: Wendy Hui Kyong Chun, *Programmed Visions: Software and Memory* (Cambridge, MA: MIT Press, 2011), 45. [^Barad]: Karen Barad, *Meeting the Universe Halfway: Quantum Physics and the Entanglement of Matter and Meaning* (Durham, North Carolina: Duke University Press, 2007). [^entangle]: 我們於此再度援引巴拉德的著作,以及她所強調的「動作內」(intra-action)人類和非人類實踐的糾葛。請參閱:Barad, *Meeting the Universe Halfway*. [^Plant1]: Sadie Plant, *Zeros + Ones: Digital Women and the New Technoculture* (London: Forth Estate, 1997), 34-35. [^master]: 這點已在第一章〈入門〉中討論過。 [^Plant2]: Plant, *Zeros + Ones*, 88. [^Hodges]: 有關這些歷史事件更詳細的敘述,請參閱:Andrew Hodges's *Alan Turing: The Enigma* (London: Burnett Books, 1983)。 [^Plant3]: Plant, *Zeros + Ones*, 98-99。更多酷兒群體與運算之間的連結之資訊,請參閱:<https://queercomputing.info/>。 [^missing_bytes]: 譯注:此處原文是「missing bytes」,意為「缺失的位元組」,與「咬了幾口」(bites)為諧音雙關。 [^Plant4]: Plant, *Zeros + Ones*, 102. [^berlant]: 勞倫・貝蘭特(Lauren Berlant)和麥可・華納(Michael Warner)討論了酷兒理論的實用性,以及他們更喜歡稱之為「酷兒評論」(queer commentary)的觀念,在學術界之外,「酷兒評論」這個詞可說是更實用、廣為大眾所知的術語。請參閱:Lauren Berlant and Michael Warner, "Guest Column: What Does Queer Theory Teach Us about X," *PMLA* 110, no. 3 (May 1995): 343–49。作為一項藝術品,《言說程式碼》已於諸多畫廊和藝術節中展出,不過,它並不僅只是一件徹頭徹尾只考慮實用性和教學的作品。《言說程式碼》首次公開推出,是作為「p5.js 中的女性主義編程研討會」的一部分,在一處獨立的藝術空間中進行。請參閱:Winnie Soon, "A Report on the Feminist Coding Workshop in p5.js," *Aesthetic Programming*, last updated November 30, 2017, <http://aestheticprogramming.siusoon.net/articles/a-report-on-the-feminist-coding-workshop-in-p5-js/>。

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully